JasonWoof Got questions, comments, patches, etc.? Contact Jason Woofenden
realloc cleanup from akfaew@jasminek.net
[spectrwm.git] / scrotwm.c
index 4b390a7..54503c6 100644 (file)
--- a/scrotwm.c
+++ b/scrotwm.c
@@ -51,7 +51,8 @@
  * DEALINGS IN THE SOFTWARE.
  */
 
-static const char      *cvstag = "$scrotwm$";
+static const char      *cvstag =
+    "$scrotwm$";
 
 #define        SWM_VERSION     "0.9.30"
 
@@ -287,6 +288,7 @@ struct ws_win {
        XWindowAttributes       wa;
        XSizeHints              sh;
        XClassHint              ch;
+       XWMHints                *hints;
 };
 TAILQ_HEAD(ws_win_list, ws_win);
 
@@ -317,8 +319,8 @@ struct layout {
        { vertical_stack,       vertical_config,        0,      "[|]" },
        { horizontal_stack,     horizontal_config,      0,      "[-]" },
        { max_stack,            NULL,
-         SWM_L_MAPONFOCUS | SWM_L_FOCUSPREV,                   "[ ]"},
-       { NULL,                 NULL,                   0,      NULL },
+         SWM_L_MAPONFOCUS | SWM_L_FOCUSPREV,                   "[ ]" },
+       { NULL,                 NULL,                   0,      NULL  },
 };
 
 /* position of max_stack mode in the layouts array */
@@ -415,6 +417,7 @@ struct quirk {
 #define SWM_Q_ANYWHERE         (1<<2)  /* don't position this window */
 #define SWM_Q_XTERM_FONTADJ    (1<<3)  /* adjust xterm fonts when resizing */
 #define SWM_Q_FULLSCREEN       (1<<4)  /* remove border */
+#define SWM_Q_FOCUSPREV                (1<<5)  /* focus on caller */
 };
 int                            quirks_size = 0, quirks_length = 0;
 struct quirk                   *quirks = NULL;
@@ -554,7 +557,8 @@ setup_ewmh(void)
                /* Report supported atoms */
                XDeleteProperty(display, screens[i].root, sup_list);
                for (j = 0; j < LENGTH(ewmh); j++)
-                       XChangeProperty(display, screens[i].root, sup_list, XA_ATOM, 32,
+                       XChangeProperty(display, screens[i].root,
+                           sup_list, XA_ATOM, 32,
                            PropModeAppend, (unsigned char *)&ewmh[j].atom,1);
        }
 }
@@ -740,7 +744,8 @@ ewmh_update_win_state(struct ws_win *win, long state, long action)
                        win->manual = (win->ewmh_flags & SWM_F_MANUAL) != 0;
        if (state == ewmh[_NET_WM_STATE_FULLSCREEN].atom)
                if (changed)
-                       if (!ewmh_set_win_fullscreen(win, win->ewmh_flags & EWMH_F_FULLSCREEN))
+                       if (!ewmh_set_win_fullscreen(win,
+                           win->ewmh_flags & EWMH_F_FULLSCREEN))
                                win->ewmh_flags = orig_flags; /* revert */
 
        XDeleteProperty(display, win->id, ewmh[_NET_WM_STATE].atom);
@@ -783,8 +788,8 @@ ewmh_get_win_state(struct ws_win *win)
        if (win->manual)
                win->ewmh_flags |= SWM_F_MANUAL;
 
-       success = get_property(win->id, ewmh[_NET_WM_STATE].atom, (~0L), XA_ATOM,
-           &n, (unsigned char **)&states);
+       success = get_property(win->id, ewmh[_NET_WM_STATE].atom,
+           (~0L), XA_ATOM, &n, (unsigned char **)&states);
 
        if (!success)
                return;
@@ -933,8 +938,9 @@ dumpwins(struct swm_region *r, union arg *args)
                if (!XGetWindowAttributes(display, win->id, &wa))
                        fprintf(stderr, "window: %lu failed "
                            "XGetWindowAttributes\n", win->id);
-               fprintf(stderr, "window: %lu map_state: %d state: %d\n",
-                   win->id, wa.map_state, state);
+               fprintf(stderr, "window: %lu map_state: %d state: %d "
+                   "transient: %lu\n",
+                   win->id, wa.map_state, state, win->transient);
        }
 
        fprintf(stderr, "===== unmanaged window list =====\n");
@@ -943,8 +949,9 @@ dumpwins(struct swm_region *r, union arg *args)
                if (!XGetWindowAttributes(display, win->id, &wa))
                        fprintf(stderr, "window: %lu failed "
                            "XGetWindowAttributes\n", win->id);
-               fprintf(stderr, "window: %lu map_state: %d state: %d\n",
-                   win->id, wa.map_state, state);
+               fprintf(stderr, "window: %lu map_state: %d state: %d "
+                   "transient: %lu\n",
+                   win->id, wa.map_state, state, win->transient);
        }
 
        fprintf(stderr, "=================================\n");
