]> code.delx.au - spectrwm/blobdiff - spectrwm.c
Fix segfault in fullscreen layout when a window with transient(s) unmap.
[spectrwm] / spectrwm.c
index 342dc69c0438a6d61695e1bea98d1ea6d65878fb..4d2128a2d72dbe6cc4a51c60a02c118ca882ea53 100644 (file)
@@ -5,7 +5,7 @@
  * Copyright (c) 2009 Pierre-Yves Ritschard <pyr@spootnik.org>
  * Copyright (c) 2010 Tuukka Kataja <stuge@xor.fi>
  * Copyright (c) 2011 Jason L. Wright <jason@thought.net>
- * Copyright (c) 2011-2013 Reginald Kennedy <rk@rejii.com>
+ * Copyright (c) 2011-2014 Reginald Kennedy <rk@rejii.com>
  * Copyright (c) 2011-2012 Lawrence Teo <lteo@lteo.net>
  * Copyright (c) 2011-2012 Tiago Cunha <tcunha@gmx.com>
  * Copyright (c) 2012-2013 David Hill <dhill@mindcry.org>
@@ -186,7 +186,7 @@ static const char   *buildstr = SPECTRWM_VERSION;
 #define SWM_D_BAR              0x4000
 #define SWM_D_INIT             0x8000
 
-u_int32_t              swm_debug = 0
+uint32_t               swm_debug = 0
                            | SWM_D_MISC
                            | SWM_D_EVENT
                            | SWM_D_WS
@@ -425,6 +425,7 @@ XftFont             *bar_font;
 int             bar_font_legacy = 1;
 char           *bar_fonts;
 XftColor        bar_font_color;
+XftColor        search_font_color;
 struct passwd  *pwd;
 char           *startup_exception;
 unsigned int    nr_exceptions = 0;
