JasonWoof Got questions, comments, patches, etc.? Contact Jason Woofenden
Better, hopefully math-exception-free logic for multi-column stacker, and
[spectrwm.git] / scrotwm.c
index 43ce724..3fb090f 100644 (file)
--- a/scrotwm.c
+++ b/scrotwm.c
@@ -128,9 +128,9 @@ u_int32_t           swm_debug = 0
 #define BUTTONMASK             (ButtonPressMask|ButtonReleaseMask)
 #define MOUSEMASK              (BUTTONMASK|PointerMotionMask)
 #define SWM_PROPLEN            (16)
-#define X(r)                   (r)->g.x        
+#define X(r)                   (r)->g.x
 #define Y(r)                   (r)->g.y
-#define WIDTH(r)               (r)->g.w        
+#define WIDTH(r)               (r)->g.w
 #define HEIGHT(r)              (r)->g.h
 
 #ifndef SWM_LIB
@@ -143,6 +143,7 @@ int                 (*xerrorxlib)(Display *, XErrorEvent *);
 int                    other_wm;
 int                    running = 1;
 int                    ss_enabled = 0;
+int                    xrandr_support;
 int                    xrandr_eventbase;
 int                    ignore_enter = 0;
 unsigned int           numlockmask = 0;
@@ -266,8 +267,10 @@ struct workspace {
        struct {
                                int horizontal_msize;
                                int horizontal_mwin;
+                               int horizontal_stacks;
                                int vertical_msize;
                                int vertical_mwin;
+                               int vertical_stacks;
        } l_state;
 };
 
@@ -279,8 +282,8 @@ enum        { SWM_S_COLOR_BAR, SWM_S_COLOR_BAR_BORDER, SWM_S_COLOR_BAR_FONT,
 struct swm_screen {
        int                     idx;            /* screen index */
        struct swm_region_list  rl;     /* list of regions on this screen */
+       struct swm_region_list  orl;    /* list of old regions */
        Window                  root;
-       int                     xrandr_support;
        struct workspace        ws[SWM_WS_MAX];
 
        /* colors */
@@ -313,6 +316,10 @@ union arg {
 #define SWM_ARG_ID_CYCLEWS_DOWN        (13)
 #define SWM_ARG_ID_CYCLESC_UP  (14)
 #define SWM_ARG_ID_CYCLESC_DOWN        (15)
+#define SWM_ARG_ID_COLINC      (16)
+#define SWM_ARG_ID_COLDEC      (17)
+#define SWM_ARG_ID_ROWINC      (16)
+#define SWM_ARG_ID_ROWDEL      (17)
 #define SWM_ARG_ID_SS_ALL      (0)
 #define SWM_ARG_ID_SS_WINDOW   (1)
 #define SWM_ARG_ID_DONTCENTER  (0)
@@ -408,8 +415,7 @@ setscreencolor(char *val, int i, int c)
                    i, ScreenCount(display));
 }
 
-void           new_region(struct swm_screen *, struct workspace *,
-                           int, int, int, int);
+void           new_region(struct swm_screen *, int, int, int, int);
 
 void
 custom_region(char *val)
@@ -435,7 +441,7 @@ custom_region(char *val)
                    "(%ux%u)\n", w, h, x, y,
                    DisplayWidth(display, sidx), DisplayHeight(display, sidx));
            
-       new_region(&screens[sidx], NULL, x, y, w, h);
+       new_region(&screens[sidx], x, y, w, h);
 }
 
 int
@@ -864,7 +870,7 @@ restart(struct swm_region *r, union arg *args)
 struct swm_region *
 root_to_region(Window root)
 {
-       struct swm_region       *r;
+       struct swm_region       *r = NULL;
        Window                  rr, cr;
        int                     i, x, y, wx, wy;
        unsigned int            mask;
@@ -874,20 +880,17 @@ root_to_region(Window root)
                        break;
 
        if (XQueryPointer(display, screens[i].root, 
-           &rr, &cr, &x, &y, &wx, &wy, &mask) == False) {
-               /* if we can't query the pointer, grab the first region */
-               r = TAILQ_FIRST(&screens[i].rl);
-       } else {
-               /* otherwise, choose a region based on pointer location */
-               TAILQ_FOREACH(r, &screens[i].rl, entry) {
+           &rr, &cr, &x, &y, &wx, &wy, &mask) != False) {
+               /* choose a region based on pointer location */
+               TAILQ_FOREACH(r, &screens[i].rl, entry)
                        if (x >= X(r) && x <= X(r) + WIDTH(r) &&
                            y >= Y(r) && y <= Y(r) + HEIGHT(r))
                                break;
-               }
-
-               if (r == NULL)
-                       r = TAILQ_FIRST(&screens[i].rl);
        }