@@ -1105,7 +1112,8 @@ custom_region(char *val)
            y < 0 || y > DisplayHeight(display, sidx) ||
            w + x > DisplayWidth(display, sidx) ||
            h + y > DisplayHeight(display, sidx)) {
-               fprintf(stderr, "ignoring region %ux%u+%u+%u - not within screen boundaries "
+               fprintf(stderr, "ignoring region %ux%u+%u+%u "
+                   "- not within screen boundaries "
                    "(%ux%u)\n", w, h, x, y,
                    DisplayWidth(display, sidx), DisplayHeight(display, sidx));
                return;
@@ -1358,12 +1366,14 @@ bar_setup(struct swm_region *r)
        if (bar_fs == NULL)
                errx(1, "couldn't create font structure");
 
-       bar_height = bar_fs->ascent + bar_fs->descent + 1 + 2 * bar_border_width;
+       bar_height = bar_fs->ascent + bar_fs->descent + 1 +
+           2 * bar_border_width;
        x = X(r);
        y = bar_at_bottom ? (Y(r) + HEIGHT(r) - bar_height) : Y(r);
 
        r->bar_window = XCreateSimpleWindow(display,
-           r->s->root, x, y, WIDTH(r) - 2 * bar_border_width, bar_height - 2 * bar_border_width,
+           r->s->root, x, y, WIDTH(r) - 2 * bar_border_width,
+           bar_height - 2 * bar_border_width,
            bar_border_width, r->s->c[SWM_S_COLOR_BAR_BORDER].color,
            r->s->c[SWM_S_COLOR_BAR].color);
        bar_gc = XCreateGC(display, r->bar_window, 0, &bar_gcv);
@@ -1379,6 +1389,18 @@ bar_setup(struct swm_region *r)
 }
 
 void
+drain_enter_notify(void)
+{
+       int                     i = 0;
+       XEvent                  cne;
+
+       while (XCheckMaskEvent(display, EnterWindowMask, &cne))
+               i++;
+
+       DNPRINTF(SWM_D_MISC, "drain_enter_notify: drained %d\n", i);
+}
+
+void
 set_win_state(struct ws_win *win, long state)
 {
        long                    data[] = {state, None};
@@ -1446,7 +1468,8 @@ config_win(struct ws_win *win, XConfigureRequestEvent  *ev)
                return;
 
        if (ev == NULL) {
-               DNPRINTF(SWM_D_MISC, "config_win: win %lu x %d y %d w %d h %d\n",
+               DNPRINTF(SWM_D_MISC,
+                   "config_win: win %lu x %d y %d w %d h %d\n",
                    win->id, win->g.x, win->g.y, win->g.w, win->g.h);
 
                ce.type = ConfigureNotify;
@@ -1461,7 +1484,8 @@ config_win(struct ws_win *win, XConfigureRequestEvent  *ev)
                ce.above = None;
                ce.override_redirect = False;
        } else {
-               DNPRINTF(SWM_D_MISC, "config_win: ev win %lu x %d y %d w %d h %d\n",
+               DNPRINTF(SWM_D_MISC,
+                   "config_win: ev win %lu x %d y %d w %d h %d\n",
                    ev->window, ev->x, ev->y, ev->width, ev->height);
                ce.type = ConfigureNotify;
                ce.display = ev->display;
@@ -1759,7 +1783,7 @@ validate_win(struct ws_win *testwin)
        int                     i, x, foundit = 0;
 
        if (testwin == NULL)
-               return(0);
+               return (0);
 
        for (i = 0, foundit = 0; i < ScreenCount(display); i++)
                TAILQ_FOREACH(r, &screens[i].rl, entry)
@@ -1887,6 +1911,13 @@ focus_win(struct ws_win *win)
        XGetInputFocus(display, &cur_focus, &rr);
        if ((cfw = find_window(cur_focus)) != NULL)
                unfocus_win(cfw);
+       else {
+               /* use larger hammer since the window was killed somehow */
+               TAILQ_FOREACH(cfw, &win->ws->winlist, entry)
+                       if (cfw->ws && cfw->ws->r && cfw->ws->r->s)
+                               XSetWindowBorder(display, cfw->id,
+                                   cfw->ws->r->s->c[SWM_S_COLOR_UNFOCUS].color);
+       }
 
        win->ws->focus = win;
 
@@ -1954,15 +1985,22 @@ switchws(struct swm_region *r, union arg *args)
        this_r->ws = new_ws;
        new_ws->r = this_r;
 
+       /* this is needed so that we can click on a window after a restart */
+       unfocus_all();
+
        stack();
        a.id = SWM_ARG_ID_FOCUSCUR;
        focus(new_ws->r, &a);
+
        bar_update();
 
        /* unmap old windows */
        if (unmap_old)
                TAILQ_FOREACH(win, &old_ws->winlist, entry)
                        unmap_window(win);
+
+       if (focus_mode == SWM_FOCUS_DEFAULT)
+               drain_enter_notify();
 }
 
 void
@@ -2065,10 +2103,33 @@ cyclescr(struct swm_region *r, union arg *args)
 }
 
 void
+sort_windows(struct ws_win_list *wl)
+{
+       struct ws_win           *win, *parent, *nxt;
+
+       if (wl == NULL)
+               return;
+
+       for (win = TAILQ_FIRST(wl); win != TAILQ_END(wl); win = nxt) {
+               nxt = TAILQ_NEXT(win, entry);
+               if (win->transient) {
+                       parent = find_window(win->transient);
+                       if (parent == NULL) {
+                               fprintf(stderr, "not possible bug\n");
+                               continue;
+                       }
+                       TAILQ_REMOVE(wl, win, entry);
+                       TAILQ_INSERT_AFTER(wl, parent, win, entry);
+               }
+       }
+
+}
+
+void
 swapwin(struct swm_region *r, union arg *args)
 {
        struct ws_win           *target, *source;
-       struct ws_win           *cur_focus, *t;
+       struct ws_win           *cur_focus;
        struct ws_win_list      *wl;
 
 
@@ -2080,17 +2141,16 @@ swapwin(struct swm_region *r, union arg *args)
        if (cur_focus == NULL)
                return;
 
-       if (cur_focus->transient) {
-               source = find_window(cur_focus->transient);
-               if (source == NULL)
-                       return;
-       } else
-               source = cur_focus;
+       source = cur_focus;
        wl = &source->ws->winlist;
 
        switch (args->id) {
        case SWM_ARG_ID_SWAPPREV:
+               if (source->transient)
+                       source = find_window(source->transient);
                target = TAILQ_PREV(source, ws_win_list, entry);
+               if (target && target->transient)
+                       target = find_window(target->transient);
                TAILQ_REMOVE(wl, source, entry);
                if (target == NULL)
                        TAILQ_INSERT_TAIL(wl, source, entry);
@@ -2099,6 +2159,9 @@ swapwin(struct swm_region *r, union arg *args)
                break;
        case SWM_ARG_ID_SWAPNEXT:
                target = TAILQ_NEXT(source, entry);
+               /* move the parent and let the sort handle the move */
+               if (source->transient)
+                       source = find_window(source->transient);
                TAILQ_REMOVE(wl, source, entry);
                if (target == NULL)
                        TAILQ_INSERT_HEAD(wl, source, entry);
@@ -2114,7 +2177,7 @@ swapwin(struct swm_region *r, union arg *args)
                                source = source->ws->focus_prev;
                        else
                                return;
-                }
+               }
                if (target == NULL || source == NULL)
                        return;
                source->ws->focus_prev = target;
@@ -2132,21 +2195,7 @@ swapwin(struct swm_region *r, union arg *args)
                return;
        }
 
-       /* keep transients after the parent */
-       if (source && source->transient) {
-               t = find_window(source->transient);
-               if (t) {
-                       TAILQ_REMOVE(wl, t, entry);
-                       TAILQ_INSERT_AFTER(wl, source, t, entry);
-               }
-       }
-       if (target && target->transient) {
-               t = find_window(target->transient);
-               if (t) {
-                       TAILQ_REMOVE(wl, t, entry);
-                       TAILQ_INSERT_AFTER(wl, target, t, entry);
-               }
-       }
+       sort_windows(wl);
 
        stack();
 }
@@ -2187,7 +2236,8 @@ focus_prev(struct ws_win *win)
        }
 
        /* if in max_stack try harder */
