JasonWoof Got questions, comments, patches, etc.? Contact Jason Woofenden
Improve support for Extended Window Manager Hints (EWMH).
authorReginald Kennedy <rk@rejii.com>
Mon, 6 May 2013 16:58:57 +0000 (00:58 +0800)
committerReginald Kennedy <rk@rejii.com>
Fri, 7 Feb 2014 15:37:39 +0000 (23:37 +0800)
Add support for _NET_CURRENT DESKTOP.

Add support for _NET_DESKTOP_NAMES.

Add support for _NET_NUMBER_OF_DESKTOPS.

Add support for _NET_CLIENT_LIST.
Windows are sorted according to _NET_CLIENT_LIST at start.

Change iconify to use _NET_WM_STATE_HIDDEN instead of _SWM_ICONIC.

Add _NET_WM_FULL_PLACEMENT to _NET_SUPPORTED.

Improve handling of _NET_WM_STATE_FULLSCREEN.

Improve general handling of EWMH.

Fix focus issues when a window maps/unmaps on an unfocused region.

Fix calls to get property length that did not adjust for item size.

Fix stacking issues.

Fix segfault.

Disable swapwin on fullscreen layout.

Remove floating property from ws_win struct.

Add new macros for accessing ewmh_flags.

Initialize variables that should be initialized.

Fix some formatting.

Improve debug output.

Closes #1 and closes #20

spectrwm.1
spectrwm.c

index 1744917..63a86cd 100644 (file)
@@ -1072,6 +1072,12 @@ or un-floated):
 $ wmctrl \-i \-r 0x4a0000b \-b toggle,_NET_WM_STATE_ABOVE
 .Ed
 .Pp
+Windows can also be iconified and un-iconified by substituting
+_NET_WM_STATE_HIDDEN for _NET_WM_STATE_ABOVE in the previous example:
+.Bd -literal -offset indent
+$ wmctrl \-i \-r 0x4a0000b \-b toggle,_NET_WM_STATE_HIDDEN
+.Ed
+.Pp
 Floating windows can also be resized and moved by sending a
 _NET_MOVERESIZE_WINDOW client message to the root window.
 For example,
index acf078a..f4b0fa5 100644 (file)
@@ -144,7 +144,7 @@ static const char   *buildstr = SPECTRWM_VERSION;
 #define xcb_icccm_get_wm_hints                 xcb_get_wm_hints
 #define xcb_icccm_wm_hints_get_urgency         xcb_wm_hints_get_urgency
 #define xcb_icccm_get_wm_hints_reply           xcb_get_wm_hints_reply
-#define        xcb_icccm_get_wm_name                   xcb_get_wm_name
+#define xcb_icccm_get_wm_name                  xcb_get_wm_name
 #define xcb_icccm_get_wm_name_reply            xcb_get_wm_name_reply
 #define xcb_icccm_get_wm_normal_hints          xcb_get_wm_normal_hints
 #define xcb_icccm_get_wm_normal_hints_reply    xcb_get_wm_normal_hints_reply
@@ -209,10 +209,22 @@ u_int32_t         swm_debug = 0
 #define DNPRINTF(n,x...)
 #endif
 
+#define SWM_EWMH_ACTION_COUNT_MAX      (8)
+#define EWMH_F_FULLSCREEN              (0x001)
+#define EWMH_F_ABOVE                   (0x002)
+#define EWMH_F_HIDDEN                  (0x004)
+#define EWMH_F_MAXIMIZED_VERT          (0x008)
+#define EWMH_F_MAXIMIZED_HORZ          (0x010)
+#define EWMH_F_SKIP_PAGER              (0x020)
+#define EWMH_F_SKIP_TASKBAR            (0x040)
+#define SWM_F_MANUAL                   (0x080)
+
+#define EWMH_F_MAXIMIZED       (EWMH_F_MAXIMIZED_VERT | EWMH_F_MAXIMIZED_HORZ)
+
 /* convert 8-bit to 16-bit */
-#define RGB_8_TO_16(col)       ((col) << 8) + (col)
+#define RGB_8_TO_16(col)       (((col) << 8) + (col))
 
-#define        PIXEL_TO_XRENDERCOLOR(px, xrc)                                  \
+#define PIXEL_TO_XRENDERCOLOR(px, xrc)                                 \
        xrc.red = RGB_8_TO_16((px) >> 16 & 0xff);                       \
        xrc.green = RGB_8_TO_16((px) >> 8 & 0xff);                      \
        xrc.blue = RGB_8_TO_16((px) & 0xff);                            \
@@ -228,26 +240,36 @@ u_int32_t         swm_debug = 0
 #define SWM_FUNCNAME_LEN       (32)
 #define SWM_KEYS_LEN           (255)
 #define SWM_QUIRK_LEN          (64)
-#define X(r)                   (r)->g.x
-#define Y(r)                   (r)->g.y
-#define WIDTH(r)               (r)->g.w
-#define HEIGHT(r)              (r)->g.h
+#define X(r)                   ((r)->g.x)
+#define Y(r)                   ((r)->g.y)
+#define WIDTH(r)               ((r)->g.w)
+#define HEIGHT(r)              ((r)->g.h)
 #define BORDER(w)              ((w)->bordered ? border_width : 0)
 #define MAX_X(r)               ((r)->g.x + (r)->g.w)
 #define MAX_Y(r)               ((r)->g.y + (r)->g.h)
-#define SH_MIN(w)              (w)->sh.flags & XCB_ICCCM_SIZE_HINT_P_MIN_SIZE
-#define SH_MIN_W(w)            (w)->sh.min_width
-#define SH_MIN_H(w)            (w)->sh.min_height
-#define SH_MAX(w)              (w)->sh.flags & XCB_ICCCM_SIZE_HINT_P_MAX_SIZE
-#define SH_MAX_W(w)            (w)->sh.max_width
-#define SH_MAX_H(w)            (w)->sh.max_height
-#define SH_INC(w)              (w)->sh.flags & XCB_ICCCM_SIZE_HINT_P_RESIZE_INC
-#define SH_INC_W(w)            (w)->sh.width_inc
-#define SH_INC_H(w)            (w)->sh.height_inc
+#define SH_MIN(w)              ((w)->sh.flags & XCB_ICCCM_SIZE_HINT_P_MIN_SIZE)
+#define SH_MIN_W(w)            ((w)->sh.min_width)
+#define SH_MIN_H(w)            ((w)->sh.min_height)
+#define SH_MAX(w)              ((w)->sh.flags & XCB_ICCCM_SIZE_HINT_P_MAX_SIZE)
+#define SH_MAX_W(w)            ((w)->sh.max_width)
+#define SH_MAX_H(w)            ((w)->sh.max_height)
+#define SH_INC(w)              ((w)->sh.flags & XCB_ICCCM_SIZE_HINT_P_RESIZE_INC)
+#define SH_INC_W(w)            ((w)->sh.width_inc)
+#define SH_INC_H(w)            ((w)->sh.height_inc)
 #define SWM_MAX_FONT_STEPS     (3)
 #define WINID(w)               ((w) ? (w)->id : XCB_WINDOW_NONE)
 #define WS_FOCUSED(ws)         ((ws)->r && (ws)->r->s->r_focus == (ws)->r)
 #define YESNO(x)               ((x) ? "yes" : "no")
+#define ICONIC(w)              ((w)->ewmh_flags & EWMH_F_HIDDEN)
+#define ABOVE(w)               ((w)->ewmh_flags & EWMH_F_ABOVE)
+#define FULLSCREEN(w)          ((w)->ewmh_flags & EWMH_F_FULLSCREEN)
+#define MAXIMIZED_VERT(w)      ((w)->ewmh_flags & EWMH_F_MAXIMIZED_VERT)
+#define MAXIMIZED_HORZ(w)      ((w)->ewmh_flags & EWMH_F_MAXIMIZED_HORZ)
+#define MAXIMIZED(w)           (MAXIMIZED_VERT(w) || MAXIMIZED_HORZ(w))
+#define MANUAL(w)              ((w)->ewmh_flags & SWM_F_MANUAL)
+#define TRANS(w)               ((w)->transient != XCB_WINDOW_NONE)
+#define FLOATING(w)            (ABOVE(w) || TRANS(w) || FULLSCREEN(w) ||      \
+    MAXIMIZED(w))
 
 /* Constrain Window flags */
 #define SWM_CW_RESIZABLE       (0x01)
@@ -263,12 +285,16 @@ u_int32_t         swm_debug = 0
 #define SWM_FOCUS_FOLLOW       (1)
 #define SWM_FOCUS_MANUAL       (2)
 
-#define SWM_CK_NONE            0
-#define SWM_CK_ALL             0xf
-#define SWM_CK_FOCUS           0x1
-#define SWM_CK_POINTER         0x2
-#define SWM_CK_FALLBACK                0x4
-#define SWM_CK_REGION          0x8
+#define SWM_CK_NONE            (0)
+#define SWM_CK_ALL             (0xf)
+#define SWM_CK_FOCUS           (0x1)
+#define SWM_CK_POINTER         (0x2)
+#define SWM_CK_FALLBACK                (0x4)
+#define SWM_CK_REGION          (0x8)
+
+#define SWM_G_ALL              (0xf)
+#define SWM_G_SIZE             (0x1)
+#define SWM_G_POS              (0x2)
 
 #define SWM_CONF_DEFAULT       (0)
 #define SWM_CONF_KEYMAPPING    (1)
@@ -281,9 +307,10 @@ char                       **start_argv;
 xcb_atom_t             a_state;
 xcb_atom_t             a_prot;
 xcb_atom_t             a_delete;
+xcb_atom_t             a_net_wm_check;
+xcb_atom_t             a_net_supported;
 xcb_atom_t             a_takefocus;
 xcb_atom_t             a_utf8_string;
-xcb_atom_t             a_swm_iconic;
 xcb_atom_t             a_swm_ws;
 volatile sig_atomic_t   running = 1;
 volatile sig_atomic_t   restart_wm = 0;