@@ -467,7 +468,7 @@ struct ws_win {
        struct swm_geometry     g;              /* current geometry */
        struct swm_geometry     g_float;        /* region coordinates */
        int                     g_floatvalid;   /* g_float geometry validity */
-       int32_t                 mapped;
+       int                     mapped;
        int                     bordered;
        uint32_t                ewmh_flags;
        int                     font_size_boundary[SWM_MAX_FONT_STEPS];
@@ -508,7 +509,7 @@ void        fancy_stacker(struct workspace *);
 struct layout {
        void            (*l_stack)(struct workspace *, struct swm_geometry *);
        void            (*l_config)(struct workspace *, int);
-       u_int32_t       flags;
+       uint32_t        flags;
 #define SWM_L_FOCUSPREV                (1<<0)
 #define SWM_L_MAPONFOCUS       (1<<1)
        void            (*l_string)(struct workspace *);
@@ -544,7 +545,7 @@ struct workspace {
        struct ws_win_list      winlist;        /* list of windows in ws */
        struct ws_win_list      unmanagedlist;  /* list of dead windows in ws */
        struct ws_win_stack     stack;          /* stacking order */
-       int32_t                 state;          /* mapping state */
+       int                     state;          /* mapping state */
        char                    stacker[10];    /* display stacker and layout */
 
        /* stacker state */
@@ -572,7 +573,9 @@ enum {
        SWM_S_COLOR_BAR_BORDER_UNFOCUS,
        SWM_S_COLOR_BAR_FONT,
        SWM_S_COLOR_FOCUS,
+       SWM_S_COLOR_FOCUS_MAXIMIZED,
        SWM_S_COLOR_UNFOCUS,
+       SWM_S_COLOR_UNFOCUS_MAXIMIZED,
        SWM_S_COLOR_MAX
 };
 
@@ -592,6 +595,7 @@ struct swm_screen {
        struct {
                uint32_t        pixel;
                char            *name;
+               int             manual;
        } c[SWM_S_COLOR_MAX];
 
        xcb_gcontext_t          bar_gc;
@@ -641,6 +645,8 @@ union arg {
 #define SWM_ARG_ID_MOVEDOWN    (101)
 #define SWM_ARG_ID_MOVELEFT    (102)
 #define SWM_ARG_ID_MOVERIGHT   (103)
+#define SWM_ARG_ID_RAISE       (105)
+#define SWM_ARG_ID_LOWER       (106)
 #define SWM_ARG_ID_BAR_TOGGLE  (110)
 #define SWM_ARG_ID_BAR_TOGGLE_WS       (111)
        char                    **argv;
@@ -664,6 +670,7 @@ struct quirk {
 #define SWM_Q_FOCUSPREV                (1<<5)  /* focus on caller */
 #define SWM_Q_NOFOCUSONMAP     (1<<6)  /* Don't focus on window when mapped. */
 #define SWM_Q_FOCUSONMAP_SINGLE        (1<<7)  /* Only focus if single win of type. */
+#define SWM_Q_OBEYAPPFOCUSREQ  (1<<8)  /* Focus when applications ask. */
 };
 TAILQ_HEAD(quirk_list, quirk);
 struct quirk_list              quirks = TAILQ_HEAD_INITIALIZER(quirks);
@@ -1023,13 +1030,14 @@ int      get_region_index(struct swm_region *);
 xcb_screen_t   *get_screen(int);
 int     get_screen_count(void);
 #ifdef SWM_DEBUG
+char   *get_source_type_label(uint32_t);
 char   *get_stack_mode_name(uint8_t);
 #endif
 int32_t         get_swm_ws(xcb_window_t);
 char   *get_win_name(xcb_window_t);
+uint8_t         get_win_state(xcb_window_t);
 void    get_wm_protocols(struct ws_win *);
 int     get_ws_idx(xcb_window_t);
-uint32_t getstate(xcb_window_t);
 void    grabbuttons(struct ws_win *);
 void    grabkeys(void);
 void    grab_windows(void);
@@ -1048,7 +1056,7 @@ void       kill_refs(struct ws_win *);
 void    leavenotify(xcb_leave_notify_event_t *);
 #endif
 void    load_float_geom(struct ws_win *);
-struct ws_win  *manage_window(xcb_window_t, uint16_t);
+struct ws_win  *manage_window(xcb_window_t, int);
 void    map_window(struct ws_win *);
 void    mapnotify(xcb_map_notify_event_t *);
 void    mappingnotify(xcb_mapping_notify_event_t *);
@@ -1118,7 +1126,7 @@ void       setup_quirks(void);
 void    setup_screens(void);
 void    setup_spawn(void);
 void    set_child_transient(struct ws_win *, xcb_window_t *);
-void    set_win_state(struct ws_win *, uint16_t);
+void    set_win_state(struct ws_win *, uint8_t);
 void    shutdown_cleanup(void);
 void    sighdlr(int);
 void    socket_setnonblock(int);
@@ -1150,6 +1158,7 @@ void       update_floater(struct ws_win *);
 void    update_modkey(unsigned int);
 void    update_win_stacking(struct ws_win *);
 void    update_window(struct ws_win *);
+void    update_window_color(struct ws_win *);
 void    update_wm_state(struct  ws_win *win);
 void    validate_spawns(void);
 int     validate_win(struct ws_win *);
@@ -1449,10 +1458,10 @@ teardown_ewmh(void)
 void
 ewmh_autoquirk(struct ws_win *win)
 {
-       uint32_t                i, n;
-       xcb_atom_t              *type;
-       xcb_get_property_cookie_t       c;
        xcb_get_property_reply_t        *r;
+       xcb_get_property_cookie_t       c;
+       xcb_atom_t                      *type;
+       int                             i, n;
 
        c = xcb_get_property(conn, 0, win->id,
            ewmh[_NET_WM_WINDOW_TYPE].atom, XCB_ATOM_ATOM, 0, UINT32_MAX);
@@ -1630,6 +1639,8 @@ ewmh_apply_flags(struct ws_win *win, uint32_t pending)
                                        ws->focus_pending = win;
                        }
                }
+
+               update_window_color(win);
                raise_window(win);
        }
 
@@ -1714,7 +1725,7 @@ ewmh_get_wm_state(struct ws_win *win)
 void
 dumpwins(struct swm_region *r, union arg *args)
 {
-       struct ws_win                           *win;
+       struct ws_win                           *w;
        uint32_t                                state;
        xcb_get_window_attributes_cookie_t      c;
        xcb_get_window_attributes_reply_t       *wa;
@@ -1728,33 +1739,40 @@ dumpwins(struct swm_region *r, union arg *args)
        }
 
        DPRINTF("=== managed window list ws %02d ===\n", r->ws->idx);
-       TAILQ_FOREACH(win, &r->ws->winlist, entry) {
-               state = getstate(win->id);
-               c = xcb_get_window_attributes(conn, win->id);
+       TAILQ_FOREACH(w, &r->ws->winlist, entry) {
+               state = get_win_state(w->id);
+               c = xcb_get_window_attributes(conn, w->id);
                wa = xcb_get_window_attributes_reply(conn, c, NULL);
                if (wa) {
                        DPRINTF("win %#x, map_state: %d, state: %u, "
-                           "transient: %#x\n", win->id, wa->map_state,
-                           state, win->transient);
+                           "transient: %#x\n", w->id, wa->map_state,
+                           state, w->transient);
                        free(wa);
                } else
                        DPRINTF("win %#x, failed xcb_get_window_attributes\n",
-                           win->id);
+                           w->id);
+       }
+
+       DPRINTF("=== stacking order (top down) === \n");
+       TAILQ_FOREACH(w, &r->ws->stack, stack_entry) {
+               DPRINTF("win %#x, fs: %s, maximized: %s, above: %s, "
+                   "iconic: %s\n", w->id, YESNO(FULLSCREEN(w)),
+                   YESNO(MAXIMIZED(w)), YESNO(ABOVE(w)), YESNO(ICONIC(w)));
        }
 
        DPRINTF("===== unmanaged window list =====\n");
-       TAILQ_FOREACH(win, &r->ws->unmanagedlist, entry) {
-               state = getstate(win->id);
-               c = xcb_get_window_attributes(conn, win->id);
+       TAILQ_FOREACH(w, &r->ws->unmanagedlist, entry) {
+               state = get_win_state(w->id);
+               c = xcb_get_window_attributes(conn, w->id);
                wa = xcb_get_window_attributes_reply(conn, c, NULL);
                if (wa) {
                        DPRINTF("win %#x, map_state: %d, state: %u, "
-                           "transient: %#x\n", win->id, wa->map_state,
-                           state, win->transient);
+                           "transient: %#x\n", w->id, wa->map_state,
+                           state, w->transient);
                        free(wa);
                } else
                        DPRINTF("win %#x, failed xcb_get_window_attributes\n",
-                           win->id);
+                           w->id);
        }
 
        DPRINTF("=================================\n");
@@ -1885,24 +1903,13 @@ name_to_pixel(int sidx, const char *colorname)
 void
 setscreencolor(const char *val, int i, int c)
 {
-       int     num_screens;
+       if (i < 0 || i >= get_screen_count())
+               return;
 
-       num_screens = get_screen_count();
-       if (i > 0 && i <= num_screens) {
-               screens[i - 1].c[c].pixel = name_to_pixel(i - 1, val);
-               free(screens[i - 1].c[c].name);
-               if ((screens[i - 1].c[c].name = strdup(val)) == NULL)
-                       err(1, "strdup");
-       } else if (i == -1) {
-               for (i = 0; i < num_screens; i++) {
-                       screens[i].c[c].pixel = name_to_pixel(0, val);
-                       free(screens[i].c[c].name);
-                       if ((screens[i].c[c].name = strdup(val)) == NULL)
-                               err(1, "strdup");
-               }
-       } else
-               errx(1, "invalid screen index: %d out of bounds (maximum %d)",
-                   i, num_screens);
+       screens[i].c[c].pixel = name_to_pixel(i, val);
+       free(screens[i].c[c].name);
+       if ((screens[i].c[c].name = strdup(val)) == NULL)
+               err(1, "strdup");
 }
 
 void
@@ -2709,6 +2716,12 @@ xft_init(struct swm_region *r)
            DefaultColormap(display, r->s->idx), &color, &bar_font_color))
                warn("Xft error: unable to allocate color.");
 
+       PIXEL_TO_XRENDERCOLOR(r->s->c[SWM_S_COLOR_BAR].pixel, color);
+
+       if (!XftColorAllocValue(display, DefaultVisual(display, r->s->idx),
+           DefaultColormap(display, r->s->idx), &color, &search_font_color))
+               warn("Xft error: unable to allocate color.");
+
        bar_height = bar_font->height + 2 * bar_border_width;
 
        if (bar_height < 1)
@@ -2786,7 +2799,7 @@ bar_cleanup(struct swm_region *r)
 }
 
 void
-set_win_state(struct ws_win *win, uint16_t state)
+set_win_state(struct ws_win *win, uint8_t state)
 {
        uint16_t                data[2] = { state, XCB_ATOM_NONE };
 
@@ -2800,12 +2813,12 @@ set_win_state(struct ws_win *win, uint16_t state)
            a_state, 32, 2, data);
 }
 
-uint32_t
-getstate(xcb_window_t w)
+uint8_t
+get_win_state(xcb_window_t w)
 {
-       uint32_t                        result = 0;
-       xcb_get_property_cookie_t       c;
        xcb_get_property_reply_t        *r;
+       xcb_get_property_cookie_t       c;
+       uint32_t                        result = 0;
 
        c = xcb_get_property(conn, 0, w, a_state, a_state, 0L, 2L);
        r = xcb_get_property_reply(conn, c, NULL);
@@ -2815,7 +2828,7 @@ getstate(xcb_window_t w)
                free(r);
        }
 