+
+       if (r == NULL)
+               r = TAILQ_FIRST(&screens[i].rl);
+
        return (r);
 }
 
@@ -1027,13 +1030,14 @@ switchws(struct swm_region *r, union arg *args)
        if (!other_r) {
                /* if the other workspace is hidden, switch windows */
                /* map new window first to prevent ugly blinking */
+               old_ws->r = NULL;
+               old_ws->restack = 1;
+
                TAILQ_FOREACH(win, &new_ws->winlist, entry)
                        XMapRaised(display, win->id);
 
                TAILQ_FOREACH(win, &old_ws->winlist, entry)
                        XUnmapWindow(display, win->id);
-               old_ws->r = NULL;
-               old_ws->restack = 1;
        } else {
                other_r->ws = old_ws;
                old_ws->r = other_r;
@@ -1306,7 +1310,7 @@ stack_master(struct workspace *ws, struct swm_geometry *g, int rot, int flip)
        XWindowChanges          wc;
        struct swm_geometry     win_g, r_g = *g;
        struct ws_win           *win, *winfocus;
-       int                     i, j, w_inc, h_inc, w_base, h_base;
+       int                     i, j, s, w_inc, h_inc, w_base, h_base, stacks; 
        int                     hrh, extra, h_slice, last_h = 0;
        int                     split, colno, winno, mwin, msize, mscale;
        int                     remain, missing, v_slice;;
@@ -1328,22 +1332,27 @@ stack_master(struct workspace *ws, struct swm_geometry *g, int rot, int flip)
                w_base = win->sh.base_width;
                mwin = ws->l_state.horizontal_mwin;
                mscale = ws->l_state.horizontal_msize;
+               stacks = ws->l_state.horizontal_stacks;
                SWAPXY(&r_g);
        } else {
                w_inc = win->sh.height_inc;
                w_base = win->sh.base_height;
                mwin = ws->l_state.vertical_mwin;
                mscale = ws->l_state.vertical_msize;
+               stacks = ws->l_state.vertical_stacks;
        }
        win_g = r_g;
 
+       if (stacks > winno - mwin)
+               stacks = winno - mwin;
+
        h_slice = r_g.h / SWM_H_SLICE;
        if (mwin && winno > mwin) {
                v_slice = r_g.w / SWM_V_SLICE;
 
                split = mwin;
                colno = split;
-               msize = v_slice * mscale;
+               win_g.w = v_slice * mscale;
 
                if (w_inc > 1 && w_inc < v_slice) {
                        /* adjust for window's requested size increment */
@@ -1359,32 +1368,44 @@ stack_master(struct workspace *ws, struct swm_geometry *g, int rot, int flip)
                        }
                }
 
-               win_g.w = msize;
+               msize = win_g.w;
                if (flip) 
                        win_g.x += r_g.w - msize;
        } else {
-               colno = winno;
-               split = 0;
+               if (stacks > 1) {
+                       colno = split = (winno - mwin) / stacks;
+               } else {
+                       split = 0;
+                       colno = winno;
+               }
        }
        hrh = r_g.h / colno;
        extra = r_g.h - (colno * hrh);
        win_g.h = hrh - 2;
 
        /*  stack all the tiled windows */
