]> Pileus Git - wmpus/blobdiff - sys-x11.c
Support graceful shutdown
[wmpus] / sys-x11.c
index 6290f80acbff90a91e29d293ed4e9303a8cd3c0b..7222b462141d7f5eb5a38b22ca62ef6585bdeaff 100644 (file)
--- a/sys-x11.c
+++ b/sys-x11.c
@@ -1,3 +1,18 @@
+/*
+ * Copyright (c) 2011, Andy Spencer <andy753421@gmail.com>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ */
+
 #include <stdio.h>
 #include <stdlib.h>
 #include <search.h>
@@ -12,7 +27,9 @@
 #include "sys.h"
 #include "wm.h"
 
+#ifndef BORDER
 #define BORDER 2
+#endif
 
 /* Internal structures */
 struct win_sys {
@@ -38,10 +55,12 @@ typedef enum {
 } color_t;
 
 /* Global data */
-static void *win_cache;
+static int   running;
+static void *cache;
 static Atom atoms[natoms];
 static int (*xerrorxlib)(Display *, XErrorEvent *);
 static unsigned long colors[ncolors];
+static list_t *screens;
 
 /* Conversion functions */
 static keymap_t key2sym[] = {
@@ -130,8 +149,25 @@ static Window getfocus(win_t *root, XEvent *event)
        return focus;
 }
 
-/* Helpers */
-static int add_strut(win_t *root, win_t *win)
+/* Strut functions
+ *   Struts are spaces at the edges of the screen that are used by
+ *   toolbars and statusbars such as dzen. */
+static int strut_copy(win_t *to, win_t *from, int scale)
+{
+       int left   = from->sys->strut.left;
+       int right  = from->sys->strut.right;
+       int top    = from->sys->strut.top;
+       int bottom = from->sys->strut.bottom;
+       if (left == 0 && right == 0 && top == 0 && bottom == 0)
+               return 0;
+       to->x += scale*(left      );
+       to->y += scale*(top       );
+       to->w -= scale*(left+right);
+       to->h -= scale*(top+bottom);
+       return 1;
+}
+
+static int strut_add(win_t *root, win_t *win)
 {
        /* Get X11 strut data */
        Atom ret_type;
@@ -144,38 +180,20 @@ static int add_strut(win_t *root, win_t *win)
        if (status != Success || ret_size != 32 || ret_items != 4)
                return 0;
 
-       int left   = ((int*)xdata)[0];
-       int right  = ((int*)xdata)[1];
-       int top    = ((int*)xdata)[2];
-       int bottom = ((int*)xdata)[3];
-       if (left == 0 && right == 0 && top == 0 && bottom == 0)
-               return 0;
-
-       win->sys->strut.left   = left;
-       win->sys->strut.right  = right;
-       win->sys->strut.top    = top;
-       win->sys->strut.bottom = bottom;
-       root->x += left;
-       root->y += top;
-       root->w -= left+right;
-       root->h -= top+bottom;
-       return 1;
+       win->sys->strut.left   = ((int*)xdata)[0];
+       win->sys->strut.right  = ((int*)xdata)[1];
+       win->sys->strut.top    = ((int*)xdata)[2];
+       win->sys->strut.bottom = ((int*)xdata)[3];
+       for (list_t *cur = screens; cur; cur = cur->next)
+               strut_copy(cur->data, win, 1);
+       return strut_copy(root, win, 1);
 }
 
-static int del_strut(win_t *root, win_t *win)
+static int strut_del(win_t *root, win_t *win)
 {
-       int left   = win->sys->strut.left;
-       int right  = win->sys->strut.right;
-       int top    = win->sys->strut.top;
-       int bottom = win->sys->strut.bottom;
-       if (left == 0 && right == 0 && top == 0 && bottom == 0)
-               return 0;
-
-       root->x -= left;
-       root->y -= top;
-       root->w += left+right;
-       root->h += top+bottom;
-       return 1;
+       for (list_t *cur = screens; cur; cur = cur->next)
+               strut_copy(cur->data, win, -1);
+       return strut_copy(root, win, -1);
 }
 
 /* Window functions */
@@ -217,16 +235,16 @@ static win_t *win_find(Display *dpy, Window xid, int create)
        win_sys_t sys = {.dpy=dpy, .xid=xid};
        win_t     tmp = {.sys=&sys};
        win_t **old = NULL, *new = NULL;
-       if ((old = tfind(&tmp, &win_cache, win_cmp)))
+       if ((old = tfind(&tmp, &cache, win_cmp)))
                return *old;
        if (create && (new = win_new(dpy,xid)))
-               tsearch(new, &win_cache, win_cmp);
+               tsearch(new, &cache, win_cmp);
        return new;
 }
 
 static void win_remove(win_t *win)
 {
-       tdelete(win, &win_cache, win_cmp);
+       tdelete(win, &cache, win_cmp);
        free(win->sys);
        free(win);
 }
@@ -241,7 +259,7 @@ static int win_viewable(win_t *win)
 }
 
 /* Drawing functions */
