JasonWoof Got questions, comments, patches, etc.? Contact Jason Woofenden
add border width for bar too
[spectrwm.git] / scrotwm.c
index 0a93e79..01cbd38 100644 (file)
--- a/scrotwm.c
+++ b/scrotwm.c
@@ -52,7 +52,7 @@
 
 static const char      *cvstag = "$scrotwm$";
 
-#define        SWM_VERSION     "0.9.25"
+#define        SWM_VERSION     "0.9.29"
 
 #include <stdio.h>
 #include <stdlib.h>
@@ -198,6 +198,7 @@ int                 bar_version = 0;
 sig_atomic_t           bar_alarm = 0;
 int                    bar_delay = 30;
 int                    bar_enabled = 1;
+int                    bar_border_width = 1;
 int                    bar_at_bottom = 0;
 int                    bar_extra = 1;
 int                    bar_extra_running = 0;
@@ -208,8 +209,10 @@ int                        clock_enabled = 1;
 char                   *clock_format = NULL;
 int                    title_name_enabled = 0;
 int                    title_class_enabled = 0;
+int                    window_name_enabled = 0;
 int                    focus_mode = SWM_FOCUS_DEFAULT;
 int                    disable_border = 0;
+int                    border_width = 1;
 pid_t                  bar_pid;
 GC                     bar_gc;
 XGCValues              bar_gcv;