-       if (ws->cur_layout->flags & SWM_L_FOCUSPREV) {
+       if ((win->quirks & SWM_Q_FOCUSPREV) ||
+           (ws->cur_layout->flags & SWM_L_FOCUSPREV)) {
                if (cur_focus != ws->focus_prev)
                        winfocus = ws->focus_prev;
                else if (cur_focus != ws->focus)
@@ -2312,6 +2362,8 @@ cycle_layout(struct swm_region *r, union arg *args)
                ws->cur_layout = &layouts[0];
 
        stack();
+       if (focus_mode == SWM_FOCUS_DEFAULT)
+               drain_enter_notify();
        a.id = SWM_ARG_ID_FOCUSCUR;
        focus(r, &a);
        bar_update();
@@ -2328,7 +2380,7 @@ stack_config(struct swm_region *r, union arg *args)
        if (ws->cur_layout->l_config != NULL)
                ws->cur_layout->l_config(ws, args->id);
 
-       if (args->id != SWM_ARG_ID_STACKINIT);
+       if (args->id != SWM_ARG_ID_STACKINIT)
                stack();
 }
 
@@ -2362,6 +2414,9 @@ stack(void) {
        }
        if (font_adjusted)
                font_adjusted--;
+
+       if (focus_mode == SWM_FOCUS_DEFAULT)
+               drain_enter_notify();
 }
 
 void