-       i = j = 0;
+       i = j = 0, s = stacks;
        TAILQ_FOREACH(win, &ws->winlist, entry) {
                if (win->transient != 0 || win->floating != 0)
                        continue;
 
                if (split && i == split) {
-                       colno = winno - split;
+                       colno = (winno - mwin) / stacks;
+                       if (s <= (winno - mwin) % stacks)
+                               colno++;
+                       split = split + colno;
                        hrh = (r_g.h / colno);
                        extra = r_g.h - (colno * hrh);
                        if (flip)
                                win_g.x = r_g.x;
                        else
-                               win_g.x += msize + 2;
-                       win_g.w = r_g.w - (msize + 2);
+                               win_g.x += win_g.w + 2;
+                       win_g.w = (((r_g.w - (msize + 2)) -
+                           ((stacks - 1) * 2)) / stacks);
+                       if (s == 1)
+                               win_g.w += (((r_g.w - (msize + 2)) -
+                                   ((stacks - 1) * 2)) % stacks);
+                       s--;
                        j = 0;
                }
                win_g.h = hrh - 2;
@@ -1392,7 +1413,7 @@ stack_master(struct workspace *ws, struct swm_geometry *g, int rot, int flip)
                        h_inc = win->sh.width_inc;
                        h_base = win->sh.base_width;
                } else {
-                       h_inc = win->sh.height_inc;     
+                       h_inc = win->sh.height_inc;
                        h_base = win->sh.base_height;
                }
                if (j == colno - 1) {
@@ -1461,6 +1482,7 @@ vertical_config(struct workspace *ws, int id)
        case SWM_ARG_ID_STACKINIT:
                ws->l_state.vertical_msize = SWM_V_SLICE / 2;
                ws->l_state.vertical_mwin = 1;
+               ws->l_state.vertical_stacks = 1;
                break;
        case SWM_ARG_ID_MASTERSHRINK:
                if (ws->l_state.vertical_msize > 1)
@@ -1476,6 +1498,12 @@ vertical_config(struct workspace *ws, int id)
        case SWM_ARG_ID_MASTERDEL:
                if (ws->l_state.vertical_mwin > 0)
                        ws->l_state.vertical_mwin--;
+       case SWM_ARG_ID_COLINC:
+               ws->l_state.vertical_stacks++;
+               break;
+       case SWM_ARG_ID_COLDEC:
+               if (ws->l_state.vertical_stacks > 1)
+                       ws->l_state.vertical_stacks--;
                break;
        default:
                return;
@@ -1500,6 +1528,7 @@ horizontal_config(struct workspace *ws, int id)
        case SWM_ARG_ID_STACKINIT:
                ws->l_state.horizontal_mwin = 1;
                ws->l_state.horizontal_msize = SWM_H_SLICE / 2;
+               ws->l_state.horizontal_stacks = 1;
                break;
        case SWM_ARG_ID_MASTERSHRINK:
                if (ws->l_state.horizontal_msize > 1)
@@ -1516,6 +1545,12 @@ horizontal_config(struct workspace *ws, int id)
                if (ws->l_state.horizontal_mwin > 0)
                        ws->l_state.horizontal_mwin--;
                break;
+       case SWM_ARG_ID_COLINC:
+               ws->l_state.horizontal_stacks++;
+               break;
+       case SWM_ARG_ID_COLDEC:
+               if (ws->l_state.horizontal_stacks > 1)
+                       ws->l_state.horizontal_stacks--;
        default:
                return;
        }
@@ -1684,6 +1719,8 @@ struct key {
        { MODKEY,               XK_l,           stack_config,   {.id = SWM_ARG_ID_MASTERGROW} },
        { MODKEY,               XK_comma,       stack_config,   {.id = SWM_ARG_ID_MASTERADD} },
        { MODKEY,               XK_period,      stack_config,   {.id = SWM_ARG_ID_MASTERDEL} },
+       { MODKEY | ShiftMask,   XK_comma,       stack_config,   {.id = SWM_ARG_ID_COLINC} },
+       { MODKEY | ShiftMask,   XK_period,      stack_config,   {.id = SWM_ARG_ID_COLDEC} },
        { MODKEY,               XK_Return,      swapwin,        {.id = SWM_ARG_ID_SWAPMAIN} },
        { MODKEY,               XK_j,           focus,          {.id = SWM_ARG_ID_FOCUSNEXT} },
        { MODKEY,               XK_k,           focus,          {.id = SWM_ARG_ID_FOCUSPREV} },
@@ -2059,7 +2096,7 @@ manage_window(Window id)
                DNPRINTF(SWM_D_MISC, "manage_window: win %u transient %u\n",
                    (unsigned)win->id, win->transient);
        }
-       
+
        /*
         * Figure out where to put the window. If it was previously assigned to
         * a workspace (either by spawn() or manually moving), and isn't
@@ -2135,7 +2172,11 @@ unmanage_window(struct ws_win *win)
 
        DNPRINTF(SWM_D_MISC, "unmanage_window:  %lu\n", win->id);
 
+       /* don't unmanage if we are switching workspaces */
        ws = win->ws;
+       if (ws->restack)
+               return;
+
        /* find a window to focus */
        if (ws->focus == win)
                ws->focus = TAILQ_PREV(win, ws_win_list, entry);