-unsigned long get_color(Display *dpy, const char *name)
+static unsigned long get_color(Display *dpy, const char *name)
 {
        XColor color;
        int screen = DefaultScreen(dpy);
@@ -258,7 +276,7 @@ static void process_event(int type, XEvent *ev, win_t *root)
        //printf("event: %d\n", type);
 
        /* Common data for all these events ... */
-       ptr_t ptr; mod_t mod;
+       ptr_t ptr = {}; mod_t mod = {};
        if (type == KeyPress    || type == KeyRelease    ||
            type == ButtonPress || type == ButtonRelease ||
            type == MotionNotify) {
@@ -322,7 +340,7 @@ static void process_event(int type, XEvent *ev, win_t *root)
        else if (type == UnmapNotify) {
                if ((win = win_find(dpy,ev->xunmap.window,0)) &&
                     win->sys->state == st_show) {
-                       if (!del_strut(root, win))
+                       if (!strut_del(root, win))
                                wm_remove(win);
                        else
                                wm_update();
@@ -346,7 +364,7 @@ static void process_event(int type, XEvent *ev, win_t *root)
                        .height = cre->height,
                });
 
-               /* This seems necessasairy for, but causes flicker
+               /* This seems necessary for, but causes flicker
                 * there could be a better way to do this */
                if ((win = win_find(dpy,ev->xmaprequest.window,0)))
                        sys_move(win, win->x, win->y, win->w, win->h);
@@ -354,7 +372,7 @@ static void process_event(int type, XEvent *ev, win_t *root)
        else if (type == MapRequest) {
                printf("map_req: %d\n", type);
                if ((win = win_find(dpy,ev->xmaprequest.window,1))) {
-                       if (!add_strut(root, win))
+                       if (!strut_add(root, win))
                                wm_insert(win);
                        else
                                wm_update();
@@ -381,19 +399,19 @@ static int xerror(Display *dpy, XErrorEvent *err)
        return xerrorxlib(dpy, err);
 }
 
-/*****************
- * Sys functions *
- *****************/
+/********************
+ * System functions *
+ ********************/
 void sys_move(win_t *win, int x, int y, int w, int h)
 {
        //printf("sys_move: %p - %d,%d  %dx%d\n", win, x, y, w, h);
        int b = 2*BORDER;
-       win->x = MAX(x,0);   win->y = MAX(y,0);
+       win->x = x; win->y = y;
        win->w = MAX(w,1+b); win->h = MAX(h,1+b);
        w      = MAX(w-b,1); h      = MAX(h-b,1);
        XMoveResizeWindow(win->sys->dpy, win->sys->xid, x, y, w, h);
 
-       /* Flush events, so moving window doesn't cuase re-focus
+       /* Flush events, so moving window doesn't cause re-focus
         * There's probably a better way to do this */
        XEvent ev;
        XSync(win->sys->dpy, False);
@@ -485,23 +503,25 @@ void sys_unwatch(win_t *win, Key_t key, mod_t mod)
 
 list_t *sys_info(win_t *win)
 {
-       int n;
-       XineramaScreenInfo *info = NULL;
-       if (XineramaIsActive(win->sys->dpy))
-               info = XineramaQueryScreens(win->sys->dpy, &n);
-       if (!info) {
-               win_t *screen = new0(win_t);
-               *screen = *win;
-               return list_insert(NULL, screen);
-       }
-       list_t *screens = NULL;
-       for (int i = 0; i < n; i++) {
-               win_t *screen = new0(win_t);
-               screen->x = info[i].x_org;
-               screen->y = info[i].y_org;
-               screen->w = info[i].width;
-               screen->h = info[i].height;
-               screens = list_append(screens, screen);
+       /* Use global copy of screens so we can add struts */
+       if (screens == NULL) {
+               int n;
+               XineramaScreenInfo *info = NULL;
+               if (XineramaIsActive(win->sys->dpy))
+                       info = XineramaQueryScreens(win->sys->dpy, &n);
+               if (!info) {
+                       win_t *screen = new0(win_t);
+                       *screen = *win;
+                       return list_insert(NULL, screen);
+               }
+               for (int i = 0; i < n; i++) {
+                       win_t *screen = new0(win_t);
+                       screen->x = info[i].x_org;
+                       screen->y = info[i].y_org;
+                       screen->w = info[i].width;
+                       screen->h = info[i].height;
+                       screens = list_append(screens, screen);
+               }
        }
        return screens;
 }
@@ -527,7 +547,7 @@ win_t *sys_init(void)
        colors[clr_urgent]  = get_color(dpy, "#ff0000");
        printf("colors = #%06lx #%06lx #%06lx\n", colors[0], colors[1], colors[2]);
 
-       /* Selec Window Managmenet events */
+       /* Select window management events */
        XSelectInput(dpy, xid, SubstructureRedirectMask|SubstructureNotifyMask);
        XSetInputFocus(dpy, None, RevertToNone, CurrentTime);
        xerrorxlib = XSetErrorHandler(xerror);
@@ -544,16 +564,22 @@ void sys_run(win_t *root)
                                &par, &xid, &kids, &nkids))
                for(int i = 0; i < nkids; i++) {
                        win_t *win = win_find(root->sys->dpy, kids[i], 1);
-                       if (win && win_viewable(win) && !add_strut(root,win))
+                       if (win && win_viewable(win) && !strut_add(root,win))
                                wm_insert(win);
                }
        wm_update(); // For struts
 
        /* Main loop */
-       for(;;)
+       running = 1;
+       while (running)
        {
                XEvent ev;
                XNextEvent(root->sys->dpy, &ev);
                process_event(ev.type, &ev, root);
        }
 }
+
+void sys_exit(void)
+{
+       running = 0;
+}