@@ -2426,8 +2481,10 @@ stack_floater(struct ws_win *win, struct swm_region *r)
                 * floaters and transients are auto-centred unless moved
                 * or resized
                 */
-               win->g.x = r->g.x + (WIDTH(r) - win->g.w) / 2 - wc.border_width;
-               win->g.y = r->g.y + (HEIGHT(r) - win->g.h) / 2 - wc.border_width;
+               win->g.x = r->g.x + (WIDTH(r) - win->g.w) /
+                   2 - wc.border_width;
+               win->g.y = r->g.y + (HEIGHT(r) - win->g.h) /
+                   2 - wc.border_width;
        }
 
        /* win can be outside r if new r smaller than old r */
@@ -2517,7 +2574,8 @@ stack_master(struct workspace *ws, struct swm_geometry *g, int rot, int flip)
                return;
 
        TAILQ_FOREACH(win, &ws->winlist, entry)
-               if (win->transient == 0 && win->floating == 0 && win->iconic == 0)
+               if (win->transient == 0 && win->floating == 0
+                   && win->iconic == 0)
                        break;
 
        if (win == NULL)
@@ -2566,7 +2624,8 @@ stack_master(struct workspace *ws, struct swm_geometry *g, int rot, int flip)
        } else {
                msize = -2;
                colno = split = winno / stacks;
-               win_g.w = ((r_g.w - (stacks * 2 * border_width) + 2 * border_width) / stacks);
+               win_g.w = ((r_g.w - (stacks * 2 * border_width) +
+                   2 * border_width) / stacks);
        }
        hrh = r_g.h / colno;
        extra = r_g.h - (colno * hrh);
@@ -2596,10 +2655,11 @@ stack_master(struct workspace *ws, struct swm_geometry *g, int rot, int flip)
                                win_g.x = r_g.x;
                        else
                                win_g.x += win_g.w + 2 * border_width;
-                       win_g.w = (r_g.w - msize - (stacks * 2 * border_width)) / stacks;
+                       win_g.w = (r_g.w - msize -
+                           (stacks * 2 * border_width)) / stacks;
                        if (s == 1)
-                               win_g.w += (r_g.w - msize - (stacks * 2 * border_width)) %
-                                   stacks;
+                               win_g.w += (r_g.w - msize -
+                                   (stacks * 2 * border_width)) % stacks;
                        s--;
                        j = 0;
                }
@@ -2862,7 +2922,7 @@ void
 send_to_ws(struct swm_region *r, union arg *args)
 {
        int                     wsid = args->id;
-       struct ws_win           *win = win;
+       struct ws_win           *win = NULL, *parent;
        struct workspace        *ws, *nws;
        Atom                    ws_idx_atom = 0;
        unsigned char           ws_idx_str[SWM_PROPLEN];
@@ -2884,6 +2944,15 @@ send_to_ws(struct swm_region *r, union arg *args)
 
        a.id = SWM_ARG_ID_FOCUSPREV;
        focus(r, &a);
+       if (win->transient) {
+               parent = find_window(win->transient);
+               if (parent) {
+                       unmap_window(parent);
+                       TAILQ_REMOVE(&ws->winlist, parent, entry);
+                       TAILQ_INSERT_TAIL(&nws->winlist, parent, entry);
+                       parent->ws = nws;
+               }
+       }
        unmap_window(win);
        TAILQ_REMOVE(&ws->winlist, win, entry);
        TAILQ_INSERT_TAIL(&nws->winlist, win, entry);
@@ -2912,6 +2981,8 @@ iconify(struct swm_region *r, union arg *args)
        unmap_window(r->ws->focus);
        update_iconic(r->ws->focus, 1);
        stack();
+       if (focus_mode == SWM_FOCUS_DEFAULT)
+               drain_enter_notify();
        r->ws->focus = NULL;
        a.id = SWM_ARG_ID_FOCUSCUR;
        focus(r, &a);
@@ -3115,6 +3186,8 @@ floating_toggle(struct swm_region *r, union arg *args)
            _NET_WM_STATE_TOGGLE);
 
        stack();
