diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..14d8b7b --- /dev/null +++ b/Makefile @@ -0,0 +1,14 @@ +OBJECTS = x-wm.o client.o + +x-wm: $(OBJECTS) + $(CC) $(CFLAGS) -o $@ $^ -lX11 -L /usr/X11R6/lib + +%.o: %.c + $(CC) $(CFLAGS) -c $*.c + +install: x-wm + strip $< + cp $< /home/x-way/local/bin + +clean: + rm -f *.o diff --git a/client.c b/client.c new file mode 100644 index 0000000..444be8b --- /dev/null +++ b/client.c @@ -0,0 +1,86 @@ +/* $Id$ */ +/* + * Copyright (c) 2007 Andreas Jaggi + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "client.h" + +XContext window_context; +//XContext frame_context; /* not used yet */ +//XContext decoration_context; /* not used yet */ + +void init_clients ( ) { + window_context = XUniqueContext(); +} + +Client* find_client ( Window w ) { + Client* c; + + if ( XFindContext(display, w, window_context, (void*)&c) != 0 ) { + c = NULL; + } + + return c; +} + +Client* create_client ( Window w ) { + XWindowAttributes winattr; + + Client* c = malloc(sizeof(Client)); + + if ( c == NULL ) { + fprintf(stderr, "x-wm: cannot create new Client, not enough memory\n"); + return NULL; + } + + XGetWindowAttributes(display, w, &winattr); + + c->window = w; + c->width = winattr.width; + c->height = winattr.height; + c->x = winattr.x; + c->y = winattr.y; + if ( c->width < DisplayWidth(display, DefaultScreen(display)) || c->height < DisplayHeight(display, DefaultScreen(display)) ) { + c->maximized = 0; + } else { + c->maximized = 1; + } + + XSaveContext(display, w, window_context, (void*)c); + + return c; +} + +void destroy_client ( Window w ) { + Client* c; + + c = find_client(w); + XDeleteContext(display, w, window_context); + + if ( c != NULL ) { + free(c); + } +} diff --git a/client.h b/client.h new file mode 100644 index 0000000..5edddc9 --- /dev/null +++ b/client.h @@ -0,0 +1,53 @@ +/* $Id$ */ +/* + * Copyright (c) 2007 Andreas Jaggi + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef _CLIENT_H_ +#define _CLIENT_H_ + +#include "X11/Xlib.h" +#include "X11/Xutil.h" +#include +#include + +typedef struct _Client { + Window window; + int width; + int height; + int x; + int y; + int maximized; +} Client; + +void init_clients(); +Client* find_client(Window w); +Client* create_client(Window w); +void destroy_client(Window w); + +extern Display* display; + +#endif diff --git a/x-wm.c b/x-wm.c new file mode 100644 index 0000000..9084e71 --- /dev/null +++ b/x-wm.c @@ -0,0 +1,527 @@ +/* $Id$ */ +/* + * Copyright (c) 2007 Andreas Jaggi + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "x-wm.h" +#include "client.h" + +Display* display; +int screen; +Window root; +Window focus; +Atom wm_delete_window; +Atom wm_protocols; +int clientcounter = 0; +int quit = 0; +char* startscript = NULL; + +void grab_keys(); +void grab_buttons(); +void loop(); +void handle_motion(XMotionEvent* ev); +void handle_crossing(XCrossingEvent* ev); +void handle_focus(XFocusChangeEvent* ev); +void handle_create(XCreateWindowEvent* ev); +void handle_destroy(XDestroyWindowEvent* ev); +void handle_buttonPress(XButtonEvent* ev); +void handle_keyPress(XKeyEvent* ev); +void close_window(Window w); + +int main ( int argc, char* argv[] ) { + + Window dw1, dw2; + Window* existing_windows; + + int i, win_count; + int r = -1; + int status; + + XSetWindowAttributes attr; + + while ( (r = getopt(argc, argv, "hlvs:")) != -1 ) { + switch ( r ) { + case 'h': + usage(); + exit(0); + case 'l': + license(); + exit(0); + case 'v': + version(); + exit(0); + case 's': + startscript = optarg; + break; + default: + usage(); + exit(1); + } + } + + fprintf(stdout, "starting x-wm...\n"); + + if ( startscript != NULL ) { + fprintf(stdout, "x-wm: running startscript: %s...\n", startscript); + switch ( fork() ) { + case 0: + execlp(startscript,startscript,0); + case -1: + fprintf(stderr, "x-wm: could not fork()!\n"); + default: + wait(&status); + + if ( WIFEXITED(status) ) { + fprintf(stderr, "x-wm: startscript (%s) ended with exit(%d)\n", startscript, WEXITSTATUS(status)); + } + if ( WIFSIGNALED(status) ) { + fprintf(stderr, "x-wm: startscript (%s) received signal %d\n", startscript, WTERMSIG(status)); + } + } + } + + if ( !(display = XOpenDisplay(NULL)) ) { + fprintf(stderr, "x-wm: cannot open display\n"); + exit(1); + } + + screen = DefaultScreen(display); + root = RootWindow(display, screen); + + attr.event_mask = 0 + //| SubstructureRedirectMask + //| SubstructureNotifyMask + | StructureNotifyMask + //| PropertyChangeMask + | EnterWindowMask + //| LeaveWindowMask + | ButtonPressMask + //| ButtonReleaseMask + | KeyPressMask + //| KeyReleaseMask + //| FocusChangeMask + //| PointerMotionMask + //| PointerMotionHintMask + //| Button1MotionMask + //| Button2MotionMask + //| Button3MotionMask + //| Button4MotionMask + //| Button5MotionMask + //| ButtonMotionMask + ; + + XChangeWindowAttributes(display, root, CWEventMask, &attr); + + wm_delete_window = XInternAtom(display, "WM_DELETE_WINDOW", False); + wm_protocols = XInternAtom(display, "WM_PROTOCOLS", False); + + grab_keys(); + + grab_buttons(); + + init_clients(); + + XQueryTree(display, root, &dw1, &dw2, &existing_windows, &win_count); + fprintf(stderr, "x-wm: win_count = %d\n", win_count); + for ( i = 0; i < win_count; i++ ) { + if ( existing_windows[i] != root ) { + clientcounter++; + create_client(existing_windows[i]); + } + } + XFree(existing_windows); + + fprintf(stderr, "x-wm: clientcount = %d\n", clientcounter); + + loop(); + + exit(0); +} + +void grab_buttons ( ) { + /* listen to mouse clicks into the root window */ + XGrabButton(display, Button1, 0, root, True, ButtonPressMask, GrabModeAsync, GrabModeAsync, None, None); + + /* listen to mouse clicks into the root window */ + XGrabButton(display, Button1, (Mod1Mask|ControlMask), root, True, ButtonPressMask, GrabModeAsync, GrabModeAsync, None, None); + + /* listen to scroll wheel + ALT */ + XGrabButton(display, Button4, Mod1Mask, root, True, ButtonPressMask, GrabModeAsync, GrabModeAsync, None, None); + XGrabButton(display, Button5, Mod1Mask, root, True, ButtonPressMask, GrabModeAsync, GrabModeAsync, None, None); + + /* listen to scroll wheel + ALT + Ctrl (+ Shift) */ + XGrabButton(display, Button4, (Mod1Mask|ControlMask), root, True, ButtonPressMask, GrabModeAsync, GrabModeAsync, None, None); + XGrabButton(display, Button5, (Mod1Mask|ControlMask), root, True, ButtonPressMask, GrabModeAsync, GrabModeAsync, None, None); + XGrabButton(display, Button4, (Mod1Mask|ControlMask|ShiftMask), root, True, ButtonPressMask, GrabModeAsync, GrabModeAsync, None, None); + XGrabButton(display, Button5, (Mod1Mask|ControlMask|ShiftMask), root, True, ButtonPressMask, GrabModeAsync, GrabModeAsync, None, None); +} + +void grab_keys ( ) { + /* listen to Alt+Tab in the root window */ + XGrabKey(display, XKeysymToKeycode(display, XStringToKeysym("Tab")), Mod1Mask, root, True, GrabModeAsync, GrabModeAsync); + /* listen to Alt+F4 in the root window */ + XGrabKey(display, XKeysymToKeycode(display, XStringToKeysym("F4")), Mod1Mask, root, True, GrabModeAsync, GrabModeAsync); + /* listen to Alt+F2 in the root window */ + XGrabKey(display, XKeysymToKeycode(display, XStringToKeysym("F2")), Mod1Mask, root, True, GrabModeAsync, GrabModeAsync); + /* listen to Alt+UP in the root window */ + XGrabKey(display, XKeysymToKeycode(display, XStringToKeysym("Up")), Mod1Mask, root, True, GrabModeAsync, GrabModeAsync); + /* listen to Alt+DOWN in the root window */ + XGrabKey(display, XKeysymToKeycode(display, XStringToKeysym("Down")), Mod1Mask, root, True, GrabModeAsync, GrabModeAsync); + /* listen to Alt+LEFT in the root window */ + XGrabKey(display, XKeysymToKeycode(display, XStringToKeysym("Left")), Mod1Mask, root, True, GrabModeAsync, GrabModeAsync); + /* listen to Alt+RIGHT in the root window */ + XGrabKey(display, XKeysymToKeycode(display, XStringToKeysym("Right")), Mod1Mask, root, True, GrabModeAsync, GrabModeAsync); +} + +void loop ( ) { + XEvent ev; + while ( !quit ) { + XNextEvent(display, &ev); + + switch ( ev.type ) { + case MotionNotify: + handle_motion(&(ev.xmotion)); + break; + case ButtonPress: + handle_buttonPress(&(ev.xbutton)); + break; + case KeyPress: + handle_keyPress(&(ev.xkey)); + break; + case EnterNotify: + handle_crossing(&(ev.xcrossing)); + break; + case CreateNotify: + handle_create(&(ev.xcreatewindow)); + break; + case DestroyNotify: + handle_destroy(&(ev.xdestroywindow)); + break; + default: + fprintf(stderr, "x-wm: received XEvent of unknown type %d\n", ev.type); + } + } +} + +void handle_destroy( XDestroyWindowEvent* ev ) { + fprintf(stdout, "x-wm: received XDestroyWindowEvent event\n"); + clientcounter--; + fprintf(stderr, "x-wm: clientcounter: %d\n", clientcounter); + destroy_client(ev->window); + + if ( ev->window == root ) { + fprintf(stderr, "x-wm: root window destroyed, quitting...\n"); + quit = 1; + } + + if ( clientcounter <= 0 ) { + fprintf(stderr, "x-wm: clientcounter <= 0 (%d), quitting...\n", clientcounter); + quit = 1; + } +} + +void handle_create ( XCreateWindowEvent* ev ) { + + fprintf(stdout, "x-wm: received XCreateWindowEvent event\n"); + + if ( find_client(ev->window) == NULL ) { + create_client(ev->window); + } + + XAddToSaveSet(display, ev->window); + XRaiseWindow(display, ev->window); + XSetInputFocus(display, ev->window, RevertToPointerRoot, CurrentTime); + + clientcounter++; + fprintf(stderr, "x-wm: clientcounter: %d\n", clientcounter); +} + +void handle_focus ( XFocusChangeEvent* ev ) { + /* TODO */ + fprintf(stdout, "x-wm: received XFocusChangeEvent event\n"); +} + +void handle_crossing ( XCrossingEvent* ev ) { + fprintf(stdout, "x-wm: received XCrossingEvent event: state %d\n", ev->state); + if ( ev->type == EnterNotify ) { + XUngrabButton(display, Button1, 0, root); + + fprintf(stdout, "x-wm: received EnterNotify event: state %d\n", ev->state); + XSetInputFocus(display, ev->window, RevertToPointerRoot, ev->time); + } + + if ( ev->type == LeaveNotify ) { + fprintf(stdout, "x-wm: received LeaveNotify event: state %d\n", ev->state); + XGrabButton(display, Button1, 0, root, True, ButtonPressMask, GrabModeAsync, GrabModeAsync, None, None); + } +} + +void handle_motion ( XMotionEvent* ev ) { + /* TODO */ + fprintf(stdout, "x-wm: received MotionNotify event: state %d\n", ev->state); +} + +void handle_buttonPress ( XButtonEvent* ev ) { + Window foo; + int bar,width,height; + XWindowAttributes winattr; + Client* c; + + fprintf(stdout, "x-wm: received ButtonPress event: button %d, state %d\n", ev->button, ev->state); + + while ( XCheckTypedEvent(display, ButtonPress, (XEvent*) ev) ) { } + + if ( XQueryPointer(display, root, &foo, &focus, &bar, &bar, &bar, &bar, &bar) == BadWindow ) { + fprintf(stderr, "x-wm: received BadWindow from XQueryPointer\n"); + } + + /* cycle through windows with scroll wheel + Alt */ + if ( ev->button == Button4 && ev->state == Mod1Mask ) { + if ( XCirculateSubwindowsUp(display, root) == BadWindow ) { + fprintf(stderr, "x-wm: error while cycling upwards through windows (BadWindow)\n"); + } else { + fprintf(stdout, "x-wm: cycle through windows\n"); + } + } + if ( ev->button == Button5 && ev->state == Mod1Mask ) { + if ( XCirculateSubwindowsDown(display, root) == BadWindow ) { + fprintf(stderr, "x-wm: error while cycling downwards through windows (BadWindow)\n"); + } else { + fprintf(stdout, "x-wm: cycle through windows\n"); + } + } + + if ( ev->button == Button1 ) { + switch ( ev->state ) { + case (Mod1Mask|ControlMask): + /* click into some window -> raise it */ + fprintf(stdout, "x-wm: raise window\n"); + XRaiseWindow(display, focus); + XSetInputFocus(display, focus, RevertToPointerRoot, CurrentTime); + //XSendEvent(display, focus, False, NoEventMask, (XEvent*)ev); + break; + case 0: + if ( focus == root || focus == None ) { + /* click into root window -> launch xterm */ + fprintf(stdout, "x-wm: launch xterm\n"); + if ( fork() == 0 ) { + execlp("xterm","xterm",0); + fprintf(stderr, "x-wm: failed to launch xterm\n"); + } + } + break; + } + } + + if ( focus == None ) { + return; + } + + /* resize focused window veticaly width scroll wheel + ALT + Ctrl */ + if ( (ev->button == Button4 || ev->button == Button5) && ev->state == (Mod1Mask|ControlMask) ) { + XGetWindowAttributes(display, focus, &winattr); + + width = winattr.width; + height = winattr.height; + + if ( ev->button == Button4 && height >= 10 ) { + XResizeWindow(display, focus, width, height-10); + + if ( (c = find_client(focus)) != NULL ) { + c->maximized = 0; + } + } + + if ( (c = find_client(focus)) == NULL || c->maximized == 0 ) { + if ( ev->button == Button5 && height+winattr.y <= DisplayHeight(display, screen)-10 ) { + XResizeWindow(display, focus, width, height+10); + } + } + } + + /* resize focused window horizontaly width scroll wheel + ALT + Ctrl + Shift */ + if ( (ev->button == Button4 || ev->button == Button5) && ev->state == (Mod1Mask|ControlMask|ShiftMask) ) { + XGetWindowAttributes(display, focus, &winattr); + + width = winattr.width; + height = winattr.height; + + if ( ev->button == Button4 && width >= 10) { + XResizeWindow(display, focus, width-10, height); + + if ( (c = find_client(focus)) != NULL ) { + c->maximized = 0; + } + } + + if ( (c = find_client(focus)) == NULL || c->maximized == 0 ) { + if ( ev->button == Button5 && width+winattr.x <= DisplayWidth(display, screen)-10) { + XResizeWindow(display, focus, width+10, height); + } + } + } +} + +void handle_keyPress ( XKeyEvent* ev ) { + Window foo; + int bar,x,y,width,height; + Client* c; + XWindowAttributes winattr; + + fprintf(stdout, "x-wm: received KeyPress event: keycode %d, state %d\n", ev->keycode, ev->state); + + if ( XQueryPointer(display, root, &foo, &focus, &bar, &bar, &bar, &bar, &bar) == BadWindow ) { + fprintf(stderr, "x-wm: received BadWindow from XQueryPointer\n"); + } + + if ( ev->keycode == XKeysymToKeycode(display, XStringToKeysym("Tab")) && ev->state == Mod1Mask ) { + /* cycle trough subwindows of root with Alt-Tab */ + if ( XCirculateSubwindowsUp(display, root) == BadWindow ) { + fprintf(stderr, "x-wm: error while cycling through windows (BadWindow)\n"); + } else { + fprintf(stdout, "x-wm: cycle through windows\n"); + } + } + + if ( focus == None ) { + return; + } + + if ( ev->keycode == XKeysymToKeycode(display, XStringToKeysym("F4")) && ev->state == Mod1Mask ) { + /* close window with Alt-F4 */ + fprintf(stdout, "x-wm: received close request for a window (Alt-F4)\n"); + close_window(focus); + } + + if ( ev->keycode == XKeysymToKeycode(display, XStringToKeysym("F2")) && ev->state == Mod1Mask ) { + /* maximize/restore window with Alt-F2 */ + + width = DisplayWidth(display, screen); + height = DisplayHeight(display, screen); + x = 0; + y = 0; + + c = find_client(focus); + + if ( c == NULL ) { + fprintf(stdout, "x-wm: found window without client struct\n"); + c = create_client(focus); + } + + if ( c->maximized ) { + fprintf(stdout, "x-wm: unmaximize window\n"); + c->maximized = 0; + x = c->x; + y = c->y; + width = c->width; + height = c->height; + } else { + XGetWindowAttributes(display, focus, &winattr); + fprintf(stdout, "x-wm: maximize window\n"); + + c->maximized = 1; + c->width = winattr.width; + c->height = winattr.height; + c->x = winattr.x; + c->y = winattr.y; + } + + XMoveResizeWindow(display, focus, x, y, width, height); + } + + if ( ev->keycode == XKeysymToKeycode(display, XStringToKeysym("Up")) && ev->state == Mod1Mask ) { + /* move window 'up' with Alt+UP */ + if ( (c = find_client(focus)) == NULL || c->maximized == 0 ) { + XGetWindowAttributes(display, focus, &winattr); + + if ( winattr.y >= 10 ) { + XMoveWindow(display, focus, winattr.x, winattr.y-10); + } + } + } + + if ( ev->keycode == XKeysymToKeycode(display, XStringToKeysym("Down")) && ev->state == Mod1Mask ) { + /* move window 'down' with Alt+Down */ + if ( (c = find_client(focus)) == NULL || c->maximized == 0 ) { + XGetWindowAttributes(display, focus, &winattr); + + if ( winattr.y <= DisplayHeight(display, screen) - winattr.height - 10 ) { + XMoveWindow(display, focus, winattr.x, winattr.y+10); + } + } + } + + if ( ev->keycode == XKeysymToKeycode(display, XStringToKeysym("Left")) && ev->state == Mod1Mask ) { + /* move window 'left' with Alt+Left */ + if ( (c = find_client(focus)) == NULL || c->maximized == 0 ) { + XGetWindowAttributes(display, focus, &winattr); + + if ( winattr.x >= 10 ) { + XMoveWindow(display, focus, winattr.x-10, winattr.y); + } + } + } + + if ( ev->keycode == XKeysymToKeycode(display, XStringToKeysym("Right")) && ev->state == Mod1Mask ) { + /* move window 'right' with Alt+Right */ + if ( (c = find_client(focus)) == NULL || c->maximized == 0 ) { + XGetWindowAttributes(display, focus, &winattr); + + if ( winattr.x <= DisplayWidth(display, screen) - winattr.width - 10 ) { + XMoveWindow(display, focus, winattr.x+10, winattr.y); + } + } + } +} + +void close_window ( Window w ) { + XEvent ev; + int protocols_count, i; + Atom* protocols; + + if ( XGetWMProtocols(display, w, &protocols, &protocols_count) ) { + for ( i = 0; i < protocols_count; i++ ) { + if ( protocols[i] == wm_delete_window ) { + ev.type = ClientMessage; + ev.xclient.window = w; + ev.xclient.message_type = wm_protocols; + ev.xclient.format = 32; + ev.xclient.data.l[0] = wm_delete_window; + ev.xclient.data.l[1] = CurrentTime; + + XSendEvent(display, w, False, NoEventMask, &ev); + XFree(protocols); + return; + } + } + + if ( protocols ) { + XFree(protocols); + } + } + + XKillClient(display, w); +} diff --git a/x-wm.h b/x-wm.h new file mode 100644 index 0000000..0f35385 --- /dev/null +++ b/x-wm.h @@ -0,0 +1,86 @@ +/* $Id$ */ +/* + * Copyright (c) 2007 Andreas Jaggi + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef _X_WM_H_ +#define _X_WM_H_ + +#include "X11/Xlib.h" +#include "X11/Xutil.h" +#include "X11/Xatom.h" + +#include +#include +#include +#include +#include + +extern Display* display; + +const char usagemsg[] = + "usage: x-wm\n" + " Look at the source code for further information.\n" + "\n" + "also: x-wm -v show version\n" + " x-wm -h display this help\n" + " x-wm -l display the (BSD) license\n" + ; + +const char versionmsg[] = "x-wm 0.0\n"; + +const char licensemsg[] = + "x-wm is copyright (c) 2007 Andreas Jaggi \n" + "All rights reserved.\n" + "\n" + "Redistribution and use in source and binary forms, with or without\n" + "modification, are permitted provided that the following conditions\n" + "are met:\n" + "1. Redistributions of source code must retain the above copyright\n" + " notice, this list of conditions and the following disclaimer.\n" + "2. Redistributions in binary form must reproduce the above copyright\n" + " notice, this list of conditions and the following disclaimer in the\n" + " documentation and/or other materials provided with the distribution.\n" + "3. The name of the author may not be used to endorse or promote products\n" + " derived from this software without specific prior written permission.\n" + "\n" + "THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR\n" + "IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES\n" + "OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.\n" + "IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,\n" + "INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT\n" + "NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\n" + "DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY\n" + "THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n" + "(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF\n" + "THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n" + ; + +#define license() fprintf(stdout, licensemsg) +#define version() fprintf(stdout, versionmsg) +#define usage() fprintf(stdout, usagemsg) + +#endif