-       DNPRINTF(SWM_D_MISC, "getstate property: win %#x state %u\n", w,
+       DNPRINTF(SWM_D_MISC, "get_win_state property: win %#x state %u\n", w,
            result);
        return (result);
 }
@@ -2996,6 +3009,9 @@ raise_window(struct ws_win *win)
                        continue;
                if (ws->cur_layout == &layouts[SWM_MAX_STACK])
                        break;
+               if (TRANS(win) && (win->transient == target->transient ||
+                   win->transient == target->id))
+                       break;
                if (FULLSCREEN(win))
                        break;
                if (FULLSCREEN(target))
@@ -3017,6 +3033,17 @@ raise_window(struct ws_win *win)
                update_win_stacking(win);
        }
 
+#ifdef SWM_DEBUG
+       if (swm_debug & SWM_D_STACK) {
+               DPRINTF("=== stacking order (top down) === \n");
+               TAILQ_FOREACH(target, &r->ws->stack, stack_entry) {
+                       DPRINTF("win %#x, fs: %s, maximized: %s, above: %s, "
+                           "iconic: %s\n", target->id, YESNO(FULLSCREEN(target)),
+                           YESNO(MAXIMIZED(target)), YESNO(ABOVE(target)),
+                           YESNO(ICONIC(target)));
+               }
+       }
+#endif
        DNPRINTF(SWM_D_EVENT, "raise_window: done\n");
 }
 
@@ -3445,8 +3472,7 @@ unfocus_win(struct ws_win *win)
                win->ws->focus_prev = NULL;
        }
 
-       xcb_change_window_attributes(conn, win->id, XCB_CW_BORDER_PIXEL,
-           &win->ws->r->s->c[SWM_S_COLOR_UNFOCUS].pixel);
+       update_window_color(win);
 
        xcb_change_property(conn, XCB_PROP_MODE_REPLACE, win->s->root,
            ewmh[_NET_ACTIVE_WINDOW].atom, XCB_ATOM_WINDOW, 32, 1, &none);
@@ -3463,13 +3489,7 @@ focus_win(struct ws_win *win)
 
        DNPRINTF(SWM_D_FOCUS, "focus_win: win %#x\n", WINID(win));
 
-       if (win == NULL)
-               goto out;
-
-       if (win->ws == NULL)
-               goto out;
-
-       if (!win->mapped)
+       if (win == NULL || win->ws == NULL || !win->mapped)
                goto out;
 
        ws = win->ws;
@@ -3490,7 +3510,9 @@ focus_win(struct ws_win *win)
                                /* Change border to unfocused color. */
                                xcb_change_window_attributes(conn, cfw->id,
                                    XCB_CW_BORDER_PIXEL,
-                                   &cfw->ws->r->s->c[SWM_S_COLOR_UNFOCUS].pixel);
+                                   &cfw->s->c[(MAXIMIZED(cfw) ?
+                                   SWM_S_COLOR_UNFOCUS_MAXIMIZED :
+                                   SWM_S_COLOR_UNFOCUS)].pixel);
                        } else {
                                unfocus_win(cfw);
                        }
@@ -3536,9 +3558,6 @@ focus_win(struct ws_win *win)
                                client_msg(win, a_takefocus, last_event_time);
                }
 
-               xcb_change_window_attributes(conn, win->id, XCB_CW_BORDER_PIXEL,
-                   &ws->r->s->c[SWM_S_COLOR_FOCUS].pixel);
-
                if (ws->cur_layout->flags & SWM_L_MAPONFOCUS ||
                    ws->always_raise) {
                        /* If a parent exists, map it first. */
@@ -3577,6 +3596,10 @@ focus_win(struct ws_win *win)
                    &win->id);
        }
 
+       if (cfw != win)
+               /* Update window border even if workspace is hidden. */
+               update_window_color(win);
+
 out:
        bar_draw();
 