@@ -258,6 +261,7 @@ struct ws_win {
        int                     floatmaxed;     /* flag: floater was maxed in max_stack */
        int                     floating;
        int                     manual;
+       unsigned int            ewmh_flags;
        int                     font_size_boundary[SWM_MAX_FONT_STEPS];
        int                     font_steps;
        int                     last_inc;
@@ -403,6 +407,335 @@ struct quirk {
 int                            quirks_size = 0, quirks_length = 0;
 struct quirk                   *quirks = NULL;
 
+/*
+ * Supported EWMH hints should be added to
+ * both the enum and the ewmh array
+ */
+enum { _NET_ACTIVE_WINDOW, _NET_MOVERESIZE_WINDOW, _NET_CLOSE_WINDOW,
+    _NET_WM_WINDOW_TYPE, _NET_WM_WINDOW_TYPE_DOCK,
+    _NET_WM_WINDOW_TYPE_TOOLBAR, _NET_WM_WINDOW_TYPE_UTILITY,
+    _NET_WM_WINDOW_TYPE_SPLASH, _NET_WM_WINDOW_TYPE_DIALOG,
+    _NET_WM_WINDOW_TYPE_NORMAL, _NET_WM_STATE,
+    _NET_WM_STATE_MAXIMIZED_HORZ, _NET_WM_STATE_MAXIMIZED_VERT,
+    _NET_WM_STATE_SKIP_TASKBAR, _NET_WM_STATE_SKIP_PAGER,
+    _NET_WM_STATE_HIDDEN, _NET_WM_STATE_ABOVE, _SWM_WM_STATE_MANUAL,
+    _NET_WM_STATE_FULLSCREEN, _NET_WM_ALLOWED_ACTIONS, _NET_WM_ACTION_MOVE,
+    _NET_WM_ACTION_RESIZE, _NET_WM_ACTION_FULLSCREEN, _NET_WM_ACTION_CLOSE,
+    SWM_EWMH_HINT_MAX };
+
+struct ewmh_hint {
+       char    *name;
+       Atom     atom;
+} ewmh[SWM_EWMH_HINT_MAX] =    {
+    /* must be in same order as in the enum */
+    {"_NET_ACTIVE_WINDOW", None},
+    {"_NET_MOVERESIZE_WINDOW", None},
+    {"_NET_CLOSE_WINDOW", None},
+    {"_NET_WM_WINDOW_TYPE", None},
+    {"_NET_WM_WINDOW_TYPE_DOCK", None},
+    {"_NET_WM_WINDOW_TYPE_TOOLBAR", None},
+    {"_NET_WM_WINDOW_TYPE_UTILITY", None},
+    {"_NET_WM_WINDOW_TYPE_SPLASH", None},
+    {"_NET_WM_WINDOW_TYPE_DIALOG", None},
+    {"_NET_WM_WINDOW_TYPE_NORMAL", None},
+    {"_NET_WM_STATE", None},
+    {"_NET_WM_STATE_MAXIMIZED_HORZ", None},
+    {"_NET_WM_STATE_MAXIMIZED_VERT", None},
+    {"_NET_WM_STATE_SKIP_TASKBAR", None},
+    {"_NET_WM_STATE_SKIP_PAGER", None},
+    {"_NET_WM_STATE_HIDDEN", None},
+    {"_NET_WM_STATE_ABOVE", None},
+    {"_SWM_WM_STATE_MANUAL", None},
+    {"_NET_WM_STATE_FULLSCREEN", None},
+    {"_NET_WM_ALLOWED_ACTIONS", None},
+    {"_NET_WM_ACTION_MOVE", None},
+    {"_NET_WM_ACTION_RESIZE", None},
+    {"_NET_WM_ACTION_FULLSCREEN", None},
+    {"_NET_WM_ACTION_CLOSE", None},
+};
+
+void   store_float_geom(struct ws_win *win, struct swm_region *r);
+int    floating_toggle_win(struct ws_win *win);
+
+int
+get_property(Window id, Atom atom, long count, Atom type,
+    unsigned long *n, unsigned char **data)
+{
+       int                     format, status;
+       unsigned long           tmp, extra;
+       unsigned long           *nitems;
+       Atom                    real;
+
+       nitems = n != NULL ? n : &tmp;
+       status = XGetWindowProperty(display, id, atom, 0L, count, False, type,
+           &real, &format, nitems, &extra, data);
+
+       if (status != Success)
+               return False;
+       if (real != type)
+               return False;
+
+       return True;
+}
+
+void
+setup_ewmh(void)
+{
+       int                     i,j;
+       Atom                    sup_list;
+
+       sup_list = XInternAtom(display, "_NET_SUPPORTED", False);
+
+       for (i = 0; i < LENGTH(ewmh); i++)
+               ewmh[i].atom = XInternAtom(display, ewmh[i].name, False);
+
+       for (i = 0; i < ScreenCount(display); i++) {
+               /* Support check window will be created by workaround(). */
+
+               /* Report supported atoms */
+               XDeleteProperty(display, screens[i].root, sup_list);
+               for (j = 0; j < LENGTH(ewmh); j++)
+                       XChangeProperty(display, screens[i].root, sup_list, XA_ATOM, 32,
+                           PropModeAppend, (unsigned char *)&ewmh[j].atom,1);
+       }
+}
+
+void
+teardown_ewmh(void)
+{
+       int                     i, success;
+       unsigned char           *data = NULL;
+       unsigned long           n;
+       Atom                    sup_check, sup_list;
+       Window                  id;
+
+       sup_check = XInternAtom(display, "_NET_SUPPORTING_WM_CHECK", False);
+       sup_list = XInternAtom(display, "_NET_SUPPORTED", False);
+
+       for (i = 0; i < ScreenCount(display); i++) {
+               /* Get the support check window and destroy it */
+               success = get_property(screens[i].root, sup_check, 1, XA_WINDOW,
+                   &n, &data);
+
+               if (success) {
+                       id = data[0];
+                       XDestroyWindow(display, id);
+                       XDeleteProperty(display, screens[i].root, sup_check);
+                       XDeleteProperty(display, screens[i].root, sup_list);
+               }
+
+               XFree(data);
+       }
+}
+
+void
+ewmh_autoquirk(struct ws_win *win)
+{
+       int                     success, i;
+       unsigned long           *data = NULL;
+       unsigned long           n;
+       Atom                    type;
+
+       success = get_property(win->id, ewmh[_NET_WM_WINDOW_TYPE].atom, (~0L),
+           XA_ATOM, &n, (unsigned char **)&data);
+
+       if (!success) {
+               XFree(data);
+               return;
+       }
+
+       for (i = 0; i < n; i++) {
+               type = data[i];
+               if (type == ewmh[_NET_WM_WINDOW_TYPE_NORMAL].atom)
+                       break;
+               if (type == ewmh[_NET_WM_WINDOW_TYPE_DOCK].atom ||
+                   type == ewmh[_NET_WM_WINDOW_TYPE_TOOLBAR].atom ||
+                   type == ewmh[_NET_WM_WINDOW_TYPE_UTILITY].atom) {
+                       win->floating = 1;
+                       win->quirks = SWM_Q_FLOAT | SWM_Q_ANYWHERE;
+                       break;
+               }
+               if (type == ewmh[_NET_WM_WINDOW_TYPE_SPLASH].atom ||
+                   type == ewmh[_NET_WM_WINDOW_TYPE_DIALOG].atom) {
+                       win->floating = 1;
+                       win->quirks = SWM_Q_FLOAT;
+                       break;
+               }
+       }
+
+       XFree(data);
+}
+
+#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)
+{
+       struct swm_geometry     rg;
+
+       if (!win->ws->r)
+               return 0;
+
+       if (!win->floating)
+               return 0;
+
+       DNPRINTF(SWM_D_MISC, "ewmh_set_win_fullscreen: win 0x%lx fs: %d\n",
+           win->id, fs);
+
+       rg = win->ws->r->g;
+
+       if (fs) {
+               store_float_geom(win, win->ws->r);
+
+               win->g.x = rg.x;
+               win->g.y = rg.y;
+               win->g.w = rg.w;
+               win->g.h = rg.h;
+       }       else {
+               if (win->g_floatvalid) {
+                       /* refloat at last floating relative position */
+                       win->g.x = win->g_float.x - win->rg_float.x + rg.x;
+                       win->g.y = win->g_float.y - win->rg_float.y + rg.y;
+                       win->g.w = win->g_float.w;
+                       win->g.h = win->g_float.h;
+               }
+       }
+
+       return 1;
+}
+
+void
+ewmh_update_actions(struct ws_win *win)
+{
+       Atom                    actions[SWM_EWMH_ACTION_COUNT_MAX];
+       int                     n = 0;
+
+       if (win == NULL)
+               return;
+
+       actions[n++] = ewmh[_NET_WM_ACTION_CLOSE].atom;
+
+       if (win->floating) {
+               actions[n++] = ewmh[_NET_WM_ACTION_MOVE].atom;
+               actions[n++] = ewmh[_NET_WM_ACTION_RESIZE].atom;
+       }
+
+       XChangeProperty(display, win->id, ewmh[_NET_WM_ALLOWED_ACTIONS].atom,
+           XA_ATOM, 32, PropModeReplace, (unsigned char *)actions, n);
+}
+
+#define _NET_WM_STATE_REMOVE   0    /* remove/unset property */
+#define _NET_WM_STATE_ADD      1    /* add/set property */
+#define _NET_WM_STATE_TOGGLE   2    /* toggle property */
+
+void
+ewmh_update_win_state(struct ws_win *win, long state, long action)
+{
+       unsigned int            mask = 0;
+       unsigned int            changed = 0;
+       unsigned int            orig_flags;
+
+       if (win == NULL)
+               return;
+
+       if (state == ewmh[_NET_WM_STATE_FULLSCREEN].atom)
+               mask = EWMH_F_FULLSCREEN;
+       if (state == ewmh[_NET_WM_STATE_ABOVE].atom)
+               mask = EWMH_F_ABOVE;
+       if (state == ewmh[_SWM_WM_STATE_MANUAL].atom)
+               mask = SWM_F_MANUAL;
+       if (state == ewmh[_NET_WM_STATE_SKIP_PAGER].atom)
+               mask = EWMH_F_SKIP_PAGER;
+       if (state == ewmh[_NET_WM_STATE_SKIP_TASKBAR].atom)
+               mask = EWMH_F_SKIP_TASKBAR;
+
+
+       orig_flags = win->ewmh_flags;
+
+       switch (action) {
+       case _NET_WM_STATE_REMOVE:
+               win->ewmh_flags &= ~mask;
+               break;
+       case _NET_WM_STATE_ADD:
+               win->ewmh_flags |= mask;
+               break;
+       case _NET_WM_STATE_TOGGLE:
+               win->ewmh_flags ^= mask;
+               break;
+       }
+
+       changed = (win->ewmh_flags & mask) ^ (orig_flags & mask) ? 1 : 0;
+
+       if (state == ewmh[_NET_WM_STATE_ABOVE].atom)
+               if (changed)
+                       if (!floating_toggle_win(win))
+                               win->ewmh_flags = orig_flags; /* revert */
+       if (state == ewmh[_SWM_WM_STATE_MANUAL].atom)
+               if (changed)
+                       win->manual = (win->ewmh_flags & SWM_F_MANUAL) != 0;
+       if (state == ewmh[_NET_WM_STATE_FULLSCREEN].atom)
+               if (changed)
+                       if (!ewmh_set_win_fullscreen(win, win->ewmh_flags & EWMH_F_FULLSCREEN))
+                               win->ewmh_flags = orig_flags; /* revert */
+
+       XDeleteProperty(display, win->id, ewmh[_NET_WM_STATE].atom);
+
+       if (win->ewmh_flags & EWMH_F_FULLSCREEN)
+               XChangeProperty(display, win->id, ewmh[_NET_WM_STATE].atom,
+                   XA_ATOM, 32, PropModeAppend,
+                   (unsigned char *)&ewmh[_NET_WM_STATE_FULLSCREEN].atom, 1);
+       if (win->ewmh_flags & EWMH_F_SKIP_PAGER)
+               XChangeProperty(display, win->id, ewmh[_NET_WM_STATE].atom,
+                   XA_ATOM, 32, PropModeAppend,
+                   (unsigned char *)&ewmh[_NET_WM_STATE_SKIP_PAGER].atom, 1);
+       if (win->ewmh_flags & EWMH_F_SKIP_TASKBAR)
+               XChangeProperty(display, win->id, ewmh[_NET_WM_STATE].atom,
+                   XA_ATOM, 32, PropModeAppend,
+                   (unsigned char *)&ewmh[_NET_WM_STATE_SKIP_TASKBAR].atom, 1);
+       if (win->ewmh_flags & EWMH_F_ABOVE)
+               XChangeProperty(display, win->id, ewmh[_NET_WM_STATE].atom,
+                   XA_ATOM, 32, PropModeAppend,
+                   (unsigned char *)&ewmh[_NET_WM_STATE_ABOVE].atom, 1);
+       if (win->ewmh_flags & SWM_F_MANUAL)
+               XChangeProperty(display, win->id, ewmh[_NET_WM_STATE].atom,
+                   XA_ATOM, 32, PropModeAppend,
+                   (unsigned char *)&ewmh[_SWM_WM_STATE_MANUAL].atom, 1);
+}
+
+void
+ewmh_get_win_state(struct ws_win *win)
+{
+       int                     success, i;
+       unsigned long           n;
+       Atom                    *states;
+
+       if (win == NULL)
+               return;
+
+       win->ewmh_flags = 0;
+       if (win->floating)
+               win->ewmh_flags |= EWMH_F_ABOVE;
+       if (win->manual)
+               win->ewmh_flags |= SWM_F_MANUAL;
+
+       success = get_property(win->id, ewmh[_NET_WM_STATE].atom, (~0L), XA_ATOM,
+           &n, (unsigned char **)&states);
+
+       if (!success)
+               return;
+
+       for (i = 0; i < n; i++)
+               ewmh_update_win_state(win, states[i], _NET_WM_STATE_ADD);
+
+       XFree(states);
+}
+
 /* events */
 #ifdef SWM_DEBUG
 void
@@ -579,6 +912,7 @@ void                        maprequest(XEvent *);
 void                   propertynotify(XEvent *);
 void                   unmapnotify(XEvent *);
 void                   visibilitynotify(XEvent *);
+void                   clientmessage(XEvent *);
 
 void                   (*handler[LASTEvent])(XEvent *) = {
                                [Expose] = expose,
@@ -596,6 +930,7 @@ void                        (*handler[LASTEvent])(XEvent *) = {
                                [PropertyNotify] = propertynotify,
                                [UnmapNotify] = unmapnotify,
                                [VisibilityNotify] = visibilitynotify,
+                               [ClientMessage] = clientmessage,
 };
 
 void
@@ -708,10 +1043,12 @@ custom_region(char *val)
        if (x  < 0 || x > DisplayWidth(display, sidx) ||
            y < 0 || y > DisplayHeight(display, sidx) ||
            w + x > DisplayWidth(display, sidx) ||
-           h + y > DisplayHeight(display, sidx))
-               errx(1, "region %ux%u+%u+%u not within screen boundaries "
+           h + y > DisplayHeight(display, sidx)) {
+               fprintf(stderr, "ignoring region %ux%u+%u+%u - not within screen boundaries "
                    "(%ux%u)\n", w, h, x, y,
                    DisplayWidth(display, sidx), DisplayHeight(display, sidx));
+               return;
+       }
 
        new_region(&screens[sidx], x, y, w, h);
 }
@@ -782,6 +1119,23 @@ out:
 }
 
 void
+bar_window_name(char *s, ssize_t sz, struct ws_win *cur_focus)
+{
+       char                    *title;
+
+       if (window_name_enabled && cur_focus != NULL) {
+               XFetchName(display, cur_focus->id, &title);
+               if (title) {
+                       if (cur_focus->floating)
+                               strlcat(s, "(f) ", sz);
+                       strlcat(s, title, sz);
+                       strlcat(s, " ", sz);
+                       XFree(title);
+               }
+       }
+}
+
+void
 bar_update(void)
 {
        time_t                  tmt;
@@ -825,8 +1179,10 @@ bar_update(void)
                x = 1;
                TAILQ_FOREACH(r, &screens[i].rl, entry) {
                        strlcpy(cn, "", sizeof cn);
-                       if (r && r->ws)
+                       if (r && r->ws) {
                                bar_class_name(cn, sizeof cn, r->ws->focus);
+                               bar_window_name(cn, sizeof cn, r->ws->focus);
+                       }
 
                        if (stack_enabled)
                                stack = r->ws->cur_layout->name;
@@ -941,13 +1297,13 @@ bar_setup(struct swm_region *r)
        if (bar_fs == NULL)
                errx(1, "couldn't create font structure");
 
-       bar_height = bar_fs->ascent + bar_fs->descent + 3;
+       bar_height = bar_fs->ascent + bar_fs->descent + 1 + 2 * bar_border_width;
        x = X(r);
        y = bar_at_bottom ? (Y(r) + HEIGHT(r) - bar_height) : Y(r);
 
        r->bar_window = XCreateSimpleWindow(display,
-           r->s->root, x, y, WIDTH(r) - 2, bar_height - 2,
-           1, r->s->c[SWM_S_COLOR_BAR_BORDER].color,
+           r->s->root, x, y, WIDTH(r) - 2 * bar_border_width, bar_height - 2 * bar_border_width,
+           bar_border_width, r->s->c[SWM_S_COLOR_BAR_BORDER].color,
            r->s->c[SWM_S_COLOR_BAR].color);
        bar_gc = XCreateGC(display, r->bar_window, 0, &bar_gcv);
        XSetFont(display, bar_gc, bar_fs->fid);
@@ -978,15 +1334,11 @@ set_win_state(struct ws_win *win, long state)
 long
 getstate(Window w)
 {
-       int                     format, status;
        long                    result = -1;
        unsigned char           *p = NULL;
-       unsigned long           n, extra;
-       Atom                    real;
+       unsigned long           n;
 
-       status = XGetWindowProperty(display, w, astate, 0L, 2L, False, astate,
-           &real, &format, &n, &extra, (unsigned char **)&p);
-       if (status != Success)
+       if (!get_property(w, astate, 2L, astate, &n, &p))
                return (-1);
        if (n != 0)
                result = *((long *)p);
@@ -1041,7 +1393,7 @@ configreq_win(struct ws_win *win)
        cr.y = win->g.y;
        cr.width = win->g.w;
        cr.height = win->g.h;
-       cr.border_width = 1;
+       cr.border_width = border_width;
 
        XSendEvent(display, win->id, False, StructureNotifyMask, (XEvent *)&cr);
 }
@@ -1065,7 +1417,7 @@ config_win(struct ws_win *win)
        ce.y = win->g.y;
        ce.width = win->g.w;
        ce.height = win->g.h;
-       ce.border_width = 1; /* XXX store this! */
+       ce.border_width = border_width; /* XXX store this! */
        ce.above = None;
        ce.override_redirect = False;
        XSendEvent(display, win->id, False, StructureNotifyMask, (XEvent *)&ce);
@@ -1110,7 +1462,7 @@ unmap_window(struct ws_win *win)
 
        XUnmapWindow(display, win->id);
        XSetWindowBorder(display, win->id,
-           win->s->c[SWM_S_COLOR_UNFOCUS].color); 
+           win->s->c[SWM_S_COLOR_UNFOCUS].color);
 }
 
 void
@@ -1223,7 +1575,8 @@ find_window(Window id)
 {
        struct ws_win           *win;
        Window                  wrr, wpr, *wcr = NULL;
-       int                     i, j, nc;
+       int                     i, j;
+       unsigned int            nc;
 
        for (i = 0; i < ScreenCount(display); i++)
                for (j = 0; j < SWM_WS_MAX; j++)
@@ -1382,6 +1735,7 @@ void
 unfocus_win(struct ws_win *win)
 {
        XEvent                  cne;
+       Window                  none = None;
 
        DNPRINTF(SWM_D_FOCUS, "unfocus_win: id: %lu\n", WINID(win));
 
@@ -1391,7 +1745,7 @@ unfocus_win(struct ws_win *win)
                return;
 
        if (validate_ws(win->ws))
-               abort(); /* XXX replace with return at some point */
+               return; /* XXX this gets hit with thunderbird, needs fixing */
 
        if (win->ws->r == NULL)
                return;
@@ -1423,6 +1777,9 @@ unfocus_win(struct ws_win *win)
        XSetWindowBorder(display, win->id,
            win->ws->r->s->c[SWM_S_COLOR_UNFOCUS].color);
 
+       XChangeProperty(display, win->s->root,
+           ewmh[_NET_ACTIVE_WINDOW].atom, XA_WINDOW, 32,
+           PropModeReplace, (unsigned char *)&none,1);
 }
 
 void
@@ -1456,7 +1813,7 @@ focus_win(struct ws_win *win)
                return;
 
        if (validate_ws(win->ws))
-               abort(); /* XXX replace with return at some point */
+               return; /* XXX this gets hit with thunderbird, needs fixing */
 
        if (validate_win(win)) {
                kill_refs(win);
@@ -1487,7 +1844,14 @@ focus_win(struct ws_win *win)
                    win->ws->r->s->c[SWM_S_COLOR_FOCUS].color);
                if (win->ws->cur_layout->flags & SWM_L_MAPONFOCUS)
                        XMapRaised(display, win->id);
+
+               XChangeProperty(display, win->s->root,
+                   ewmh[_NET_ACTIVE_WINDOW].atom, XA_WINDOW, 32,
+                   PropModeReplace, (unsigned char *)&win->id,1);
        }
+
+       if (window_name_enabled)
+               bar_update();
 }
 
 void