@@ -2405,28 +2446,10 @@ getstate(Window w)
 }
 
 void
-remove_region(struct swm_region *r) 
-{
-       struct swm_screen       *s = r->s;
-       struct ws_win           *win;
-
-       DNPRINTF(SWM_D_MISC, "removing region: screen[%d]:%dx%d+%d+%d\n",
-            s->idx, WIDTH(r), HEIGHT(r), X(r), Y(r));
-
-       TAILQ_FOREACH(win, &r->ws->winlist, entry)
-               XUnmapWindow(display, win->id);
-       r->ws->r = NULL;
-
-       XDestroyWindow(display, r->bar_window);
-       TAILQ_REMOVE(&s->rl, r, entry);
-       free(r);
-}
-
-void
-new_region(struct swm_screen *s, struct workspace *ws,
-    int x, int y, int w, int h)
+new_region(struct swm_screen *s, int x, int y, int w, int h)
 {
        struct swm_region       *r, *n;
+       struct workspace        *ws = NULL;
        int                     i;
 
        DNPRINTF(SWM_D_MISC, "new region: screen[%d]:%dx%d+%d+%d\n",
@@ -2441,26 +2464,45 @@ new_region(struct swm_screen *s, struct workspace *ws,
                    (X(r) + WIDTH(r)) > x &&
                    Y(r) < (y + h) &&
                    (Y(r) + HEIGHT(r)) > y) {
-                       if (ws == NULL)
-                               ws = r->ws;
-                       remove_region(r);
+                       XDestroyWindow(display, r->bar_window);
+                       TAILQ_REMOVE(&s->rl, r, entry);
+                       TAILQ_INSERT_TAIL(&s->orl, r, entry);
                }
        }
 
-       /* pick an appropriate workspace */
+       /* search old regions for one to reuse */
+
+       /* size + location match */
+       TAILQ_FOREACH(r, &s->orl, entry)
+               if (X(r) == x && Y(r) == y &&
+                   HEIGHT(r) == h && WIDTH(r) == w)
+                       break;
+
+       /* size match */
+       TAILQ_FOREACH(r, &s->orl, entry)
+               if (HEIGHT(r) == h && WIDTH(r) == w)
+                       break;
+
+       if (r != NULL) {
+               TAILQ_REMOVE(&s->orl, r, entry);
+               /* try to use old region's workspace */
+               if (r->ws->r == NULL)
+                       ws = r->ws;
+       } else
+               if ((r = calloc(1, sizeof(struct swm_region))) == NULL)
+                       errx(1, "calloc: failed to allocate memory for screen");
+
+       /* if we don't have a workspace already, find one */
        if (ws == NULL) {
                for (i = 0; i < SWM_WS_MAX; i++)
                        if (s->ws[i].r == NULL) {
                                ws = &s->ws[i];
                                break;
                        }
-
-               if (ws == NULL)
-                       errx(1, "no free regions\n");
        }
 
-       if ((r = calloc(1, sizeof(struct swm_region))) == NULL)
-               errx(1, "calloc: failed to allocate memory for screen");
+       if (ws == NULL)
+               errx(1, "no free workspaces\n");
 
        X(r) = x;
        Y(r) = y;
@@ -2474,20 +2516,100 @@ new_region(struct swm_screen *s, struct workspace *ws,
 }
 
 void
-setup_screens(void)
+scan_xrandr(int i)
 {
 #ifdef SWM_XRR_HAS_CRTC
        XRRCrtcInfo             *ci;
        XRRScreenResources      *sr;
        int                     c;
+       int                     ncrtc = 0;
 #endif /* SWM_XRR_HAS_CRTC */
+       struct swm_region       *r;
+
+
+       if (i >= ScreenCount(display))
+               errx(1, "invalid screen");
+
+       /* remove any old regions */
+       while ((r = TAILQ_FIRST(&screens[i].rl)) != NULL) {
+               r->ws->r = NULL;
+               XDestroyWindow(display, r->bar_window);
+               TAILQ_REMOVE(&screens[i].rl, r, entry);
+               TAILQ_INSERT_TAIL(&screens[i].orl, r, entry);
+       }
+
+       /* map virtual screens onto physical screens */
+#ifdef SWM_XRR_HAS_CRTC
+       if (xrandr_support) {
+               sr = XRRGetScreenResources(display, screens[i].root);
+               if (sr == NULL)
+                       new_region(&screens[i], 0, 0,
+                           DisplayWidth(display, i),
+                           DisplayHeight(display, i)); 
+               else 
+                       ncrtc = sr->ncrtc;
+
+               for (c = 0, ci = NULL; c < ncrtc; c++) {
+                       ci = XRRGetCrtcInfo(display, sr, sr->crtcs[c]);
+                       if (ci->noutput == 0)
+                               continue;
+
+                       if (ci != NULL && ci->mode == None)
+                               new_region(&screens[i], 0, 0,
+                                   DisplayWidth(display, i),
+                                   DisplayHeight(display, i)); 
+                       else
+                               new_region(&screens[i],
+                                   ci->x, ci->y, ci->width, ci->height);
+               }
+               if (ci)
+                       XRRFreeCrtcInfo(ci);
+               XRRFreeScreenResources(sr);
+       } else
+#endif /* SWM_XRR_HAS_CRTC */
+       {
+               new_region(&screens[i], 0, 0, DisplayWidth(display, i),
+                   DisplayHeight(display, i)); 
+       }
+}
+
+void
+screenchange(XEvent *e) {
+       XRRScreenChangeNotifyEvent      *xe = (XRRScreenChangeNotifyEvent *)e;
+       struct swm_region               *r;
+       struct ws_win                   *win;
+       int                             i;
+
+       DNPRINTF(SWM_D_EVENT, "screenchange: %lu\n", xe->root);
+
+       if (!XRRUpdateConfiguration(e))
+               return;
+
+       /* silly event doesn't include the screen index */
+       for (i = 0; i < ScreenCount(display); i++)
+               if (screens[i].root == xe->root)
+                       break;
+       if (i >= ScreenCount(display))
+               errx(1, "screenchange: screen not found\n");
+
+       /* brute force for now, just re-enumerate the regions */
+       scan_xrandr(i);
+
+       /* hide any windows that went away */
+       TAILQ_FOREACH(r, &screens[i].rl, entry)
+               TAILQ_FOREACH(win, &r->ws->winlist, entry)
+                       XUnmapWindow(display, win->id);
+       stack();
+}
+
+void
+setup_screens(void)
+{
        Window                  d1, d2, *wins = NULL;
        XWindowAttributes       wa;
-       struct swm_region       *r;
        unsigned int            no;
-       int                     errorbase, major, minor;
-       int                     ncrtc = 0, w = 0;
         int                    i, j, k;
+       int                     errorbase, major, minor;
        struct workspace        *ws;
        int                     ws_idx_atom;
 
@@ -2497,13 +2619,20 @@ setup_screens(void)
                errx(1, "calloc: screens");
 
        ws_idx_atom = XInternAtom(display, "_SWM_WS", False);
-       
+
+       /* initial Xrandr setup */
+       xrandr_support = XRRQueryExtension(display,
+           &xrandr_eventbase, &errorbase);
+       if (xrandr_support)
+               if (XRRQueryVersion(display, &major, &minor) && major < 1)
+                               xrandr_support = 0;
 
        /* map physical screens */
        for (i = 0; i < ScreenCount(display); i++) {
                DNPRINTF(SWM_D_WS, "setup_screens: init screen %d\n", i);
                screens[i].idx = i;
                TAILQ_INIT(&screens[i].rl);
+               TAILQ_INIT(&screens[i].orl);
                screens[i].root = RootWindow(display, i);
 
                /* set default colors */
@@ -2514,6 +2643,7 @@ setup_screens(void)
                setscreencolor("rgb:a0/a0/a0", i + 1, SWM_S_COLOR_BAR_FONT);
 
                /* init all workspaces */
+               /* XXX these should be dynamically allocated too */
                for (j = 0; j < SWM_WS_MAX; j++) {
                        ws = &screens[i].ws[j];
                        ws->idx = j;
@@ -2528,83 +2658,38 @@ setup_screens(void)
                                            SWM_ARG_ID_STACKINIT);
                        ws->cur_layout = &layouts[0];
                }
-
-               /* map virtual screens onto physical screens */
-               screens[i].xrandr_support = XRRQueryExtension(display,
-                   &xrandr_eventbase, &errorbase);
-               if (screens[i].xrandr_support)
-                       if (XRRQueryVersion(display, &major, &minor) &&
-                           major < 1)
-                               screens[i].xrandr_support = 0;
-
-#if 0  /* not ready for dynamic screen changes */
-               if (screens[i].xrandr_support)
-                       XRRSelectInput(display,
-                           screens[r->s].root,
-                           RRScreenChangeNotifyMask);
-#endif
-
                /* grab existing windows (before we build the bars)*/
                if (!XQueryTree(display, screens[i].root, &d1, &d2, &wins, &no))
                        continue;
 
-#ifdef SWM_XRR_HAS_CRTC
-               sr = XRRGetScreenResources(display, screens[i].root);
-               if (sr == NULL)
-                       new_region(&screens[i], &screens[i].ws[w],
-                           0, 0, DisplayWidth(display, i),
-                           DisplayHeight(display, i)); 
-               else 
-                       ncrtc = sr->ncrtc;
-
-               for (c = 0, ci = NULL; c < ncrtc; c++) {
-                       ci = XRRGetCrtcInfo(display, sr, sr->crtcs[c]);
-                       if (ci->noutput == 0)
-                               continue;
+               scan_xrandr(i);
 
-                       if (ci != NULL && ci->mode == None)
-                               new_region(&screens[i], &screens[i].ws[w], 0, 0,
-                                   DisplayWidth(display, i),
-                                   DisplayHeight(display, i)); 
-                       else
-                               new_region(&screens[i], &screens[i].ws[w],
-                                   ci->x, ci->y, ci->width, ci->height);
-                       w++;
-               }
-               if (ci)
-                       XRRFreeCrtcInfo(ci);
-               XRRFreeScreenResources(sr);
-#else
-               new_region(&screens[i], &screens[i].ws[w], 0, 0,
-                   DisplayWidth(display, i),
-                   DisplayHeight(display, i)); 
-#endif /* SWM_XRR_HAS_CRTC */
+               if (xrandr_support)
+                       XRRSelectInput(display, screens[i].root,
+                           RRScreenChangeNotifyMask);
 
                /* attach windows to a region */
                /* normal windows */
-               if ((r = TAILQ_FIRST(&screens[i].rl)) == NULL)
-                       errx(1, "no regions on screen %d", i);
-
-               for (i = 0; i < no; i++) {
-                        XGetWindowAttributes(display, wins[i], &wa);
-                       if (!XGetWindowAttributes(display, wins[i], &wa) ||
+               for (j = 0; j < no; j++) {
+                        XGetWindowAttributes(display, wins[j], &wa);
+                       if (!XGetWindowAttributes(display, wins[j], &wa) ||
                            wa.override_redirect ||
-                           XGetTransientForHint(display, wins[i], &d1))
+                           XGetTransientForHint(display, wins[j], &d1))
                                continue;
 
                        if (wa.map_state == IsViewable ||
-                           getstate(wins[i]) == NormalState)
-                               manage_window(wins[i]);
+                           getstate(wins[j]) == NormalState)
+                               manage_window(wins[j]);
                }
                /* transient windows */
-               for (i = 0; i < no; i++) {
-                       if (!XGetWindowAttributes(display, wins[i], &wa))
+               for (j = 0; j < no; j++) {
+                       if (!XGetWindowAttributes(display, wins[j], &wa))
                                continue;
 
-                       if (XGetTransientForHint(display, wins[i], &d1) &&
-                           (wa.map_state == IsViewable || getstate(wins[i]) ==
+                       if (XGetTransientForHint(display, wins[j], &d1) &&
+                           (wa.map_state == IsViewable || getstate(wins[j]) ==
                            NormalState))
-                               manage_window(wins[i]);
+                               manage_window(wins[j]);
                 }
                 if (wins) {
                         XFree(wins);
@@ -2675,10 +2760,25 @@ main(int argc, char *argv[])
                        bar_alarm = 0;
                        bar_update();
                }
-               while(XPending(display)) {
+               while (XPending(display)) {
                        XNextEvent(display, &e);
-                       if (handler[e.type])
-                               handler[e.type](&e);
+                       if (e.type < LASTEvent) {
+                               if (handler[e.type])
+                                       handler[e.type](&e);
+                               else
+                                       DNPRINTF(SWM_D_EVENT,
+                                           "unkown event: %d\n", e.type);
+                       } else {
+                               switch (e.type - xrandr_eventbase) {
+                               case RRScreenChangeNotify:
+                                       screenchange(&e);
+                                       break;
+                               default:
+                                       DNPRINTF(SWM_D_EVENT,
+                                           "unkown event: %d\n", e.type);
+                                       break;
+                               }
+                       }
                }
        }