@@ -3727,8 +3750,7 @@ switchws(struct swm_region *r, union arg *args)
                return;
 
        if ((win = old_ws->focus) != NULL) {
-               xcb_change_window_attributes(conn, win->id, XCB_CW_BORDER_PIXEL,
-                   &win->ws->r->s->c[SWM_S_COLOR_UNFOCUS].pixel);
+               update_window_color(win);
 
                xcb_change_property(conn, XCB_PROP_MODE_REPLACE, win->s->root,
                    ewmh[_NET_ACTIVE_WINDOW].atom, XCB_ATOM_WINDOW, 32, 1,
@@ -3797,7 +3819,7 @@ cyclews(struct swm_region *r, union arg *args)
        union                   arg a;
        struct swm_screen       *s = r->s;
        int                     cycle_all = 0;
-       int                     move = 0;
+       int                     mv = 0;
 
        DNPRINTF(SWM_D_WS, "cyclews: id: %d, screen[%d]:%dx%d+%d+%d, ws: %d\n",
            args->id, r->s->idx, WIDTH(r), HEIGHT(r), X(r), Y(r), r->ws->idx);
@@ -3807,7 +3829,7 @@ cyclews(struct swm_region *r, union arg *args)
        do {
                switch (args->id) {
                case SWM_ARG_ID_CYCLEWS_MOVE_UP:
-                       move = 1;
+                       mv = 1;
                        /* FALLTHROUGH */
                case SWM_ARG_ID_CYCLEWS_UP_ALL:
                        cycle_all = 1;
@@ -3816,7 +3838,7 @@ cyclews(struct swm_region *r, union arg *args)
                        a.id = (a.id < workspace_limit - 1) ? a.id + 1 : 0;
                        break;
                case SWM_ARG_ID_CYCLEWS_MOVE_DOWN:
-                       move = 1;
+                       mv = 1;
                        /* FALLTHROUGH */
                case SWM_ARG_ID_CYCLEWS_DOWN_ALL:
                        cycle_all = 1;
@@ -3834,7 +3856,7 @@ cyclews(struct swm_region *r, union arg *args)
                if (!cycle_visible && s->ws[a.id].r != NULL)
                        continue;
 
-               if (move)
+               if (mv)
                        send_to_ws(r, &a);
 
                switchws(r, &a);
@@ -3956,9 +3978,39 @@ swapwin(struct swm_region *r, union arg *args)
            args->id, r->s->idx, WIDTH(r), HEIGHT(r), X(r), Y(r), r->ws->idx);
 
        cur_focus = r->ws->focus;
-       if (cur_focus == NULL || ABOVE(cur_focus) || FULLSCREEN(cur_focus))
+       if (cur_focus == NULL || FULLSCREEN(cur_focus))
                return;
 
+       /* Adjust stacking in floating layer. */
+       if (ABOVE(cur_focus)) {
+               switch (args->id) {
+               case SWM_ARG_ID_SWAPPREV:
+                       target = TAILQ_PREV(cur_focus, ws_win_stack,
+                           stack_entry);
+                       if (target != NULL && FLOATING(target)) {
+                               TAILQ_REMOVE(&cur_focus->ws->stack, cur_focus,
+                                   stack_entry);
+                               TAILQ_INSERT_BEFORE(target, cur_focus,
+                                   stack_entry);
+                               update_win_stacking(cur_focus);
+                               focus_flush();
+                       }
+                       break;
+               case SWM_ARG_ID_SWAPNEXT:
+                       target = TAILQ_NEXT(cur_focus, stack_entry);
+                       if (target != NULL && FLOATING(target)) {
+                               TAILQ_REMOVE(&cur_focus->ws->stack, cur_focus,
+                                   stack_entry);
+                               TAILQ_INSERT_AFTER(&cur_focus->ws->stack,
+                                   target, cur_focus, stack_entry);
+                               update_win_stacking(cur_focus);
+                               focus_flush();
+                       }
+                       break;
+               }
+               goto out;
+       }
+
        if (r->ws->cur_layout == &layouts[SWM_MAX_STACK])
                return;
 
@@ -4018,12 +4070,12 @@ swapwin(struct swm_region *r, union arg *args)
        }
 
        sort_windows(wl);
-
        ewmh_update_client_list();
 
        stack();
-
        focus_flush();
+out:
+       DNPRINTF(SWM_D_MOVE, "swapwin: done\n");
 }
 
 struct ws_win *
@@ -4441,6 +4493,8 @@ update_floater(struct ws_win *win)
 
        DNPRINTF(SWM_D_MISC, "update_floater: win %#x\n", win->id);
 
+       win->bordered = 1;
+
        if (FULLSCREEN(win)) {
                /* _NET_WM_FULLSCREEN: fullscreen without border. */
                if (!win->g_floatvalid)
@@ -4456,14 +4510,11 @@ update_floater(struct ws_win *win)
                win->g = r->g;
 
                if (bar_enabled && ws->bar_enabled) {
-                       win->bordered = 1;
                        if (!bar_at_bottom)
                                Y(win) += bar_height;
                        HEIGHT(win) -= bar_height;
                } else if (disable_border) {
                        win->bordered = 0;
-               } else {
-                       win->bordered = 1;
                }
 
                if (win->bordered) {
@@ -4868,7 +4919,10 @@ max_stack(struct workspace *ws, struct swm_geometry *g)
        else
                win = TAILQ_FIRST(&ws->winlist);
 
-       DNPRINTF(SWM_D_STACK, "max_stack: win: %#x\n", win->id);
+       DNPRINTF(SWM_D_STACK, "max_stack: focus_pending: %#x, focus: %#x, "
+           "focus_prev: %#x, first: %#x, win: %#x\n", WINID(ws->focus_pending),
+           WINID(ws->focus), WINID(ws->focus_prev),
+           WINID(TAILQ_FIRST(&ws->winlist)), win->id);
 
        /* Update window geometry. */
        TAILQ_FOREACH(w, &ws->winlist, entry) {
@@ -4906,8 +4960,7 @@ max_stack(struct workspace *ws, struct swm_geometry *g)
                }
        }
 
-       if (TRANS(win)) {
-               parent = find_window(win->transient);
+       if (TRANS(win) && (parent = find_window(win->transient))) {
                raise_window(parent);
 
                TAILQ_FOREACH(w, &ws->stack, stack_entry)
@@ -4970,6 +5023,7 @@ region_under(struct swm_screen *s, int x, int y)
        return (NULL);
 }
 
+/* Transfer focused window to target workspace and focus. */
 void
 send_to_ws(struct swm_region *r, union arg *args)
 {
@@ -4983,7 +5037,7 @@ send_to_ws(struct swm_region *r, union arg *args)
 
        DNPRINTF(SWM_D_MOVE, "send_to_ws: win %#x, ws %d\n", win->id, wsid);
 
-       if (wsid >= workspace_limit)
+       if (wsid < 0 || wsid >= workspace_limit)
                return;
 
        if (win->ws->idx == wsid)
@@ -4991,20 +5045,38 @@ send_to_ws(struct swm_region *r, union arg *args)
 
        win_to_ws(win, wsid, 1);
 
+       /* Set new focus on target ws. */
+       if (focus_mode != SWM_FOCUS_FOLLOW) {
+               win->ws->focus_prev = win->ws->focus;
+               win->ws->focus = win;
+               win->ws->focus_pending = NULL;
+
+               if (win->ws->focus_prev)
+                       update_window_color(win->ws->focus_prev);
+       }
+
+       DNPRINTF(SWM_D_STACK, "send_to_ws: focus_pending: %#x, focus: %#x, "
+           "focus_prev: %#x, first: %#x, win: %#x\n",
+           WINID(r->ws->focus_pending), WINID(r->ws->focus),
+           WINID(r->ws->focus_prev), WINID(TAILQ_FIRST(&r->ws->winlist)),
+           win->id);
+
        ewmh_apply_flags(win, win->ewmh_flags & ~EWMH_F_MAXIMIZED);
        ewmh_update_wm_state(win);
 
-       /* Restack and set new focus. */
+       /* Restack and set new focus on current ws. */
+       if (FLOATING(win))
+               load_float_geom(win);
+
        stack();
 
        if (focus_mode != SWM_FOCUS_FOLLOW) {
-               if (r->ws->focus_pending) {
-                       focus_win(r->ws->focus_pending);
-                       r->ws->focus_pending = NULL;
+               if (r->ws->focus != NULL) {
+                       focus_win(r->ws->focus);
                } else {
-                       xcb_set_input_focus(conn,
-                           XCB_INPUT_FOCUS_PARENT, r->id,
+                       xcb_set_input_focus(conn, XCB_INPUT_FOCUS_PARENT, r->id,
                            XCB_CURRENT_TIME);
+                       bar_draw();
                }
        }
 
@@ -5017,7 +5089,7 @@ win_to_ws(struct ws_win *win, int wsid, int unfocus)
        struct ws_win           *parent;
        struct workspace        *ws, *nws, *pws;
 
-       if (wsid >= workspace_limit)
+       if (wsid < 0 || wsid >= workspace_limit)
                return;
 
        if (win->ws->idx == wsid)
@@ -5029,7 +5101,9 @@ win_to_ws(struct ws_win *win, int wsid, int unfocus)
        DNPRINTF(SWM_D_MOVE, "win_to_ws: win %#x, ws %d -> %d\n", win->id,
            ws->idx, wsid);
 
-       if (focus_mode != SWM_FOCUS_FOLLOW)
+       /* Cleanup focus on source ws. */
+       if (focus_mode != SWM_FOCUS_FOLLOW &&
+           (ws->focus == win || ws->focus_pending == win))
                ws->focus_pending = get_focus_prev(win);
 
        /* Move the parent if this is a transient window. */
@@ -5073,6 +5147,14 @@ win_to_ws(struct ws_win *win, int wsid, int unfocus)
        if (unfocus)
                unfocus_win(win);
 
+       if (ws->focus_prev == win)
+               ws->focus_prev = NULL;
+
+       if (focus_mode != SWM_FOCUS_FOLLOW && ws->focus_pending != NULL) {
+               ws->focus = ws->focus_pending;
+               ws->focus_pending = NULL;
+       }
+
        /* Don't unmap if new ws is visible */
        if (nws->r == NULL)
                unmap_window(win);
@@ -5084,10 +5166,6 @@ win_to_ws(struct ws_win *win, int wsid, int unfocus)
        TAILQ_INSERT_TAIL(&nws->stack, win, stack_entry);
        win->ws = nws;
 
-       /* Set focus on new ws. */
-       unfocus_win(nws->focus);
-       nws->focus = win;
-
        /* Update the window's workspace property: _NET_WM_DESKTOP */
        DNPRINTF(SWM_D_PROP, "win_to_ws: set property: "
            "_NET_WM_DESKTOP: %d\n", wsid);
@@ -5303,7 +5381,8 @@ search_win(struct swm_region *r, union arg *args)
        struct ws_win           *win = NULL;
        struct search_window    *sw = NULL;
        xcb_window_t            w;
-       uint32_t                wa[2];
+       uint32_t                wa[3];
+       xcb_screen_t            *screen;
        int                     i, width, height;
        char                    s[8];
        FILE                    *lfile;
@@ -5324,6 +5403,9 @@ search_win(struct swm_region *r, union arg *args)
        if ((lfile = fdopen(select_list_pipe[1], "w")) == NULL)
                return;
 
+       if ((screen = get_screen(r->s->idx)) == NULL)
+               errx(1, "ERROR: can't get screen %d.", r->s->idx);
+
        TAILQ_INIT(&search_wl);
 
        i = 1;
@@ -5347,6 +5429,7 @@ search_win(struct swm_region *r, union arg *args)
                w = xcb_generate_id(conn);
                wa[0] = r->s->c[SWM_S_COLOR_FOCUS].pixel;
                wa[1] = r->s->c[SWM_S_COLOR_UNFOCUS].pixel;
+               wa[2] = screen->default_colormap;
 
                if (bar_font_legacy) {
                        XmbTextExtents(bar_fs, s, len, &l_ibox, &l_lbox);
@@ -5359,10 +5442,10 @@ search_win(struct swm_region *r, union arg *args)
                        height = bar_font->height + 4;
                }
 
-               xcb_create_window(conn, XCB_COPY_FROM_PARENT, w, win->id, 0, 0,
+               xcb_create_window(conn, screen->root_depth, w, win->id, 0, 0,
                    width, height, 1, XCB_WINDOW_CLASS_INPUT_OUTPUT,
-                   XCB_COPY_FROM_PARENT, XCB_CW_BACK_PIXEL |
-                   XCB_CW_BORDER_PIXEL, wa);
+                   screen->root_visual, XCB_CW_BACK_PIXEL |
+                   XCB_CW_BORDER_PIXEL | XCB_CW_COLORMAP, wa);
 
                xcb_map_window(conn, w);
 
@@ -5387,7 +5470,7 @@ search_win(struct swm_region *r, union arg *args)
                            DefaultVisual(display, r->s->idx),
                            DefaultColormap(display, r->s->idx));
 
-                       XftDrawStringUtf8(draw, &bar_font_color, bar_font, 2,
+                       XftDrawStringUtf8(draw, &search_font_color, bar_font, 2,
                            (HEIGHT(r->bar) + bar_font->height) / 2 -
                            bar_font->descent, (FcChar8 *)s, len);
 
@@ -5478,7 +5561,7 @@ ewmh_update_desktop_names(void)
                        ++len;
                }
 
-               if((name_list = calloc(sizeof(char *), len)) == NULL)
+               if((name_list = calloc(len, sizeof(char))) == NULL)
                        err(1, "update_desktop_names: calloc: failed to "
                            "allocate memory.");
 
@@ -5561,7 +5644,7 @@ ewmh_update_client_list(void)
                if (count == 0)
                        continue;
 
-               wins = calloc(sizeof(xcb_window_t), count);
+               wins = calloc(count, sizeof(xcb_window_t));
                if (wins == NULL)
                        err(1, "ewmh_update_client_list: calloc: failed to "
                            "allocate memory.");
@@ -5596,7 +5679,7 @@ ewmh_update_desktops(void)
        int                     num_screens, i, j;
        uint32_t                *vals;
 
-       vals = calloc(sizeof(uint32_t), workspace_limit * 2);
+       vals = calloc(workspace_limit * 2, sizeof(uint32_t));
        if (vals == NULL)
                err(1, "ewmh_update_desktops: calloc: failed to allocate "
                    "memory.");
@@ -5819,26 +5902,32 @@ maximize_toggle(struct swm_region *r, union arg *args)
 void
 floating_toggle(struct swm_region *r, union arg *args)
 {
-       struct ws_win           *win = r->ws->focus;
+       struct ws_win           *w = r->ws->focus;
 
        /* suppress unused warning since var is needed */
        (void)args;
 
-       if (win == NULL)
+       if (w == NULL)
                return;
 
-       if (FULLSCREEN(win) || TRANS(win))
+       DNPRINTF(SWM_D_MISC, "floating_toggle: win %#x\n", w->id);
+
+       if (FULLSCREEN(w) || TRANS(w))
                return;
 
-       ewmh_apply_flags(win, win->ewmh_flags ^ EWMH_F_ABOVE);
-       ewmh_update_wm_state(win);
+       if (w->ws->cur_layout == &layouts[SWM_MAX_STACK])
+               return;
+
+       ewmh_apply_flags(w, w->ewmh_flags ^ EWMH_F_ABOVE);
+       ewmh_update_wm_state(w);
 
        stack();
 
-       if (win == win->ws->focus)
-               focus_win(win);
+       if (w == w->ws->focus)
+               focus_win(w);
 
        focus_flush();
+       DNPRINTF(SWM_D_MISC, "floating_toggle: done\n");
 }
 
 void
@@ -5928,6 +6017,24 @@ constrain_window(struct ws_win *win, struct swm_geometry *b, int *opts)
        }
 }
 
+void
+update_window_color(struct ws_win *win)
+{
+       uint32_t        *pixel;
+
+       if (WS_FOCUSED(win->ws) && win->ws->focus == win)
+               pixel = MAXIMIZED(win) ?
+                   &win->s->c[SWM_S_COLOR_FOCUS_MAXIMIZED].pixel :
+                   &win->s->c[SWM_S_COLOR_FOCUS].pixel;
+       else
+               pixel = MAXIMIZED(win) ?
+                   &win->s->c[SWM_S_COLOR_UNFOCUS_MAXIMIZED].pixel :
+                   &win->s->c[SWM_S_COLOR_UNFOCUS].pixel;
+
+       xcb_change_window_attributes(conn, win->id,
+           XCB_CW_BORDER_PIXEL, pixel);
+}
+
 void
 update_window(struct ws_win *win)
 {
@@ -6124,6 +6231,12 @@ resize(struct ws_win *win, union arg *args)
                                xcb_flush(conn);
                        }
                        break;
+               case XCB_KEY_PRESS:
+                       /* Ignore. */
+                       xcb_allow_events(conn, XCB_ALLOW_ASYNC_KEYBOARD,
+                           ((xcb_key_press_event_t *)evt)->time);
+                       xcb_flush(conn);
+                       break;
                default:
                        event_handle(evt);
 
@@ -6174,9 +6287,18 @@ regionize(struct ws_win *win, int x, int y)
                r = region_under(win->s, X(win) + WIDTH(win) / 2,
                    Y(win) + HEIGHT(win) / 2);
 
-       if (r && r != win->ws->r) {
+       if (r != NULL && r != win->ws->r) {
+               if (clear_maximized(r->ws) > 0)
+                       stack();
+
                win_to_ws(win, r->ws->idx, 0);
+
+               /* Set focus on new ws. */
+               unfocus_win(r->ws->focus);
+               r->ws->focus = win;
+
                set_region(r);
+               raise_window(win);
        }
 }
 
@@ -6297,6 +6419,12 @@ move(struct ws_win *win, union arg *args)
                                xcb_flush(conn);
                        }
                        break;
+               case XCB_KEY_PRESS:
+                       /* Ignore. */
+                       xcb_allow_events(conn, XCB_ALLOW_ASYNC_KEYBOARD,
+                           ((xcb_key_press_event_t *)evt)->time);
+                       xcb_flush(conn);
+                       break;
                default:
                        event_handle(evt);
 
@@ -6316,6 +6444,13 @@ move(struct ws_win *win, union arg *args)
                xcb_flush(conn);
        }
        store_float_geom(win);
+
+       /* New region set to fullscreen layout. */
+       if (win->ws->cur_layout == &layouts[SWM_MAX_STACK]) {
+               stack();
+               focus_flush();
+       }
+
 out:
        free(qpr);
        xcb_ungrab_pointer(conn, XCB_CURRENT_TIME);
@@ -6572,11 +6707,21 @@ spawn_expand(struct swm_region *r, union arg *args, const char *spawn_name,
                            strdup(r->s->c[SWM_S_COLOR_FOCUS].name))
                            == NULL)
                                err(1, "spawn_custom color focus");