@@ -1583,14 +1947,14 @@ void
 priorws(struct swm_region *r, union arg *args)
 {
        union arg               a;
-       
+
        DNPRINTF(SWM_D_WS, "priorws id %d "
            "in screen[%d]:%dx%d+%d+%d ws %d\n", args->id,
            r->s->idx, WIDTH(r), HEIGHT(r), X(r), Y(r), r->ws->idx);
-       
+
        if (r->ws_prior == NULL)
                return;
-       
+
        a.id = r->ws_prior->idx;
        switchws(r, &a);
 }
@@ -1880,8 +2244,8 @@ stack(void) {
 
                        /* start with screen geometry, adjust for bar */
                        g = r->g;
-                       g.w -= 2;
-                       g.h -= 2;
+                       g.w -= 2 * border_width;
+                       g.h -= 2 * border_width;
                        if (bar_enabled) {
                                if (!bar_at_bottom)
                                        g.y += bar_height;
@@ -1928,7 +2292,8 @@ stack_floater(struct ws_win *win, struct swm_region *r)
         * geom on ws switches or return from max mode
         */
 
-       if (win->floatmaxed || (r != r->ws->old_r && win->g_floatvalid) ) {
+       if (win->floatmaxed || (r != r->ws->old_r && win->g_floatvalid
+           && !(win->ewmh_flags & EWMH_F_FULLSCREEN))) {
                /*
                 * use stored g and rg to set relative position and size
                 * as in old region or before max stack mode
@@ -1946,7 +2311,7 @@ stack_floater(struct ws_win *win, struct swm_region *r)
            (win->g.h >= HEIGHT(r)))
                wc.border_width = 0;
        else
-               wc.border_width = 1;
+               wc.border_width = border_width;
        if (win->transient && (win->quirks & SWM_Q_TRANSSZ)) {
                win->g.w = (double)WIDTH(r) * dialog_ratio;
                win->g.h = (double)HEIGHT(r) * dialog_ratio;
@@ -1957,22 +2322,22 @@ stack_floater(struct ws_win *win, struct swm_region *r)
                 * floaters and transients are auto-centred unless moved
                 * or resized
                 */
-                win->g.x = r->g.x + (WIDTH(r) - win->g.w) / 2;
-                win->g.y = r->g.y + (HEIGHT(r) - win->g.h) / 2;
+               win->g.x = r->g.x + (WIDTH(r) - win->g.w) / 2 - border_width;
+               win->g.y = r->g.y + (HEIGHT(r) - win->g.h) / 2 - border_width;
        }
 
        /* win can be outside r if new r smaller than old r */
        /* Ensure top left corner inside r (move probs otherwise) */
-       if (win->g.x < r->g.x )
-               win->g.x = r->g.x;
+       if (win->g.x < r->g.x - border_width)
+               win->g.x = r->g.x - border_width;
        if (win->g.x > r->g.x + r->g.w - 1)
                win->g.x = (win->g.w > r->g.w) ? r->g.x :
-                   (r->g.x + r->g.w - win->g.w - 2);
-       if (win->g.y < r->g.y )
-               win->g.y = r->g.y;
+                   (r->g.x + r->g.w - win->g.w - 2 * border_width);
+       if (win->g.y < r->g.y - border_width)
+               win->g.y = r->g.y - border_width;
        if (win->g.y > r->g.y + r->g.h - 1)
                win->g.y = (win->g.h > r->g.h) ? r->g.y :
-                   (r->g.y + r->g.h - win->g.h - 2);
+                   (r->g.y + r->g.h - win->g.h - 2 * border_width);
 
        wc.x = win->g.x;
        wc.y = win->g.y;
@@ -1983,7 +2348,8 @@ stack_floater(struct ws_win *win, struct swm_region *r)
         * Retain floater and transient geometry for correct positioning
         * when ws changes region
         */
-       store_float_geom(win, r);
+       if (!(win->ewmh_flags & EWMH_F_FULLSCREEN))
+               store_float_geom(win, r);
 
        DNPRINTF(SWM_D_MISC, "stack_floater: win %lu x %d y %d w %d h %d\n",
            win->id, wc.x, wc.y, wc.width, wc.height);
@@ -2032,7 +2398,7 @@ stack_master(struct workspace *ws, struct swm_geometry *g, int rot, int flip)
        XWindowChanges          wc;
        XWindowAttributes       wa;
        struct swm_geometry     win_g, r_g = *g;
-       struct ws_win           *win;
+       struct ws_win           *win, *fs_win = 0;
        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;
@@ -2097,11 +2463,11 @@ stack_master(struct workspace *ws, struct swm_geometry *g, int rot, int flip)
        } else {
                msize = -2;
                colno = split = winno / stacks;
-               win_g.w = ((r_g.w - (stacks * 2) + 2) / 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;
+       win_g.h = hrh - 2 * border_width;
 
        /*  stack all the tiled windows */
        i = j = 0, s = stacks;
@@ -2109,6 +2475,11 @@ stack_master(struct workspace *ws, struct swm_geometry *g, int rot, int flip)
                if (win->transient != 0 || win->floating != 0)
                        continue;
 
+               if (win->ewmh_flags & EWMH_F_FULLSCREEN) {
+                       fs_win = win;
+                       continue;
+               }
+
                if (split && i == split) {
                        colno = (winno - mwin) / stacks;
                        if (s <= (winno - mwin) % stacks)
@@ -2119,15 +2490,15 @@ stack_master(struct workspace *ws, struct swm_geometry *g, int rot, int flip)
                        if (flip)
                                win_g.x = r_g.x;
                        else
-                               win_g.x += win_g.w + 2;
-                       win_g.w = (r_g.w - msize - (stacks * 2)) / stacks;
+                               win_g.x += win_g.w + 2 * border_width;
+                       win_g.w = (r_g.w - msize - (stacks * 2 * border_width)) / stacks;
                        if (s == 1)
-                               win_g.w += (r_g.w - msize - (stacks * 2)) %
+                               win_g.w += (r_g.w - msize - (stacks * 2 * border_width)) %
                                    stacks;
                        s--;
                        j = 0;
                }
-               win_g.h = hrh - 2;
+               win_g.h = hrh - 2 * border_width;
                if (rot) {
                        h_inc = win->sh.width_inc;
                        h_base = win->sh.base_width;
@@ -2154,15 +2525,15 @@ stack_master(struct workspace *ws, struct swm_geometry *g, int rot, int flip)
                if (j == 0)
                        win_g.y = r_g.y;
                else
-                       win_g.y += last_h + 2;
+                       win_g.y += last_h + 2 * border_width;
 
                bzero(&wc, sizeof wc);
                if (disable_border && bar_enabled == 0 && winno == 1){
                        wc.border_width = 0;
-                       win_g.w += 2;
-                       win_g.h += 2;
+                       win_g.w += 2 * border_width;
+                       win_g.h += 2 * border_width;
                } else
-                       wc.border_width = 1;
+                       wc.border_width = border_width;
                reconfigure = 0;
                if (rot) {
                        if (win->g.x != win_g.y || win->g.y != win_g.x ||
@@ -2205,9 +2576,19 @@ stack_master(struct workspace *ws, struct swm_geometry *g, int rot, int flip)
                if (win->transient == 0 && win->floating == 0)
                        continue;
 
+               if (win->ewmh_flags & EWMH_F_FULLSCREEN) {
+                       fs_win = win;
+                       continue;
+               }
+
                stack_floater(win, ws->r);
                XMapRaised(display, win->id);
        }
+
+       if (fs_win) {
+               stack_floater(fs_win, ws->r);
+               XMapRaised(display, fs_win->id);
+       }
 }
 
 void
@@ -2346,13 +2727,13 @@ max_stack(struct workspace *ws, struct swm_geometry *g)
                        win->g.x = wc.x = gg.x;
                        win->g.y = wc.y = gg.y;
                        if (bar_enabled){
-                               wc.border_width = 1;
+                               wc.border_width = border_width;
                                win->g.w = wc.width = gg.w;
                                win->g.h = wc.height = gg.h;
                        } else {
                                wc.border_width = 0;
-                               win->g.w = wc.width = gg.w + 2;
-                               win->g.h = wc.height = gg.h + 2;
+                               win->g.w = wc.width = gg.w + 2 * border_width;
+                               win->g.h = wc.height = gg.h + 2 * border_width;
                        }
                        mask = CWX | CWY | CWWidth | CWHeight | CWBorderWidth;
                        XConfigureWindow(display, win->id, mask, &wc);
@@ -2413,6 +2794,7 @@ send_to_ws(struct swm_region *r, union arg *args)
                XChangeProperty(display, win->id, ws_idx_atom, XA_STRING, 8,
                    PropModeReplace, ws_idx_str, SWM_PROPLEN);
        }
+
        stack();
 }
 
@@ -2421,7 +2803,7 @@ wkill(struct swm_region *r, union arg *args)
 {
        DNPRINTF(SWM_D_MISC, "wkill %d\n", args->id);
 
-       if(r->ws->focus == NULL)
+       if (r->ws->focus == NULL)
                return;
 
        if (args->id == SWM_ARG_ID_KILLWINDOW)
@@ -2431,18 +2813,23 @@ wkill(struct swm_region *r, union arg *args)
                        client_msg(r->ws->focus, adelete);
 }
 
-void
-floating_toggle(struct swm_region *r, union arg *args)
+
+int
+floating_toggle_win(struct ws_win *win)
 {
-       struct ws_win   *win = r->ws->focus;
-       union arg       a;
+       struct swm_region       *r;
 
        if (win == NULL)
-               return;
+               return 0;
+
+       if (!win->ws->r)
+               return 0;
+
+       r = win->ws->r;
 
        /* reject floating toggles in max stack mode */
-       if (r->ws->cur_layout == &layouts[SWM_MAX_STACK])
-               return;
+       if (win->ws->cur_layout == &layouts[SWM_MAX_STACK])
+               return 0;
 
        if (win->floating) {
                if (!win->floatmaxed) {
@@ -2452,18 +2839,38 @@ floating_toggle(struct swm_region *r, union arg *args)
                win->floating = 0;
        } else {
                if (win->g_floatvalid) {
-                        /* refloat at last floating relative position */
-                        win->g.x = win->g_float.x - win->rg_float.x + r->g.x;
-                        win->g.y = win->g_float.y - win->rg_float.y + r->g.y;
-                        win->g.w = win->g_float.w;
-                        win->g.h = win->g_float.h;
-                }
+                       /* refloat at last floating relative position */
+                       win->g.x = win->g_float.x - win->rg_float.x + r->g.x;
+                       win->g.y = win->g_float.y - win->rg_float.y + r->g.y;
+                       win->g.w = win->g_float.w;
+                       win->g.h = win->g_float.h;
+               }
                win->floating = 1;
        }
 
+       ewmh_update_actions(win);
+
+       return 1;
+}
+
+void
+floating_toggle(struct swm_region *r, union arg *args)
+{
+       struct ws_win           *win = r->ws->focus;
+       union arg               a;
+
+       if (win == NULL)
+               return;
+
+       ewmh_update_win_state(win, ewmh[_NET_WM_STATE_ABOVE].atom,
+           _NET_WM_STATE_TOGGLE);
+
        stack();
-       a.id = SWM_ARG_ID_FOCUSCUR;
-       focus(win->ws->r, &a);
+
+       if (win == win->ws->focus) {
+               a.id = SWM_ARG_ID_FOCUSCUR;
+               focus(win->ws->r, &a);
+       }
 }
 
 void
@@ -2476,12 +2883,12 @@ resize_window(struct ws_win *win, int center)
        r = root_to_region(win->wa.root);
        bzero(&wc, sizeof wc);
        mask = CWBorderWidth | CWWidth | CWHeight;
-       wc.border_width = 1;
+       wc.border_width = border_width;
        wc.width = win->g.w;
        wc.height = win->g.h;
        if (center == SWM_ARG_ID_CENTER) {
-               wc.x = (WIDTH(r) - win->g.w) / 2;
-               wc.y = (HEIGHT(r) - win->g.h) / 2;
+               wc.x = (WIDTH(r) - win->g.w) / 2 - border_width;
+               wc.y = (HEIGHT(r) - win->g.h) / 2 - border_width;
                mask |= CWX | CWY;
        }
 
@@ -2513,6 +2920,8 @@ resize(struct ws_win *win, union arg *args)
                return;
 
        win->manual = 1;
+       ewmh_update_win_state(win, ewmh[_SWM_WM_STATE_MANUAL].atom,
+           _NET_WM_STATE_ADD);
        /* raise the window = move to last in window list */
        a.id = SWM_ARG_ID_MOVELAST;
        swapwin(r, &a);
@@ -2524,14 +2933,14 @@ resize(struct ws_win *win, union arg *args)
 
        /* place pointer at bottom left corner or nearest point inside r */
        if ( win->g.x + win->g.w < r->g.x + r->g.w - 1)
-               relx = win->g.w;
+               relx = win->g.w - 1;
        else
-               relx = r->g.x + r->g.w - win->g.x - 2;
+               relx = r->g.x + r->g.w - win->g.x - 1;
 
        if ( win->g.y + win->g.h < r->g.y + r->g.h - 1)
-               rely = win->g.h;
+               rely = win->g.h - 1;
        else
-               rely = r->g.y + r->g.h - win->g.y - 2;
+               rely = r->g.y + r->g.h - win->g.y - 1;
 
        XWarpPointer(display, None, win->id, 0, 0, 0, 0, relx, rely);
        do {
@@ -2555,11 +2964,11 @@ resize(struct ws_win *win, union arg *args)
                                ev.xmotion.x = 1;
                        if (ev.xmotion.y <= 1)
                                ev.xmotion.y = 1;
-                       win->g.w = ev.xmotion.x;
-                       win->g.h = ev.xmotion.y;
+                       win->g.w = ev.xmotion.x + 1;
+                       win->g.h = ev.xmotion.y + 1;
 
-                       /* not free, don't sync more than 60 times / second */
-                       if ((ev.xmotion.time - time) > (1000 / 60) ) {
+                       /* not free, don't sync more than 120 times / second */
+                       if ((ev.xmotion.time - time) > (1000 / 120) ) {
                                time = ev.xmotion.time;
                                XSync(display, False);
                                resize_window(win, args->id);
@@ -2619,7 +3028,11 @@ move(struct ws_win *win, union arg *args)
        win->manual = 1;
        if (win->floating == 0 && !win->transient) {
                win->floating = 1;
+               ewmh_update_win_state(win, ewmh[_NET_WM_STATE_ABOVE].atom,
+                   _NET_WM_STATE_ADD);
        }
+       ewmh_update_win_state(win, ewmh[_SWM_WM_STATE_MANUAL].atom,
+           _NET_WM_STATE_ADD);
 
        /* raise the window = move to last in window list */
        a.id = SWM_ARG_ID_MOVELAST;
@@ -2629,7 +3042,7 @@ move(struct ws_win *win, union arg *args)
        if (XGrabPointer(display, win->id, False, MOUSEMASK, GrabModeAsync,
            GrabModeAsync, None, None /* cursor */, CurrentTime) != GrabSuccess)
                return;
-       XWarpPointer(display, None, win->id, 0, 0, 0, 0, -1, -1);
+       XWarpPointer(display, None, win->id, 0, 0, 0, 0, 0, 0);
        do {
                XMaskEvent(display, MOUSEMASK | ExposureMask |
                    SubstructureRedirectMask, &ev);
@@ -2647,11 +3060,11 @@ move(struct ws_win *win, union arg *args)
                                ev.xmotion.y_root > r->g.y + r->g.h - 1)
                                continue;
 
-                       win->g.x = ev.xmotion.x_root;
-                       win->g.y = ev.xmotion.y_root;
+                       win->g.x = ev.xmotion.x_root - border_width;
+                       win->g.y = ev.xmotion.y_root - border_width;
 
-                       /* not free, don't sync more than 60 times / second */
-                       if ((ev.xmotion.time - time) > (1000 / 60) ) {
+                       /* not free, don't sync more than 120 times / second */
+                       if ((ev.xmotion.time - time) > (1000 / 120) ) {
                                time = ev.xmotion.time;
                                XSync(display, False);
                                move_window(win);
@@ -3382,7 +3795,7 @@ grabbuttons(struct ws_win *win, int focused)
 
        updatenumlockmask();
        XUngrabButton(display, AnyButton, AnyModifier, win->id);
-       if(focused) {
+       if (focused) {
                for (i = 0; i < LENGTH(buttons); i++)
                        if (buttons[i].action == client_click)
                                for (j = 0; j < LENGTH(modifiers); j++)
@@ -3554,11 +3967,11 @@ setup_quirks(void)
 /* conf file stuff */
 #define SWM_CONF_FILE  "scrotwm.conf"
 
-enum   { SWM_S_BAR_DELAY, SWM_S_BAR_ENABLED, SWM_S_STACK_ENABLED,
+enum   { SWM_S_BAR_DELAY, SWM_S_BAR_ENABLED, SWM_S_BAR_BORDER_WIDTH, SWM_S_STACK_ENABLED,
          SWM_S_CLOCK_ENABLED, SWM_S_CLOCK_FORMAT, SWM_S_CYCLE_EMPTY,
          SWM_S_CYCLE_VISIBLE, SWM_S_SS_ENABLED, SWM_S_TERM_WIDTH,
-         SWM_S_TITLE_CLASS_ENABLED, SWM_S_TITLE_NAME_ENABLED,
-         SWM_S_FOCUS_MODE, SWM_S_DISABLE_BORDER, SWM_S_BAR_FONT,
+         SWM_S_TITLE_CLASS_ENABLED, SWM_S_TITLE_NAME_ENABLED, SWM_S_WINDOW_NAME_ENABLED,
+         SWM_S_FOCUS_MODE, SWM_S_DISABLE_BORDER, SWM_S_BORDER_WIDTH, SWM_S_BAR_FONT,
          SWM_S_BAR_ACTION, SWM_S_SPAWN_TERM, SWM_S_SS_APP, SWM_S_DIALOG_RATIO,
          SWM_S_BAR_AT_BOTTOM
        };
@@ -3573,6 +3986,9 @@ setconfvalue(char *selector, char *value, int flags)
        case SWM_S_BAR_ENABLED:
                bar_enabled = atoi(value);
                break;
+       case SWM_S_BAR_BORDER_WIDTH:
+               bar_border_width = atoi(value);
+               break;
        case SWM_S_BAR_AT_BOTTOM:
                bar_at_bottom = atoi(value);
                break;
@@ -3604,6 +4020,9 @@ setconfvalue(char *selector, char *value, int flags)
        case SWM_S_TITLE_CLASS_ENABLED:
                title_class_enabled = atoi(value);
                break;
+       case SWM_S_WINDOW_NAME_ENABLED:
+               window_name_enabled = atoi(value);
+               break;
        case SWM_S_TITLE_NAME_ENABLED:
                title_name_enabled = atoi(value);
                break;
@@ -3620,6 +4039,9 @@ setconfvalue(char *selector, char *value, int flags)
        case SWM_S_DISABLE_BORDER:
                disable_border = atoi(value);
                break;
+       case SWM_S_BORDER_WIDTH:
+               border_width = atoi(value);
+               break;
        case SWM_S_BAR_FONT:
                free(bar_fonts[0]);
                if ((bar_fonts[0] = strdup(value)) == NULL)
@@ -3688,6 +4110,7 @@ struct config_option configopt[] = {
        { "bar_enabled",                setconfvalue,   SWM_S_BAR_ENABLED },
        { "bar_at_bottom",              setconfvalue,   SWM_S_BAR_AT_BOTTOM },
        { "bar_border",                 setconfcolor,   SWM_S_COLOR_BAR_BORDER },
+       { "bar_border_width",                   setconfvalue,   SWM_S_BAR_BORDER_WIDTH },
        { "bar_color",                  setconfcolor,   SWM_S_COLOR_BAR },
        { "bar_font_color",             setconfcolor,   SWM_S_COLOR_BAR_FONT },
        { "bar_font",                   setconfvalue,   SWM_S_BAR_FONT },
@@ -3709,11 +4132,13 @@ struct config_option configopt[] = {
        { "spawn_term",                 setconfvalue,   SWM_S_SPAWN_TERM },
        { "screenshot_enabled",         setconfvalue,   SWM_S_SS_ENABLED },
        { "screenshot_app",             setconfvalue,   SWM_S_SS_APP },
+       { "window_name_enabled",        setconfvalue,   SWM_S_WINDOW_NAME_ENABLED },
        { "term_width",                 setconfvalue,   SWM_S_TERM_WIDTH },
        { "title_class_enabled",        setconfvalue,   SWM_S_TITLE_CLASS_ENABLED },
        { "title_name_enabled",         setconfvalue,   SWM_S_TITLE_NAME_ENABLED },
        { "focus_mode",                 setconfvalue,   SWM_S_FOCUS_MODE },
        { "disable_border",             setconfvalue,   SWM_S_DISABLE_BORDER },
+       { "border_width",               setconfvalue,   SWM_S_BORDER_WIDTH },
 };
 
 
@@ -3850,6 +4275,7 @@ manage_window(Window id)
                TAILQ_INSERT_TAIL(&win->ws->winlist, win, entry);
                if (win->transient)
                        set_child_transient(win);
+               ewmh_update_actions(win);
                return (win);
        }
 
@@ -3870,6 +4296,7 @@ manage_window(Window id)
                DNPRINTF(SWM_D_MISC, "manage_window: win %lu transient %lu\n",
                    win->id, win->transient);
        }
+
        /* get supported protocols */
        if (XGetWMProtocols(display, id, &prot, &n)) {
                for (i = 0, pp = prot; i < n; i++, pp++) {
@@ -3924,6 +4351,7 @@ manage_window(Window id)
        win->g.y = win->wa.y;
        win->g_floatvalid = 0;
        win->floatmaxed = 0;
+       win->ewmh_flags = 0;
 
        /* Set window properties so we can remember this after reincarnation */
        if (ws_idx_atom && prop == NULL &&
@@ -3933,7 +4361,10 @@ manage_window(Window id)
                XChangeProperty(display, win->id, ws_idx_atom, XA_STRING, 8,
                    PropModeReplace, ws_idx_str, SWM_PROPLEN);
        }
-       XFree(prop);
+       if (prop)
+               XFree(prop);
+
+       ewmh_autoquirk(win);
 
        if (XGetClassHint(display, win->id, &win->ch)) {
                DNPRINTF(SWM_D_CLASS, "class: %s name: %s\n",
@@ -3964,7 +4395,7 @@ manage_window(Window id)
                win->manual = 1; /* don't center the quirky windows */
                bzero(&wc, sizeof wc);
                mask = 0;
-               if (win->g.y < bar_height) {
+               if (bar_enabled && win->g.y < bar_height) {
                        win->g.y = wc.y = bar_height;
                        mask |= CWY;
                }
@@ -3983,10 +4414,14 @@ manage_window(Window id)
                        fake_keypress(win, XK_KP_Add, ShiftMask);
        }
 
+       ewmh_get_win_state(win);
+       ewmh_update_actions(win);
+       ewmh_update_win_state(win, None, _NET_WM_STATE_REMOVE);
+
        /* border me */
        if (border_me) {
                bzero(&wc, sizeof wc);
-               wc.border_width = 1;
+               wc.border_width = border_width;
                mask = CWBorderWidth;
                XConfigureWindow(display, win->id, mask, &wc);
                configreq_win(win);
@@ -4046,7 +4481,9 @@ unmanage_window(struct ws_win *win)
                        parent->child_trans = NULL;
        }
 
-       /* work around for mplayer going full screen */
+       /* focus on root just in case */
+       XSetInputFocus(display, PointerRoot, PointerRoot, CurrentTime);
+
        if (!win->floating)
                focus_prev(win);
 
@@ -4473,6 +4910,8 @@ propertynotify(XEvent *e)
                XMoveResizeWindow(display, win->id,
                    win->g.x, win->g.y, win->g.w, win->g.h);
 #endif
+               if (window_name_enabled)
+                       bar_update();
                break;
        default:
                break;
@@ -4512,6 +4951,59 @@ visibilitynotify(XEvent *e)
                                        bar_update();
 }
 
+void
+clientmessage(XEvent *e)
+{
+       XClientMessageEvent *ev;
+       struct ws_win *win;
+
+       ev = &e->xclient;
+
+       win = find_window(ev->window);
+       if (win == NULL)
+               return;
+
+       DNPRINTF(SWM_D_EVENT, "clientmessage: window: 0x%lx type: %ld \n",
+           ev->window, ev->message_type);
+
+       if (ev->message_type == ewmh[_NET_ACTIVE_WINDOW].atom) {
+               DNPRINTF(SWM_D_EVENT, "clientmessage: _NET_ACTIVE_WINDOW \n");
+               focus_win(win);
+       }
+       if (ev->message_type == ewmh[_NET_CLOSE_WINDOW].atom) {
+               DNPRINTF(SWM_D_EVENT, "clientmessage: _NET_CLOSE_WINDOW \n");
+               if (win->can_delete)
+                       client_msg(win, adelete);
+               else
+                       XKillClient(display, win->id);
+       }
+       if (ev->message_type == ewmh[_NET_MOVERESIZE_WINDOW].atom) {
+               DNPRINTF(SWM_D_EVENT, "clientmessage: _NET_MOVERESIZE_WINDOW \n");
+               if (win->floating) {
+                       if (ev->data.l[0] & (1<<8)) /* x */
+                               win->g.x = ev->data.l[1];
+                       if (ev->data.l[0] & (1<<9)) /* y */
+                               win->g.y = ev->data.l[2];
+                       if (ev->data.l[0] & (1<<10)) /* width */
+                               win->g.w = ev->data.l[3];
+                       if (ev->data.l[0] & (1<<11)) /* height */
+                               win->g.h = ev->data.l[4];
+               }
+               else {
+                       /* TODO: Change stack sizes */
+               }
+               config_win(win);
+       }
+       if (ev->message_type == ewmh[_NET_WM_STATE].atom) {
+               DNPRINTF(SWM_D_EVENT, "clientmessage: _NET_WM_STATE \n");
+               ewmh_update_win_state(win, ev->data.l[1], ev->data.l[0]);
+               if (ev->data.l[2])
+                       ewmh_update_win_state(win, ev->data.l[2], ev->data.l[0]);
+
+               stack();
+       }
+}
+
 int
 xerror_start(Display *d, XErrorEvent *ee)
 {
@@ -4706,16 +5198,57 @@ screenchange(XEvent *e) {
 }
 
 void
-setup_screens(void)
+grab_windows(void)
 {
        Window                  d1, d2, *wins = NULL;
        XWindowAttributes       wa;
        unsigned int            no;
-        int                    i, j, k;
+       int                     i, j;
+       long                    state, manage;
+
+       for (i = 0; i < ScreenCount(display); i++) {
+               if (!XQueryTree(display, screens[i].root, &d1, &d2, &wins, &no))
+                       continue;
+
+               /* attach windows to a region */
+               /* normal windows */
+               for (j = 0; j < no; j++) {
+                       if (!XGetWindowAttributes(display, wins[j], &wa) ||
+                           wa.override_redirect ||
+                           XGetTransientForHint(display, wins[j], &d1))
+                               continue;
+
+                       state = getstate(wins[j]);
+                       manage = state == IconicState;
+                       if (wa.map_state == IsViewable || manage)
+                               manage_window(wins[j]);
+               }
+               /* transient windows */
+               for (j = 0; j < no; j++) {
+                       if (!XGetWindowAttributes(display, wins[j], &wa) ||
+                           wa.override_redirect)
+                               continue;
+
+                       state = getstate(wins[j]);
+                       manage = state == IconicState;
+                       if (XGetTransientForHint(display, wins[j], &d1) &&
+                           manage)
+                               manage_window(wins[j]);
+               }
+               if (wins) {
+                       XFree(wins);
+                       wins = NULL;
+               }
+       }
+}
+
+void
+setup_screens(void)
+{
+       int                     i, j, k;
        int                     errorbase, major, minor;
        struct workspace        *ws;
        int                     ws_idx_atom;
-       long                    state, manage;
 
        if ((screens = calloc(ScreenCount(display),
             sizeof(struct swm_screen))) == NULL)
@@ -4766,45 +5299,12 @@ setup_screens(void)
                                            SWM_ARG_ID_STACKINIT);
                        ws->cur_layout = &layouts[0];
                }
-               /* grab existing windows (before we build the bars)*/
-               if (!XQueryTree(display, screens[i].root, &d1, &d2, &wins, &no))
-                       continue;
 
                scan_xrandr(i);
 
                if (xrandr_support)
                        XRRSelectInput(display, screens[i].root,
                            RRScreenChangeNotifyMask);
-
-               /* attach windows to a region */
-               /* normal windows */
-               for (j = 0; j < no; j++) {
-                       if (!XGetWindowAttributes(display, wins[j], &wa) ||
-                           wa.override_redirect ||
-                           XGetTransientForHint(display, wins[j], &d1))
-                               continue;
-
-                       state = getstate(wins[j]);
-                       manage = state == IconicState;
-                       if (wa.map_state == IsViewable || manage)
-                               manage_window(wins[j]);
-               }
-               /* transient windows */
-               for (j = 0; j < no; j++) {
-                       if (!XGetWindowAttributes(display, wins[j], &wa) ||
-                           wa.override_redirect)
-                               continue;
-
-                       state = getstate(wins[j]);
-                       manage = state == IconicState;
-                       if (XGetTransientForHint(display, wins[j], &d1) &&
-                           manage)
-                               manage_window(wins[j]);
-                }
-                if (wins) {
-                        XFree(wins);
-                       wins = NULL;
-               }
        }
 }
 
@@ -4831,7 +5331,7 @@ workaround(void)
 {
        int                     i;
        Atom                    netwmcheck, netwmname, utf8_string;
-       Window                  root;
+       Window                  root, win;
 
        /* work around sun jdk bugs, code from wmname */
        netwmcheck = XInternAtom(display, "_NET_SUPPORTING_WM_CHECK", False);
@@ -4839,10 +5339,16 @@ workaround(void)
        utf8_string = XInternAtom(display, "UTF8_STRING", False);
        for (i = 0; i < ScreenCount(display); i++) {
                root = screens[i].root;
+               win = XCreateSimpleWindow(display,root, 0, 0, 1, 1, 0,
+                   screens[i].c[SWM_S_COLOR_UNFOCUS].color,
+                   screens[i].c[SWM_S_COLOR_UNFOCUS].color);
+
                XChangeProperty(display, root, netwmcheck, XA_WINDOW, 32,
-                   PropModeReplace, (unsigned char *)&root, 1);
-               XChangeProperty(display, root, netwmname, utf8_string, 8,
-                   PropModeReplace, "LG3D", strlen("LG3D"));
+                   PropModeReplace, (unsigned char *)&win,1);
+               XChangeProperty(display, win, netwmcheck, XA_WINDOW, 32,
+                   PropModeReplace, (unsigned char *)&win,1);
+               XChangeProperty(display, win, netwmname, utf8_string, 8,
+                   PropModeReplace, (unsigned char*)"LG3D", strlen("LG3D"));
        }
 }
 
@@ -4903,6 +5409,7 @@ main(int argc, char *argv[])
        setup_quirks();
        setup_spawn();
 
+       /* load config */
        snprintf(conf, sizeof conf, "%s/.%s", pwd->pw_dir, SWM_CONF_FILE);
        if (stat(conf, &sb) != -1) {
                if (S_ISREG(sb.st_mode))
@@ -4917,6 +5424,13 @@ main(int argc, char *argv[])
        if (cfile)
                conf_load(cfile);
 
+       setup_ewmh();
+       /* set some values to work around bad programs */
+       workaround();
+
+       /* grab existing windows (before we build the bars) */
+       grab_windows();
+
        /* setup all bars */
        for (i = 0; i < ScreenCount(display); i++)
                TAILQ_FOREACH(r, &screens[i].rl, entry) {
@@ -4925,9 +5439,6 @@ main(int argc, char *argv[])
                        bar_setup(r);
                }
 
-       /* set some values to work around bad programs */
-       workaround();
-
        unfocus_all();
 
        grabkeys();
@@ -4998,6 +5509,7 @@ main(int argc, char *argv[])
                }
        }
 done:
+       teardown_ewmh();
        bar_extra_stop();
        XFreeGC(display, bar_gc);
        XCloseDisplay(display);