+       if (focus_mode == SWM_FOCUS_DEFAULT)
+               drain_enter_notify();
 
        if (win == win->ws->focus) {
                a.id = SWM_ARG_ID_FOCUSCUR;
@@ -3154,7 +3227,6 @@ resize(struct ws_win *win, union arg *args)
        Time                    time = 0;
        struct swm_region       *r = win->ws->r;
        int                     relx, rely;
-       union arg               a;
 
 
        DNPRINTF(SWM_D_MOUSE, "resize: win %lu floating %d trans %lu\n",
@@ -3170,10 +3242,10 @@ resize(struct ws_win *win, union arg *args)
        win->manual = 1;
        ewmh_update_win_state(win, ewmh[_SWM_WM_STATE_MANUAL].atom,
            _NET_WM_STATE_ADD);
-       /* raise the window = move to last in window list */
-       a.id = SWM_ARG_ID_MOVELAST;
-       swapwin(r, &a);
+
        stack();
+       if (focus_mode == SWM_FOCUS_DEFAULT)
+               drain_enter_notify();
 
        if (XGrabPointer(display, win->id, False, MOUSEMASK, GrabModeAsync,
            GrabModeAsync, None, None /* cursor */, CurrentTime) != GrabSuccess)
@@ -3194,7 +3266,7 @@ resize(struct ws_win *win, union arg *args)
        do {
                XMaskEvent(display, MOUSEMASK | ExposureMask |
                    SubstructureRedirectMask, &ev);
-               switch(ev.type) {
+               switch (ev.type) {
                case ConfigureRequest:
                case Expose:
                case MapRequest:
@@ -3235,7 +3307,7 @@ resize(struct ws_win *win, union arg *args)
        XUngrabPointer(display, CurrentTime);
 
        /* drain events */
-       while (XCheckMaskEvent(display, EnterWindowMask, &ev));
+       drain_enter_notify();
 }
 
 void
@@ -3264,7 +3336,6 @@ move(struct ws_win *win, union arg *args)
        XEvent                  ev;
        Time                    time = 0;
        struct swm_region       *r = win->ws->r;
-       union arg               a;
 
        DNPRINTF(SWM_D_MOUSE, "move: win %lu floating %d trans %lu\n",
            win->id, win->floating, win->transient);
@@ -3275,16 +3346,12 @@ move(struct ws_win *win, union arg *args)
 
        win->manual = 1;
        if (win->floating == 0 && !win->transient) {
-               win->floating = 1;
                ewmh_update_win_state(win, ewmh[_NET_WM_STATE_ABOVE].atom,
                    _NET_WM_STATE_ADD);
        }
        ewmh_update_win_state(win, ewmh[_SWM_WM_STATE_MANUAL].atom,
            _NET_WM_STATE_ADD);
 
-       /* raise the window = move to last in window list */
-       a.id = SWM_ARG_ID_MOVELAST;
-       swapwin(r, &a);
        stack();
 
        if (XGrabPointer(display, win->id, False, MOUSEMASK, GrabModeAsync,
@@ -3294,7 +3361,7 @@ move(struct ws_win *win, union arg *args)
        do {
                XMaskEvent(display, MOUSEMASK | ExposureMask |
                    SubstructureRedirectMask, &ev);
-               switch(ev.type) {
+               switch (ev.type) {
                case ConfigureRequest:
                case Expose:
                case MapRequest:
@@ -3329,7 +3396,7 @@ move(struct ws_win *win, union arg *args)
        XUngrabPointer(display, CurrentTime);
 
        /* drain events */
-       while (XCheckMaskEvent(display, EnterWindowMask, &ev));
+       drain_enter_notify();
 }
 
 /* user/key callable function IDs */
@@ -3768,8 +3835,9 @@ setconfspawn(char *selector, char *value, int flags)
                        cp += (long)strspn(cp, " \t");
                if (strlen(word) > 0) {
                        prog->argc++;
-                       prog->argv = realloc(prog->argv,
-                           prog->argc * sizeof(char *));
+                       if ((prog->argv = realloc(prog->argv,
+                           prog->argc * sizeof(char *))) == NULL)
+                               err(1, "setconfspawn: realloc");
                        if ((prog->argv[prog->argc - 1] = strdup(word)) == NULL)
                                err(1, "setconfspawn: strdup");
                }
@@ -3868,7 +3936,8 @@ strdupsafe(char *str)
 }
 
 void
-setkeybinding(unsigned int mod, KeySym ks, enum keyfuncid kfid, char *spawn_name)
+setkeybinding(unsigned int mod, KeySym ks, enum keyfuncid kfid,
+    char *spawn_name)
 {
        int                     i, j;
        DNPRINTF(SWM_D_KEY, "setkeybinding: enter %s [%s]\n",
@@ -3915,7 +3984,7 @@ setkeybinding(unsigned int mod, KeySym ks, enum keyfuncid kfid, char *spawn_name
                keys_size = 4;
                DNPRINTF(SWM_D_KEY, "setkeybinding: init list %d\n", keys_size);
                keys = malloc((size_t)keys_size * sizeof(struct key));
-               if (!keys) {
+               if (keys == NULL) {
                        fprintf(stderr, "malloc failed\n");
                        perror(" failed");
                        quit(NULL, NULL);
@@ -3924,7 +3993,7 @@ setkeybinding(unsigned int mod, KeySym ks, enum keyfuncid kfid, char *spawn_name
                keys_size *= 2;
                DNPRINTF(SWM_D_KEY, "setkeybinding: grow list %d\n", keys_size);
                keys = realloc(keys, (size_t)keys_size * sizeof(struct key));
-               if (!keys) {
+               if (keys == NULL) {
                        fprintf(stderr, "realloc failed\n");
                        perror(" failed");
                        quit(NULL, NULL);
@@ -3940,7 +4009,7 @@ setkeybinding(unsigned int mod, KeySym ks, enum keyfuncid kfid, char *spawn_name
                keys[j].spawn_name = strdupsafe(spawn_name);
        } else {
                fprintf(stderr, "keys array problem?\n");
-               if (!keys) {
+               if (keys == NULL) {
                        fprintf(stderr, "keys array problem\n");
                        quit(NULL, NULL);
                }
@@ -4071,7 +4140,7 @@ updatenumlockmask(void)
        for (i = 0; i < 8; i++)
                for (j = 0; j < modmap->max_keypermod; j++)
                        if (modmap->modifiermap[i * modmap->max_keypermod + j]
-                         == XKeysymToKeycode(display, XK_Num_Lock))
+                           == XKeysymToKeycode(display, XK_Num_Lock))
                                numlockmask = (1 << i);
 
        XFreeModifiermap(modmap);
@@ -4133,6 +4202,7 @@ const char *quirkname[] = {
        "ANYWHERE",
        "XTERM_FONTADJ",
        "FULLSCREEN",
+       "FOCUSPREV",
 };
 
 /* SWM_Q_WS: retain '|' for back compat for now (2009-08-11) */
@@ -4153,7 +4223,8 @@ parsequirks(char *qstr, unsigned long *quirk)
                        cp += (long)strspn(cp, SWM_Q_WS);
                for (i = 0; i < LENGTH(quirkname); i++) {
                        if (!strncasecmp(name, quirkname[i], SWM_QUIRK_LEN)) {
-                               DNPRINTF(SWM_D_QUIRK, "parsequirks: %s\n", name);
+                               DNPRINTF(SWM_D_QUIRK,
+                                   "parsequirks: %s\n", name);
                                if (i == 0) {
                                        *quirk = 0;
                                        return (0);
@@ -4216,7 +4287,7 @@ setquirk(const char *class, const char *name, const int quirk)
                quirks_size = 4;
                DNPRINTF(SWM_D_QUIRK, "setquirk: init list %d\n", quirks_size);
                quirks = malloc((size_t)quirks_size * sizeof(struct quirk));
-               if (!quirks) {
+               if (quirks == NULL) {
                        fprintf(stderr, "setquirk: malloc failed\n");
                        perror(" failed");
                        quit(NULL, NULL);
@@ -4224,8 +4295,9 @@ setquirk(const char *class, const char *name, const int quirk)
        } else if (quirks_length == quirks_size) {
                quirks_size *= 2;
                DNPRINTF(SWM_D_QUIRK, "setquirk: grow list %d\n", quirks_size);
-               quirks = realloc(quirks, (size_t)quirks_size * sizeof(struct quirk));
-               if (!quirks) {
+               quirks = realloc(quirks,
+                   (size_t)quirks_size * sizeof(struct quirk));
+               if (quirks == NULL) {
                        fprintf(stderr, "setquirk: realloc failed\n");
                        perror(" failed");
                        quit(NULL, NULL);
@@ -4239,7 +4311,7 @@ setquirk(const char *class, const char *name, const int quirk)
                quirks[j].quirk = quirk;
        } else {
                fprintf(stderr, "quirks array problem?\n");
-               if (!quirks) {
+               if (quirks == NULL) {
                        fprintf(stderr, "quirks array problem!\n");
                        quit(NULL, NULL);
                }
@@ -4267,7 +4339,7 @@ setconfquirk(char *selector, char *value, int flags)
 void
 setup_quirks(void)
 {
-       setquirk("MPlayer",             "xv",           SWM_Q_FLOAT | SWM_Q_FULLSCREEN);
+       setquirk("MPlayer",             "xv",           SWM_Q_FLOAT | SWM_Q_FULLSCREEN | SWM_Q_FOCUSPREV);
        setquirk("OpenOffice.org 3.2",  "VCLSalFrame",  SWM_Q_FLOAT);
        setquirk("Firefox-bin",         "firefox-bin",  SWM_Q_TRANSSZ);
        setquirk("Firefox",             "Dialog",       SWM_Q_FLOAT);
@@ -4279,18 +4351,20 @@ setup_quirks(void)
        setquirk("Xitk",                "Xine Window",  SWM_Q_FLOAT | SWM_Q_ANYWHERE);
        setquirk("xine",                "xine Video Fullscreen Window", SWM_Q_FULLSCREEN | SWM_Q_FLOAT);
        setquirk("pcb",                 "pcb",          SWM_Q_FLOAT);
+       setquirk("SDL_App",             "SDL_App",      SWM_Q_FLOAT | SWM_Q_FULLSCREEN);
 }
 
 /* conf file stuff */
 #define SWM_CONF_FILE  "scrotwm.conf"
 
-enum   { SWM_S_BAR_DELAY, SWM_S_BAR_ENABLED, SWM_S_BAR_BORDER_WIDTH, SWM_S_STACK_ENABLED,
-         SWM_S_CLOCK_ENABLED, SWM_S_CLOCK_FORMAT, SWM_S_CYCLE_EMPTY,
-         SWM_S_CYCLE_VISIBLE, SWM_S_SS_ENABLED, SWM_S_TERM_WIDTH,
-         SWM_S_TITLE_CLASS_ENABLED, SWM_S_TITLE_NAME_ENABLED, SWM_S_WINDOW_NAME_ENABLED,
-         SWM_S_FOCUS_MODE, SWM_S_DISABLE_BORDER, SWM_S_BORDER_WIDTH, SWM_S_BAR_FONT,
-         SWM_S_BAR_ACTION, SWM_S_SPAWN_TERM, SWM_S_SS_APP, SWM_S_DIALOG_RATIO,
-         SWM_S_BAR_AT_BOTTOM
+enum   { SWM_S_BAR_DELAY, SWM_S_BAR_ENABLED, SWM_S_BAR_BORDER_WIDTH,
+         SWM_S_STACK_ENABLED, SWM_S_CLOCK_ENABLED, SWM_S_CLOCK_FORMAT,
+         SWM_S_CYCLE_EMPTY, SWM_S_CYCLE_VISIBLE, SWM_S_SS_ENABLED,
+         SWM_S_TERM_WIDTH, SWM_S_TITLE_CLASS_ENABLED,
+         SWM_S_TITLE_NAME_ENABLED, SWM_S_WINDOW_NAME_ENABLED,
+         SWM_S_FOCUS_MODE, SWM_S_DISABLE_BORDER, SWM_S_BORDER_WIDTH,
+         SWM_S_BAR_FONT, SWM_S_BAR_ACTION, SWM_S_SPAWN_TERM,
+         SWM_S_SS_APP, SWM_S_DIALOG_RATIO, SWM_S_BAR_AT_BOTTOM
        };
 
 int
@@ -4556,13 +4630,52 @@ conf_load(char *filename)
 }
 
 void
-set_child_transient(struct ws_win *win)
+set_child_transient(struct ws_win *win, Window *trans)
 {
-       struct ws_win           *parent;
+       struct ws_win           *parent, *w;
+       XWMHints                *wmh = NULL;
+       struct swm_region       *r;
+       struct workspace        *ws;
 
        parent = find_window(win->transient);
        if (parent)
                parent->child_trans = win;
+       else {
+               DNPRINTF(SWM_D_MISC, "set_child_transient: parent doesn't exist"
+                   " for %lu trans %lu\n", win->id, win->transient);
+
+               if (win->hints == NULL) {
+                       fprintf(stderr, "no hints for %lu\n", win->id);
+                       return;
+               }
+
+               r = root_to_region(win->wa.root);
+               ws = r->ws;
+               /* parent doen't exist in our window list */
+               TAILQ_FOREACH(w, &ws->winlist, entry) {
+                       if (wmh)
+                               XFree(wmh);
+
+                       if ((wmh = XGetWMHints(display, w->id)) == NULL) {
+                               fprintf(stderr, "can't get hints for %lu\n",
+                                   w->id);
+                               continue;
+                       }
+
+                       if (win->hints->window_group != wmh->window_group)
+                               continue;
+
+                       w->child_trans = win;
+                       win->transient = w->id;
+                       *trans = w->id;
+                       DNPRINTF(SWM_D_MISC, "set_child_transient: asjusting "
+                           "transient to %lu\n", win->transient);
+                       break;
+               }
+       }
+
+       if (wmh)
+               XFree(wmh);
 }
 
 struct ws_win *
@@ -4589,9 +4702,9 @@ manage_window(Window id)
                DNPRINTF(SWM_D_MISC, "manage previously unmanaged window "
                    "%lu\n", win->id);
                TAILQ_REMOVE(&win->ws->unmanagedlist, win, entry);
-               if (win->transient)
-                       set_child_transient(win);
-               if (trans && (ww = find_window(trans)))
+               if (win->transient) {
+                       set_child_transient(win, &trans);
+               } if (trans && (ww = find_window(trans)))
                        TAILQ_INSERT_AFTER(&win->ws->winlist, ww, win, entry);
                else
                        TAILQ_INSERT_TAIL(&win->ws->winlist, win, entry);
@@ -4611,10 +4724,11 @@ manage_window(Window id)
                    False, XA_STRING, &type, &format, &nitems, &bytes, &prop);
        XGetWindowAttributes(display, id, &win->wa);
        XGetWMNormalHints(display, id, &win->sh, &mask);
+       win->hints = XGetWMHints(display, id);
        XGetTransientForHint(display, id, &trans);
        if (trans) {
                win->transient = trans;
-               set_child_transient(win);
+               set_child_transient(win, &trans);
                DNPRINTF(SWM_D_MISC, "manage_window: win %lu transient %lu\n",
                    win->id, win->transient);
        }
@@ -4755,10 +4869,6 @@ manage_window(Window id)
 
        XSelectInput(display, id, EnterWindowMask | FocusChangeMask |
            PropertyChangeMask | StructureNotifyMask);
-       if (win->iconic)
-               set_win_state(win, IconicState);
-       else
-               set_win_state(win, NormalState);
 
        /* floaters need to be mapped if they are in the current workspace */
        if ((win->floating || win->transient) && (ws->idx == r->ws->idx))
@@ -4873,8 +4983,8 @@ keypress(XEvent *e)
        keysym = XKeycodeToKeysym(display, (KeyCode)ev->keycode, 0);
        for (i = 0; i < keys_length; i++)
                if (keysym == keys[i].keysym
-                  && CLEANMASK(keys[i].mod) == CLEANMASK(ev->state)
-                  && keyfuncs[keys[i].funcid].func) {
+                   && CLEANMASK(keys[i].mod) == CLEANMASK(ev->state)
+                   && keyfuncs[keys[i].funcid].func) {
                        if (keys[i].funcid == kf_spawn_custom)
                                spawn_custom(
                                    root_to_region(ev->root),
@@ -4958,6 +5068,8 @@ configurenotify(XEvent *e)
                adjust_font(win);
                if (font_adjusted)
                        stack();
+               if (focus_mode == SWM_FOCUS_DEFAULT)
+                       drain_enter_notify();
        }
 }
 
@@ -4981,6 +5093,8 @@ destroynotify(XEvent *e)
 
        unmanage_window(win);
        stack();
+       if (focus_mode == SWM_FOCUS_DEFAULT)
+               drain_enter_notify();
        free_window(win);
 }
 
@@ -5002,11 +5116,6 @@ enternotify(XEvent *e)
 
        switch (focus_mode) {
        case SWM_FOCUS_DEFAULT:
-               if (QLength(display)) {
-                       DNPRINTF(SWM_D_EVENT, "ignore enternotify %d\n",
-                           QLength(display));
-                       return;
-               }
                break;
        case SWM_FOCUS_FOLLOW:
                break;
@@ -5256,7 +5365,25 @@ unmapnotify(XEvent *e)
        if (getstate(e->xunmap.window) == NormalState) {
                unmanage_window(win);
                stack();
+
+               /* giant hack for apps that don't destroy transient windows */
+               /* eat a bunch of events to prevent remanaging the window */
+               XEvent                  cne;
+               while (XCheckWindowEvent(display, e->xunmap.window,
+                   EnterWindowMask, &cne))
+                       ;
+               while (XCheckWindowEvent(display, e->xunmap.window,
+                   StructureNotifyMask, &cne))
+                       ;
+               while (XCheckWindowEvent(display, e->xunmap.window,
+                   SubstructureNotifyMask, &cne))
+                       ;
+               /* resend unmap because we ated it */
+               XUnmapWindow(display, e->xunmap.window);
        }
+
+       if (focus_mode == SWM_FOCUS_DEFAULT)
+               drain_enter_notify();
 }
 
 void
@@ -5301,7 +5428,8 @@ clientmessage(XEvent *e)
                        XKillClient(display, win->id);
        }
        if (ev->message_type == ewmh[_NET_MOVERESIZE_WINDOW].atom) {
-               DNPRINTF(SWM_D_EVENT, "clientmessage: _NET_MOVERESIZE_WINDOW \n");
+               DNPRINTF(SWM_D_EVENT,
+                   "clientmessage: _NET_MOVERESIZE_WINDOW \n");
                if (win->floating) {
                        if (ev->data.l[0] & (1<<8)) /* x */
                                win->g.x = ev->data.l[1];
@@ -5321,7 +5449,8 @@ clientmessage(XEvent *e)
                DNPRINTF(SWM_D_EVENT, "clientmessage: _NET_WM_STATE \n");
                ewmh_update_win_state(win, ev->data.l[1], ev->data.l[0]);
                if (ev->data.l[2])
-                       ewmh_update_win_state(win, ev->data.l[2], ev->data.l[0]);
+                       ewmh_update_win_state(win, ev->data.l[2],
+                           ev->data.l[0]);
 
                stack();
        }
@@ -5518,6 +5647,8 @@ screenchange(XEvent *e) {
                TAILQ_FOREACH(r, &screens[i].rl, entry)
                        bar_setup(r);
        stack();
+       if (focus_mode == SWM_FOCUS_DEFAULT)
+               drain_enter_notify();
 }
 
 void
@@ -5751,6 +5882,8 @@ main(int argc, char *argv[])
        if (cfile)
                conf_load(cfile);
 
+       custom_region("screen[1]:1280x1009+0+15");
+
        setup_ewmh();
        /* set some values to work around bad programs */
        workaround();
@@ -5770,6 +5903,8 @@ main(int argc, char *argv[])
 
        grabkeys();
        stack();
+       if (focus_mode == SWM_FOCUS_DEFAULT)
+               drain_enter_notify();
 
        xfd = ConnectionNumber(display);
        while (running) {