+               } else if (strcasecmp(ap, "$color_focus_maximized") == 0) {
+                       if ((real_args[c] =
+                           strdup(r->s->c[SWM_S_COLOR_FOCUS_MAXIMIZED].name))
+                           == NULL)
+                               err(1, "spawn_custom color focus maximized");
                } else if (strcasecmp(ap, "$color_unfocus") == 0) {
                        if ((real_args[c] =
                            strdup(r->s->c[SWM_S_COLOR_UNFOCUS].name))
                            == NULL)
                                err(1, "spawn_custom color unfocus");
+               } else if (strcasecmp(ap, "$color_unfocus_maximized") == 0) {
+                       if ((real_args[c] =
+                           strdup(r->s->c[SWM_S_COLOR_UNFOCUS_MAXIMIZED].name))
+                           == NULL)
+                               err(1, "spawn_custom color unfocus maximized");
                } else if (strcasecmp(ap, "$region_index") == 0) {
                        if (asprintf(&real_args[c], "%d",
                            get_region_index(r) + 1) < 1)
@@ -6720,7 +6865,7 @@ void
 spawn_insert(const char *name, const char *args, int flags)
 {
        struct spawn_prog       *sp;
-       char                    *arg, *dup, *ptr;
+       char                    *arg, *cp, *ptr;
 
        DNPRINTF(SWM_D_SPAWN, "spawn_insert: %s[%s]\n", name, args);
 
@@ -6733,7 +6878,7 @@ spawn_insert(const char *name, const char *args, int flags)
                err(1, "spawn_insert: strdup");
 
        /* Convert the arguments to an argument list. */
-       if ((ptr = dup = strdup(args)) == NULL)
+       if ((ptr = cp = strdup(args)) == NULL)
                err(1, "spawn_insert: strdup");
        while ((arg = argsep(&ptr)) != NULL) {
                /* Null argument; skip it. */
@@ -6747,7 +6892,7 @@ spawn_insert(const char *name, const char *args, int flags)
                if ((sp->argv[sp->argc - 1] = strdup(arg)) == NULL)
                        err(1, "spawn_insert: strdup");
        }
-       free(dup);
+       free(cp);
 
        sp->flags = flags;
 
@@ -7381,6 +7526,7 @@ const char *quirkname[] = {
        "FOCUSPREV",
        "NOFOCUSONMAP",
        "FOCUSONMAP_SINGLE",
+       "OBEYAPPFOCUSREQ",
 };
 
 /* SWM_Q_WS: retain '|' for back compat for now (2009-08-11) */
@@ -7686,7 +7832,8 @@ enum {
        SWM_S_WINDOW_CLASS_ENABLED,
        SWM_S_WINDOW_INSTANCE_ENABLED,
        SWM_S_WINDOW_NAME_ENABLED,
-       SWM_S_WORKSPACE_LIMIT
+       SWM_S_WORKSPACE_LIMIT,
+       SWM_S_WORKSPACE_NAME,
 };
 
 int
@@ -7694,7 +7841,7 @@ setconfvalue(const char *selector, const char *value, int flags)
 {
        struct workspace        *ws;
        int                     i, ws_id, num_screens;
-       char                    *b, *str;
+       char                    *b, *str, s[1024];
 
        switch (flags) {
        case SWM_S_BAR_ACTION:
@@ -7908,6 +8055,32 @@ setconfvalue(const char *selector, const char *value, int flags)
 
                ewmh_update_desktops();
                break;
+       case SWM_S_WORKSPACE_NAME:
+               if (getenv("SWM_STARTED") != NULL)
+                       return (0);
+
+               bzero(s, sizeof s);
+               if (sscanf(value, "ws[%d]:%1023c", &ws_id, s) != 2)
+                       errx(1, "invalid entry, should be 'ws[<idx>]:name'");
+               ws_id--;
+               if (ws_id < 0 || ws_id >= workspace_limit)
+                       errx(1, "setconfvalue: workspace_name: invalid "
+                           "workspace %d.", ws_id + 1);
+
+               num_screens = get_screen_count();
+               for (i = 0; i < num_screens; ++i) {
+                       ws = (struct workspace *)&screens[i].ws;
+
+                       if (strlen(s) > 0) {
+                               free(ws[ws_id].name);
+                               if ((ws[ws_id].name = strdup(s)) == NULL)
+                                       err(1, "setconfvalue: workspace_name.");
+
+                               ewmh_update_desktop_names();
+                               ewmh_get_desktop_names();
+                       }
+               }
+               break;
        default:
                return (1);
        }
@@ -7937,9 +8110,42 @@ setconfmodkey(const char *selector, const char *value, int flags)
 int
 setconfcolor(const char *selector, const char *value, int flags)
 {
-       setscreencolor(value,
-           (selector == NULL || strlen(selector) == 0) ? -1 : atoi(selector),
-           flags);
+       int     first, last, i = 0, num_screens;
+
+       num_screens = get_screen_count();
+
+       /* conf screen indices begin at 1; treat vals <= 0 as 'all screens.' */
+       if (selector == NULL || strlen(selector) == 0 ||
+           (last = atoi(selector) - 1) < 0) {
+               first = 0;
+               last = num_screens - 1;
+       } else {
+               first = last;
+       }
+
+       if (last >= num_screens) {
+               add_startup_exception("invalid screen index: %d out of bounds "
+                   "(maximum %d)", last + 1, num_screens);
+               return (1);
+       }
+
+       for (i = first; i <= last; ++i) {
+               setscreencolor(value, i, flags);
+
+               /*
+                * When setting focus/unfocus colors, we need to also
+                * set maximize colors to match if they haven't been customized.
+                */
+               if (flags == SWM_S_COLOR_FOCUS &&
+                   !screens[i].c[SWM_S_COLOR_FOCUS_MAXIMIZED].manual)
+                       setscreencolor(value, i, SWM_S_COLOR_FOCUS_MAXIMIZED);
+               else if (flags == SWM_S_COLOR_UNFOCUS &&
+                   !screens[i].c[SWM_S_COLOR_UNFOCUS_MAXIMIZED].manual)
+                       setscreencolor(value, i, SWM_S_COLOR_UNFOCUS_MAXIMIZED);
+
+               screens[i].c[flags].manual = 1;
+       }
+
        return (0);
 }
 
@@ -8138,7 +8344,9 @@ struct config_option configopt[] = {
        { "clock_enabled",              setconfvalue,   SWM_S_CLOCK_ENABLED },
        { "clock_format",               setconfvalue,   SWM_S_CLOCK_FORMAT },
        { "color_focus",                setconfcolor,   SWM_S_COLOR_FOCUS },
+       { "color_focus_maximized",      setconfcolor,   SWM_S_COLOR_FOCUS_MAXIMIZED },
        { "color_unfocus",              setconfcolor,   SWM_S_COLOR_UNFOCUS },
+       { "color_unfocus_maximized",    setconfcolor,   SWM_S_COLOR_UNFOCUS_MAXIMIZED },
        { "cycle_empty",                setconfvalue,   SWM_S_CYCLE_EMPTY },
        { "cycle_visible",              setconfvalue,   SWM_S_CYCLE_VISIBLE },
        { "dialog_ratio",               setconfvalue,   SWM_S_DIALOG_RATIO },
@@ -8170,6 +8378,7 @@ struct config_option configopt[] = {
        { "window_instance_enabled",    setconfvalue,   SWM_S_WINDOW_INSTANCE_ENABLED },
        { "window_name_enabled",        setconfvalue,   SWM_S_WINDOW_NAME_ENABLED },
        { "workspace_limit",            setconfvalue,   SWM_S_WORKSPACE_LIMIT },
+       { "name",                       setconfvalue,   SWM_S_WORKSPACE_NAME },
 };
 
 void
@@ -8474,17 +8683,17 @@ get_ws_idx(xcb_window_t id)
 }
 
 struct ws_win *
-manage_window(xcb_window_t id, uint16_t mapped)
+manage_window(xcb_window_t id, int mapped)
 {
-       xcb_window_t            trans = XCB_WINDOW_NONE;
        struct ws_win           *win, *ww;
-       int                     ws_idx;
-       char                    *class, *instance, *name;
        struct swm_region       *r;
        struct pid_e            *p;
        struct quirk            *qp;
-       uint32_t                i, wa[2], new_flags;
        xcb_get_geometry_reply_t        *gr;
+       xcb_window_t            trans = XCB_WINDOW_NONE;
+       uint32_t                i, wa[2], new_flags;
+       int                     ws_idx;
+       char                    *class, *instance, *name;
 
        if ((win = find_window(id)) != NULL) {
                DNPRINTF(SWM_D_MISC, "manage_window: win %#x already "
@@ -9040,14 +9249,18 @@ configurerequest(xcb_configure_request_event_t *e)
 
                win->g_floatvalid = 1;
 
-               if (ABOVE(win) && r && !MAXIMIZED(win) && (TRANS(win) ||
-                   win->ws->cur_layout != &layouts[SWM_MAX_STACK])) {
+               if (!MAXIMIZED(win) && !FULLSCREEN(win) &&
+                   (TRANS(win) || (ABOVE(win) &&
+                   win->ws->cur_layout != &layouts[SWM_MAX_STACK]))) {
                        WIDTH(win) = win->g_float.w;
                        HEIGHT(win) = win->g_float.h;
 
-                       if (r) {
+                       if (r != NULL) {
                                update_floater(win);
                                focus_flush();
+                       } else {
+                               config_win(win, e);
+                               xcb_flush(conn);
                        }
                } else {
                        config_win(win, e);
@@ -9227,6 +9440,13 @@ enternotify(xcb_enter_notify_event_t *e)
                        return;
                }
        } else {
+               if (e->mode == XCB_NOTIFY_MODE_NORMAL &&
+                   e->detail == XCB_NOTIFY_DETAIL_INFERIOR) {
+                       DNPRINTF(SWM_D_EVENT, "enternotify: entering from "
+                           "inferior; ignoring\n");
+                       return;
+               }
+
                focus_win(get_focus_magic(win));
        }
 
@@ -9543,6 +9763,30 @@ unmapnotify(xcb_unmap_notify_event_t *e)
        focus_flush();
 }
 
+#ifdef SWM_DEBUG
+char *
+get_source_type_label(uint32_t type)
+{
+       char *label;
+
+       switch (type) {
+       case EWMH_SOURCE_TYPE_NONE:
+               label = "None";
+               break;
+       case EWMH_SOURCE_TYPE_NORMAL:
+               label = "Normal";
+               break;
+       case EWMH_SOURCE_TYPE_OTHER:
+               label = "Other";
+               break;
+       default:
+               label = "Invalid";
+       }
+
+       return label;
+}
+#endif
+
 void
 clientmessage(xcb_client_message_event_t *e)
 {
@@ -9569,8 +9813,7 @@ clientmessage(xcb_client_message_event_t *e)
                                break;
                        }
 
-               if (r && e->data.data32[0] <
-                   (uint32_t)workspace_limit) {
+               if (r && e->data.data32[0] < (uint32_t)workspace_limit) {
                        a.id = e->data.data32[0];
                        switchws(r, &a);
                        focus_flush();
@@ -9592,11 +9835,22 @@ clientmessage(xcb_client_message_event_t *e)
        }
 
        if (e->type == ewmh[_NET_ACTIVE_WINDOW].atom) {
-               DNPRINTF(SWM_D_EVENT, "clientmessage: _NET_ACTIVE_WINDOW\n");
-               if (WS_FOCUSED(win->ws))
-                       focus_win(win);
-               else
-                       win->ws->focus_pending = win;
+               DNPRINTF(SWM_D_EVENT, "clientmessage: _NET_ACTIVE_WINDOW, "
+                   "source_type: %s(%d)\n",
+                   get_source_type_label(e->data.data32[0]),
+                   e->data.data32[0]);
+
+               /*
+                * Allow focus changes that are a result of direct user
+                * action and from applications that use the old EWMH spec.
+                */
+               if (e->data.data32[0] != EWMH_SOURCE_TYPE_NORMAL ||
+                   win->quirks & SWM_Q_OBEYAPPFOCUSREQ) {
+                       if (WS_FOCUSED(win->ws))
+                               focus_win(win);
+                       else
+                               win->ws->focus_pending = win;
+               }
        } else if (e->type == ewmh[_NET_CLOSE_WINDOW].atom) {
                DNPRINTF(SWM_D_EVENT, "clientmessage: _NET_CLOSE_WINDOW\n");
                if (win->can_delete)
@@ -9618,9 +9872,9 @@ clientmessage(xcb_client_message_event_t *e)
 
                        update_window(win);
                } else {
-                       /* TODO: Change stack sizes */
-                       /* notify no change was made. */
+                       /* Notify no change was made. */
                        config_win(win, NULL);
+                       /* TODO: Change stack sizes */
                }
        } else if (e->type == ewmh[_NET_RESTACK_WINDOW].atom) {
                DNPRINTF(SWM_D_EVENT, "clientmessage: _NET_RESTACK_WINDOW\n");
@@ -9638,6 +9892,19 @@ clientmessage(xcb_client_message_event_t *e)
 
                ewmh_update_wm_state(win);
                stack();
+       } else if (e->type == ewmh[_NET_WM_DESKTOP].atom) {
+               DNPRINTF(SWM_D_EVENT, "clientmessage: _NET_WM_DESKTOP\n");
+               r = win->ws->r;
+
+               win_to_ws(win, e->data.data32[0], 1);
+
+               /* Restack if either the source or destination ws is mapped. */
+               if (r != NULL || win->ws->r != NULL) {
+                       if (FLOATING(win))
+                               load_float_geom(win);
+
+                       stack();
+               }
        }
 
        focus_flush();
@@ -10005,6 +10272,11 @@ grab_windows(void)
                                            "skip %#x; region input window.\n",
                                            wins[j]);
                                        break;
+                               } else if (r->bar->id == wins[j]) {
+                                       DNPRINTF(SWM_D_INIT, "grab_windows: "
+                                           "skip %#x; region bar.\n",
+                                           wins[j]);
+                                       break;
                                }
                        }
 
@@ -10035,7 +10307,7 @@ grab_windows(void)
                                continue;
                        }
 
-                       state = getstate(wins[j]);
+                       state = get_win_state(wins[j]);
                        manage = state != XCB_ICCCM_WM_STATE_WITHDRAWN;
                        mapped = gar->map_state == XCB_MAP_STATE_VIEWABLE;
                        if (mapped || manage)
@@ -10060,7 +10332,7 @@ grab_windows(void)
                                continue;
                        }
 
-                       state = getstate(wins[j]);
+                       state = get_win_state(wins[j]);
                        manage = state != XCB_ICCCM_WM_STATE_WITHDRAWN;
                        mapped = gar->map_state == XCB_MAP_STATE_VIEWABLE;
                        pc = xcb_icccm_get_wm_transient_for(conn, wins[j]);
@@ -10121,13 +10393,16 @@ setup_screens(void)
                screens[i].root = screen->root;
 
                /* set default colors */
-               setscreencolor("red", i + 1, SWM_S_COLOR_FOCUS);
-               setscreencolor("rgb:88/88/88", i + 1, SWM_S_COLOR_UNFOCUS);
-               setscreencolor("rgb:00/80/80", i + 1, SWM_S_COLOR_BAR_BORDER);
-               setscreencolor("rgb:00/40/40", i + 1,
+               setscreencolor("red", i, SWM_S_COLOR_FOCUS);
+               setscreencolor("rgb:88/88/88", i, SWM_S_COLOR_UNFOCUS);
+               setscreencolor("rgb:00/80/80", i, SWM_S_COLOR_BAR_BORDER);
+               setscreencolor("rgb:00/40/40", i,
                    SWM_S_COLOR_BAR_BORDER_UNFOCUS);
-               setscreencolor("black", i + 1, SWM_S_COLOR_BAR);
-               setscreencolor("rgb:a0/a0/a0", i + 1, SWM_S_COLOR_BAR_FONT);
+               setscreencolor("black", i, SWM_S_COLOR_BAR);
+               setscreencolor("rgb:a0/a0/a0", i, SWM_S_COLOR_BAR_FONT);
+               setscreencolor("red", i, SWM_S_COLOR_FOCUS_MAXIMIZED);
+               setscreencolor("rgb:88/88/88", i,
+                   SWM_S_COLOR_UNFOCUS_MAXIMIZED);
 
                /* create graphics context on screen */
                screens[i].bar_gc = xcb_generate_id(conn);
@@ -10218,9 +10493,12 @@ shutdown_cleanup(void)
 
                if (screens[i].bar_gc != XCB_NONE)
                        xcb_free_gc(conn, screens[i].bar_gc);
-               if (!bar_font_legacy)
+               if (!bar_font_legacy) {
                        XftColorFree(display, DefaultVisual(display, i),
                            DefaultColormap(display, i), &bar_font_color);
+                       XftColorFree(display, DefaultVisual(display, i),
+                           DefaultColormap(display, i), &search_font_color);
+               }
        }
 
        if (bar_font_legacy)
@@ -10424,9 +10702,6 @@ noconfig:
 
        validate_spawns();
 
-       /* grab existing windows (before we build the bars) */
-       grab_windows();
-
        if (getenv("SWM_STARTED") == NULL)
                setenv("SWM_STARTED", "YES", 1);
 
@@ -10436,6 +10711,9 @@ noconfig:
                TAILQ_FOREACH(r, &screens[i].rl, entry)
                        bar_setup(r);
 
+       /* Manage existing windows. */
+       grab_windows();
+
        grabkeys();
        stack();
        bar_draw();