@@ -334,8 +361,8 @@ enum {
 
 #define SWM_STACK_TOP          (0)
 #define SWM_STACK_BOTTOM       (1)
-#define        SWM_STACK_ABOVE         (2)
-#define        SWM_STACK_BELOW         (3)
+#define SWM_STACK_ABOVE                (2)
+#define SWM_STACK_BELOW                (3)
 
 /* dialog windows */
 double                 dialog_ratio = 0.6;
@@ -345,10 +372,10 @@ double                    dialog_ratio = 0.6;
 #define SWM_BAR_JUSTIFY_CENTER (1)
 #define SWM_BAR_JUSTIFY_RIGHT  (2)
 #define SWM_BAR_OFFSET         (4)
-#define SWM_BAR_FONTS          "-*-terminus-medium-*-*-*-12-*-*-*-*-*-*-*," \
-                               "-*-profont-*-*-*-*-12-*-*-*-*-*-*-*,"      \
-                               "-*-times-medium-r-*-*-12-*-*-*-*-*-*-*,"    \
-                               "-misc-fixed-medium-r-*-*-12-*-*-*-*-*-*-*,"  \
+#define SWM_BAR_FONTS          "-*-terminus-medium-*-*-*-12-*-*-*-*-*-*-*,"    \
+                               "-*-profont-*-*-*-*-12-*-*-*-*-*-*-*,"          \
+                               "-*-times-medium-r-*-*-12-*-*-*-*-*-*-*,"       \
+                               "-misc-fixed-medium-r-*-*-12-*-*-*-*-*-*-*,"    \
                                "-*-*-*-r-*-*-*-*-*-*-*-*-*-*"
 
 #ifdef X_HAVE_UTF8_STRING
@@ -432,19 +459,16 @@ TAILQ_HEAD(swm_region_list, swm_region);
 
 struct ws_win {
        TAILQ_ENTRY(ws_win)     entry;
+       TAILQ_ENTRY(ws_win)     stack_entry;
        xcb_window_t            id;
        xcb_window_t            transient;
        struct ws_win           *focus_child;   /* focus on child transient */
        struct swm_geometry     g;              /* current geometry */
        struct swm_geometry     g_float;        /* region coordinates */
        int                     g_floatvalid;   /* g_float geometry validity */
-       int                     floating;
-       int                     manual;
        int32_t                 mapped;
-       int32_t                 iconic;
-       int32_t                 maximized;
        int                     bordered;
-       unsigned int            ewmh_flags;
+       uint32_t                ewmh_flags;
        int                     font_size_boundary[SWM_MAX_FONT_STEPS];
        int                     font_steps;
        int                     last_inc;
@@ -459,6 +483,7 @@ struct ws_win {
        xcb_icccm_wm_hints_t    hints;
 };
 TAILQ_HEAD(ws_win_list, ws_win);
+TAILQ_HEAD(ws_win_stack, ws_win);
 
 /* pid goo */
 struct pid_e {
@@ -517,7 +542,8 @@ struct workspace {
        struct swm_region       *old_r;         /* may be NULL */
        struct ws_win_list      winlist;        /* list of windows in ws */
        struct ws_win_list      unmanagedlist;  /* list of dead windows in ws */
-       int32_t                 state;
+       struct ws_win_stack     stack;          /* stacking order */
+       int32_t                 state;          /* mapping state */
        char                    stacker[10];    /* display stacker and layout */
 
        /* stacker state */
@@ -647,7 +673,10 @@ struct quirk_list          quirks = TAILQ_HEAD_INITIALIZER(quirks);
  */
 enum {
        _NET_ACTIVE_WINDOW,
+       _NET_CLIENT_LIST,
        _NET_CLOSE_WINDOW,
+       _NET_CURRENT_DESKTOP,
+       _NET_DESKTOP_NAMES,
        _NET_MOVERESIZE_WINDOW,
        _NET_WM_ACTION_ABOVE,
        _NET_WM_ACTION_CLOSE,
@@ -655,13 +684,16 @@ enum {
        _NET_WM_ACTION_MOVE,
        _NET_WM_ACTION_RESIZE,
        _NET_WM_ALLOWED_ACTIONS,
+       _NET_WM_DESKTOP,
+       _NET_WM_FULL_PLACEMENT,
        _NET_WM_NAME,
+       _NET_NUMBER_OF_DESKTOPS,
        _NET_WM_STATE,
        _NET_WM_STATE_ABOVE,
        _NET_WM_STATE_FULLSCREEN,
        _NET_WM_STATE_HIDDEN,
-       _NET_WM_STATE_MAXIMIZED_HORZ,
        _NET_WM_STATE_MAXIMIZED_VERT,
+       _NET_WM_STATE_MAXIMIZED_HORZ,
        _NET_WM_STATE_SKIP_PAGER,
        _NET_WM_STATE_SKIP_TASKBAR,
        _NET_WM_WINDOW_TYPE,
@@ -681,7 +713,10 @@ struct ewmh_hint {
 } ewmh[SWM_EWMH_HINT_MAX] =    {
     /* must be in same order as in the enum */
     {"_NET_ACTIVE_WINDOW", XCB_ATOM_NONE},
+    {"_NET_CLIENT_LIST", XCB_ATOM_NONE},
     {"_NET_CLOSE_WINDOW", XCB_ATOM_NONE},
+    {"_NET_CURRENT_DESKTOP", XCB_ATOM_NONE},
+    {"_NET_DESKTOP_NAMES", XCB_ATOM_NONE},
     {"_NET_MOVERESIZE_WINDOW", XCB_ATOM_NONE},
     {"_NET_WM_ACTION_ABOVE", XCB_ATOM_NONE},
     {"_NET_WM_ACTION_CLOSE", XCB_ATOM_NONE},
@@ -689,13 +724,16 @@ struct ewmh_hint {
     {"_NET_WM_ACTION_MOVE", XCB_ATOM_NONE},
     {"_NET_WM_ACTION_RESIZE", XCB_ATOM_NONE},
     {"_NET_WM_ALLOWED_ACTIONS", XCB_ATOM_NONE},
+    {"_NET_WM_DESKTOP", XCB_ATOM_NONE},
+    {"_NET_WM_FULL_PLACEMENT", XCB_ATOM_NONE},
     {"_NET_WM_NAME", XCB_ATOM_NONE},
+    {"_NET_NUMBER_OF_DESKTOPS", XCB_ATOM_NONE},
     {"_NET_WM_STATE", XCB_ATOM_NONE},
     {"_NET_WM_STATE_ABOVE", XCB_ATOM_NONE},
     {"_NET_WM_STATE_FULLSCREEN", XCB_ATOM_NONE},
     {"_NET_WM_STATE_HIDDEN", XCB_ATOM_NONE},
-    {"_NET_WM_STATE_MAXIMIZED_HORZ", XCB_ATOM_NONE},
     {"_NET_WM_STATE_MAXIMIZED_VERT", XCB_ATOM_NONE},
+    {"_NET_WM_STATE_MAXIMIZED_HORZ", XCB_ATOM_NONE},
     {"_NET_WM_STATE_SKIP_PAGER", XCB_ATOM_NONE},
     {"_NET_WM_STATE_SKIP_TASKBAR", XCB_ATOM_NONE},
     {"_NET_WM_WINDOW_TYPE", XCB_ATOM_NONE},
@@ -708,6 +746,13 @@ struct ewmh_hint {
     {"_SWM_WM_STATE_MANUAL", XCB_ATOM_NONE},
 };
 
+/* EWMH source type */
+enum {
+       EWMH_SOURCE_TYPE_NONE = 0,
+       EWMH_SOURCE_TYPE_NORMAL = 1,
+       EWMH_SOURCE_TYPE_OTHER = 2,
+};
+
 /* Cursors */
 enum {
        XC_FLEUR,
@@ -734,7 +779,7 @@ struct cursors {
        {"top_right_corner", XC_top_right_corner, XCB_CURSOR_NONE},
 };
 
-#define        SWM_SPAWN_OPTIONAL              0x1
+#define SWM_SPAWN_OPTIONAL             0x1
 
 /* spawn */
 struct spawn_prog {
@@ -926,11 +971,16 @@ void       enternotify(xcb_enter_notify_event_t *);
 void    event_drain(uint8_t);
 void    event_error(xcb_generic_error_t *);
 void    event_handle(xcb_generic_event_t *);
+void    ewmh_apply_flags(struct ws_win *, uint32_t);
 void    ewmh_autoquirk(struct ws_win *);
-void    ewmh_get_win_state(struct ws_win *);
-int     ewmh_set_win_fullscreen(struct ws_win *, int);
+void    ewmh_get_desktop_names(void);
+void    ewmh_get_wm_state(struct ws_win *);
 void    ewmh_update_actions(struct ws_win *);
-void    ewmh_update_win_state(struct ws_win *, xcb_atom_t, long);
+void    ewmh_update_client_list(void);
+void    ewmh_update_current_desktop(void);
+void    ewmh_update_desktop_names(void);
+void    ewmh_change_wm_state(struct ws_win *, xcb_atom_t, long);
+void    ewmh_update_wm_state(struct ws_win *);
 char   *expand_tilde(const char *);
 void    expose(xcb_expose_event_t *);
 void    fake_keypress(struct ws_win *, xcb_keysym_t, uint16_t);
@@ -938,7 +988,6 @@ struct pid_e        *find_pid(pid_t);
 struct ws_win  *find_unmanaged_window(xcb_window_t);
 struct ws_win  *find_window(xcb_window_t);
 void    floating_toggle(struct swm_region *, union arg *);
-int     floating_toggle_win(struct ws_win *);
 void    focus(struct swm_region *, union arg *);
 #ifdef SWM_DEBUG
 void    focusin(xcb_focus_in_event_t *);
@@ -964,12 +1013,11 @@ struct ws_win    *get_pointer_win(xcb_window_t);
 struct ws_win  *get_region_focus(struct swm_region *);
 int     get_region_index(struct swm_region *);
 xcb_screen_t   *get_screen(int);
-xcb_window_t    get_sibling(struct ws_win *, int);
 int     get_screen_count(void);
 #ifdef SWM_DEBUG
 char   *get_stack_mode_name(uint8_t);
 #endif
-int32_t         get_swm_iconic(struct ws_win *);
+int32_t         get_swm_ws(xcb_window_t);
 char   *get_win_name(xcb_window_t);
 void    get_wm_protocols(struct ws_win *);
 int     get_ws_idx(xcb_window_t);
@@ -1020,6 +1068,7 @@ void       quirk_replace(struct quirk *, const char *, const char *, const char *,
             unsigned long);
 void    quit(struct swm_region *, union arg *);
 void    raise_toggle(struct swm_region *, union arg *);
+void    raise_window(struct ws_win *);
 void    region_containment(struct ws_win *, struct swm_region *, int);
 struct swm_region      *region_under(struct swm_screen *, int, int);
 void    regionize(struct ws_win *, int, int);
@@ -1061,7 +1110,6 @@ void       setup_quirks(void);
 void    setup_screens(void);
 void    setup_spawn(void);
 void    set_child_transient(struct ws_win *, xcb_window_t *);
-void    set_swm_iconic(struct ws_win *, int);
 void    set_win_state(struct ws_win *, uint16_t);
 void    shutdown_cleanup(void);
 void    sighdlr(int);
@@ -1076,9 +1124,7 @@ void       spawn_remove(struct spawn_prog *);
 void    spawn_replace(struct spawn_prog *, const char *, const char *, int);
 void    spawn_select(struct swm_region *, union arg *, const char *, int *);
 void    stack_config(struct swm_region *, union arg *);
-void    stack_floater(struct ws_win *);
 void    stack_master(struct workspace *, struct swm_geometry *, int, int);
-void    reorder_window(struct ws_win *, uint32_t);
 void    store_float_geom(struct ws_win *);
 char   *strdupsafe(const char *);
 void    swapwin(struct swm_region *, union arg *);
@@ -1092,8 +1138,11 @@ void      unmapnotify(xcb_unmap_notify_event_t *);
 void    unmap_all(void);
 void    unmap_window(struct ws_win *);
 void    updatenumlockmask(void);
+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_wm_state(struct  ws_win *win);
 void    validate_spawns(void);
 int     validate_win(struct ws_win *);
 int     validate_ws(struct workspace *);
@@ -1102,6 +1151,7 @@ void       win_to_ws(struct ws_win *, int, int);
 pid_t   window_get_pid(xcb_window_t);
 void    wkill(struct swm_region *, union arg *);
 void    workaround(void);
+void    update_ws_stack(struct workspace *);
 void    xft_init(struct swm_region *);
 void    _add_startup_exception(const char *, va_list);
 void    add_startup_exception(const char *, ...);
@@ -1310,46 +1360,10 @@ get_wm_protocols(struct ws_win *win) {
 }
 
 void
-set_swm_iconic(struct ws_win *win, int newv)
-{
-       int32_t                         v = newv;
-
-       win->iconic = newv;
-
-       if (newv)
-               xcb_change_property(conn, XCB_PROP_MODE_REPLACE, win->id,
-                   a_swm_iconic, XCB_ATOM_INTEGER, 32, 1, &v);
-       else
-               xcb_delete_property(conn, win->id, a_swm_iconic);
-}
-
-int32_t
-get_swm_iconic(struct ws_win *win)
-{
-       int32_t                         v = 0;
-       xcb_get_property_reply_t        *pr = NULL;
-
-       pr = xcb_get_property_reply(conn,
-           xcb_get_property(conn, 0, win->id, a_swm_iconic,
-           XCB_ATOM_INTEGER, 0, 1), NULL);
-       if (pr == NULL)
-               goto out;
-       if (pr->type != XCB_ATOM_INTEGER || pr->format != 32)
-               goto out;
-       v = *((int32_t *)xcb_get_property_value(pr));
-out:
-       if (pr)
-               free(pr);
-       return (v);
-}
-
-void
 setup_ewmh(void)
 {
-       xcb_atom_t                      sup_list;
        int                             i, j, num_screens;
 
-       sup_list = get_atom_from_string("_NET_SUPPORTED");
 
        for (i = 0; i < LENGTH(ewmh); i++)
                ewmh[i].atom = get_atom_from_string(ewmh[i].name);
@@ -1359,11 +1373,15 @@ setup_ewmh(void)
                /* Support check window will be created by workaround(). */
 
                /* Report supported atoms */
-               xcb_delete_property(conn, screens[i].root, sup_list);
+               xcb_delete_property(conn, screens[i].root, a_net_supported);
                for (j = 0; j < LENGTH(ewmh); j++)
                        xcb_change_property(conn, XCB_PROP_MODE_APPEND,
-                           screens[i].root, sup_list, XCB_ATOM_ATOM, 32, 1,
-                           &ewmh[j].atom);
+                           screens[i].root, a_net_supported, XCB_ATOM_ATOM,
+                           32, 1, &ewmh[j].atom);
+
+               xcb_change_property(conn, XCB_PROP_MODE_REPLACE,
+                   screens[i].root, ewmh[_NET_NUMBER_OF_DESKTOPS].atom,
+                   XCB_ATOM_CARDINAL, 32, 1, &workspace_limit);
        }
 }
 
@@ -1371,28 +1389,27 @@ void
 teardown_ewmh(void)
 {
        int                             i, num_screens;
-       xcb_atom_t                      sup_check, sup_list;
        xcb_window_t                    id;
        xcb_get_property_cookie_t       pc;
        xcb_get_property_reply_t        *pr;
 
-       sup_check = get_atom_from_string("_NET_SUPPORTING_WM_CHECK");
-       sup_list = get_atom_from_string("_NET_SUPPORTED");
        num_screens = get_screen_count();
 
        for (i = 0; i < num_screens; i++) {
                /* Get the support check window and destroy it */
-               pc = xcb_get_property(conn, 0, screens[i].root, sup_check,
+               pc = xcb_get_property(conn, 0, screens[i].root, a_net_wm_check,
                    XCB_ATOM_WINDOW, 0, 1);
                pr = xcb_get_property_reply(conn, pc, NULL);
                if (pr == NULL)
                        continue;
-               if (pr->format == sup_check) {
+               if (pr->format == a_net_wm_check) {
                        id = *((xcb_window_t *)xcb_get_property_value(pr));
 
                        xcb_destroy_window(conn, id);
-                       xcb_delete_property(conn, screens[i].root, sup_check);
-                       xcb_delete_property(conn, screens[i].root, sup_list);
+                       xcb_delete_property(conn, screens[i].root,
+                           a_net_wm_check);
+                       xcb_delete_property(conn, screens[i].root,
+                           a_net_supported);
                }
                free(pr);
        }
@@ -1412,8 +1429,8 @@ ewmh_autoquirk(struct ws_win *win)
        if (r == NULL)
                return;
 
-       n = xcb_get_property_value_length(r);
        type = xcb_get_property_value(r);
+       n = xcb_get_property_value_length(r) / sizeof(xcb_atom_t);
 
        for (i = 0; i < n; i++) {
                if (type[i] == ewmh[_NET_WM_WINDOW_TYPE_NORMAL].atom)
@@ -1421,13 +1438,11 @@ ewmh_autoquirk(struct ws_win *win)
                if (type[i] == ewmh[_NET_WM_WINDOW_TYPE_DOCK].atom ||
                    type[i] == ewmh[_NET_WM_WINDOW_TYPE_TOOLBAR].atom ||
                    type[i] == ewmh[_NET_WM_WINDOW_TYPE_UTILITY].atom) {
-                       win->floating = 1;
                        win->quirks = SWM_Q_FLOAT | SWM_Q_ANYWHERE;
                        break;
                }
                if (type[i] == ewmh[_NET_WM_WINDOW_TYPE_SPLASH].atom ||
                    type[i] == ewmh[_NET_WM_WINDOW_TYPE_DIALOG].atom) {
-                       win->floating = 1;
                        win->quirks = SWM_Q_FLOAT;
                        break;
                }
@@ -1435,39 +1450,6 @@ ewmh_autoquirk(struct ws_win *win)
        free(r);
 }
 
-#define SWM_EWMH_ACTION_COUNT_MAX      (6)
-#define EWMH_F_FULLSCREEN              (1<<0)
-#define EWMH_F_ABOVE                   (1<<1)
-#define EWMH_F_HIDDEN                  (1<<2)
-#define EWMH_F_SKIP_PAGER              (1<<3)
-#define EWMH_F_SKIP_TASKBAR            (1<<4)
-#define SWM_F_MANUAL                   (1<<5)
-
-int
-ewmh_set_win_fullscreen(struct ws_win *win, int fs)
-{
-       if (win->ws->r == NULL)
-               return (0);
-
-       if (!win->floating)
-               return (0);
-
-       DNPRINTF(SWM_D_MISC, "ewmh_set_win_fullscreen: window: 0x%x, "
-           "fullscreen %s\n", win->id, YESNO(fs));
-
-       if (fs) {
-               if (!win->g_floatvalid)
-                       store_float_geom(win);
-
-               win->g = win->ws->r->g;
-               win->bordered = 0;
-       } else {
-               load_float_geom(win);
-       }
-
-       return (1);
-}
-
 void
 ewmh_update_actions(struct ws_win *win)
 {
@@ -1479,7 +1461,7 @@ ewmh_update_actions(struct ws_win *win)
 
        actions[n++] = ewmh[_NET_WM_ACTION_CLOSE].atom;
 
-       if (win->floating) {
+       if (ABOVE(win)) {
                actions[n++] = ewmh[_NET_WM_ACTION_MOVE].atom;
                actions[n++] = ewmh[_NET_WM_ACTION_RESIZE].atom;
                actions[n++] = ewmh[_NET_WM_ACTION_ABOVE].atom;
@@ -1494,90 +1476,182 @@ ewmh_update_actions(struct ws_win *win)
 #define _NET_WM_STATE_TOGGLE   2    /* toggle property */
 
 void
-ewmh_update_win_state(struct ws_win *win, xcb_atom_t state, long action)
+ewmh_change_wm_state(struct ws_win *win, xcb_atom_t state, long action)
 {
-       unsigned int            mask = 0;
-       unsigned int            changed = 0;
-       unsigned int            orig_flags;
+       uint32_t                flag = 0;
+       uint32_t                new_flags;
 #ifdef SWM_DEBUG
        char                    *name;
-#endif
 
-       if (win == NULL)
-               return;
-
-#ifdef SWM_DEBUG
        name = get_atom_name(state);
-       DNPRINTF(SWM_D_PROP, "ewmh_update_win_state: window: 0x%x, state: %s, "
-           "action: %ld\n", win->id, name, action);
+       DNPRINTF(SWM_D_PROP, "ewmh_change_wm_state: win %#x, state: %s, "
+           "action: %ld\n", WINID(win), name, action);
        free(name);
 #endif
+       if (win == NULL)
+               goto out;
 
        if (state == ewmh[_NET_WM_STATE_FULLSCREEN].atom)
-               mask = EWMH_F_FULLSCREEN;
+               flag = EWMH_F_FULLSCREEN;
        else if (state == ewmh[_NET_WM_STATE_ABOVE].atom)
-               mask = EWMH_F_ABOVE;
+               flag = EWMH_F_ABOVE;
+       else if (state == ewmh[_NET_WM_STATE_HIDDEN].atom)
+               flag = EWMH_F_HIDDEN;
+       else if (state == ewmh[_NET_WM_STATE_MAXIMIZED_VERT].atom ||
+           state == ewmh[_NET_WM_STATE_MAXIMIZED_HORZ].atom)
+               flag = EWMH_F_MAXIMIZED;
        else if (state == ewmh[_SWM_WM_STATE_MANUAL].atom)
-               mask = SWM_F_MANUAL;
+               flag = SWM_F_MANUAL;
        else if (state == ewmh[_NET_WM_STATE_SKIP_PAGER].atom)
-               mask = EWMH_F_SKIP_PAGER;
+               flag = EWMH_F_SKIP_PAGER;
        else if (state == ewmh[_NET_WM_STATE_SKIP_TASKBAR].atom)
-               mask = EWMH_F_SKIP_TASKBAR;
+               flag = EWMH_F_SKIP_TASKBAR;
+
+       /* Disallow unfloating transients. */
+       if (TRANS(win) && flag == EWMH_F_ABOVE)
+               goto out;
 
-       orig_flags = win->ewmh_flags;
+       new_flags = win->ewmh_flags;
 
        switch (action) {
        case _NET_WM_STATE_REMOVE:
-               win->ewmh_flags &= ~mask;
+               new_flags &= ~flag;
                break;
        case _NET_WM_STATE_ADD:
-               win->ewmh_flags |= mask;
+               new_flags |= flag;
                break;
        case _NET_WM_STATE_TOGGLE:
-               win->ewmh_flags ^= mask;
+               new_flags ^= flag;
                break;
        }
 
-       changed = (win->ewmh_flags & mask) ^ (orig_flags & mask) ? 1 : 0;
+       ewmh_apply_flags(win, new_flags);
 
-       if (state == ewmh[_NET_WM_STATE_ABOVE].atom) {
-               if (changed && !floating_toggle_win(win))
-                               win->ewmh_flags = orig_flags; /* revert */
-       } else if (state == ewmh[_SWM_WM_STATE_MANUAL].atom) {
-               if (changed)
-                       win->manual = (win->ewmh_flags & SWM_F_MANUAL) != 0;
-       } else if (state == ewmh[_NET_WM_STATE_FULLSCREEN].atom) {
-               if (changed && !ewmh_set_win_fullscreen(win,
-                           win->ewmh_flags & EWMH_F_FULLSCREEN))
-                               win->ewmh_flags = orig_flags; /* revert */
+out:
+       DNPRINTF(SWM_D_PROP, "ewmh_change_wm_state: done.\n");
+}
+
+void
+ewmh_apply_flags(struct ws_win *win, uint32_t pending)
+{
+       struct workspace        *ws;
+       uint32_t                changed;
+
+       changed = win->ewmh_flags ^ pending;
+       if (changed == 0)
+               return;
+
+       DNPRINTF(SWM_D_PROP, "ewmh_apply_flags: pending: %d\n", pending);
+
+       win->ewmh_flags = pending;
+       ws = win->ws;
+
+       if (changed & EWMH_F_HIDDEN) {
+               if (ICONIC(win)) {
+                       if (focus_mode != SWM_FOCUS_FOLLOW)
+                               ws->focus_pending = get_focus_prev(win);
+
+                       unfocus_win(win);
+                       unmap_window(win);
+               } else {
+                       /* Reload floating geometry in case region changed. */
+                       if (FLOATING(win))
+                               load_float_geom(win);
+
+                       /* The window is no longer iconic, prepare focus. */
+                       if (focus_mode != SWM_FOCUS_FOLLOW)
+                               ws->focus_pending = get_focus_magic(win);
+                       raise_window(win);
+               }
+       }
+
+       if (changed & EWMH_F_ABOVE) {
+               if (ws->cur_layout != &layouts[SWM_MAX_STACK]) {
+                       if (ABOVE(win))
+                               load_float_geom(win);
+                       else if (!MAXIMIZED(win))
+                               store_float_geom(win);
+
+                       win->ewmh_flags &= ~EWMH_F_MAXIMIZED;
+                       changed &= ~EWMH_F_MAXIMIZED;
+                       raise_window(win);
+               } else {
+                       /* Revert. */
+                       win->ewmh_flags ^= EWMH_F_ABOVE & pending;
+               }
+       }
+
+       if (changed & EWMH_F_MAXIMIZED) {
+               /* VERT and/or HORZ changed. */
+               if (ABOVE(win)) {
+                       if (!MAXIMIZED(win))
+                               load_float_geom(win);
+                       else
+                               store_float_geom(win);
+               }
+
+               if (MAXIMIZED(win)) {
+                       if (focus_mode != SWM_FOCUS_FOLLOW &&
+                           ws->cur_layout != &layouts[SWM_MAX_STACK]) {
+                               if (WS_FOCUSED(ws))
+                                       focus_win(win);
+                               else
+                                       ws->focus_pending = win;
+                       }
+               }
+               raise_window(win);
        }
 
-       xcb_delete_property(conn, win->id, ewmh[_NET_WM_STATE].atom);
+       if (changed & EWMH_F_FULLSCREEN) {
+               if (FULLSCREEN(win)) {
+                       if (focus_mode != SWM_FOCUS_FOLLOW) {
+                               if (WS_FOCUSED(ws))
+                                       focus_win(win);
+                               else
+                                       ws->focus_pending = win;
+                       }
+               } else {
+                       load_float_geom(win);
+               }
+
+               win->ewmh_flags &= ~EWMH_F_MAXIMIZED;
+               raise_window(win);
+       }
 
-       if (win->ewmh_flags & EWMH_F_FULLSCREEN)
-               xcb_change_property(conn, XCB_PROP_MODE_APPEND, win->id,
-                   ewmh[_NET_WM_STATE].atom, XCB_ATOM_ATOM, 32, 1,
-                   &ewmh[_NET_WM_STATE_FULLSCREEN].atom);
-       else if (win->ewmh_flags & EWMH_F_SKIP_PAGER)
-               xcb_change_property(conn, XCB_PROP_MODE_APPEND, win->id,
-                   ewmh[_NET_WM_STATE].atom, XCB_ATOM_ATOM, 32, 1,
-                   &ewmh[_NET_WM_STATE_SKIP_PAGER].atom);
-       else if (win->ewmh_flags & EWMH_F_SKIP_TASKBAR)
-               xcb_change_property(conn, XCB_PROP_MODE_APPEND, win->id,
-                   ewmh[_NET_WM_STATE].atom, XCB_ATOM_ATOM, 32, 1,
-                   &ewmh[_NET_WM_STATE_SKIP_TASKBAR].atom);
-       else if (win->ewmh_flags & EWMH_F_ABOVE)
-               xcb_change_property(conn, XCB_PROP_MODE_APPEND, win->id,
-                   ewmh[_NET_WM_STATE].atom, XCB_ATOM_ATOM, 32, 1,
-                   &ewmh[_NET_WM_STATE_ABOVE].atom);
-       else if (win->ewmh_flags & SWM_F_MANUAL)
-               xcb_change_property(conn, XCB_PROP_MODE_APPEND, win->id,
-                   ewmh[_NET_WM_STATE].atom, XCB_ATOM_ATOM, 32, 1,
-                   &ewmh[_SWM_WM_STATE_MANUAL].atom);
+       DNPRINTF(SWM_D_PROP, "ewmh_apply_flags: done.\n");
 }
 
 void
-ewmh_get_win_state(struct ws_win *win)
+ewmh_update_wm_state(struct  ws_win *win) {
+       xcb_atom_t              vals[SWM_EWMH_ACTION_COUNT_MAX];
+       int                     n = 0;
+
+       if (ICONIC(win))
+               vals[n++] = ewmh[_NET_WM_STATE_HIDDEN].atom;
+       if (FULLSCREEN(win))
+               vals[n++] = ewmh[_NET_WM_STATE_FULLSCREEN].atom;
+       if (MAXIMIZED_VERT(win))
+               vals[n++] = ewmh[_NET_WM_STATE_MAXIMIZED_VERT].atom;
+       if (MAXIMIZED_HORZ(win))
+               vals[n++] = ewmh[_NET_WM_STATE_MAXIMIZED_HORZ].atom;
+       if (win->ewmh_flags & EWMH_F_SKIP_PAGER)
+               vals[n++] = ewmh[_NET_WM_STATE_SKIP_PAGER].atom;
+       if (win->ewmh_flags & EWMH_F_SKIP_TASKBAR)
+               vals[n++] = ewmh[_NET_WM_STATE_SKIP_TASKBAR].atom;
+       if (win->ewmh_flags & EWMH_F_ABOVE)
+               vals[n++] = ewmh[_NET_WM_STATE_ABOVE].atom;
+       if (win->ewmh_flags & SWM_F_MANUAL)
+               vals[n++] = ewmh[_SWM_WM_STATE_MANUAL].atom;
+
+       if (n > 0)
+               xcb_change_property(conn, XCB_PROP_MODE_REPLACE, win->id,
+                   ewmh[_NET_WM_STATE].atom, XCB_ATOM_ATOM, 32, n, vals);
+       else
+               xcb_delete_property(conn, win->id, ewmh[_NET_WM_STATE].atom);
+}
+
+void
+ewmh_get_wm_state(struct ws_win *win)
 {
        xcb_atom_t                      *states;
        xcb_get_property_cookie_t       c;
@@ -1588,10 +1662,6 @@ ewmh_get_win_state(struct ws_win *win)
                return;
 
        win->ewmh_flags = 0;
-       if (win->floating)
-               win->ewmh_flags |= EWMH_F_ABOVE;
-       if (win->manual)
-               win->ewmh_flags |= SWM_F_MANUAL;
 
        c = xcb_get_property(conn, 0, win->id, ewmh[_NET_WM_STATE].atom,
            XCB_ATOM_ATOM, 0, UINT32_MAX);
@@ -1600,10 +1670,10 @@ ewmh_get_win_state(struct ws_win *win)
                return;
 
        states = xcb_get_property_value(r);
-       n = xcb_get_property_value_length(r);
+       n = xcb_get_property_value_length(r) / sizeof(xcb_atom_t);
 
        for (i = 0; i < n; i++)
-               ewmh_update_win_state(win, states[i], _NET_WM_STATE_ADD);
+               ewmh_change_wm_state(win, states[i], _NET_WM_STATE_ADD);
 
        free(r);
 }
@@ -1622,41 +1692,41 @@ dumpwins(struct swm_region *r, union arg *args)
        (void)args;
 
        if (r->ws == NULL) {
-               warnx("dumpwins: invalid workspace");
+               DPRINTF("dumpwins: invalid workspace\n");
                return;
        }
 
-       warnx("=== managed window list ws %02d ===", r->ws->idx);
+       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);
                wa = xcb_get_window_attributes_reply(conn, c, NULL);
                if (wa) {
-                       warnx("window: 0x%x, map_state: %d, state: %u, "
-                           "transient: 0x%x", win->id, wa->map_state,
+                       DPRINTF("win %#x, map_state: %d, state: %u, "
+                           "transient: %#x\n", win->id, wa->map_state,
                            state, win->transient);
                        free(wa);
                } else
-                       warnx("window: 0x%x, failed xcb_get_window_attributes",
+                       DPRINTF("win %#x, failed xcb_get_window_attributes\n",
                            win->id);
        }
 
-       warnx("===== unmanaged window list =====");
+       DPRINTF("===== unmanaged window list =====\n");
        TAILQ_FOREACH(win, &r->ws->unmanagedlist, entry) {
                state = getstate(win->id);
                c = xcb_get_window_attributes(conn, win->id);
                wa = xcb_get_window_attributes_reply(conn, c, NULL);
                if (wa) {
-                       warnx("window: 0x%x, map_state: %d, state: %u, "
-                           "transient: 0x%x", win->id, wa->map_state,
+                       DPRINTF("win %#x, map_state: %d, state: %u, "
+                           "transient: %#x\n", win->id, wa->map_state,
                            state, win->transient);
                        free(wa);
                } else
-                       warnx("window: 0x%x, failed xcb_get_window_attributes",
+                       DPRINTF("win %#x, failed xcb_get_window_attributes\n",
                            win->id);
        }
 
-       warnx("=================================");
+       DPRINTF("=================================\n");
 }
 #else
 void
@@ -1812,7 +1882,7 @@ fancy_stacker(struct workspace *ws)
                snprintf(ws->stacker, sizeof ws->stacker,
                    ws->l_state.vertical_flip ? "[%d>%d]" : "[%d|%d]",
                    ws->l_state.vertical_mwin, ws->l_state.vertical_stacks);
-       if (ws->cur_layout->l_stack == horizontal_stack)
+       else if (ws->cur_layout->l_stack == horizontal_stack)
                snprintf(ws->stacker, sizeof ws->stacker,
                    ws->l_state.horizontal_flip ? "[%dv%d]" : "[%d-%d]",
                    ws->l_state.horizontal_mwin, ws->l_state.horizontal_stacks);
@@ -1825,7 +1895,7 @@ plain_stacker(struct workspace *ws)
        if (ws->cur_layout->l_stack == vertical_stack)
                strlcpy(ws->stacker, ws->l_state.vertical_flip ? "[>]" : "[|]",
                    sizeof ws->stacker);
-       if (ws->cur_layout->l_stack == horizontal_stack)
+       else if (ws->cur_layout->l_stack == horizontal_stack)
                strlcpy(ws->stacker, ws->l_state.horizontal_flip ? "[v]" : "[-]",
                    sizeof ws->stacker);
 }
@@ -2034,9 +2104,9 @@ bar_window_state(char *s, size_t sz, struct swm_region *r)
 {
        if (r == NULL || r ->ws == NULL || r->ws->focus == NULL)
                return;
-       if (r->ws->focus->maximized)
+       if (MAXIMIZED(r->ws->focus))
                strlcat(s, "(m)", sz);
-       else if (r->ws->focus->floating)
+       else if (ABOVE(r->ws->focus))
                strlcat(s, "(f)", sz);
 }
 
@@ -2123,7 +2193,7 @@ bar_fmt(const char *fmtexp, char *fmtnew, struct swm_region *r, size_t sz)
        /* If enabled, only show the iconic count if there are iconic wins. */
        if (iconic_enabled && r != NULL && r->ws != NULL)
                TAILQ_FOREACH(w, &r->ws->winlist, entry)
-                       if (w->iconic) {
+                       if (ICONIC(w)) {
                                strlcat(fmtnew, "{+M}", sz);
                                break;
                        }
@@ -2153,7 +2223,7 @@ bar_fmt(const char *fmtexp, char *fmtnew, struct swm_region *r, size_t sz)
                        strlcat(fmtnew, "+T+4<", sz);
                }
                if (window_name_enabled) {
-                       if (r->ws->focus->floating || r->ws->focus->maximized)
+                       if (ABOVE(r->ws->focus) || MAXIMIZED(r->ws->focus))
                                strlcat(fmtnew, "+F ", sz);
                        strlcat(fmtnew, "+64W ", sz);
                }
@@ -2221,7 +2291,7 @@ bar_replace_seq(char *fmt, char *fmtrep, struct swm_region *r, size_t *offrep,
        case 'M':
                count = 0;
                TAILQ_FOREACH(w, &r->ws->winlist, entry)
-                       if (w->iconic)
+                       if (ICONIC(w))
                                ++count;
 
                snprintf(tmp, sizeof tmp, "%d", count);
@@ -2666,7 +2736,7 @@ bar_setup(struct swm_region *r)
        if (bar_enabled)
                xcb_map_window(conn, r->bar->id);
 
-       DNPRINTF(SWM_D_BAR, "bar_setup: window: 0x%x, (x,y) w x h: (%d,%d) "
+       DNPRINTF(SWM_D_BAR, "bar_setup: win %#x, (x,y) w x h: (%d,%d) "
            "%d x %d\n", WINID(r->bar), X(r->bar), Y(r->bar), WIDTH(r->bar),
            HEIGHT(r->bar));
 
@@ -2689,7 +2759,7 @@ set_win_state(struct ws_win *win, uint16_t state)
 {
        uint16_t                data[2] = { state, XCB_ATOM_NONE };
 
-       DNPRINTF(SWM_D_EVENT, "set_win_state: window: 0x%x, state: %u\n",
+       DNPRINTF(SWM_D_EVENT, "set_win_state: win %#x, state: %u\n",
            win->id, state);
 
        if (win == NULL)
@@ -2714,7 +2784,7 @@ getstate(xcb_window_t w)
                free(r);
        }
 
-       DNPRINTF(SWM_D_MISC, "getstate property: win 0x%x state %u\n", w,
+       DNPRINTF(SWM_D_MISC, "getstate property: win %#x state %u\n", w,
            result);
        return (result);
 }
@@ -2749,7 +2819,7 @@ client_msg(struct ws_win *win, xcb_atom_t a, xcb_timestamp_t t)
                return;
 #ifdef SWM_DEBUG
        name = get_atom_name(a);
-       DNPRINTF(SWM_D_EVENT, "client_msg: window: 0x%x, atom: %s(%u), "
+       DNPRINTF(SWM_D_EVENT, "client_msg: win %#x, atom: %s(%u), "
            "time: %#x\n",
            win->id, name, a, t);
        free(name);
@@ -2798,7 +2868,7 @@ config_win(struct ws_win *win, xcb_configure_request_event_t *ev)
 
                /* make response appear more WM_SIZE_HINTS-compliant */
                if (win->sh.flags) {
-                       DNPRINTF(SWM_D_MISC, "config_win: hints: window: 0x%x,"
+                       DNPRINTF(SWM_D_MISC, "config_win: hints: win %#x,"
                            " sh.flags: %u, min: %d x %d, max: %d x %d, inc: "
                            "%d x %d\n", win->id, win->sh.flags, SH_MIN_W(win),
                            SH_MIN_H(win), SH_MAX_W(win), SH_MAX_H(win),
@@ -2840,7 +2910,7 @@ config_win(struct ws_win *win, xcb_configure_request_event_t *ev)
                ce.above_sibling = ev->sibling;
        }
 
-       DNPRINTF(SWM_D_MISC, "config_win: ewmh: %s, window: 0x%x, (x,y) w x h: "
+       DNPRINTF(SWM_D_MISC, "config_win: ewmh: %s, win %#x, (x,y) w x h: "
            "(%d,%d) %d x %d, border: %d\n", YESNO(ev == NULL), win->id, ce.x,
            ce.y, ce.width, ce.height, ce.border_width);
 
@@ -2855,11 +2925,9 @@ count_win(struct workspace *ws, int count_transient)
        int                     count = 0;
 
        TAILQ_FOREACH(win, &ws->winlist, entry) {
-               if (!count_transient && win->floating)
-                       continue;
-               if (!count_transient && win->transient)
+               if (!count_transient && FLOATING(win))
                        continue;
-               if (win->iconic)
+               if (ICONIC(win))
                        continue;
                count++;
        }
@@ -2880,99 +2948,70 @@ quit(struct swm_region *r, union arg *args)
 }
 
 void
-reorder_window(struct ws_win *win, uint32_t mode)
+raise_window(struct ws_win *win)
 {
-       struct ws_win           *w = win;
+       struct ws_win           *target = NULL;
        struct swm_region       *r;
        struct workspace        *ws;
-       uint32_t                val[2];
 
        if (win == NULL || (r = win->ws->r) == NULL)
                return;
        ws = win->ws;
 
-       DNPRINTF(SWM_D_EVENT, "reorder_window: win 0x%x, mode: %d\n",
-           win->id, mode);
+       DNPRINTF(SWM_D_EVENT, "raise_window: win %#x\n", win->id);
 
-       switch (mode) {
-       case SWM_STACK_TOP:
-               /* Position above top-most sibling. */
-               TAILQ_FOREACH_REVERSE(w, &ws->winlist, ws_win_list, entry) {
-                       if (w == win || w->iconic)
-                               continue;
-                       if ((win->ewmh_flags & EWMH_F_FULLSCREEN) !=
-                           (w->ewmh_flags & EWMH_F_FULLSCREEN))
-                               continue;
-                       if (!win->maximized && w->maximized)
-                               continue;
-                       if (win->maximized) {
-                               if (w->floating)
-                                       break;
-                               continue;
-                       }
-                       if (win->floating == w->floating)
-                               break;
-               }
-               break;
-       case SWM_STACK_ABOVE:
-               /* Stack above win directly prior. */
-               while ((w = TAILQ_PREV(w, ws_win_list, entry)) != NULL) {
-                       if (w == win || w->iconic)
-                               continue;
-                       if ((win->ewmh_flags & EWMH_F_FULLSCREEN) !=
-                           (w->ewmh_flags & EWMH_F_FULLSCREEN))
-                               continue;
-                       if (win->maximized != w->maximized)
-                               continue;
-                       if (win->floating == w->floating)
-                               break;
-               }
-               break;
-       case SWM_STACK_BELOW:
-               /* Stack above win directly prior. */
-               while ((w = TAILQ_NEXT(w, entry)) != NULL) {
-                       if (w == win || w->iconic)
-                               continue;
-                       if ((win->ewmh_flags & EWMH_F_FULLSCREEN) !=
-                           (w->ewmh_flags & EWMH_F_FULLSCREEN))
-                               continue;
-                       if (win->maximized != w->maximized)
-                               continue;
-                       if (win->floating == w->floating)
-                               break;
-               }
-               break;
-       case SWM_STACK_BOTTOM:
-               /* Position above top-most sibling. */
-               TAILQ_FOREACH(w, &ws->winlist, entry) {
-                       if (w == win || w->iconic)
-                               continue;
-                       if ((win->ewmh_flags & EWMH_F_FULLSCREEN) !=
-                           (w->ewmh_flags & EWMH_F_FULLSCREEN))
-                               continue;
-                       if (win->maximized != w->maximized)
-                               continue;
-                       if (win->floating == w->floating)
-                               break;
-               }
-               break;
+       TAILQ_FOREACH(target, &ws->stack, stack_entry) {
+               if (target == win || ICONIC(target))
+                       continue;
+               if (ws->cur_layout == &layouts[SWM_MAX_STACK])
+                       break;
+               if (FULLSCREEN(win))
+                       break;
+               if (FULLSCREEN(target))
+                       continue;
+               if (MAXIMIZED(win))
+                       break;
+               if (MAXIMIZED(target))
+                       continue;
+               if (ABOVE(win) || TRANS(win))
+                       break;
+               if (!ABOVE(target) && !TRANS(target))
+                       break;
        }
 
-       if (w == NULL) {
-               if (win->floating || (win->ewmh_flags & EWMH_F_FULLSCREEN)
-                   || win->maximized)
-                       val[0] = r->bar->id;
-               else
-                       val[0] = r->id;
-       } else {
-               val[0] = w->id;
+       if (target != NULL) {
+               /* Change stack position. */
+               TAILQ_REMOVE(&ws->stack, win, stack_entry);
+               TAILQ_INSERT_BEFORE(target, win, stack_entry);
+               update_win_stacking(win);
        }
-       DNPRINTF(SWM_D_EVENT, "reorder_window: sibling: 0x%x\n", val[0]);
+
+       DNPRINTF(SWM_D_EVENT, "raise_window: done\n");
+}
+
+void
+update_win_stacking(struct ws_win *win)
+{
+       struct ws_win           *sibling;
+       struct swm_region       *r;
+       uint32_t                val[2];
+
+       if (win == NULL || (r = win->ws->r) == NULL)
+               return;
+
+       sibling = TAILQ_NEXT(win, stack_entry);
+       if (sibling != NULL && FLOATING(win) == FLOATING(sibling))
+               val[0] = sibling->id;
+       else
+               val[0] = FLOATING(win) ? r->bar->id : r->id;
+
+       DNPRINTF(SWM_D_EVENT, "update_win_stacking: %#x, sibling %#x\n",
+           win->id, val[0]);
 
        val[1] = XCB_STACK_MODE_ABOVE;
 
-       xcb_configure_window(conn, win->id, XCB_CONFIG_WINDOW_STACK_MODE |
-           XCB_CONFIG_WINDOW_SIBLING, val);
+       xcb_configure_window(conn, win->id, XCB_CONFIG_WINDOW_SIBLING |
+           XCB_CONFIG_WINDOW_STACK_MODE, val);
 }
 
 void
@@ -2981,7 +3020,7 @@ map_window(struct ws_win *win)
        if (win == NULL)
                return;
 
-       DNPRINTF(SWM_D_EVENT, "map_window: win 0x%x, mapped: %s\n",
+       DNPRINTF(SWM_D_EVENT, "map_window: win %#x, mapped: %s\n",
            win->id, YESNO(win->mapped));
 
        if (win->mapped)
@@ -2998,7 +3037,7 @@ unmap_window(struct ws_win *win)
        if (win == NULL)
                return;
 
-       DNPRINTF(SWM_D_EVENT, "unmap_window: win 0x%x, mapped: %s\n", win->id,
+       DNPRINTF(SWM_D_EVENT, "unmap_window: win %#x, mapped: %s\n", win->id,
            YESNO(win->mapped));
 
        if (!win->mapped)
@@ -3033,7 +3072,7 @@ fake_keypress(struct ws_win *win, xcb_keysym_t keysym, uint16_t modifiers)
 
        keycode = xcb_key_symbols_get_keycode(syms, keysym);
 
-       DNPRINTF(SWM_D_MISC, "fake_keypress: win 0x%x keycode %u\n",
+       DNPRINTF(SWM_D_MISC, "fake_keypress: win %#x, keycode %u\n",
            win->id, *keycode);
 
        bzero(&event, sizeof(event));
@@ -3082,13 +3121,13 @@ get_pointer_win(xcb_window_t root)
        struct ws_win                   *win = NULL;
        xcb_query_pointer_reply_t       *r;
 
-       DNPRINTF(SWM_D_EVENT, "get_pointer_win: root: 0x%x.\n", root);
+       DNPRINTF(SWM_D_EVENT, "get_pointer_win: root: %#x.\n", root);
 
        r = xcb_query_pointer_reply(conn, xcb_query_pointer(conn, root), NULL);
        if (r) {
                win = find_window(r->child);
                if (win) {
-                       DNPRINTF(SWM_D_EVENT, "get_pointer_win: 0x%x.\n",
+                       DNPRINTF(SWM_D_EVENT, "get_pointer_win: %#x.\n",
                            win->id);
                } else {
                        DNPRINTF(SWM_D_EVENT, "get_pointer_win: none.\n");
@@ -3108,7 +3147,7 @@ root_to_region(xcb_window_t root, int check)
        xcb_query_pointer_reply_t       *qpr;
        xcb_get_input_focus_reply_t     *gifr;
 
-       DNPRINTF(SWM_D_MISC, "root_to_region: window: 0x%x\n", root);
+       DNPRINTF(SWM_D_MISC, "root_to_region: win %#x\n", root);
 
        num_screens = get_screen_count();
        for (i = 0; i < num_screens; i++)
@@ -3334,10 +3373,11 @@ unfocus_win(struct ws_win *win)
 {
        xcb_window_t            none = XCB_WINDOW_NONE;
 
-       DNPRINTF(SWM_D_FOCUS, "unfocus_win: window: 0x%x\n", WINID(win));
+       DNPRINTF(SWM_D_FOCUS, "unfocus_win: win %#x\n", WINID(win));
 
        if (win == NULL)
                return;
+
        if (win->ws == NULL) {
                DNPRINTF(SWM_D_FOCUS, "unfocus_win: NULL ws.\n");
                return;
@@ -3360,8 +3400,6 @@ unfocus_win(struct ws_win *win)
        }
 
        if (win->ws->focus == win) {
-               if (tile_gap < 0 && !win->floating && !win->maximized)
-                       reorder_window(win, SWM_STACK_ABOVE);
                win->ws->focus = NULL;
                win->ws->focus_prev = win;
        }
@@ -3390,9 +3428,9 @@ focus_win(struct ws_win *win)
 {
        struct ws_win                   *cfw = NULL, *parent = NULL, *w;
        struct workspace                *ws;
-       xcb_get_input_focus_reply_t     *r;
+       xcb_get_input_focus_reply_t     *gifr;
 
-       DNPRINTF(SWM_D_FOCUS, "focus_win: window: 0x%x\n", WINID(win));
+       DNPRINTF(SWM_D_FOCUS, "focus_win: win %#x\n", WINID(win));
 
        if (win == NULL)
                goto out;
@@ -3413,12 +3451,20 @@ focus_win(struct ws_win *win)
                goto out;
        }
 
-       r = xcb_get_input_focus_reply(conn, xcb_get_input_focus(conn), NULL);
-       if (r) {
-               cfw = find_window(r->focus);
-               if (cfw != win)
-                       unfocus_win(cfw);
-               free(r);
+       gifr = xcb_get_input_focus_reply(conn, xcb_get_input_focus(conn), NULL);
+       if (gifr) {
+               cfw = find_window(gifr->focus);
+               if (cfw != NULL && cfw != win) {
+                       if (cfw->ws != ws && cfw->ws->r != NULL) {
+                               /* 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);
+                       } else {
+                               unfocus_win(cfw);
+                       }
+               }
+               free(gifr);
        }
 
        if (ws->focus != win) {
@@ -3432,7 +3478,7 @@ focus_win(struct ws_win *win)
                win->focus_child = NULL;
 
        /* If transient, adjust parent's focus child for focus_magic. */
-       if (win->transient) {
+       if (TRANS(win)) {
                parent = find_window(win->transient);
                if (parent && parent->focus_child != win)
                        parent->focus_child = win;
@@ -3452,7 +3498,7 @@ focus_win(struct ws_win *win)
                /* Tell app it can adjust focus to a specific window. */
                if (win->take_focus) {
                        /* java is special; always tell parent */
-                       if (win->transient && win->java)
+                       if (TRANS(win) && win->java)
                                client_msg(parent, a_takefocus,
                                    last_event_time);
                        else
@@ -3466,34 +3512,30 @@ focus_win(struct ws_win *win)
                    ws->always_raise) {
                        /* If a parent exists, map it first. */
                        if (parent) {
-                               reorder_window(parent, SWM_STACK_TOP);
+                               raise_window(parent);
                                map_window(parent);
 
                                /* Map siblings next. */
                                TAILQ_FOREACH(w, &ws->winlist, entry)
-                                       if (w != win && !w->iconic &&
-                                           w->transient == parent->id) {
-                                               reorder_window(w, SWM_STACK_ABOVE);
+                                       if (w != win && !ICONIC(w) &&
+                                           win->transient == parent->id)
                                                map_window(w);
-                                       }
                        }
 
                        /* Map focused window. */
-                       reorder_window(win, SWM_STACK_TOP);
+                       raise_window(win);
                        map_window(win);
 
                        /* Finally, map children of focus window. */
                        TAILQ_FOREACH(w, &ws->winlist, entry)
-                               if (w->transient == win->id && !w->iconic) {
-                                       reorder_window(w, SWM_STACK_ABOVE);
+                               if (w->transient == win->id && !ICONIC(w))
                                        map_window(w);
-                               }
-               } else if (tile_gap < 0 && !win->floating) {
+               } else if (tile_gap < 0 && !ABOVE(win)) {
                        /*
                         * Windows overlap in the layout.
                         * Raise focused win above all tiled wins.
                         */
-                       reorder_window(win, SWM_STACK_TOP);
+                       raise_window(win);
                        map_window(win);
                }
 
@@ -3517,11 +3559,11 @@ get_focus_magic(struct ws_win *win)
        struct ws_win   *parent = NULL;
        struct ws_win   *child = NULL;
 
-       DNPRINTF(SWM_D_FOCUS, "get_focus_magic: window: 0x%x\n", WINID(win));
+       DNPRINTF(SWM_D_FOCUS, "get_focus_magic: win %#x\n", WINID(win));
        if (win == NULL)
                return win;
 
-       if (win->transient) {
+       if (TRANS(win)) {
                parent = find_window(win->transient);
 
                /* If parent prefers focus elsewhere, then try to do so. */
@@ -3583,6 +3625,8 @@ set_region(struct swm_region *r)
            XCB_CW_BORDER_PIXEL, &r->s->c[SWM_S_COLOR_BAR_BORDER].pixel);
 
        r->s->r_focus = r;
+
+       ewmh_update_current_desktop();
 }
 
 void
@@ -3697,6 +3741,8 @@ switchws(struct swm_region *r, union arg *args)
                bar_draw();
        }
 
+       ewmh_update_current_desktop();
+
        focus_flush();
        new_ws->state = SWM_WS_STATE_MAPPED;
 
@@ -3751,6 +3797,8 @@ cyclews(struct swm_region *r, union arg *args)
 
                switchws(r, &a);
        } while (a.id != r->ws->idx);
+
+       DNPRINTF(SWM_D_FOCUS, "cyclews: done\n");
 }
 
 void
@@ -3768,6 +3816,7 @@ priorws(struct swm_region *r, union arg *args)
 
        a.id = r->ws_prior->idx;
        switchws(r, &a);
+       DNPRINTF(SWM_D_FOCUS, "priorws: done\n");
 }
 
 void
@@ -3792,6 +3841,7 @@ focusrg(struct swm_region *r, union arg *args)
 
        focus_region(rr);
        focus_flush();
+       DNPRINTF(SWM_D_FOCUS, "focusrg: done\n");
 }
 
 void
@@ -3806,6 +3856,8 @@ cyclerg(struct swm_region *r, union arg *args)
                return;
 
        i = r->s->idx;
+       DNPRINTF(SWM_D_FOCUS, "cyclerg: id: %d, region: %d\n", args->id, i);
+
        switch (args->id) {
        case SWM_ARG_ID_CYCLERG_UP:
                rr = TAILQ_NEXT(r, entry);
@@ -3825,8 +3877,10 @@ cyclerg(struct swm_region *r, union arg *args)
 
        focus_region(rr);
        focus_flush();
+       DNPRINTF(SWM_D_FOCUS, "cyclerg: done\n");
 }
 
+/* Sorts transients after parent. */
 void
 sort_windows(struct ws_win_list *wl)
 {
@@ -3837,7 +3891,7 @@ sort_windows(struct ws_win_list *wl)
 
        for (win = TAILQ_FIRST(wl); win != TAILQ_END(wl); win = nxt) {
                nxt = TAILQ_NEXT(win, entry);
-               if (win->transient) {
+               if (TRANS(win)) {
                        parent = find_window(win->transient);
                        if (parent == NULL) {
                                warnx("not possible bug");
@@ -3847,7 +3901,6 @@ sort_windows(struct ws_win_list *wl)
                        TAILQ_INSERT_AFTER(wl, parent, win, entry);
                }
        }
-
 }
 
 void
@@ -3861,7 +3914,10 @@ 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)
+       if (cur_focus == NULL || ABOVE(cur_focus) || FULLSCREEN(cur_focus))
+               return;
+
+       if (r->ws->cur_layout == &layouts[SWM_MAX_STACK])
                return;
 
        clear_maximized(r->ws);
@@ -3871,7 +3927,7 @@ swapwin(struct swm_region *r, union arg *args)
 
        switch (args->id) {
        case SWM_ARG_ID_SWAPPREV:
-               if (source->transient)
+               if (TRANS(source))
                        source = find_window(source->transient);
                target = TAILQ_PREV(source, ws_win_list, entry);
                if (target && target->transient)
@@ -3885,7 +3941,7 @@ swapwin(struct swm_region *r, union arg *args)
        case SWM_ARG_ID_SWAPNEXT:
                target = TAILQ_NEXT(source, entry);
                /* move the parent and let the sort handle the move */
-               if (source->transient)
+               if (TRANS(source))
                        source = find_window(source->transient);
                TAILQ_REMOVE(wl, source, entry);
                if (target == NULL)
@@ -3921,6 +3977,8 @@ swapwin(struct swm_region *r, union arg *args)
 
        sort_windows(wl);
 
+       ewmh_update_client_list();
+
        stack();
 
        focus_flush();
@@ -3941,8 +3999,8 @@ get_focus_prev(struct ws_win *win)
        wl = &ws->winlist;
        cur_focus = ws->focus;
 
-       DNPRINTF(SWM_D_FOCUS, "get_focus_prev: window: 0x%x, cur_focus: 0x%x, "
-           "focus_prev: 0x%x\n", WINID(win), WINID(cur_focus),
+       DNPRINTF(SWM_D_FOCUS, "get_focus_prev: win %#x, cur_focus: %#x, "
+           "focus_prev: %#x\n", WINID(win), WINID(cur_focus),
            WINID(ws->focus_prev));
 
        /* pickle, just focus on whatever */
@@ -3954,7 +4012,7 @@ get_focus_prev(struct ws_win *win)
        }
 
        /* if transient focus on parent */
-       if (cur_focus->transient) {
+       if (TRANS(cur_focus)) {
                winfocus = find_window(cur_focus->transient);
                goto done;
        }
@@ -3976,29 +4034,29 @@ get_focus_prev(struct ws_win *win)
                switch (focus_close) {
                case SWM_STACK_BOTTOM:
                        TAILQ_FOREACH(winfocus, wl, entry)
-                               if (!winfocus->iconic && winfocus != cur_focus)
+                               if (!ICONIC(winfocus) && winfocus != cur_focus)
                                        break;
                        break;
                case SWM_STACK_TOP:
                        TAILQ_FOREACH_REVERSE(winfocus, wl, ws_win_list, entry)
-                               if (!winfocus->iconic && winfocus != cur_focus)
+                               if (!ICONIC(winfocus) && winfocus != cur_focus)
                                        break;
                        break;
                case SWM_STACK_ABOVE:
                        winfocus = TAILQ_NEXT(cur_focus, entry);
-                       while (winfocus && winfocus->iconic)
+                       while (winfocus && ICONIC(winfocus))
                                winfocus = TAILQ_NEXT(winfocus, entry);
 
                        if (winfocus == NULL) {
                                if (focus_close_wrap) {
                                        TAILQ_FOREACH(winfocus, wl, entry)
-                                               if (!winfocus->iconic &&
+                                               if (!ICONIC(winfocus) &&
                                                    winfocus != cur_focus)
                                                        break;
                                } else {
                                        TAILQ_FOREACH_REVERSE(winfocus, wl,
                                            ws_win_list, entry)
-                                               if (!winfocus->iconic &&
+                                               if (!ICONIC(winfocus) &&
                                                    winfocus != cur_focus)
                                                        break;
                                }
@@ -4006,7 +4064,7 @@ get_focus_prev(struct ws_win *win)
                        break;
                case SWM_STACK_BELOW:
                        winfocus = TAILQ_PREV(cur_focus, ws_win_list, entry);
-                       while (winfocus && winfocus->iconic)
+                       while (winfocus && ICONIC(winfocus))
                                winfocus = TAILQ_PREV(winfocus, ws_win_list,
                                    entry);
 
@@ -4014,12 +4072,12 @@ get_focus_prev(struct ws_win *win)
                                if (focus_close_wrap) {
                                        TAILQ_FOREACH_REVERSE(winfocus, wl,
                                            ws_win_list, entry)
-                                               if (!winfocus->iconic &&
+                                               if (!ICONIC(winfocus) &&
                                                    winfocus != cur_focus)
                                                        break;
                                } else {
                                        TAILQ_FOREACH(winfocus, wl, entry)
-                                               if (!winfocus->iconic &&
+                                               if (!ICONIC(winfocus) &&
                                                    winfocus != cur_focus)
                                                        break;
                                }
@@ -4029,14 +4087,14 @@ get_focus_prev(struct ws_win *win)
        }
 done:
        if (winfocus == NULL ||
-           (winfocus && (winfocus->iconic || winfocus == cur_focus))) {
+           (winfocus && (ICONIC(winfocus) || winfocus == cur_focus))) {
                if (focus_default == SWM_STACK_TOP) {
                        TAILQ_FOREACH_REVERSE(winfocus, wl, ws_win_list, entry)
-                               if (!winfocus->iconic && winfocus != cur_focus)
+                               if (!ICONIC(winfocus) && winfocus != cur_focus)
                                        break;
                } else {
                        TAILQ_FOREACH(winfocus, wl, entry)
-                               if (!winfocus->iconic && winfocus != cur_focus)
+                               if (!ICONIC(winfocus) && winfocus != cur_focus)
                                        break;
                }
        }
@@ -4054,13 +4112,13 @@ get_region_focus(struct swm_region *r)
        if (!(r && r->ws))
                return NULL;
 
-       if (r->ws->focus && !r->ws->focus->iconic)
+       if (r->ws->focus && !ICONIC(r->ws->focus))
                winfocus = r->ws->focus;
-       else if (r->ws->focus_prev && !r->ws->focus_prev->iconic)
+       else if (r->ws->focus_prev && !ICONIC(r->ws->focus_prev))
                winfocus = r->ws->focus_prev;
        else
                TAILQ_FOREACH(winfocus, &r->ws->winlist, entry)
-                       if (!winfocus->iconic)
+                       if (!ICONIC(winfocus))
                                break;
 
        return get_focus_magic(winfocus);
@@ -4088,7 +4146,7 @@ focus(struct swm_region *r, union arg *args)
        /* Make sure an uniconified window has focus, if one exists. */
        if (cur_focus == NULL) {
                cur_focus = TAILQ_FIRST(wl);
-               while (cur_focus != NULL && cur_focus->iconic)
+               while (cur_focus != NULL && ICONIC(cur_focus))
                        cur_focus = TAILQ_NEXT(cur_focus, entry);
        }
 
@@ -4105,7 +4163,7 @@ focus(struct swm_region *r, union arg *args)
                        if (winfocus == cur_focus)
                                break;
                } while (winfocus != NULL &&
-                   (winfocus->iconic || winfocus->id == cur_focus->transient));
+                   (ICONIC(winfocus) || winfocus->id == cur_focus->transient));
                break;
        case SWM_ARG_ID_FOCUSNEXT:
                if (cur_focus == NULL)
@@ -4119,7 +4177,7 @@ focus(struct swm_region *r, union arg *args)
                        if (winfocus == cur_focus)
                                break;
                } while (winfocus != NULL &&
-                   (winfocus->iconic || winfocus->id == cur_focus->transient));
+                   (ICONIC(winfocus) || winfocus->id == cur_focus->transient));
                break;
        case SWM_ARG_ID_FOCUSMAIN:
                if (cur_focus == NULL)
@@ -4226,8 +4284,9 @@ stack_config(struct swm_region *r, union arg *args)
 void
 stack(void) {
        struct swm_geometry     g;
-       struct swm_region       *r;
+       struct swm_region       *r, *r_prev = NULL;
        int                     i, num_screens;
+       uint32_t                val[2];
 #ifdef SWM_DEBUG
        int j;
 #endif
@@ -4256,10 +4315,30 @@ stack(void) {
                            "%d, region: %d), (x,y) WxH: (%d,%d) %d x %d\n",
                            r->ws->idx, i, j++, g.x, g.y, g.w, g.h);
 
+                       if (r_prev) {
+                               /* Stack bar/input relative to prev. region. */
+                               val[1] = XCB_STACK_MODE_ABOVE;
+
+                               val[0] = r_prev->id;
+                               DNPRINTF(SWM_D_STACK, "stack: region input %#x "
+                                   "relative to %#x.\n", r->id, val[0]);
+                               xcb_configure_window(conn, r->id,
+                                   XCB_CONFIG_WINDOW_SIBLING |
+                                   XCB_CONFIG_WINDOW_STACK_MODE, val);
+
+                               val[0] = r_prev->bar->id;
+                               DNPRINTF(SWM_D_STACK, "stack: region bar %#x "
+                                   "relative to %#x.\n", r->bar->id, val[0]);
+                               xcb_configure_window(conn, r->bar->id,
+                                   XCB_CONFIG_WINDOW_SIBLING |
+                                   XCB_CONFIG_WINDOW_STACK_MODE, val);
+                       }
+
                        r->ws->cur_layout->l_stack(r->ws, &g);
                        r->ws->cur_layout->l_string(r->ws);
                        /* save r so we can track region changes */
                        r->ws->old_r = r;
+                       r_prev = r;
                }
        }
        if (font_adjusted)
@@ -4279,7 +4358,7 @@ store_float_geom(struct ws_win *win)
        win->g_float.x -= X(win->ws->r);
        win->g_float.y -= Y(win->ws->r);
        win->g_floatvalid = 1;
-       DNPRINTF(SWM_D_MISC, "store_float_geom: window: 0x%x, g: (%d,%d)"
+       DNPRINTF(SWM_D_MISC, "store_float_geom: win %#x, g: (%d,%d)"
            " %d x %d, g_float: (%d,%d) %d x %d\n", win->id, X(win), Y(win),
            WIDTH(win), HEIGHT(win), win->g_float.x, win->g_float.y,
            win->g_float.w, win->g_float.h);
@@ -4295,17 +4374,17 @@ load_float_geom(struct ws_win *win)
                win->g = win->g_float;
                X(win) += X(win->ws->r);
                Y(win) += Y(win->ws->r);
-               DNPRINTF(SWM_D_MISC, "load_float_geom: window: 0x%x, g: (%d,%d)"
+               DNPRINTF(SWM_D_MISC, "load_float_geom: win %#x, g: (%d,%d)"
                    "%d x %d\n", win->id, X(win), Y(win), WIDTH(win),
                    HEIGHT(win));
        } else {
-               DNPRINTF(SWM_D_MISC, "load_float_geom: window: 0x%x, g_float "
+               DNPRINTF(SWM_D_MISC, "load_float_geom: win %#x, g_float "
                    "is not set.\n", win->id);
        }
 }
 
 void
-stack_floater(struct ws_win *win)
+update_floater(struct ws_win *win)
 {
        struct workspace        *ws;
        struct swm_region       *r;
@@ -4318,16 +4397,16 @@ stack_floater(struct ws_win *win)
        if ((r = ws->r) == NULL)
                return;
 
-       DNPRINTF(SWM_D_MISC, "stack_floater: window: 0x%x\n", win->id);
+       DNPRINTF(SWM_D_MISC, "update_floater: win %#x\n", win->id);
 
-       if (win->ewmh_flags & EWMH_F_FULLSCREEN) {
+       if (FULLSCREEN(win)) {
                /* _NET_WM_FULLSCREEN: fullscreen without border. */
                if (!win->g_floatvalid)
                        store_float_geom(win);
 
                win->g = r->g;
                win->bordered = 0;
-       } else if (win->maximized) {
+       } else if (MAXIMIZED(win)) {
                /* Maximize: like a single stacked window. */
                if (!win->g_floatvalid)
                        store_float_geom(win);
@@ -4359,8 +4438,8 @@ stack_floater(struct ws_win *win)
                    WIDTH(win) >= WIDTH(r) && HEIGHT(win) >= HEIGHT(r)) {
                        /* Remove border for FULLSCREEN quirk. */
                        win->bordered = 0;
-               } else if (!win->manual) {
-                       if (win->transient && (win->quirks & SWM_Q_TRANSSZ)) {
+               } else if (!MANUAL(win)) {
+                       if (TRANS(win) && (win->quirks & SWM_Q_TRANSSZ)) {
                                /* Adjust size on TRANSSZ quirk. */
                                WIDTH(win) = (double)WIDTH(r) * dialog_ratio;
                                HEIGHT(win) = (double)HEIGHT(r) * dialog_ratio;
@@ -4395,7 +4474,7 @@ void
 adjust_font(struct ws_win *win)
 {
        if (!(win->quirks & SWM_Q_XTERM_FONTADJ) ||
-           win->floating || win->transient)
+           ABOVE(win) || TRANS(win))
                return;
 
        if (win->sh.width_inc && win->last_inc != win->sh.width_inc &&
@@ -4425,7 +4504,7 @@ void
 stack_master(struct workspace *ws, struct swm_geometry *g, int rot, int flip)
 {
        struct swm_geometry     win_g, r_g = *g;
-       struct ws_win           *win, *fs_win = NULL, *max_win = NULL;
+       struct ws_win           *win;
        int                     i, j, s, stacks;
        int                     w_inc = 1, h_inc, w_base = 1, h_base;
        int                     hrh, extra = 0, h_slice, last_h = 0;
@@ -4436,82 +4515,75 @@ stack_master(struct workspace *ws, struct swm_geometry *g, int rot, int flip)
        DNPRINTF(SWM_D_STACK, "stack_master: workspace: %d, rot: %s, "
            "flip: %s\n", ws->idx, YESNO(rot), YESNO(flip));
 
-       winno = count_win(ws, 0);
-       if (winno == 0 && count_win(ws, 1) == 0)
-               return;
-
-       /* Find first tiled window. */
-       TAILQ_FOREACH(win, &ws->winlist, entry)
-               if (!win->transient && !win->floating && !win->iconic)
-                       break;
-
-       if (win == NULL)
-               goto notiles;
-
-       if (rot) {
-               w_inc = win->sh.width_inc;
-               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;
-       if (stacks < 1)
-               stacks = 1;
-
-       h_slice = r_g.h / SWM_H_SLICE;
-       if (mwin && winno > mwin) {
-               v_slice = r_g.w / SWM_V_SLICE;
+       /* Prepare tiling variables, if needed. */
+       if ((winno = count_win(ws, 0)) > 0) {
+               /* Find first tiled window. */
+               TAILQ_FOREACH(win, &ws->winlist, entry)
+                       if (!FLOATING(win) && !ICONIC(win))
+                               break;
 
-               split = mwin;
-               colno = split;
-               win_g.w = v_slice * mscale;
+               /* Take into account size hints of first tiled window. */
+               if (rot) {
+                       w_inc = win->sh.width_inc;
+                       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;
+               if (stacks < 1)
+                       stacks = 1;
+
+               h_slice = r_g.h / SWM_H_SLICE;
+               if (mwin && winno > mwin) {
+                       v_slice = r_g.w / SWM_V_SLICE;
+
+                       split = mwin;
+                       colno = split;
+                       win_g.w = v_slice * mscale;
+
+                       if (w_inc > 1 && w_inc < v_slice) {
+                               /* Adjust for requested size increment. */
+                               remain = (win_g.w - w_base) % w_inc;
+                               win_g.w -= remain;
+                       }
 
-               if (w_inc > 1 && w_inc < v_slice) {
-                       /* adjust for window's requested size increment */
-                       remain = (win_g.w - w_base) % w_inc;
-                       win_g.w -= remain;
+                       msize = win_g.w;
+                       if (flip)
+                               win_g.x += r_g.w - msize;
+               } else {
+                       msize = -2;
+                       colno = split = winno / stacks;
+                       win_g.w = ((r_g.w - (stacks * 2 * border_width) +
+                           2 * border_width) / stacks);
                }
-
-               msize = win_g.w;
-               if (flip)
-                       win_g.x += r_g.w - msize;
-       } else {
-               msize = -2;
-               colno = split = winno / 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);
+               win_g.h = hrh - 2 * border_width;
+               i = j = 0, s = stacks;
        }
-       hrh = r_g.h / colno;
-       extra = r_g.h - (colno * hrh);
-       win_g.h = hrh - 2 * border_width;
 
-       /*  stack all the tiled windows */
-       i = j = 0, s = stacks;
+       /* Update window geometry. */
        TAILQ_FOREACH(win, &ws->winlist, entry) {
-               if (win->transient || win->floating || win->iconic)
+               if (ICONIC(win))
                        continue;
 
-               if (win->ewmh_flags & EWMH_F_FULLSCREEN) {
-                       fs_win = win;
-                       continue;
-               }
-
-               if (win->maximized) {
-                       max_win = win;
+               if (FLOATING(win)) {
+                       update_floater(win);
                        continue;
                }
 
+               /* Tiled. */
                if (split && i == split) {
                        colno = (winno - mwin) / stacks;
                        if (s <= (winno - mwin) % stacks)
@@ -4608,54 +4680,22 @@ stack_master(struct workspace *ws, struct swm_geometry *g, int rot, int flip)
                        update_window(win);
                }
 
-               reorder_window(win, SWM_STACK_ABOVE);
-               map_window(win);
-
                last_h = win_g.h;
                i++;
                j++;
        }
 
-       /* Map/raise focused tiled window to top if windows could overlap. */
-       if (tile_gap < 0 && ws->focus != NULL && !ws->focus->floating &&
-           !ws->focus->maximized) {
-               reorder_window(ws->focus, SWM_STACK_TOP);
-               map_window(ws->focus);
-       }
-
-notiles:
-       /* now, stack all the floaters and transients */
-       TAILQ_FOREACH(win, &ws->winlist, entry) {
-               if ((!win->transient && !win->floating) || win->iconic)
-                       continue;
-
-               if (win->ewmh_flags & EWMH_F_FULLSCREEN) {
-                       fs_win = win;
-                       continue;
-               }
-
-               if (win->maximized) {
-                       max_win = win;
-                       continue;
-               }
-
-               stack_floater(win);
-               reorder_window(win, SWM_STACK_ABOVE);
-               map_window(win);
-       }
+       /* Stack all windows from bottom up. */
+       TAILQ_FOREACH_REVERSE(win, &ws->stack, ws_win_stack, stack_entry)
+               if (!ICONIC(win))
+                       update_win_stacking(win);
 
-       /* Make sure fs_win is stacked on top. */
-       if (fs_win) {
-               stack_floater(fs_win);
-               reorder_window(fs_win, SWM_STACK_TOP);
-               map_window(fs_win);
-       } else if (max_win) {
-               stack_floater(max_win);
-               reorder_window(max_win, SWM_STACK_TOP);
-               map_window(max_win);
-       }
+       /* Map all windows from top down. */
+       TAILQ_FOREACH(win, &ws->stack, stack_entry)
+               if (!ICONIC(win))
+                       map_window(win);
 
-       DNPRINTF(SWM_D_STACK, "stack_master: max_win: 0x%x\n", WINID(max_win));
+       DNPRINTF(SWM_D_STACK, "stack_master: done\n");
 }
 
 void
@@ -4786,31 +4826,29 @@ max_stack(struct workspace *ws, struct swm_geometry *g)
        else
                win = TAILQ_FIRST(&ws->winlist);
 
-       if (win->transient)
-               parent = find_window(win->transient);
-
-       DNPRINTF(SWM_D_STACK, "max_stack: win: 0x%x\n", win->id);
+       DNPRINTF(SWM_D_STACK, "max_stack: win: %#x\n", win->id);
 
-       /* maximize all top level windows */
+       /* Update window geometry. */
        TAILQ_FOREACH(w, &ws->winlist, entry) {
-               if (w->transient || w->iconic)
+               if (ICONIC(w))
                        continue;
 
-               if (!w->mapped && w != win) {
-                       reorder_window(w, SWM_STACK_TOP);
-                       map_window(w);
+               if (TRANS(w)) {
+                       update_floater(w);
+                       continue;
                }
 
-               if (w->floating && !w->maximized) {
-                       /*
-                        * retain geometry for retrieval on exit from
-                        * max_stack mode
-                        */
-                       store_float_geom(w);
-                       w->maximized = 1;
+               /* Set maximized flag for all maxed windows. */
+               if (!MAXIMIZED(w)) {
+                       /* Preserve floating geometry. */
+                       if (ABOVE(w))
+                               store_float_geom(w);
+
+                       ewmh_apply_flags(w, w->ewmh_flags | EWMH_F_MAXIMIZED);
+                       ewmh_update_wm_state(w);
                }
 
-               /* only reconfigure if necessary */
+               /* Only reconfigure if necessary. */
                if (X(w) != gg.x || Y(w) != gg.y || WIDTH(w) != gg.w ||
                    HEIGHT(w) != gg.h) {
                        w->g = gg;
@@ -4826,32 +4864,25 @@ max_stack(struct workspace *ws, struct swm_geometry *g)
                }
        }
 
-       /* If a parent exists, map/raise it first. */
-       if (parent) {
-               reorder_window(parent, SWM_STACK_TOP);
-               map_window(parent);
+       if (TRANS(win)) {
+               parent = find_window(win->transient);
+               raise_window(parent);
 
-               /* Map siblings next. */
-               TAILQ_FOREACH(w, &ws->winlist, entry)
-                       if (w != win && !w->iconic &&
-                           w->transient == parent->id) {
-                               stack_floater(w);
-                               reorder_window(w, SWM_STACK_ABOVE);
-                               map_window(w);
-                       }
+               TAILQ_FOREACH(w, &ws->stack, stack_entry)
+                       if (w->transient == parent->id)
+                               raise_window(w);
        }
 
-       /* Map/raise focused window. */
-       reorder_window(win, SWM_STACK_TOP);
-       map_window(win);
+       raise_window(win);
+
+       TAILQ_FOREACH(w, &ws->stack, stack_entry)
+               if (w->transient == win->id)
+                       raise_window(w);
 
-       /* Finally, map/raise children of focus window. */
-       TAILQ_FOREACH(w, &ws->winlist, entry)
-               if (w->transient == win->id && !w->iconic) {
-                       stack_floater(w);
-                       reorder_window(w, SWM_STACK_ABOVE);
+       /* Map all windows. */
+       TAILQ_FOREACH(w, &ws->stack, stack_entry)
+               if (!ICONIC(w))
                        map_window(w);
-               }
 }
 
 void
@@ -4908,7 +4939,7 @@ send_to_ws(struct swm_region *r, union arg *args)
        else
                return;
 
-       DNPRINTF(SWM_D_MOVE, "send_to_ws: win 0x%x, ws %d\n", win->id, wsid);
+       DNPRINTF(SWM_D_MOVE, "send_to_ws: win %#x, ws %d\n", win->id, wsid);
 
        if (wsid >= workspace_limit)
                return;
@@ -4918,7 +4949,8 @@ send_to_ws(struct swm_region *r, union arg *args)
 
        win_to_ws(win, wsid, 1);
 
-       win->maximized = 0;
+       ewmh_apply_flags(win, win->ewmh_flags & ~EWMH_F_MAXIMIZED);
+       ewmh_update_wm_state(win);
 
        /* Restack and set new focus. */
        stack();
@@ -4942,7 +4974,6 @@ win_to_ws(struct ws_win *win, int wsid, int unfocus)
 {
        struct ws_win           *parent;
        struct workspace        *ws, *nws, *pws;
-       char                    ws_idx_str[SWM_PROPLEN];
 
        if (wsid >= workspace_limit)
                return;
@@ -4953,72 +4984,75 @@ win_to_ws(struct ws_win *win, int wsid, int unfocus)
        ws = win->ws;
        nws = &win->s->ws[wsid];
 
-       DNPRINTF(SWM_D_MOVE, "win_to_ws: win 0x%x, ws %d -> %d\n", win->id,
+       DNPRINTF(SWM_D_MOVE, "win_to_ws: win %#x, ws %d -> %d\n", win->id,
            ws->idx, wsid);
 
-       /* Update the window's workspace property: _SWM_WS */
-       if (snprintf(ws_idx_str, SWM_PROPLEN, "%d", nws->idx) < SWM_PROPLEN) {
-               if (focus_mode != SWM_FOCUS_FOLLOW)
-                       ws->focus_pending = get_focus_prev(win);
+       if (focus_mode != SWM_FOCUS_FOLLOW)
+               ws->focus_pending = get_focus_prev(win);
 
-               /* Move the parent if this is a transient window. */
-               if (win->transient) {
-                       parent = find_window(win->transient);
-                       if (parent) {
-                               pws = parent->ws;
-                               /* Set new focus in parent's ws if needed. */
-                               if (pws->focus == parent) {
-                                       if (focus_mode != SWM_FOCUS_FOLLOW)
-                                               pws->focus_pending =
-                                                   get_focus_prev(parent);
-
-                                       unfocus_win(parent);
-
-                                       if (focus_mode != SWM_FOCUS_FOLLOW) {
-                                               pws->focus = pws->focus_pending;
-                                               pws->focus_pending = NULL;
-                                       }
+       /* Move the parent if this is a transient window. */
+       if (TRANS(win)) {
+               parent = find_window(win->transient);
+               if (parent) {
+                       pws = parent->ws;
+                       /* Set new focus in parent's ws if needed. */
+                       if (pws->focus == parent) {
+                               if (focus_mode != SWM_FOCUS_FOLLOW)
+                                       pws->focus_pending =
+                                           get_focus_prev(parent);
+
+                               unfocus_win(parent);
+
+                               if (focus_mode != SWM_FOCUS_FOLLOW) {
+                                       pws->focus = pws->focus_pending;
+                                       pws->focus_pending = NULL;
                                }
+                       }
 
-                               /* Don't unmap parent if new ws is visible */
-                               if (nws->r == NULL)
-                                       unmap_window(parent);
+                       /* Don't unmap parent if new ws is visible */
+                       if (nws->r == NULL)
+                               unmap_window(parent);
 
-                               /* Transfer */
-                               TAILQ_REMOVE(&ws->winlist, parent, entry);
-                               TAILQ_INSERT_TAIL(&nws->winlist, parent, entry);
-                               parent->ws = nws;
+                       /* Transfer */
+                       TAILQ_REMOVE(&ws->winlist, parent, entry);
+                       TAILQ_REMOVE(&ws->stack, parent, stack_entry);
+                       TAILQ_INSERT_TAIL(&nws->winlist, parent, entry);
+                       TAILQ_INSERT_TAIL(&nws->stack, parent, stack_entry);
+                       parent->ws = nws;
 
-                               DNPRINTF(SWM_D_PROP, "win_to_ws: set "
-                                   "property: _SWM_WS: %s\n", ws_idx_str);
-                               xcb_change_property(conn, XCB_PROP_MODE_REPLACE,
-                                   parent->id, a_swm_ws, XCB_ATOM_STRING, 8,
-                                   strlen(ws_idx_str), ws_idx_str);
-                       }
+                       DNPRINTF(SWM_D_PROP, "win_to_ws: set property: "
+                           "_NET_WM_DESKTOP: %d\n", wsid);
+                       xcb_change_property(conn, XCB_PROP_MODE_REPLACE,
+                           parent->id, ewmh[_NET_WM_DESKTOP].atom,
+                           XCB_ATOM_CARDINAL, 32, 1, &wsid);
                }
+       }
 
-               if (unfocus)
-                       unfocus_win(win);
+       if (unfocus)
+               unfocus_win(win);
 
-               /* Don't unmap if new ws is visible */
-               if (nws->r == NULL)
-                       unmap_window(win);
+       /* Don't unmap if new ws is visible */
+       if (nws->r == NULL)
+               unmap_window(win);
 
-               /* Transfer */
-               TAILQ_REMOVE(&ws->winlist, win, entry);
-               TAILQ_INSERT_TAIL(&nws->winlist, win, entry);
-               win->ws = nws;
+       /* Transfer */
+       TAILQ_REMOVE(&ws->winlist, win, entry);
+       TAILQ_REMOVE(&ws->stack, win, stack_entry);
+       TAILQ_INSERT_TAIL(&nws->winlist, win, entry);
+       TAILQ_INSERT_TAIL(&nws->stack, win, stack_entry);
+       win->ws = nws;
 
-               /* Set focus on new ws. */
-               unfocus_win(nws->focus);
-               nws->focus = win;
+       /* Set focus on new ws. */
+       unfocus_win(nws->focus);
+       nws->focus = win;
 
-               DNPRINTF(SWM_D_PROP, "win_to_ws: set property: _SWM_WS: %s\n",
-                   ws_idx_str);
-               xcb_change_property(conn, XCB_PROP_MODE_REPLACE, win->id,
-                   a_swm_ws, XCB_ATOM_STRING, 8, strlen(ws_idx_str),
-                   ws_idx_str);
-       }
+       /* Update the window's workspace property: _NET_WM_DESKTOP */
+       DNPRINTF(SWM_D_PROP, "win_to_ws: set property: "
+           "_NET_WM_DESKTOP: %d\n", wsid);
+       xcb_change_property(conn, XCB_PROP_MODE_REPLACE, win->id,
+           ewmh[_NET_WM_DESKTOP].atom, XCB_ATOM_CARDINAL, 32, 1, &wsid);
+
+       ewmh_update_client_list();
 
        DNPRINTF(SWM_D_MOVE, "win_to_ws: done.\n");
 }
@@ -5044,7 +5078,7 @@ raise_toggle(struct swm_region *r, union arg *args)
        if (r == NULL || r->ws == NULL)
                return;
 
-       if (r->ws->focus && r->ws->focus->maximized)
+       if (r->ws->focus && MAXIMIZED(r->ws->focus))
                return;
 
        r->ws->always_raise = !r->ws->always_raise;
@@ -5059,15 +5093,19 @@ raise_toggle(struct swm_region *r, union arg *args)
 void
 iconify(struct swm_region *r, union arg *args)
 {
+       struct ws_win           *w;
        /* suppress unused warning since var is needed */
        (void)args;
 
-       if (r->ws->focus == NULL)
+       if ((w = r->ws->focus) == NULL)
                return;
 
-       set_swm_iconic(r->ws->focus, 1);
+       ewmh_apply_flags(w, w->ewmh_flags | EWMH_F_HIDDEN);
+       ewmh_update_wm_state(w);
 
-       xcb_flush(conn);
+       stack();
+
+       focus_flush();
 }
 
 char *
@@ -5120,10 +5158,13 @@ uniconify(struct swm_region *r, union arg *args)
        TAILQ_FOREACH(win, &r->ws->winlist, entry) {
                if (win->ws == NULL)
                        continue; /* should never happen */
-               if (!win->iconic)
+               if (!ICONIC(win))
                        continue;
                count++;
        }
+
+       DNPRINTF(SWM_D_MISC, "uniconify: count: %d\n", count);
+
        if (count == 0)
                return;
 
@@ -5138,7 +5179,7 @@ uniconify(struct swm_region *r, union arg *args)
        TAILQ_FOREACH(win, &r->ws->winlist, entry) {
                if (win->ws == NULL)
                        continue; /* should never happen */
-               if (!win->iconic)
+               if (!ICONIC(win))
                        continue;
 
                name = get_win_name(win->id);
@@ -5245,7 +5286,7 @@ search_win(struct swm_region *r, union arg *args)
 
        i = 1;
        TAILQ_FOREACH(win, &r->ws->winlist, entry) {
-               if (win->iconic)
+               if (ICONIC(win))
                        continue;
 
                sw = calloc(1, sizeof(struct search_window));
@@ -5311,7 +5352,7 @@ search_win(struct swm_region *r, union arg *args)
                        XftDrawDestroy(draw);
                }
 
-               DNPRINTF(SWM_D_MISC, "search_win: mapped window: 0x%x\n", w);
+               DNPRINTF(SWM_D_MISC, "search_win: mapped win %#x\n", w);
 
                fprintf(lfile, "%d\n", i);
                i++;
@@ -5332,7 +5373,7 @@ search_resp_uniconify(const char *resp, size_t len)
        DNPRINTF(SWM_D_MISC, "search_resp_uniconify: resp: %s\n", resp);
 
        TAILQ_FOREACH(win, &search_r->ws->winlist, entry) {
-               if (!win->iconic)
+               if (!ICONIC(win))
                        continue;
                name = get_win_name(win->id);
                if (asprintf(&s, "%s.%u", name, win->id) == -1) {
@@ -5342,7 +5383,9 @@ search_resp_uniconify(const char *resp, size_t len)
                free(name);
                if (strncmp(s, resp, len) == 0) {
                        /* XXX this should be a callback to generalize */
-                       set_swm_iconic(win, 0);
+                       ewmh_apply_flags(win, win->ewmh_flags & ~EWMH_F_HIDDEN);
+                       ewmh_update_wm_state(win);
+                       stack();
                        free(s);
                        break;
                }
@@ -5373,7 +5416,136 @@ search_resp_name_workspace(const char *resp, size_t len)
                            "strdup: %s", strerror(errno));
                        return;
                }
+
+               ewmh_update_desktop_names();
+               ewmh_get_desktop_names();
+       }
+}
+
+void
+ewmh_update_desktop_names(void)
+{
+       char                    *name_list = NULL, *p;
+       int                     num_screens, i, j, len = 0, tot = 0;
+
+       num_screens = get_screen_count();
+       for (i = 0; i < num_screens; ++i) {
+               for (j = 0; j < workspace_limit; ++j) {
+                       if (screens[i].ws[j].name != NULL)
+                               len += strlen(screens[i].ws[j].name);
+                       ++len;
+               }
+
+               if((name_list = calloc(sizeof(char *), len)) == NULL)
+                       err(1, "update_desktop_names: calloc: failed to "
+                           "allocate memory.");
+
+               p = name_list;
+               for (j = 0; j < workspace_limit; ++j) {
+                       if (screens[i].ws[j].name != NULL) {
+                               len = strlen(screens[i].ws[j].name);
+                               memcpy(p, screens[i].ws[j].name, len);
+                       } else {
+                               len = 0;
+                       }
+
+                       p += len + 1;
+                       tot += len + 1;
+               }
+
+               xcb_change_property(conn, XCB_PROP_MODE_REPLACE,
+                   screens[i].root, ewmh[_NET_DESKTOP_NAMES].atom,
+                   a_utf8_string, 8, tot, name_list);
+
+               free(name_list);
+               name_list = NULL;
        }
+
+       free(name_list);
+}
+
+void
+ewmh_get_desktop_names(void)
+{
+       char                            *names = NULL;
+       xcb_get_property_cookie_t       c;
+       xcb_get_property_reply_t        *r;
+       int                             num_screens, i, j, n, k;
+
+       num_screens = get_screen_count();
+       for (i = 0; i < num_screens; ++i) {
+               for (j = 0; j < workspace_limit; ++j) {
+                       free(screens[i].ws[j].name);
+                       screens[i].ws[j].name = NULL;
+               }
+
+               c = xcb_get_property(conn, 0, screens[i].root,
+                   ewmh[_NET_DESKTOP_NAMES].atom,
+                   a_utf8_string, 0, UINT32_MAX);
+               r = xcb_get_property_reply(conn, c, NULL);
+               if (r == NULL)
+                       continue;
+
+               names = xcb_get_property_value(r);
+               n = xcb_get_property_value_length(r);
+
+               for (j = 0, k = 0; j < n; ++j) {
+                       if (*(names + j) != '\0') {
+                               screens[i].ws[k].name = strdup(names + j);
+                               j += strlen(names + j);
+                       }
+                       ++k;
+               }
+               free(r);
+       }
+}
+
+void
+ewmh_update_client_list(void)
+{
+       struct ws_win           *win;
+       int                     num_screens, i, j, k = 0, count = 0;
+       xcb_window_t            *wins;
+
+       num_screens = get_screen_count();
+       for (i = 0; i < num_screens; ++i) {
+               for (j = 0; j < workspace_limit; ++j)
+                       TAILQ_FOREACH(win, &screens[i].ws[j].winlist, entry)
+                               ++count;
+
+               DNPRINTF(SWM_D_PROP, "ewmh_update_client_list: win count: %d\n",
+                   count);
+
+               if (count == 0)
+                       continue;
+
+               wins = calloc(sizeof(xcb_window_t), count);
+               if (wins == NULL)
+                       err(1, "ewmh_update_client_list: calloc: failed to "
+                           "allocate memory.");
+
+               for (j = 0, k = 0; j < workspace_limit; ++j)
+                       TAILQ_FOREACH(win, &screens[i].ws[j].winlist, entry)
+                               wins[k++] = win->id;
+
+               xcb_change_property(conn, XCB_PROP_MODE_REPLACE,
+                   screens[i].root, ewmh[_NET_CLIENT_LIST].atom,
+                   XCB_ATOM_WINDOW, 32, count, wins);
+
+               free(wins);
+       }
+}
+
+void
+ewmh_update_current_desktop(void)
+{
+       int                     num_screens, i;
+
+       num_screens = get_screen_count();
+       for (i = 0; i < num_screens; ++i)
+               xcb_change_property(conn, XCB_PROP_MODE_REPLACE,
+                   screens[i].root, ewmh[_NET_CURRENT_DESKTOP].atom,
+                   XCB_ATOM_CARDINAL, 32, 1, &screens[i].r_focus->ws->idx);
 }
 
 void
@@ -5523,12 +5695,11 @@ clear_maximized(struct workspace *ws)
        struct ws_win           *w;
        int                     count = 0;
 
-       /* Clear any maximized win(s) on ws. */
-       TAILQ_FOREACH(w, &ws->winlist, entry)
-               if (w->maximized) {
-                       w->maximized = 0;
-                       if (w->floating)
-                               load_float_geom(w);
+       /* Clear any maximized win(s) on ws, from bottom up. */
+       TAILQ_FOREACH_REVERSE(w, &ws->stack, ws_win_stack, stack_entry)
+               if (MAXIMIZED(w)) {
+                       ewmh_apply_flags(w, w->ewmh_flags & ~EWMH_F_MAXIMIZED);
+                       ewmh_update_wm_state(w);
                        ++count;
                }
 
@@ -5538,68 +5709,34 @@ clear_maximized(struct workspace *ws)
 void
 maximize_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;
 
-       DNPRINTF(SWM_D_MISC, "maximize_toggle: win %#x\n", win->id);
+       DNPRINTF(SWM_D_MISC, "maximize_toggle: win %#x\n", w->id);
 
-       if (win->ewmh_flags & EWMH_F_FULLSCREEN)
+       if (FULLSCREEN(w))
                return;
 
-       if (win->ws->cur_layout == &layouts[SWM_MAX_STACK])
+       if (w->ws->cur_layout == &layouts[SWM_MAX_STACK])
                return;
 
-       if (win->floating) {
-               if (win->maximized)
-                       load_float_geom(win);
-               else
-                       store_float_geom(win);
-       }
-
-       win->maximized = !win->maximized;
+       ewmh_apply_flags(w, w->ewmh_flags ^ EWMH_F_MAXIMIZED);
+       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, "maximize_toggle: done\n");
 }
 
-int
-floating_toggle_win(struct ws_win *win)
-{
-       if (win == NULL)
-               return (0);
-
-       /* reject floating toggles in max stack mode */
-       if (win->ws->cur_layout == &layouts[SWM_MAX_STACK])
-               return (0);
-
-       if (win->ws->r == NULL)
-               return (0);
-
-       if (win->floating) {
-               if (!win->maximized)
-                       store_float_geom(win);
-       } else {
-               load_float_geom(win);
-       }
-
-       win->floating = !win->floating;
-       win->maximized = 0;
-
-       ewmh_update_actions(win);
-
-       return (1);
-}
-
 void
 floating_toggle(struct swm_region *r, union arg *args)
 {
@@ -5611,11 +5748,11 @@ floating_toggle(struct swm_region *r, union arg *args)
        if (win == NULL)
                return;
 
-       if (win->ewmh_flags & EWMH_F_FULLSCREEN)
+       if (FULLSCREEN(win) || TRANS(win))
                return;
 
-       ewmh_update_win_state(win, ewmh[_NET_WM_STATE_ABOVE].atom,
-           _NET_WM_STATE_TOGGLE);
+       ewmh_apply_flags(win, win->ewmh_flags ^ EWMH_F_ABOVE);
+       ewmh_update_wm_state(win);
 
        stack();
 
@@ -5643,7 +5780,7 @@ region_containment(struct ws_win *win, struct swm_region *r, int opts)
        bm = opts & SWM_CW_BOTTOM ? MAX_Y(win) + BORDER(win) - MAX_Y(r) : bw;
        tp = opts & SWM_CW_TOP ? Y(r) - Y(win) + BORDER(win) : bw;
 
-       DNPRINTF(SWM_D_MISC, "region_containment: win 0x%x, rt: %d, lt: %d, "
+       DNPRINTF(SWM_D_MISC, "region_containment: win %#x, rt: %d, lt: %d, "
            "bm: %d, tp: %d, SOFTBOUNDARY: %s, HARDBOUNDARY: %s\n", win->id, rt,
            lt, bm, tp, YESNO(opts & SWM_CW_SOFTBOUNDARY),
            YESNO(opts & SWM_CW_HARDBOUNDARY));
@@ -5668,7 +5805,7 @@ region_containment(struct ws_win *win, struct swm_region *r, int opts)
 void
 constrain_window(struct ws_win *win, struct swm_geometry *b, int *opts)
 {
-       DNPRINTF(SWM_D_MISC, "constrain_window: window: 0x%x, (x,y) w x h: "
+       DNPRINTF(SWM_D_MISC, "constrain_window: win %#x, (x,y) w x h: "
            "(%d,%d) %d x %d, box: (x,y) w x h: (%d,%d) %d x %d, rt: %s, "
            "lt: %s, bt: %s, tp: %s, allow resize: %s\n", win->id, X(win),
            Y(win), WIDTH(win), HEIGHT(win), b->x, b->y, b->w, b->h,
@@ -5727,7 +5864,7 @@ update_window(struct ws_win *win)
        wc[3] = HEIGHT(win);
        wc[4] = BORDER(win);
 
-       DNPRINTF(SWM_D_EVENT, "update_window: window: 0x%x, (x,y) w x h: "
+       DNPRINTF(SWM_D_EVENT, "update_window: win %#x, (x,y) w x h: "
            "(%d,%d) %d x %d, bordered: %s\n", win->id, wc[0], wc[1], wc[2],
            wc[3], YESNO(win->bordered));
 
@@ -5741,8 +5878,8 @@ resize(struct ws_win *win, union arg *args)
 {
        xcb_timestamp_t         timestamp = 0;
        struct swm_region       *r = NULL;
-       int                     resize_stp = 0;
        struct swm_geometry     g;
+       int                     resize_stp = 0;
        int                     top = 0, left = 0, resizing;
        int                     dx, dy;
        xcb_cursor_t                    cursor;
@@ -5754,27 +5891,25 @@ resize(struct ws_win *win, union arg *args)
                return;
        r = win->ws->r;
 
-       if (win->ewmh_flags & EWMH_F_FULLSCREEN)
-               return;
-
-       DNPRINTF(SWM_D_EVENT, "resize: window: 0x%x, floating: %s, "
-           "transient: 0x%x\n", win->id, YESNO(win->floating),
-           win->transient);
-
-       if (!win->transient && !win->floating)
+       if (FULLSCREEN(win))
                return;
 
        /* In max_stack mode, should only resize transients. */
-       if (win->ws->cur_layout == &layouts[SWM_MAX_STACK] && !win->transient)
+       if (win->ws->cur_layout == &layouts[SWM_MAX_STACK] && !TRANS(win))
                return;
 
-       win->maximized = 0;
+       DNPRINTF(SWM_D_EVENT, "resize: win %#x, floating: %s, "
+           "transient: %#x\n", win->id, YESNO(ABOVE(win)),
+           win->transient);
 
-       if (!win->manual) {
-               win->manual = 1;
-               ewmh_update_win_state(win, ewmh[_SWM_WM_STATE_MANUAL].atom,
-                   _NET_WM_STATE_ADD);
-       }
+       if (MAXIMIZED(win))
+               store_float_geom(win);
+       else if (!(TRANS(win) || ABOVE(win)))
+               return;
+
+       ewmh_apply_flags(win, (win->ewmh_flags | SWM_F_MANUAL | EWMH_F_ABOVE) &
+           ~EWMH_F_MAXIMIZED);
+       ewmh_update_wm_state(win);
 
        stack();
 
@@ -5971,8 +6106,9 @@ regionize(struct ws_win *win, int x, int y)
 void
 move(struct ws_win *win, union arg *args)
 {
-       xcb_timestamp_t         timestamp = 0;
-       int                     move_stp = 0, moving;
+       struct swm_region               *r;
+       xcb_timestamp_t                 timestamp = 0;
+       int                             move_stp = 0, moving, restack = 0;
        xcb_query_pointer_reply_t       *qpr = NULL;
        xcb_generic_event_t             *evt;
        xcb_motion_notify_event_t       *mne;
@@ -5980,31 +6116,30 @@ move(struct ws_win *win, union arg *args)
        if (win == NULL)
                return;
 
-       if (win->ewmh_flags & EWMH_F_FULLSCREEN)
+       if ((r = win->ws->r) == NULL)
                return;
 
-       DNPRINTF(SWM_D_EVENT, "move: window: 0x%x, floating: %s, transient: "
-           "0x%x\n", win->id, YESNO(win->floating), win->transient);
+       if (FULLSCREEN(win))
+               return;
+
+       DNPRINTF(SWM_D_EVENT, "move: win %#x, floating: %s, transient: "
+           "%#x\n", win->id, YESNO(ABOVE(win)), win->transient);
 
        /* in max_stack mode should only move transients */
-       if (win->ws->cur_layout == &layouts[SWM_MAX_STACK] && !win->transient)
+       if (win->ws->cur_layout == &layouts[SWM_MAX_STACK] && !TRANS(win))
                return;
 
-       win->maximized = 0;
-
-       if (!win->manual) {
-               win->manual = 1;
-               ewmh_update_win_state(win, ewmh[_SWM_WM_STATE_MANUAL].atom,
-                   _NET_WM_STATE_ADD);
+       if (!(ABOVE(win) || TRANS(win)) || MAXIMIZED(win)) {
+               store_float_geom(win);
+               restack = 1;
        }
 
-       /* When a stacked win is moved, float it and restack. */
-       if (!win->floating && !win->transient) {
-               store_float_geom(win);
-               ewmh_update_win_state(win, ewmh[_NET_WM_STATE_ABOVE].atom,
-                   _NET_WM_STATE_ADD);
+       ewmh_apply_flags(win, (win->ewmh_flags | SWM_F_MANUAL | EWMH_F_ABOVE) &
+           ~EWMH_F_MAXIMIZED);
+       ewmh_update_wm_state(win);
+
+       if (restack)
                stack();
-       }
 
        focus_flush();
 
@@ -6069,7 +6204,7 @@ move(struct ws_win *win, union arg *args)
                        break;
                case XCB_MOTION_NOTIFY:
                        mne = (xcb_motion_notify_event_t *)evt;
-                       DNPRINTF(SWM_D_EVENT, "motion: root: 0x%x\n", mne->root);
+                       DNPRINTF(SWM_D_EVENT, "motion: root: %#x\n", mne->root);
                        X(win) = mne->root_x - qpr->win_x - border_width;
                        Y(win) = mne->root_y - qpr->win_y - border_width;
 
@@ -6118,7 +6253,7 @@ move_step(struct swm_region *r, union arg *args)
        else
                return;
 
-       if (!win->transient && !win->floating)
+       if (!TRANS(win) && !ABOVE(win))
                return;
 
        move(win, args);
@@ -6687,7 +6822,7 @@ setup_spawn(void)
 
 /* key bindings */
 #define SWM_MODNAME_SIZE       32
-#define        SWM_KEY_WS              "\n+ \t"
+#define SWM_KEY_WS             "\n+ \t"
 int
 parsekeys(const char *keystr, unsigned int currmod, unsigned int *mod, KeySym *ks)
 {
@@ -7139,7 +7274,7 @@ grabbuttons(struct ws_win *win)
        unsigned int    modifiers[4];
        int             i, j;
 
-       DNPRINTF(SWM_D_MOUSE, "grabbuttons: win 0x%x\n", win->id);
+       DNPRINTF(SWM_D_MOUSE, "grabbuttons: win %#x\n", win->id);
        updatenumlockmask();
 
        modifiers[0] = 0;
@@ -7170,7 +7305,7 @@ const char *quirkname[] = {
 };
 
 /* SWM_Q_WS: retain '|' for back compat for now (2009-08-11) */
-#define        SWM_Q_WS                "\n|+ \t"
+#define SWM_Q_WS               "\n|+ \t"
 int
 parsequirks(const char *qstr, unsigned long *quirk)
 {
@@ -7691,6 +7826,13 @@ setconfvalue(const char *selector, const char *value, int flags)
                        workspace_limit = SWM_WS_MAX;
                else if (workspace_limit < 1)
                        workspace_limit = 1;
+
+               num_screens = get_screen_count();
+               for (i = 0; i < num_screens; i++) {
+                       xcb_change_property(conn, XCB_PROP_MODE_REPLACE,
+                           screens[i].root, ewmh[_NET_NUMBER_OF_DESKTOPS].atom,
+                           XCB_ATOM_CARDINAL, 32, 1, &workspace_limit);
+               }
                break;
        default:
                return (1);
@@ -8115,7 +8257,7 @@ set_child_transient(struct ws_win *win, xcb_window_t *trans)
                parent->focus_child = win;
        else {
                DNPRINTF(SWM_D_MISC, "set_child_transient: parent doesn't exist"
-                   " for 0x%x trans 0x%x\n", win->id, win->transient);
+                   " for %#x trans %#x\n", win->id, win->transient);
 
                r = root_to_region(win->s->root, SWM_CK_ALL);
                ws = r->ws;
@@ -8124,7 +8266,7 @@ set_child_transient(struct ws_win *win, xcb_window_t *trans)
                        if (xcb_icccm_get_wm_hints_reply(conn,
                            xcb_icccm_get_wm_hints(conn, w->id),
                            &wmh, NULL) != 1) {
-                               warnx("can't get hints for 0x%x", w->id);
+                               warnx("can't get hints for %#x", w->id);
                                continue;
                        }
 
@@ -8135,7 +8277,7 @@ set_child_transient(struct ws_win *win, xcb_window_t *trans)
                        win->transient = w->id;
                        *trans = w->id;
                        DNPRINTF(SWM_D_MISC, "set_child_transient: adjusting "
-                           "transient to 0x%x\n", win->transient);
+                           "transient to %#x\n", win->transient);
                        break;
                }
        }
@@ -8188,7 +8330,7 @@ tryharder:
 }
 
 int
-get_ws_idx(xcb_window_t id)
+get_swm_ws(xcb_window_t id)
 {
        int                     ws_idx = -1;
        char                    *prop = NULL;
@@ -8217,10 +8359,10 @@ get_ws_idx(xcb_window_t id)
        free(gpr);
 
        if (prop) {
-               DNPRINTF(SWM_D_PROP, "get_ws_idx: _SWM_WS: %s\n", prop);
+               DNPRINTF(SWM_D_PROP, "get_swm_ws: _SWM_WS: %s\n", prop);
                ws_idx = (int)strtonum(prop, 0, workspace_limit - 1, &errstr);
                if (errstr) {
-                       DNPRINTF(SWM_D_PROP, "get_ws_idx: window: #%s: %s",
+                       DNPRINTF(SWM_D_PROP, "get_swm_ws: win #%s: %s",
                            errstr, prop);
                }
                free(prop);
@@ -8229,38 +8371,65 @@ get_ws_idx(xcb_window_t id)
        return ws_idx;
 }
 
+int
+get_ws_idx(xcb_window_t id)
+{
+       xcb_get_property_reply_t        *gpr;
+       int                     ws_idx = -1;
+
+       gpr = xcb_get_property_reply(conn,
+               xcb_get_property(conn, 0, id, ewmh[_NET_WM_DESKTOP].atom,
+                   XCB_ATOM_CARDINAL, 0, 1),
+               NULL);
+       if (gpr) {
+               if (gpr->type == XCB_ATOM_CARDINAL && gpr->format == 32)
+                       ws_idx = *((int *)xcb_get_property_value(gpr));
+               free(gpr);
+       }
+
+       if (ws_idx == -1)
+               if ((ws_idx = get_swm_ws(id)) != -1)
+                       xcb_delete_property(conn, id, a_swm_ws);
+
+       if (ws_idx > workspace_limit - 1 || ws_idx < -1)
+               ws_idx = -1;
+
+       DNPRINTF(SWM_D_PROP, "get_ws_idx: win %#x, ws_idx: %d\n", id, ws_idx);
+
+       return ws_idx;
+}
+
 struct ws_win *
 manage_window(xcb_window_t id, uint16_t mapped)
 {
        xcb_window_t            trans = XCB_WINDOW_NONE;
        struct ws_win           *win, *ww;
        int                     ws_idx;
-       char                    ws_idx_str[SWM_PROPLEN];
        char                    *class, *instance, *name;
        struct swm_region       *r;
        struct pid_e            *p;
        struct quirk            *qp;
-       uint32_t                i, wa[2];
+       uint32_t                i, wa[2], new_flags;
        xcb_get_geometry_reply_t        *gr;
 
        if ((win = find_window(id)) != NULL) {
-               DNPRINTF(SWM_D_MISC, "manage_window: win 0x%x already "
+               DNPRINTF(SWM_D_MISC, "manage_window: win %#x already "
                    "managed; skipping.)\n", id);
                return (win);   /* Already managed. */
        }
 
        /* See if window is on the unmanaged list. */
        if ((win = find_unmanaged_window(id)) != NULL) {
-               DNPRINTF(SWM_D_MISC, "manage_window: win 0x%x found on "
+               DNPRINTF(SWM_D_MISC, "manage_window: win %#x found on "
                    "unmanaged list.\n", id);
                TAILQ_REMOVE(&win->ws->unmanagedlist, win, entry);
 
-               if (win->transient)
+               if (TRANS(win))
                        set_child_transient(win, &trans);
 
                goto out;
        } else {
-               DNPRINTF(SWM_D_MISC, "manage_window: win 0x%x is new.\n", id);
+               DNPRINTF(SWM_D_MISC, "manage_window: win %#x is new.\n", id);
        }
 
        /* Try to get initial window geometry. */
@@ -8287,8 +8456,6 @@ manage_window(xcb_window_t id, uint16_t mapped)
        Y(win) = gr->y + gr->border_width - border_width;
        win->bordered = 1;
        win->mapped = mapped;
-       win->maximized = 0;
-       win->ewmh_flags = 0;
        win->s = r->s;  /* this never changes */
 
        free(gr);
@@ -8326,8 +8493,6 @@ manage_window(xcb_window_t id, uint16_t mapped)
        /* Get WM_PROTOCOLS. */
        get_wm_protocols(win);
 
-       win->iconic = get_swm_iconic(win);
-
        /* Figure out which workspace the window belongs to. */
        if ((p = find_pid(window_get_pid(win->id))) != NULL) {
                win->ws = &r->s->ws[p->ws];
@@ -8335,7 +8500,7 @@ manage_window(xcb_window_t id, uint16_t mapped)
                free(p);
                p = NULL;
        } else if ((ws_idx = get_ws_idx(win->id)) != -1 &&
-           !win->transient) {
+           !TRANS(win)) {
                /* _SWM_WS is set; use that. */
                win->ws = &r->s->ws[ws_idx];
        } else if (trans && (ww = find_window(trans)) != NULL) {
@@ -8345,20 +8510,16 @@ manage_window(xcb_window_t id, uint16_t mapped)
                win->ws = r->ws;
        }
 
-       /* Set the _SWM_WS atom so we can remember this after reincarnation. */
-       if (snprintf(ws_idx_str, SWM_PROPLEN, "%d", win->ws->idx) <
-           SWM_PROPLEN) {
-               DNPRINTF(SWM_D_PROP, "manage_window: set _SWM_WS: %s\n",
-                   ws_idx_str);
-               xcb_change_property(conn, XCB_PROP_MODE_REPLACE, win->id,
-                   a_swm_ws, XCB_ATOM_STRING, 8, strlen(ws_idx_str),
-                   ws_idx_str);
-       }
+       /* Set the _NET_WM_DESKTOP atom. */
+       DNPRINTF(SWM_D_PROP, "manage_window: set _NET_WM_DESKTOP: %d\n",
+           win->ws->idx);
+       xcb_change_property(conn, XCB_PROP_MODE_REPLACE, win->id,
+           ewmh[_NET_WM_DESKTOP].atom, XCB_ATOM_CARDINAL, 32, 1, &win->ws->idx);
 
        /* WS must already be set for this to work. */
        store_float_geom(win);
 
-       /* Handle EWMH */
+       /* Set initial quirks based on EWMH. */
        ewmh_autoquirk(win);
 
        /* Determine initial quirks. */
@@ -8374,7 +8535,7 @@ manage_window(xcb_window_t id, uint16_t mapped)
            "name: %s\n", class, instance, name);
 
        /* java is retarded so treat it special */
-       if (win->ch.instance_name && strstr(win->ch.instance_name, "sun-awt")) {
+       if (strstr(instance, "sun-awt")) {
                DNPRINTF(SWM_D_CLASS, "manage_window: java window detected.\n");
                win->java = 1;
        }
@@ -8386,18 +8547,12 @@ manage_window(xcb_window_t id, uint16_t mapped)
                        DNPRINTF(SWM_D_CLASS, "manage_window: matched "
                            "quirk: %s:%s:%s mask: %#lx\n", qp->class,
                            qp->instance, qp->name, qp->quirk);
-                       if (qp->quirk & SWM_Q_FLOAT)
-                               win->floating = 1;
                        win->quirks = qp->quirk;
                }
        }
 
        free(name);
 
-       /* Alter window position if quirky */
-       if (win->quirks & SWM_Q_ANYWHERE)
-               win->manual = 1;
-
        /* Reset font sizes (the bruteforce way; no default keybinding). */
        if (win->quirks & SWM_Q_XTERM_FONTADJ) {
                for (i = 0; i < SWM_MAX_FONT_STEPS; i++)
@@ -8433,17 +8588,34 @@ out:
                TAILQ_INSERT_HEAD(&win->ws->winlist, win, entry);
        }
 
-       /* Get initial _NET_WM_STATE */
-       ewmh_get_win_state(win);
+       ewmh_update_client_list();
+
+       TAILQ_INSERT_TAIL(&win->ws->stack, win, stack_entry);
+
+       /* Get/apply initial _NET_WM_STATE */
+       ewmh_get_wm_state(win);
+
+       /* Apply quirks. */
+       new_flags = win->ewmh_flags;
+
+       if (win->quirks & SWM_Q_FLOAT)
+               new_flags |= EWMH_F_ABOVE;
+
+       if (win->quirks & SWM_Q_ANYWHERE)
+               new_flags |= SWM_F_MANUAL;
+
+       ewmh_apply_flags(win, new_flags);
+       ewmh_update_wm_state(win);
+
        /* Set initial _NET_WM_ALLOWED_ACTIONS */
        ewmh_update_actions(win);
 
        grabbuttons(win);
 
-       DNPRINTF(SWM_D_MISC, "manage_window: done. window: 0x%x, (x,y) w x h: "
-           "(%d,%d) %d x %d, ws: %d, iconic: %s, transient: 0x%x\n", win->id,
+       DNPRINTF(SWM_D_MISC, "manage_window: done. win %#x, (x,y) w x h: "
+           "(%d,%d) %d x %d, ws: %d, iconic: %s, transient: %#x\n", win->id,
            X(win), Y(win), WIDTH(win), HEIGHT(win), win->ws->idx,
-           YESNO(win->iconic), win->transient);
+           YESNO(ICONIC(win)), win->transient);
 
        return (win);
 }
@@ -8451,7 +8623,7 @@ out:
 void
 free_window(struct ws_win *win)
 {
-       DNPRINTF(SWM_D_MISC, "free_window: window: 0x%x\n", win->id);
+       DNPRINTF(SWM_D_MISC, "free_window: win %#x\n", win->id);
 
        if (win == NULL)
                return;
@@ -8477,16 +8649,19 @@ unmanage_window(struct ws_win *win)
        if (win == NULL)
                return;
 
-       DNPRINTF(SWM_D_MISC, "unmanage_window: window: 0x%x\n", win->id);
+       DNPRINTF(SWM_D_MISC, "unmanage_window: win %#x\n", win->id);
 
-       if (win->transient) {
+       if (TRANS(win)) {
                parent = find_window(win->transient);
                if (parent)
                        parent->focus_child = NULL;
        }
 
+       TAILQ_REMOVE(&win->ws->stack, win, stack_entry);
        TAILQ_REMOVE(&win->ws->winlist, win, entry);
        TAILQ_INSERT_TAIL(&win->ws->unmanagedlist, win, entry);
+
+       ewmh_update_client_list();
 }
 
 void
@@ -8495,7 +8670,7 @@ expose(xcb_expose_event_t *e)
        int                     i, num_screens;
        struct swm_region       *r;
 
-       DNPRINTF(SWM_D_EVENT, "expose: window: 0x%x\n", e->window);
+       DNPRINTF(SWM_D_EVENT, "expose: win %#x\n", e->window);
 
        num_screens = get_screen_count();
        for (i = 0; i < num_screens; i++)
@@ -8510,7 +8685,7 @@ expose(xcb_expose_event_t *e)
 void
 focusin(xcb_focus_in_event_t *e)
 {
-       DNPRINTF(SWM_D_EVENT, "focusin: window: 0x%x, mode: %s(%u), "
+       DNPRINTF(SWM_D_EVENT, "focusin: win %#x, mode: %s(%u), "
            "detail: %s(%u)\n", e->event, get_notify_mode_label(e->mode),
            e->mode, get_notify_detail_label(e->detail), e->detail);
 }
@@ -8518,7 +8693,7 @@ focusin(xcb_focus_in_event_t *e)
 void
 focusout(xcb_focus_out_event_t *e)
 {
-       DNPRINTF(SWM_D_EVENT, "focusout: window: 0x%x, mode: %s(%u), "
+       DNPRINTF(SWM_D_EVENT, "focusout: win %#x, mode: %s(%u), "
            "detail: %s(%u)\n", e->event, get_notify_mode_label(e->mode),
            e->mode, get_notify_detail_label(e->detail), e->detail);
 }
@@ -8532,8 +8707,8 @@ keypress(xcb_key_press_event_t *e)
 
        keysym = xcb_key_press_lookup_keysym(syms, e, 0);
 
-       DNPRINTF(SWM_D_EVENT, "keypress: keysym: %u, win (x,y): 0x%x (%d,%d), "
-           "detail: %u, time: %u, root (x,y): 0x%x (%d,%d), child: 0x%x, "
+       DNPRINTF(SWM_D_EVENT, "keypress: keysym: %u, win (x,y): %#x (%d,%d), "
+           "detail: %u, time: %u, root (x,y): %#x (%d,%d), child: %#x, "
            "state: %u, same_screen: %s\n", keysym, e->event, e->event_x,
            e->event_y, e->detail, e->time, e->root, e->root_x, e->root_y,
            e->child, e->state, YESNO(e->same_screen));
@@ -8566,8 +8741,8 @@ buttonpress(xcb_button_press_event_t *e)
        int                     i;
        int                     handled = 0;
 
-       DNPRINTF(SWM_D_EVENT, "buttonpress: win (x,y): 0x%x (%d,%d), "
-           "detail: %u, time: %u, root (x,y): 0x%x (%d,%d), child: 0x%x, "
+       DNPRINTF(SWM_D_EVENT, "buttonpress: win (x,y): %#x (%d,%d), "
+           "detail: %u, time: %u, root (x,y): %#x (%d,%d), child: %#x, "
            "state: %u, same_screen: %s\n", e->event, e->event_x, e->event_y,
            e->detail, e->time, e->root, e->root_x, e->root_y, e->child,
            e->state, YESNO(e->same_screen));
@@ -8644,12 +8819,12 @@ print_win_geom(xcb_window_t w)
 
        wa = xcb_get_geometry_reply(conn, xcb_get_geometry(conn, w), NULL);
        if (wa == NULL) {
-               DNPRINTF(SWM_D_MISC, "print_win_geom: window not found: 0x%x\n",
+               DNPRINTF(SWM_D_MISC, "print_win_geom: window not found: %#x\n",
                    w);
                return;
        }
 
-       DNPRINTF(SWM_D_MISC, "print_win_geom: window: 0x%x, root: 0x%x, "
+       DNPRINTF(SWM_D_MISC, "print_win_geom: win %#x, root: %#x, "
            "depth: %u, (x,y) w x h: (%d,%d) %d x %d, border: %d\n",
            w, wa->root, wa->depth, wa->x,  wa->y, wa->width, wa->height,
            wa->border_width);
@@ -8705,8 +8880,8 @@ configurerequest(xcb_configure_request_event_t *e)
        if (swm_debug & SWM_D_EVENT) {
                print_win_geom(e->window);
 
-               DNPRINTF(SWM_D_EVENT, "configurerequest: window: 0x%x, "
-                   "parent: 0x%x, new: %s, value_mask: %u { ", e->window,
+               DNPRINTF(SWM_D_EVENT, "configurerequest: win %#x, "
+                   "parent: %#x, new: %s, value_mask: %u { ", e->window,
                    e->parent, YESNO(new), e->value_mask);
                if (e->value_mask & XCB_CONFIG_WINDOW_X)
                        DPRINTF("X: %d ", e->x);
@@ -8719,7 +8894,7 @@ configurerequest(xcb_configure_request_event_t *e)
                if (e->value_mask & XCB_CONFIG_WINDOW_BORDER_WIDTH)
                        DPRINTF("Border: %u ", e->border_width);
                if (e->value_mask & XCB_CONFIG_WINDOW_SIBLING)
-                       DPRINTF("Sibling: 0x%x ", e->sibling);
+                       DPRINTF("Sibling: %#x ", e->sibling);
                if (e->value_mask & XCB_CONFIG_WINDOW_STACK_MODE)
                        DPRINTF("StackMode: %s(%u) ",
                            get_stack_mode_name(e->stack_mode), e->stack_mode);
@@ -8761,8 +8936,8 @@ configurerequest(xcb_configure_request_event_t *e)
                        xcb_configure_window(conn, e->window, mask, wc);
                        xcb_flush(conn);
                }
-       } else if ((!win->manual || win->quirks & SWM_Q_ANYWHERE) &&
-           !(win->ewmh_flags & EWMH_F_FULLSCREEN) && !win->maximized) {
+       } else if ((!MANUAL(win) || win->quirks & SWM_Q_ANYWHERE) &&
+           !FULLSCREEN(win) && !MAXIMIZED(win)) {
                if (win->ws->r)
                        r = win->ws->r;
                else if (win->ws->old_r)
@@ -8791,14 +8966,13 @@ configurerequest(xcb_configure_request_event_t *e)
 
                win->g_floatvalid = 1;
 
-               if (win->floating && r && (win->transient ||
-                   win->ws->cur_layout != &layouts[SWM_MAX_STACK])
-                   && !win->maximized) {
+               if (ABOVE(win) && r && !MAXIMIZED(win) && (TRANS(win) ||
+                   win->ws->cur_layout != &layouts[SWM_MAX_STACK])) {
                        WIDTH(win) = win->g_float.w;
                        HEIGHT(win) = win->g_float.h;
 
                        if (r) {
-                               stack_floater(win);
+                               update_floater(win);
                                focus_flush();
                        }
                } else {
@@ -8818,8 +8992,8 @@ configurenotify(xcb_configure_notify_event_t *e)
 {
        struct ws_win           *win;
 
-       DNPRINTF(SWM_D_EVENT, "configurenotify: win 0x%x, event win: 0x%x, "
-           "(x,y) WxH: (%d,%d) %ux%u, border: %u, above_sibling: 0x%x, "
+       DNPRINTF(SWM_D_EVENT, "configurenotify: win %#x, event win: %#x, "
+           "(x,y) WxH: (%d,%d) %ux%u, border: %u, above_sibling: %#x, "
            "override_redirect: %s\n", e->window, e->event, e->x, e->y,
            e->width, e->height, e->border_width, e->above_sibling,
            YESNO(e->override_redirect));
@@ -8842,7 +9016,7 @@ destroynotify(xcb_destroy_notify_event_t *e)
 {
        struct ws_win           *win;
 
-       DNPRINTF(SWM_D_EVENT, "destroynotify: window: 0x%x\n", e->window);
+       DNPRINTF(SWM_D_EVENT, "destroynotify: win %#x\n", e->window);
 
        if ((win = find_window(e->window)) == NULL) {
                if ((win = find_unmanaged_window(e->window)) == NULL)
@@ -8945,9 +9119,9 @@ enternotify(xcb_enter_notify_event_t *e)
        struct ws_win           *win;
        struct swm_region       *r;
 
-       DNPRINTF(SWM_D_FOCUS, "enternotify: time: %u, win (x,y): 0x%x "
-           "(%d,%d), mode: %s(%d), detail: %s(%d), root (x,y): 0x%x (%d,%d), "
-           "child: 0x%x, same_screen_focus: %s, state: %d\n",
+       DNPRINTF(SWM_D_FOCUS, "enternotify: time: %u, win (x,y): %#x "
+           "(%d,%d), mode: %s(%d), detail: %s(%d), root (x,y): %#x (%d,%d), "
+           "child: %#x, same_screen_focus: %s, state: %d\n",
            e->time, e->event, e->event_x, e->event_y,
            get_notify_mode_label(e->mode), e->mode,
            get_notify_detail_label(e->detail), e->detail,
@@ -8989,9 +9163,9 @@ enternotify(xcb_enter_notify_event_t *e)
 void
 leavenotify(xcb_leave_notify_event_t *e)
 {
-       DNPRINTF(SWM_D_FOCUS, "leavenotify: time: %u, win (x,y): 0x%x "
-           "(%d,%d), mode: %s(%d), detail: %s(%d), root (x,y): 0x%x (%d,%d), "
-           "child: 0x%x, same_screen_focus: %s, state: %d\n",
+       DNPRINTF(SWM_D_FOCUS, "leavenotify: time: %u, win (x,y): %#x "
+           "(%d,%d), mode: %s(%d), detail: %s(%d), root (x,y): %#x (%d,%d), "
+           "child: %#x, same_screen_focus: %s, state: %d\n",
            e->time, e->event, e->event_x, e->event_y,
            get_notify_mode_label(e->mode), e->mode,
            get_notify_detail_label(e->detail), e->detail,
@@ -9006,7 +9180,7 @@ mapnotify(xcb_map_notify_event_t *e)
        struct ws_win           *win, *parent = NULL;
        struct workspace        *ws;
 
-       DNPRINTF(SWM_D_EVENT, "mapnotify: window: 0x%x\n", e->window);
+       DNPRINTF(SWM_D_EVENT, "mapnotify: win %#x\n", e->window);
 
        if ((win = manage_window(e->window, 1)) == NULL)
                return;
@@ -9014,11 +9188,11 @@ mapnotify(xcb_map_notify_event_t *e)
 
        /* Need to know if win was mapped due to ws switch. */
        if (ws->state == SWM_WS_STATE_MAPPED) {
-               if (ws->focus_pending && ws->focus_pending->transient)
+               if (ws->focus_pending && TRANS(ws->focus_pending))
                        parent = find_window(win->transient);
 
                /* If window's parent is maximized, don't clear it. */
-               if ((parent == NULL) || !parent->maximized)
+               if ((parent == NULL) || !MAXIMIZED(parent))
                        if (clear_maximized(ws) > 0)
                                stack();
        }
@@ -9064,7 +9238,7 @@ maprequest(xcb_map_request_event_t *e)
        struct ws_win           *win, *w = NULL;
        xcb_get_window_attributes_reply_t *war;
 
-       DNPRINTF(SWM_D_EVENT, "maprequest: win 0x%x\n",
+       DNPRINTF(SWM_D_EVENT, "maprequest: win %#x\n",
            e->window);
 
        war = xcb_get_window_attributes_reply(conn,
@@ -9129,12 +9303,12 @@ out:
 void
 motionnotify(xcb_motion_notify_event_t *e)
 {
-       struct swm_region       *r;
+       struct swm_region       *r = NULL;
        int                     i, num_screens;
 
-       DNPRINTF(SWM_D_FOCUS, "motionnotify: time: %u, win (x,y): 0x%x "
-           "(%d,%d), detail: %s(%d), root (x,y): 0x%x (%d,%d), "
-           "child: 0x%x, same_screen_focus: %s, state: %d\n",
+       DNPRINTF(SWM_D_FOCUS, "motionnotify: time: %u, win (x,y): %#x "
+           "(%d,%d), detail: %s(%d), root (x,y): %#x (%d,%d), "
+           "child: %#x, same_screen_focus: %s, state: %d\n",
            e->time, e->event, e->event_x, e->event_y,
            get_notify_detail_label(e->detail), e->detail,
            e->root, e->root_x, e->root_y, e->child,
@@ -9201,7 +9375,7 @@ propertynotify(xcb_property_notify_event_t *e)
        char                    *name;
 
        name = get_atom_name(e->atom);
-       DNPRINTF(SWM_D_EVENT, "propertynotify: window: 0x%x, atom: %s(%u), "
+       DNPRINTF(SWM_D_EVENT, "propertynotify: win %#x, atom: %s(%u), "
            "time: %#x, state: %u\n", e->window, name, e->atom, e->time,
            e->state);
        free(name);
@@ -9214,47 +9388,7 @@ propertynotify(xcb_property_notify_event_t *e)
 
        last_event_time = e->time;
 
-       if (e->atom == a_swm_iconic) {
-               if (e->state == XCB_PROPERTY_NEW_VALUE) {
-                       if (focus_mode != SWM_FOCUS_FOLLOW)
-                               ws->focus_pending = get_focus_prev(win);
-
-                       unfocus_win(win);
-                       unmap_window(win);
-
-                       if (ws->r) {
-                               stack();
-
-                               if (focus_mode != SWM_FOCUS_FOLLOW &&
-                                   WS_FOCUSED(ws)) {
-                                       if (ws->focus_pending) {
-                                               focus_win(ws->focus_pending);
-                                               ws->focus_pending = NULL;
-                                       } else {
-                                               xcb_set_input_focus(conn,
-                                                   XCB_INPUT_FOCUS_PARENT,
-                                                   ws->r->id,
-                                                   XCB_CURRENT_TIME);
-                                       }
-                               }
-
-                               focus_flush();
-                       }
-               } else if (e->state == XCB_PROPERTY_DELETE) {
-                       /* Reload floating geometry in case region changed. */
-                       if (win->floating)
-                               load_float_geom(win);
-
-                       /* The window is no longer iconic, restack ws. */
-                       if (focus_mode != SWM_FOCUS_FOLLOW)
-                               ws->focus_pending = get_focus_magic(win);
-
-                       stack();
-
-                       /* Flush EnterNotify for mapnotify, if needed. */
-                       focus_flush();
-               }
-       } else if (e->atom == a_state) {
+       if (e->atom == a_state) {
                /* State just changed, make sure it gets focused if mapped. */
                if (e->state == XCB_PROPERTY_NEW_VALUE) {
                        if (focus_mode != SWM_FOCUS_FOLLOW && WS_FOCUSED(ws)) {
@@ -9281,74 +9415,96 @@ unmapnotify(xcb_unmap_notify_event_t *e)
        struct ws_win           *win;
        struct workspace        *ws;
 
-       DNPRINTF(SWM_D_EVENT, "unmapnotify: window: 0x%x\n", e->window);
+       DNPRINTF(SWM_D_EVENT, "unmapnotify: win %#x\n", e->window);
 
        /* If we aren't managing the window, then ignore. */
        win = find_window(e->window);
        if (win == NULL || win->id != e->window)
                return;
 
-       ws = win->ws;
-
-       if (getstate(e->window) != XCB_ICCCM_WM_STATE_ICONIC)
-               set_win_state(win, XCB_ICCCM_WM_STATE_ICONIC);
-
-       if (win->mapped) {
-               /* window unmapped itself */
-               /* do unmap/unfocus/restack and unmanage */
-               win->mapped = 0;
+       /* Do nothing if already withdrawn. */
+       if (!win->mapped && !ICONIC(win))
+               return;
 
-               /* If win was focused, make sure to focus on something else. */
-               if (win == ws->focus) {
-                       if (focus_mode != SWM_FOCUS_FOLLOW) {
-                               ws->focus_pending = get_focus_prev(win);
-                               DNPRINTF(SWM_D_EVENT, "unmapnotify: "
-                                   "focus_pending: 0x%x\n",
-                                   WINID(ws->focus_pending));
-                       }
+       ws = win->ws;
+       win->mapped = 0;
 
-                       unfocus_win(win);
+       /* If win was focused, make sure to focus on something else. */
+       if (win == ws->focus) {
+               if (focus_mode != SWM_FOCUS_FOLLOW) {
+                       ws->focus_pending = get_focus_prev(win);
+                       DNPRINTF(SWM_D_EVENT, "unmapnotify: "
+                           "focus_pending: %#x\n",
+                           WINID(ws->focus_pending));
                }
 
+               unfocus_win(win);
+       }
+
+       if (ICONIC(win)) {
+               /* Iconify. */
+               set_win_state(win, XCB_ICCCM_WM_STATE_ICONIC);
+       } else {
+               /* Withdraw. */
+               set_win_state(win, XCB_ICCCM_WM_STATE_WITHDRAWN);
                unmanage_window(win);
+       }
 
-               if (ws->r)
-                       stack();
+       if (ws->r)
+               stack();
 
-               if (WS_FOCUSED(ws)) {
-                       if (focus_mode == SWM_FOCUS_FOLLOW) {
-                               focus_win(get_pointer_win(ws->r->s->root));
-                       } else if (ws->focus_pending) {
-                               focus_win(ws->focus_pending);
-                               ws->focus_pending = NULL;
-                       } else if (ws->focus == NULL) {
-                               xcb_set_input_focus(conn, XCB_INPUT_FOCUS_PARENT,
-                                   ws->r->id, XCB_CURRENT_TIME);
-                       }
+       /* Update focus if ws is active. */
+       if (WS_FOCUSED(ws)) {
+               if (focus_mode == SWM_FOCUS_FOLLOW) {
+                       focus_win(get_pointer_win(ws->r->s->root));
+               } else if (ws->focus_pending) {
+                       focus_win(ws->focus_pending);
+                       ws->focus_pending = NULL;
+               } else if (ws->focus == NULL) {
+                       xcb_set_input_focus(conn, XCB_INPUT_FOCUS_PARENT,
+                           ws->r->id, XCB_CURRENT_TIME);
                }
        }
 
-       if (getstate(e->window) == XCB_ICCCM_WM_STATE_NORMAL)
-               set_win_state(win, XCB_ICCCM_WM_STATE_ICONIC);
-
        focus_flush();
 }
 
 void
 clientmessage(xcb_client_message_event_t *e)
 {
-       struct ws_win *win;
+       struct ws_win           *win;
+       struct swm_region       *r = NULL;
+       union arg               a;
+       int                     num_screens, i;
        xcb_map_request_event_t mre;
 #ifdef SWM_DEBUG
        char                    *name;
 
        name = get_atom_name(e->type);
-       DNPRINTF(SWM_D_EVENT, "clientmessage: window: 0x%x, atom: %s(%u)\n",
+       DNPRINTF(SWM_D_EVENT, "clientmessage: win %#x, atom: %s(%u)\n",
            e->window, name, e->type);
        free(name);
 #endif
-       win = find_window(e->window);
 
+       if (e->type == ewmh[_NET_CURRENT_DESKTOP].atom) {
+               num_screens = get_screen_count();
+               for (i = 0; i < num_screens; i++)
+                       if (screens[i].root == e->window) {
+                               r = screens[i].r_focus;
+                               break;
+                       }
+
+               if (r && e->data.data32[0] <
+                   (uint32_t)workspace_limit) {
+                       a.id = e->data.data32[0];
+                       switchws(r, &a);
+                       focus_flush();
+               }
+
+               return;
+       }
+
+       win = find_window(e->window);
        if (win == NULL) {
                if (e->type == ewmh[_NET_ACTIVE_WINDOW].atom) {
                        /* Manage the window with maprequest. */
@@ -9366,18 +9522,16 @@ clientmessage(xcb_client_message_event_t *e)
                        focus_win(win);
                else
                        win->ws->focus_pending = win;
-       }
-       if (e->type == ewmh[_NET_CLOSE_WINDOW].atom) {
+       } else if (e->type == ewmh[_NET_CLOSE_WINDOW].atom) {
                DNPRINTF(SWM_D_EVENT, "clientmessage: _NET_CLOSE_WINDOW\n");
                if (win->can_delete)
                        client_msg(win, a_delete, 0);
                else
                        xcb_kill_client(conn, win->id);
-       }
-       if (e->type == ewmh[_NET_MOVERESIZE_WINDOW].atom) {
+       } else if (e->type == ewmh[_NET_MOVERESIZE_WINDOW].atom) {
                DNPRINTF(SWM_D_EVENT,
                    "clientmessage: _NET_MOVERESIZE_WINDOW\n");
-               if (win->floating) {
+               if (ABOVE(win)) {
                        if (e->data.data32[0] & (1<<8)) /* x */
                                X(win) = e->data.data32[1];
                        if (e->data.data32[0] & (1<<9)) /* y */
@@ -9394,14 +9548,14 @@ clientmessage(xcb_client_message_event_t *e)
                        /* notify no change was made. */
                        config_win(win, NULL);
                }
-       }
-       if (e->type == ewmh[_NET_WM_STATE].atom) {
+       } else  if (e->type == ewmh[_NET_WM_STATE].atom) {
                DNPRINTF(SWM_D_EVENT, "clientmessage: _NET_WM_STATE\n");
-               ewmh_update_win_state(win, e->data.data32[1], e->data.data32[0]);
+               ewmh_change_wm_state(win, e->data.data32[1], e->data.data32[0]);
                if (e->data.data32[2])
-                       ewmh_update_win_state(win, e->data.data32[2],
+                       ewmh_change_wm_state(win, e->data.data32[2],
                            e->data.data32[0]);
 
+               ewmh_update_wm_state(win);
                stack();
        }
 
@@ -9456,7 +9610,7 @@ enable_wm(void)
        for (i = 0; i < num_screens; i++) {
                if ((sc = get_screen(i)) == NULL)
                        errx(1, "ERROR: can't get screen %d.", i);
-               DNPRINTF(SWM_D_INIT, "enable_wm: screen %d, root: 0x%x\n",
+               DNPRINTF(SWM_D_INIT, "enable_wm: screen %d, root: %#x\n",
                    i, sc->root);
                wac = xcb_change_window_attributes_checked(conn, sc->root,
                    XCB_CW_EVENT_MASK, &val);
@@ -9479,7 +9633,7 @@ enable_wm(void)
 void
 new_region(struct swm_screen *s, int x, int y, int w, int h)
 {
-       struct swm_region       *r, *n;
+       struct swm_region       *r = NULL, *n;
        struct workspace        *ws = NULL;
        int                     i;
        uint32_t                wa[1];
@@ -9562,6 +9716,10 @@ new_region(struct swm_screen *s, int x, int y, int w, int h)
            X(r), Y(r), WIDTH(r), HEIGHT(r), 0, XCB_WINDOW_CLASS_INPUT_ONLY,
            XCB_COPY_FROM_PARENT, XCB_CW_EVENT_MASK, wa);
 
+       /* Make sure region input is at the bottom. */
+       wa[0] = XCB_STACK_MODE_BELOW;
+       xcb_configure_window(conn, r->id, XCB_CONFIG_WINDOW_STACK_MODE, wa);
+
        xcb_map_window(conn, r->id);
 }
 
@@ -9667,7 +9825,7 @@ screenchange(xcb_randr_screen_change_notify_event_t *e)
        struct swm_region               *r;
        int                             i, num_screens;
 
-       DNPRINTF(SWM_D_EVENT, "screenchange: root: 0x%x\n", e->root);
+       DNPRINTF(SWM_D_EVENT, "screenchange: root: %#x\n", e->root);
 
        num_screens = get_screen_count();
        /* silly event doesn't include the screen index */
@@ -9713,16 +9871,16 @@ void
 grab_windows(void)
 {
        struct swm_region       *r = NULL;
-       xcb_window_t            *wins = NULL, trans;
-       int                     no;
-       int                     i, j, num_screens;
-       uint16_t                state, manage, mapped;
+       xcb_window_t            *wins = NULL, trans, *cwins = NULL;
+       int                     i, j, k, n, no, num_screens, manage, mapped;
+       uint8_t                 state;
 
        xcb_query_tree_cookie_t                 qtc;
        xcb_query_tree_reply_t                  *qtr;
        xcb_get_window_attributes_cookie_t      gac;
        xcb_get_window_attributes_reply_t       *gar;
        xcb_get_property_cookie_t               pc;
+       xcb_get_property_reply_t                *pr;
 
        DNPRINTF(SWM_D_INIT, "grab_windows: begin\n");
        num_screens = get_screen_count();
@@ -9733,6 +9891,29 @@ grab_windows(void)
                        continue;
                wins = xcb_query_tree_children(qtr);
                no = xcb_query_tree_children_length(qtr);
+
+               /* Try to sort windows according to _NET_CLIENT_LIST. */
+               pr = xcb_get_property_reply(conn, xcb_get_property(conn, 0,
+                   screens[i].root, ewmh[_NET_CLIENT_LIST].atom,
+                   XCB_ATOM_WINDOW, 0, UINT32_MAX), NULL);
+               if (pr != NULL) {
+                       cwins = xcb_get_property_value(pr);
+                       n = xcb_get_property_value_length(pr) /
+                           sizeof(xcb_atom_t);
+
+                       for (j = 0; j < n; ++j) {
+                               for (k = j; k < no; ++k) {
+                                       if (wins[k] == cwins[j]) {
+                                               /* Swap wins j and k. */
+                                               wins[k] = wins[j];
+                                               wins[j] = cwins[j];
+                                       }
+                               }
+                       }
+
+                       free(pr);
+               }
+
                /* attach windows to a region */
                /* normal windows */
                DNPRINTF(SWM_D_INIT, "grab_windows: grab top level windows.\n");
@@ -9775,7 +9956,7 @@ grab_windows(void)
 
                        state = getstate(wins[j]);
                        manage = state != XCB_ICCCM_WM_STATE_WITHDRAWN;
-                       mapped = gar->map_state != XCB_MAP_STATE_UNMAPPED;
+                       mapped = gar->map_state == XCB_MAP_STATE_VIEWABLE;
                        if (mapped || manage)
                                manage_window(wins[j], mapped);
                        free(gar);
@@ -9800,7 +9981,7 @@ grab_windows(void)
 
                        state = getstate(wins[j]);
                        manage = state != XCB_ICCCM_WM_STATE_WITHDRAWN;
-                       mapped = gar->map_state != XCB_MAP_STATE_UNMAPPED;
+                       mapped = gar->map_state == XCB_MAP_STATE_VIEWABLE;
                        pc = xcb_icccm_get_wm_transient_for(conn, wins[j]);
                        if (xcb_icccm_get_wm_transient_for_reply(conn, pc,
                            &trans, NULL) && manage)
@@ -9890,6 +10071,7 @@ setup_screens(void)
                        ws->r = NULL;
                        ws->old_r = NULL;
                        ws->state = SWM_WS_STATE_HIDDEN;
+                       TAILQ_INIT(&ws->stack);
                        TAILQ_INIT(&ws->winlist);
                        TAILQ_INIT(&ws->unmanagedlist);
 
@@ -9924,9 +10106,10 @@ setup_globals(void)
        a_state = get_atom_from_string("WM_STATE");
        a_prot = get_atom_from_string("WM_PROTOCOLS");
        a_delete = get_atom_from_string("WM_DELETE_WINDOW");
+       a_net_supported = get_atom_from_string("_NET_SUPPORTED");
+       a_net_wm_check = get_atom_from_string("_NET_SUPPORTING_WM_CHECK");
        a_takefocus = get_atom_from_string("WM_TAKE_FOCUS");
        a_utf8_string = get_atom_from_string("UTF8_STRING");
-       a_swm_iconic = get_atom_from_string("_SWM_ICONIC");
        a_swm_ws = get_atom_from_string("_SWM_WS");
 }
 
@@ -9934,11 +10117,9 @@ void
 workaround(void)
 {
        int                     i, num_screens;
-       xcb_atom_t              netwmcheck;
        xcb_window_t            root, win;
 
        /* work around sun jdk bugs, code from wmname */
-       netwmcheck = get_atom_from_string("_NET_SUPPORTING_WM_CHECK");
 
        num_screens = get_screen_count();
        for (i = 0; i < num_screens; i++) {
@@ -9950,9 +10131,9 @@ workaround(void)
                    XCB_COPY_FROM_PARENT, 0, NULL);
 
                xcb_change_property(conn, XCB_PROP_MODE_REPLACE, root,
-                   netwmcheck, XCB_ATOM_WINDOW, 32, 1, &win);
+                   a_net_wm_check, XCB_ATOM_WINDOW, 32, 1, &win);
                xcb_change_property(conn, XCB_PROP_MODE_REPLACE, win,
-                   netwmcheck, XCB_ATOM_WINDOW, 32, 1, &win);
+                   a_net_wm_check, XCB_ATOM_WINDOW, 32, 1, &win);
                xcb_change_property(conn, XCB_PROP_MODE_REPLACE, win,
                    ewmh[_NET_WM_NAME].atom, a_utf8_string, 8, strlen("LG3D"),
                    "LG3D");
@@ -9978,6 +10159,9 @@ shutdown_cleanup(void)
 
        num_screens = get_screen_count();
        for (i = 0; i < num_screens; ++i) {
+               xcb_set_input_focus(conn, XCB_INPUT_FOCUS_POINTER_ROOT,
+                   screens[i].root, XCB_CURRENT_TIME);
+
                if (screens[i].bar_gc != XCB_NONE)
                        xcb_free_gc(conn, screens[i].bar_gc);
                if (!bar_font_legacy)
@@ -10139,6 +10323,7 @@ main(int argc, char *argv[])
 
        setup_globals();
        setup_screens();
+       setup_ewmh();
        setup_keys();
        setup_quirks();
        setup_spawn();
@@ -10185,7 +10370,6 @@ noconfig:
 
        validate_spawns();
 
-       setup_ewmh();
        /* set some values to work around bad programs */
        workaround();
        /* grab existing windows (before we build the bars) */
@@ -10207,6 +10391,11 @@ noconfig:
        xcb_ungrab_server(conn);
        xcb_flush(conn);
 
+       /* Update state of each newly mapped workspace. */
+       for (i = 0; i < num_screens; i++)
+               TAILQ_FOREACH(r, &screens[i].rl, entry)
+                       r->ws->state = SWM_WS_STATE_MAPPED;
+
        rd_max = xfd > STDIN_FILENO ? xfd : STDIN_FILENO;
 
        while (running) {