summary refs log tree commit diff
diff options
context:
space:
mode:
authorokan <okan>2014-09-18 13:56:58 +0000
committerokan <okan>2014-09-18 13:56:58 +0000
commit2540b3f4fe34c6bc6ed0593e9c6d713d84b2c301 (patch)
tree640369d4716c7067b56d78f937397887a07260c8
parent973592780997d20ff46e8df168df5246ddb1df82 (diff)
parentcbc7f760748f0519c70fa6c6d3c40a05810b7f9c (diff)
downloadcwm-2540b3f4fe34c6bc6ed0593e9c6d713d84b2c301.tar.gz
cwm-2540b3f4fe34c6bc6ed0593e9c6d713d84b2c301.tar.xz
cwm-2540b3f4fe34c6bc6ed0593e9c6d713d84b2c301.zip
cvsimport
-rw-r--r--calmwm.c7
-rw-r--r--calmwm.h61
-rw-r--r--client.c144
-rw-r--r--conf.c33
-rw-r--r--group.c106
-rw-r--r--kbfunc.c36
-rw-r--r--menu.c26
-rw-r--r--mousefunc.c45
-rw-r--r--screen.c16
-rw-r--r--search.c14
-rw-r--r--xevents.c10
-rw-r--r--xmalloc.c8
-rw-r--r--xutil.c52
13 files changed, 301 insertions, 257 deletions
diff --git a/calmwm.c b/calmwm.c
index 3c76bb4..afc5e18 100644
--- a/calmwm.c
+++ b/calmwm.c
@@ -41,7 +41,6 @@ Atom				 cwmh[CWMH_NITEMS];
 Atom				 ewmh[EWMH_NITEMS];
 
 struct screen_ctx_q		 Screenq = TAILQ_HEAD_INITIALIZER(Screenq);
-struct client_ctx_q		 Clientq = TAILQ_HEAD_INITIALIZER(Clientq);
 
 int				 HasRandr, Randr_ev;
 struct conf			 Conf;
@@ -120,7 +119,7 @@ main(int argc, char **argv)
 	if (cwm_status == CWM_RESTART)
 		x_restart(cwm_argv);
 
-	return (0);
+	return(0);
 }
 
 static void
@@ -185,7 +184,7 @@ x_wmerrorhandler(Display *dpy, XErrorEvent *e)
 {
 	errx(1, "root window unavailable - perhaps another wm is running?");
 
-	return (0);
+	return(0);
 }
 
 static int
@@ -201,7 +200,7 @@ x_errorhandler(Display *dpy, XErrorEvent *e)
 
 	warnx("%s(0x%x): %s", req, (unsigned int)e->resourceid, msg);
 #endif
-	return (0);
+	return(0);
 }
 
 static void
diff --git a/calmwm.h b/calmwm.h
index 02f31d1..5fe8c78 100644
--- a/calmwm.h
+++ b/calmwm.h
@@ -162,9 +162,8 @@ TAILQ_HEAD(winname_q, winname);
 TAILQ_HEAD(ignore_q, winname);
 
 struct client_ctx {
-	TAILQ_ENTRY(client_ctx) entry;
-	TAILQ_ENTRY(client_ctx) group_entry;
-	TAILQ_ENTRY(client_ctx) mru_entry;
+	TAILQ_ENTRY(client_ctx)	 entry;
+	TAILQ_ENTRY(client_ctx)	 group_entry;
 	struct screen_ctx	*sc;
 	Window			 win;
 	Colormap		 colormap;
@@ -200,12 +199,12 @@ struct client_ctx {
 #define CLIENT_URGENCY			0x0400
 #define CLIENT_FULLSCREEN		0x0800
 #define CLIENT_STICKY			0x1000
+#define CLIENT_ACTIVE			0x2000
 
 #define CLIENT_HIGHLIGHT		(CLIENT_GROUP | CLIENT_UNGROUP)
 #define CLIENT_MAXFLAGS			(CLIENT_VMAXIMIZED | CLIENT_HMAXIMIZED)
 #define CLIENT_MAXIMIZED		(CLIENT_VMAXIMIZED | CLIENT_HMAXIMIZED)
 	int			 flags;
-	int			 active;
 	int			 stackingorder;
 	struct winname_q	 nameq;
 #define CLIENT_MAXNAMEQLEN		5
@@ -218,11 +217,11 @@ struct client_ctx {
 	XWMHints		*wmh;
 };
 TAILQ_HEAD(client_ctx_q, client_ctx);
-TAILQ_HEAD(cycle_entry_q, client_ctx);
 
 struct group_ctx {
 	TAILQ_ENTRY(group_ctx)	 entry;
-	struct client_ctx_q	 clients;
+	struct screen_ctx	*sc;
+	struct client_ctx_q	 clientq;
 	char			*name;
 	int			 num;
 };
@@ -253,13 +252,12 @@ struct screen_ctx {
 	struct geom		 view; /* viewable area */
 	struct geom		 work; /* workable area, gap-applied */
 	struct gap		 gap;
-	struct cycle_entry_q	 mruq;
+	struct client_ctx_q	 clientq;
 	struct region_ctx_q	 regionq;
 	XftColor		 xftcolor[CWM_COLOR_NITEMS];
 	XftDraw			*xftdraw;
 	XftFont			*xftfont;
 #define CALMWM_NGROUPS		 10
-	struct group_ctx	 groups[CALMWM_NGROUPS];
 	struct group_ctx_q	 groupq;
 	int			 group_hideall;
 	struct group_ctx	*group_active;
@@ -334,7 +332,6 @@ struct mwm_hints {
 extern Display				*X_Dpy;
 extern Time				 Last_Event_Time;
 extern struct screen_ctx_q		 Screenq;
-extern struct client_ctx_q		 Clientq;
 extern struct conf			 Conf;
 extern const char			*homedir;
 extern int				 HasRandr, Randr_ev;
@@ -366,10 +363,11 @@ enum {
 	_NET_WM_DESKTOP,
 	_NET_CLOSE_WINDOW,
 	_NET_WM_STATE,
-#define	_NET_WM_STATES_NITEMS	5
+#define	_NET_WM_STATES_NITEMS	6
 	_NET_WM_STATE_STICKY,
 	_NET_WM_STATE_MAXIMIZED_VERT,
 	_NET_WM_STATE_MAXIMIZED_HORZ,
+	_NET_WM_STATE_HIDDEN,
 	_NET_WM_STATE_FULLSCREEN,
 	_NET_WM_STATE_DEMANDS_ATTENTION,
 	EWMH_NITEMS
@@ -392,16 +390,12 @@ void			 client_cycle_leave(struct screen_ctx *);
 void			 client_delete(struct client_ctx *);
 void			 client_draw_border(struct client_ctx *);
 struct client_ctx	*client_find(Window);
-void			 client_freeze(struct client_ctx *);
-void			 client_fullscreen(struct client_ctx *);
 long			 client_get_wm_state(struct client_ctx *);
 void			 client_getsizehints(struct client_ctx *);
 void			 client_hide(struct client_ctx *);
-void			 client_hmaximize(struct client_ctx *);
 void 			 client_htile(struct client_ctx *);
 void			 client_lower(struct client_ctx *);
 void			 client_map(struct client_ctx *);
-void			 client_maximize(struct client_ctx *);
 void			 client_msg(struct client_ctx *, Atom, Time);
 void			 client_move(struct client_ctx *);
 struct client_ctx	*client_init(Window, struct screen_ctx *);
@@ -414,11 +408,16 @@ void			 client_set_wm_state(struct client_ctx *, long);
 void			 client_setactive(struct client_ctx *);
 void			 client_setname(struct client_ctx *);
 int			 client_snapcalc(int, int, int, int, int);
-void			 client_sticky(struct client_ctx *);
+void			 client_toggle_freeze(struct client_ctx *);
+void			 client_toggle_fullscreen(struct client_ctx *);
+void			 client_toggle_hidden(struct client_ctx *);
+void			 client_toggle_hmaximize(struct client_ctx *);
+void			 client_toggle_maximize(struct client_ctx *);
+void			 client_toggle_sticky(struct client_ctx *);
+void			 client_toggle_vmaximize(struct client_ctx *);
 void			 client_transient(struct client_ctx *);
 void			 client_unhide(struct client_ctx *);
 void			 client_urgency(struct client_ctx *);
-void			 client_vmaximize(struct client_ctx *);
 void 			 client_vtile(struct client_ctx *);
 void			 client_warp(struct client_ctx *);
 void			 client_wm_hints(struct client_ctx *);
@@ -426,14 +425,14 @@ void			 client_wm_hints(struct client_ctx *);
 void			 group_alltoggle(struct screen_ctx *);
 void			 group_autogroup(struct client_ctx *);
 void			 group_cycle(struct screen_ctx *, int);
-int			 group_hidden_state(struct group_ctx *);
-void			 group_hide(struct screen_ctx *, struct group_ctx *);
+void			 group_hide(struct group_ctx *);
 void			 group_hidetoggle(struct screen_ctx *, int);
+int			 group_holds_only_hidden(struct group_ctx *);
+int			 group_holds_only_sticky(struct group_ctx *);
 void			 group_init(struct screen_ctx *);
 void			 group_movetogroup(struct client_ctx *, int);
 void			 group_only(struct screen_ctx *, int);
-void			 group_show(struct screen_ctx *, struct group_ctx *);
-void			 group_sticky(struct client_ctx *);
+void			 group_show(struct group_ctx *);
 void			 group_sticky_toggle_enter(struct client_ctx *);
 void			 group_sticky_toggle_exit(struct client_ctx *);
 void			 group_update_names(struct screen_ctx *);
@@ -450,9 +449,9 @@ void			 search_match_text(struct menu_q *, struct menu_q *,
 			     char *);
 void			 search_print_client(struct menu *, int);
 
+struct screen_ctx	*screen_find(Window);
 struct geom		 screen_find_xinerama(struct screen_ctx *,
     			     int, int, int);
-struct screen_ctx	*screen_fromroot(Window);
 void			 screen_init(int);
 void			 screen_update_geometry(struct screen_ctx *);
 void			 screen_updatestackingorder(struct screen_ctx *);
@@ -461,21 +460,14 @@ void			 kbfunc_client_cycle(struct client_ctx *, union arg *);
 void			 kbfunc_client_cyclegroup(struct client_ctx *,
 			     union arg *);
 void			 kbfunc_client_delete(struct client_ctx *, union arg *);
-void			 kbfunc_client_freeze(struct client_ctx *, union arg *);
-void			 kbfunc_client_fullscreen(struct client_ctx *,
-			     union arg *);
 void			 kbfunc_client_group(struct client_ctx *, union arg *);
 void			 kbfunc_client_grouponly(struct client_ctx *,
 			     union arg *);
 void			 kbfunc_client_grouptoggle(struct client_ctx *,
 			     union arg *);
 void			 kbfunc_client_hide(struct client_ctx *, union arg *);
-void			 kbfunc_client_hmaximize(struct client_ctx *,
-			     union arg *);
 void			 kbfunc_client_label(struct client_ctx *, union arg *);
 void			 kbfunc_client_lower(struct client_ctx *, union arg *);
-void			 kbfunc_client_maximize(struct client_ctx *,
-			     union arg *);
 void			 kbfunc_client_moveresize(struct client_ctx *,
 			     union arg *);
 void			 kbfunc_client_movetogroup(struct client_ctx *,
@@ -485,8 +477,17 @@ void			 kbfunc_client_nogroup(struct client_ctx *,
 void			 kbfunc_client_raise(struct client_ctx *, union arg *);
 void			 kbfunc_client_rcycle(struct client_ctx *, union arg *);
 void			 kbfunc_client_search(struct client_ctx *, union arg *);
-void			 kbfunc_client_sticky(struct client_ctx *, union arg *);
-void			 kbfunc_client_vmaximize(struct client_ctx *,
+void			 kbfunc_client_toggle_freeze(struct client_ctx *,
+    			     union arg *);
+void			 kbfunc_client_toggle_fullscreen(struct client_ctx *,
+			     union arg *);
+void			 kbfunc_client_toggle_hmaximize(struct client_ctx *,
+			     union arg *);
+void			 kbfunc_client_toggle_maximize(struct client_ctx *,
+			     union arg *);
+void			 kbfunc_client_toggle_sticky(struct client_ctx *,
+    			     union arg *);
+void			 kbfunc_client_toggle_vmaximize(struct client_ctx *,
 			     union arg *);
 void			 kbfunc_cmdexec(struct client_ctx *, union arg *);
 void			 kbfunc_cwm_status(struct client_ctx *, union arg *);
diff --git a/client.c b/client.c
index 6e5781c..be51067 100644
--- a/client.c
+++ b/client.c
@@ -31,8 +31,8 @@
 
 #include "calmwm.h"
 
-static struct client_ctx	*client_mrunext(struct client_ctx *);
-static struct client_ctx	*client_mruprev(struct client_ctx *);
+static struct client_ctx	*client_next(struct client_ctx *);
+static struct client_ctx	*client_prev(struct client_ctx *);
 static void			 client_mtf(struct client_ctx *);
 static void			 client_none(struct screen_ctx *);
 static void			 client_placecalc(struct client_ctx *);
@@ -45,13 +45,16 @@ struct client_ctx	*curcc = NULL;
 struct client_ctx *
 client_find(Window win)
 {
+	struct screen_ctx	*sc;
 	struct client_ctx	*cc;
 
-	TAILQ_FOREACH(cc, &Clientq, entry)
-		if (cc->win == win)
-			return (cc);
-
-	return (NULL);
+	TAILQ_FOREACH(sc, &Screenq, entry) {
+		TAILQ_FOREACH(cc, &sc->clientq, entry) {
+			if (cc->win == win)
+				return(cc);
+		}
+	}
+	return(NULL);
 }
 
 struct client_ctx *
@@ -63,16 +66,16 @@ client_init(Window win, struct screen_ctx *sc)
 	int			 mapped;
 
 	if (win == None)
-		return (NULL);
+		return(NULL);
 	if (!XGetWindowAttributes(X_Dpy, win, &wattr))
-		return (NULL);
+		return(NULL);
 
 	if (sc == NULL) {
-		sc = screen_fromroot(wattr.root);
+		sc = screen_find(wattr.root);
 		mapped = 1;
 	} else {
 		if (wattr.override_redirect || wattr.map_state != IsViewable)
-			return (NULL);
+			return(NULL);
 		mapped = wattr.map_state != IsUnmapped;
 	}
 
@@ -126,8 +129,7 @@ client_init(Window win, struct screen_ctx *sc)
 
 	(state == IconicState) ? client_hide(cc) : client_unhide(cc);
 
-	TAILQ_INSERT_TAIL(&sc->mruq, cc, mru_entry);
-	TAILQ_INSERT_TAIL(&Clientq, cc, entry);
+	TAILQ_INSERT_TAIL(&sc->clientq, cc, entry);
 
 	xu_ewmh_net_client_list(sc);
 	xu_ewmh_restore_net_wm_state(cc);
@@ -138,7 +140,7 @@ client_init(Window win, struct screen_ctx *sc)
 	XSync(X_Dpy, False);
 	XUngrabServer(X_Dpy);
 
-	return (cc);
+	return(cc);
 }
 
 void
@@ -147,13 +149,12 @@ client_delete(struct client_ctx *cc)
 	struct screen_ctx	*sc = cc->sc;
 	struct winname		*wn;
 
-	TAILQ_REMOVE(&sc->mruq, cc, mru_entry);
-	TAILQ_REMOVE(&Clientq, cc, entry);
+	TAILQ_REMOVE(&sc->clientq, cc, entry);
 
 	xu_ewmh_net_client_list(sc);
 
 	if (cc->group != NULL)
-		TAILQ_REMOVE(&cc->group->clients, cc, group_entry);
+		TAILQ_REMOVE(&cc->group->clientq, cc, group_entry);
 
 	if (cc == client_current())
 		client_none(sc);
@@ -186,7 +187,7 @@ client_setactive(struct client_ctx *cc)
 	XInstallColormap(X_Dpy, cc->colormap);
 
 	if ((cc->flags & CLIENT_INPUT) ||
-	    ((cc->flags & CLIENT_WM_TAKE_FOCUS) == 0)) {
+	    (!(cc->flags & CLIENT_WM_TAKE_FOCUS))) {
 		XSetInputFocus(X_Dpy, cc->win,
 		    RevertToPointerRoot, CurrentTime);
 	}
@@ -194,7 +195,7 @@ client_setactive(struct client_ctx *cc)
 		client_msg(cc, cwmh[WM_TAKE_FOCUS], Last_Event_Time);
 
 	if ((oldcc = client_current())) {
-		oldcc->active = 0;
+		oldcc->flags &= ~CLIENT_ACTIVE;
 		client_draw_border(oldcc);
 	}
 
@@ -203,7 +204,7 @@ client_setactive(struct client_ctx *cc)
 		client_mtf(cc);
 
 	curcc = cc;
-	cc->active = 1;
+	cc->flags |= CLIENT_ACTIVE;
 	cc->flags &= ~CLIENT_URGENCY;
 	client_draw_border(cc);
 	conf_grab_mouse(cc->win);
@@ -226,11 +227,11 @@ client_none(struct screen_ctx *sc)
 struct client_ctx *
 client_current(void)
 {
-	return (curcc);
+	return(curcc);
 }
 
 void
-client_freeze(struct client_ctx *cc)
+client_toggle_freeze(struct client_ctx *cc)
 {
 	if (cc->flags & CLIENT_FREEZE)
 		cc->flags &= ~CLIENT_FREEZE;
@@ -239,7 +240,18 @@ client_freeze(struct client_ctx *cc)
 }
 
 void
-client_sticky(struct client_ctx *cc)
+client_toggle_hidden(struct client_ctx *cc)
+{
+	if (cc->flags & CLIENT_HIDDEN)
+		cc->flags &= ~CLIENT_HIDDEN;
+	else
+		cc->flags |= CLIENT_HIDDEN;
+
+	xu_ewmh_set_net_wm_state(cc);
+}
+
+void
+client_toggle_sticky(struct client_ctx *cc)
 {
 	if (cc->flags & CLIENT_STICKY)
 		cc->flags &= ~CLIENT_STICKY;
@@ -250,7 +262,7 @@ client_sticky(struct client_ctx *cc)
 }
 
 void
-client_fullscreen(struct client_ctx *cc)
+client_toggle_fullscreen(struct client_ctx *cc)
 {
 	struct screen_ctx	*sc = cc->sc;
 	struct geom		 xine;
@@ -259,7 +271,7 @@ client_fullscreen(struct client_ctx *cc)
 	    !(cc->flags & CLIENT_FULLSCREEN))
 		return;
 
-	if ((cc->flags & CLIENT_FULLSCREEN)) {
+	if (cc->flags & CLIENT_FULLSCREEN) {
 		cc->bwidth = Conf.bwidth;
 		cc->geom = cc->fullgeom;
 		cc->flags &= ~(CLIENT_FULLSCREEN | CLIENT_FREEZE);
@@ -282,12 +294,12 @@ resize:
 }
 
 void
-client_maximize(struct client_ctx *cc)
+client_toggle_maximize(struct client_ctx *cc)
 {
 	struct screen_ctx	*sc = cc->sc;
 	struct geom		 xine;
 
-	if (cc->flags & CLIENT_FREEZE)
+	if (cc->flags & (CLIENT_FREEZE|CLIENT_STICKY))
 		return;
 
 	if ((cc->flags & CLIENT_MAXFLAGS) == CLIENT_MAXIMIZED) {
@@ -296,12 +308,12 @@ client_maximize(struct client_ctx *cc)
 		goto resize;
 	}
 
-	if ((cc->flags & CLIENT_VMAXIMIZED) == 0) {
+	if (!(cc->flags & CLIENT_VMAXIMIZED)) {
 		cc->savegeom.h = cc->geom.h;
 		cc->savegeom.y = cc->geom.y;
 	}
 
-	if ((cc->flags & CLIENT_HMAXIMIZED) == 0) {
+	if (!(cc->flags & CLIENT_HMAXIMIZED)) {
 		cc->savegeom.w = cc->geom.w;
 		cc->savegeom.x = cc->geom.x;
 	}
@@ -327,12 +339,12 @@ resize:
 }
 
 void
-client_vmaximize(struct client_ctx *cc)
+client_toggle_vmaximize(struct client_ctx *cc)
 {
 	struct screen_ctx	*sc = cc->sc;
 	struct geom		 xine;
 
-	if (cc->flags & CLIENT_FREEZE)
+	if (cc->flags & (CLIENT_FREEZE|CLIENT_STICKY))
 		return;
 
 	if (cc->flags & CLIENT_VMAXIMIZED) {
@@ -359,12 +371,12 @@ resize:
 }
 
 void
-client_hmaximize(struct client_ctx *cc)
+client_toggle_hmaximize(struct client_ctx *cc)
 {
 	struct screen_ctx	*sc = cc->sc;
 	struct geom		 xine;
 
-	if (cc->flags & CLIENT_FREEZE)
+	if (cc->flags & (CLIENT_FREEZE|CLIENT_STICKY))
 		return;
 
 	if (cc->flags & CLIENT_HMAXIMIZED) {
@@ -484,7 +496,7 @@ client_hide(struct client_ctx *cc)
 
 	XUnmapWindow(X_Dpy, cc->win);
 
-	cc->active = 0;
+	cc->flags &= ~CLIENT_ACTIVE;
 	cc->flags |= CLIENT_HIDDEN;
 	client_set_wm_state(cc, IconicState);
 
@@ -508,7 +520,7 @@ client_unhide(struct client_ctx *cc)
 void
 client_urgency(struct client_ctx *cc)
 {
-	if (!cc->active)
+	if (!(cc->flags & CLIENT_ACTIVE))
 		cc->flags |= CLIENT_URGENCY;
 }
 
@@ -518,7 +530,7 @@ client_draw_border(struct client_ctx *cc)
 	struct screen_ctx	*sc = cc->sc;
 	unsigned long		 pixel;
 
-	if (cc->active)
+	if (cc->flags & CLIENT_ACTIVE)
 		switch (cc->flags & CLIENT_HIGHLIGHT) {
 		case CLIENT_GROUP:
 			pixel = sc->xftcolor[CWM_COLOR_BORDER_GROUP].pixel;
@@ -605,14 +617,14 @@ client_setname(struct client_ctx *cc)
 		if (!xu_getstrprop(cc->win, XA_WM_NAME, &newname))
 			newname = xstrdup("");
 
-	TAILQ_FOREACH(wn, &cc->nameq, entry)
+	TAILQ_FOREACH(wn, &cc->nameq, entry) {
 		if (strcmp(wn->name, newname) == 0) {
 			/* Move to the last since we got a hit. */
 			TAILQ_REMOVE(&cc->nameq, wn, entry);
 			TAILQ_INSERT_TAIL(&cc->nameq, wn, entry);
 			goto match;
 		}
-
+	}
 	wn = xmalloc(sizeof(*wn));
 	wn->name = newname;
 	TAILQ_INSERT_TAIL(&cc->nameq, wn, entry);
@@ -638,27 +650,26 @@ client_cycle(struct screen_ctx *sc, int flags)
 	struct client_ctx	*oldcc, *newcc;
 	int			 again = 1;
 
-	oldcc = client_current();
-
-	/* If no windows then you cant cycle */
-	if (TAILQ_EMPTY(&sc->mruq))
+	if (TAILQ_EMPTY(&sc->clientq))
 		return;
 
+	oldcc = client_current();
 	if (oldcc == NULL)
 		oldcc = (flags & CWM_RCYCLE ?
-		    TAILQ_LAST(&sc->mruq, cycle_entry_q) :
-		    TAILQ_FIRST(&sc->mruq));
+		    TAILQ_LAST(&sc->clientq, client_ctx_q) :
+		    TAILQ_FIRST(&sc->clientq));
 
 	newcc = oldcc;
 	while (again) {
 		again = 0;
 
-		newcc = (flags & CWM_RCYCLE ? client_mruprev(newcc) :
-		    client_mrunext(newcc));
+		newcc = (flags & CWM_RCYCLE ? client_prev(newcc) :
+		    client_next(newcc));
 
 		/* Only cycle visible and non-ignored windows. */
 		if ((newcc->flags & (CLIENT_HIDDEN|CLIENT_IGNORE))
-			|| ((flags & CWM_INGROUP) && (newcc->group != oldcc->group)))
+		    || ((flags & CWM_INGROUP) &&
+			(newcc->group != oldcc->group)))
 			again = 1;
 
 		/* Is oldcc the only non-hidden window? */
@@ -691,23 +702,23 @@ client_cycle_leave(struct screen_ctx *sc)
 }
 
 static struct client_ctx *
-client_mrunext(struct client_ctx *cc)
+client_next(struct client_ctx *cc)
 {
 	struct screen_ctx	*sc = cc->sc;
 	struct client_ctx	*ccc;
 
-	return ((ccc = TAILQ_NEXT(cc, mru_entry)) != NULL ?
-	    ccc : TAILQ_FIRST(&sc->mruq));
+	return((ccc = TAILQ_NEXT(cc, entry)) != NULL ?
+	    ccc : TAILQ_FIRST(&sc->clientq));
 }
 
 static struct client_ctx *
-client_mruprev(struct client_ctx *cc)
+client_prev(struct client_ctx *cc)
 {
 	struct screen_ctx	*sc = cc->sc;
 	struct client_ctx	*ccc;
 
-	return ((ccc = TAILQ_PREV(cc, cycle_entry_q, mru_entry)) != NULL ?
-	    ccc : TAILQ_LAST(&sc->mruq, cycle_entry_q));
+	return((ccc = TAILQ_PREV(cc, client_ctx_q, entry)) != NULL ?
+	    ccc : TAILQ_LAST(&sc->clientq, client_ctx_q));
 }
 
 static void
@@ -765,8 +776,8 @@ client_mtf(struct client_ctx *cc)
 {
 	struct screen_ctx	*sc = cc->sc;
 
-	TAILQ_REMOVE(&sc->mruq, cc, mru_entry);
-	TAILQ_INSERT_HEAD(&sc->mruq, cc, mru_entry);
+	TAILQ_REMOVE(&sc->clientq, cc, entry);
+	TAILQ_INSERT_HEAD(&sc->clientq, cc, entry);
 }
 
 void
@@ -871,11 +882,12 @@ client_mwm_hints(struct client_ctx *cc)
 	struct mwm_hints	*mwmh;
 
 	if (xu_getprop(cc->win, cwmh[_MOTIF_WM_HINTS], cwmh[_MOTIF_WM_HINTS],
-	    PROP_MWM_HINTS_ELEMENTS, (unsigned char **)&mwmh) == MWM_NUMHINTS)
+	    PROP_MWM_HINTS_ELEMENTS, (unsigned char **)&mwmh) == MWM_NUMHINTS) {
 		if (mwmh->flags & MWM_HINTS_DECORATIONS &&
 		    !(mwmh->decorations & MWM_DECOR_ALL) &&
 		    !(mwmh->decorations & MWM_DECOR_BORDER))
 			cc->bwidth = 0;
+	}
 }
 
 void
@@ -896,7 +908,7 @@ client_transient(struct client_ctx *cc)
 static int
 client_inbound(struct client_ctx *cc, int x, int y)
 {
-	return (x < cc->geom.w && x >= 0 &&
+	return(x < cc->geom.w && x >= 0 &&
 	    y < cc->geom.h && y >= 0);
 }
 
@@ -916,15 +928,15 @@ client_snapcalc(int n0, int n1, int e0, int e1, int snapdist)
 	/* possible to snap in both directions */
 	if (s0 != 0 && s1 != 0)
 		if (abs(s0) < abs(s1))
-			return (s0);
+			return(s0);
 		else
-			return (s1);
+			return(s1);
 	else if (s0 != 0)
-		return (s0);
+		return(s0);
 	else if (s1 != 0)
-		return (s1);
+		return(s1);
 	else
-		return (0);
+		return(0);
 }
 
 void
@@ -940,7 +952,7 @@ client_htile(struct client_ctx *cc)
 		return;
 	i = n = 0;
 
-	TAILQ_FOREACH(ci, &gc->clients, group_entry) {
+	TAILQ_FOREACH(ci, &gc->clientq, group_entry) {
 		if (ci->flags & CLIENT_HIDDEN ||
 		    ci->flags & CLIENT_IGNORE || (ci == cc))
 			continue;
@@ -968,7 +980,7 @@ client_htile(struct client_ctx *cc)
 	x = xine.x;
 	w = xine.w / n;
 	h = xine.h - mh;
-	TAILQ_FOREACH(ci, &gc->clients, group_entry) {
+	TAILQ_FOREACH(ci, &gc->clientq, group_entry) {
 		if (ci->flags & CLIENT_HIDDEN ||
 		    ci->flags & CLIENT_IGNORE || (ci == cc))
 			continue;
@@ -999,7 +1011,7 @@ client_vtile(struct client_ctx *cc)
 		return;
 	i = n = 0;
 
-	TAILQ_FOREACH(ci, &gc->clients, group_entry) {
+	TAILQ_FOREACH(ci, &gc->clientq, group_entry) {
 		if (ci->flags & CLIENT_HIDDEN ||
 		    ci->flags & CLIENT_IGNORE || (ci == cc))
 			continue;
@@ -1027,7 +1039,7 @@ client_vtile(struct client_ctx *cc)
 	y = xine.y;
 	h = xine.h / n;
 	w = xine.w - mw;
-	TAILQ_FOREACH(ci, &gc->clients, group_entry) {
+	TAILQ_FOREACH(ci, &gc->clientq, group_entry) {
 		if (ci->flags & CLIENT_HIDDEN ||
 		    ci->flags & CLIENT_IGNORE || (ci == cc))
 			continue;
diff --git a/conf.c b/conf.c
index 390368c..94c1773 100644
--- a/conf.c
+++ b/conf.c
@@ -382,12 +382,12 @@ static const struct {
 	{ "rcycleingroup", kbfunc_client_cycle, CWM_WIN,
 	    {.i = CWM_RCYCLE|CWM_INGROUP} },
 	{ "grouptoggle", kbfunc_client_grouptoggle, CWM_WIN, {0}},
-	{ "sticky", kbfunc_client_sticky, CWM_WIN, {0} },
-	{ "fullscreen", kbfunc_client_fullscreen, CWM_WIN, {0} },
-	{ "maximize", kbfunc_client_maximize, CWM_WIN, {0} },
-	{ "vmaximize", kbfunc_client_vmaximize, CWM_WIN, {0} },
-	{ "hmaximize", kbfunc_client_hmaximize, CWM_WIN, {0} },
-	{ "freeze", kbfunc_client_freeze, CWM_WIN, {0} },
+	{ "sticky", kbfunc_client_toggle_sticky, CWM_WIN, {0} },
+	{ "fullscreen", kbfunc_client_toggle_fullscreen, CWM_WIN, {0} },
+	{ "maximize", kbfunc_client_toggle_maximize, CWM_WIN, {0} },
+	{ "vmaximize", kbfunc_client_toggle_vmaximize, CWM_WIN, {0} },
+	{ "hmaximize", kbfunc_client_toggle_hmaximize, CWM_WIN, {0} },
+	{ "freeze", kbfunc_client_toggle_freeze, CWM_WIN, {0} },
 	{ "restart", kbfunc_cwm_status, 0, {.i = CWM_RESTART} },
 	{ "quit", kbfunc_cwm_status, 0, {.i = CWM_QUIT} },
 	{ "exec", kbfunc_exec, 0, {.i = CWM_EXEC_PROGRAM} },
@@ -475,14 +475,14 @@ conf_bind_getmask(const char *name, unsigned int *mask)
 
 	*mask = 0;
 	if ((dash = strchr(name, '-')) == NULL)
-		return (name);
+		return(name);
 	for (i = 0; i < nitems(bind_mods); i++) {
 		if ((ch = strchr(name, bind_mods[i].ch)) != NULL && ch < dash)
 			*mask |= bind_mods[i].mask;
 	}
 
 	/* Skip past modifiers. */
-	return (dash + 1);
+	return(dash + 1);
 }
 
 int
@@ -500,7 +500,7 @@ conf_bind_kbd(struct conf *c, const char *bind, const char *cmd)
 	if (kb->press.keysym == NoSymbol) {
 		warnx("unknown symbol: %s", key);
 		free(kb);
-		return (0);
+		return(0);
 	}
 
 	/* We now have the correct binding, remove duplicates. */
@@ -508,7 +508,7 @@ conf_bind_kbd(struct conf *c, const char *bind, const char *cmd)
 
 	if (strcmp("unmap", cmd) == 0) {
 		free(kb);
-		return (1);
+		return(1);
 	}
 
 	for (i = 0; i < nitems(name_to_func); i++) {
@@ -520,7 +520,7 @@ conf_bind_kbd(struct conf *c, const char *bind, const char *cmd)
 		kb->argument = name_to_func[i].argument;
 		kb->argtype |= ARG_INT;
 		TAILQ_INSERT_TAIL(&c->keybindingq, kb, entry);
-		return (1);
+		return(1);
 	}
 
 	kb->callback = kbfunc_cmdexec;
@@ -528,7 +528,7 @@ conf_bind_kbd(struct conf *c, const char *bind, const char *cmd)
 	kb->argument.c = xstrdup(cmd);
 	kb->argtype |= ARG_CHAR;
 	TAILQ_INSERT_TAIL(&c->keybindingq, kb, entry);
-	return (1);
+	return(1);
 }
 
 static void
@@ -564,7 +564,7 @@ conf_bind_mouse(struct conf *c, const char *bind, const char *cmd)
 	if (errstr) {
 		warnx("button number is %s: %s", errstr, button);
 		free(mb);
-		return (0);
+		return(0);
 	}
 
 	/* We now have the correct binding, remove duplicates. */
@@ -572,7 +572,7 @@ conf_bind_mouse(struct conf *c, const char *bind, const char *cmd)
 
 	if (strcmp("unmap", cmd) == 0) {
 		free(mb);
-		return (1);
+		return(1);
 	}
 
 	for (i = 0; i < nitems(name_to_func); i++) {
@@ -583,10 +583,10 @@ conf_bind_mouse(struct conf *c, const char *bind, const char *cmd)
 		mb->flags = name_to_func[i].flags;
 		mb->argument = name_to_func[i].argument;
 		TAILQ_INSERT_TAIL(&c->mousebindingq, mb, entry);
-		return (1);
+		return(1);
 	}
 
-	return (0);
+	return(0);
 }
 
 static void
@@ -675,6 +675,7 @@ static char *ewmhints[] = {
 	"_NET_WM_STATE_STICKY",
 	"_NET_WM_STATE_MAXIMIZED_VERT",
 	"_NET_WM_STATE_MAXIMIZED_HORZ",
+	"_NET_WM_STATE_HIDDEN",
 	"_NET_WM_STATE_FULLSCREEN",
 	"_NET_WM_STATE_DEMANDS_ATTENTION",
 };
diff --git a/group.c b/group.c
index cdc5912..1cae681 100644
--- a/group.c
+++ b/group.c
@@ -33,7 +33,7 @@
 #include "calmwm.h"
 
 static void		 group_assign(struct group_ctx *, struct client_ctx *);
-static void		 group_restack(struct screen_ctx *, struct group_ctx *);
+static void		 group_restack(struct group_ctx *);
 static void		 group_setactive(struct screen_ctx *, long);
 
 const char *num_to_name[] = {
@@ -45,55 +45,55 @@ static void
 group_assign(struct group_ctx *gc, struct client_ctx *cc)
 {
 	if (cc->group != NULL)
-		TAILQ_REMOVE(&cc->group->clients, cc, group_entry);
+		TAILQ_REMOVE(&cc->group->clientq, cc, group_entry);
 
 	cc->group = gc;
 
 	if (cc->group != NULL)
-		TAILQ_INSERT_TAIL(&gc->clients, cc, group_entry);
+		TAILQ_INSERT_TAIL(&gc->clientq, cc, group_entry);
 
 	xu_ewmh_net_wm_desktop(cc);
 }
 
 void
-group_hide(struct screen_ctx *sc, struct group_ctx *gc)
+group_hide(struct group_ctx *gc)
 {
 	struct client_ctx	*cc;
 
-	screen_updatestackingorder(sc);
+	screen_updatestackingorder(gc->sc);
 
-	TAILQ_FOREACH(cc, &gc->clients, group_entry)
+	TAILQ_FOREACH(cc, &gc->clientq, group_entry)
 		client_hide(cc);
 }
 
 void
-group_show(struct screen_ctx *sc, struct group_ctx *gc)
+group_show(struct group_ctx *gc)
 {
 	struct client_ctx	*cc;
 
-	TAILQ_FOREACH(cc, &gc->clients, group_entry)
+	TAILQ_FOREACH(cc, &gc->clientq, group_entry)
 		client_unhide(cc);
 
-	group_restack(sc, gc);
-	group_setactive(sc, gc->num);
+	group_restack(gc);
+	group_setactive(gc->sc, gc->num);
 }
 
 static void
-group_restack(struct screen_ctx *sc, struct group_ctx *gc)
+group_restack(struct group_ctx *gc)
 {
 	struct client_ctx	*cc;
 	Window			*winlist;
 	int			 i, lastempty = -1;
 	int			 nwins = 0, highstack = 0;
 
-	TAILQ_FOREACH(cc, &gc->clients, group_entry) {
+	TAILQ_FOREACH(cc, &gc->clientq, group_entry) {
 		if (cc->stackingorder > highstack)
 			highstack = cc->stackingorder;
 	}
 	winlist = xcalloc((highstack + 1), sizeof(*winlist));
 
 	/* Invert the stacking order for XRestackWindows(). */
-	TAILQ_FOREACH(cc, &gc->clients, group_entry) {
+	TAILQ_FOREACH(cc, &gc->clientq, group_entry) {
 		winlist[highstack - cc->stackingorder] = cc->win;
 		nwins++;
 	}
@@ -116,16 +116,19 @@ group_restack(struct screen_ctx *sc, struct group_ctx *gc)
 void
 group_init(struct screen_ctx *sc)
 {
-	int	 i;
+	struct group_ctx	*gc;
+	int			 i;
 
 	TAILQ_INIT(&sc->groupq);
 	sc->group_hideall = 0;
 
 	for (i = 0; i < CALMWM_NGROUPS; i++) {
-		TAILQ_INIT(&sc->groups[i].clients);
-		sc->groups[i].name = xstrdup(num_to_name[i]);
-		sc->groups[i].num = i;
-		TAILQ_INSERT_TAIL(&sc->groupq, &sc->groups[i], entry);
+		gc = xcalloc(1, sizeof(*gc));
+		gc->sc = sc;
+		TAILQ_INIT(&gc->clientq);
+		gc->name = xstrdup(num_to_name[i]);
+		gc->num = i;
+		TAILQ_INSERT_TAIL(&sc->groupq, gc, entry);
 	}
 
 	xu_ewmh_net_desktop_names(sc);
@@ -140,7 +143,13 @@ group_init(struct screen_ctx *sc)
 static void
 group_setactive(struct screen_ctx *sc, long idx)
 {
-	sc->group_active = &sc->groups[idx];
+	struct group_ctx	*gc;
+
+	TAILQ_FOREACH(gc, &sc->groupq, entry) {
+		if (gc->num == idx)
+			break;
+	}
+	sc->group_active = gc;
 
 	xu_ewmh_net_current_desktop(sc, idx);
 }
@@ -154,11 +163,14 @@ group_movetogroup(struct client_ctx *cc, int idx)
 	if (idx < 0 || idx >= CALMWM_NGROUPS)
 		errx(1, "group_movetogroup: index out of range (%d)", idx);
 
-	gc = &sc->groups[idx];
+	TAILQ_FOREACH(gc, &sc->groupq, entry) {
+		if (gc->num == idx)
+			break;
+	}
 
 	if (cc->group == gc)
 		return;
-	if (group_hidden_state(gc))
+	if (group_holds_only_hidden(gc))
 		client_hide(cc);
 	group_assign(gc, cc);
 }
@@ -190,16 +202,25 @@ group_sticky_toggle_exit(struct client_ctx *cc)
 	client_draw_border(cc);
 }
 
-/*
- * If all clients in a group are hidden, then the group state is hidden.
- */
 int
-group_hidden_state(struct group_ctx *gc)
+group_holds_only_sticky(struct group_ctx *gc)
+{
+	struct client_ctx	*cc;
+
+	TAILQ_FOREACH(cc, &gc->clientq, group_entry) {
+		if (!(cc->flags & CLIENT_STICKY))
+			return(0);
+	}
+	return(1);
+}
+
+int
+group_holds_only_hidden(struct group_ctx *gc)
 {
 	struct client_ctx	*cc;
 	int			 hidden = 0, same = 0;
 
-	TAILQ_FOREACH(cc, &gc->clients, group_entry) {
+	TAILQ_FOREACH(cc, &gc->clientq, group_entry) {
 		if (cc->flags & CLIENT_STICKY)
 			continue;
 		if (hidden == ((cc->flags & CLIENT_HIDDEN) ? 1 : 0))
@@ -220,14 +241,17 @@ group_hidetoggle(struct screen_ctx *sc, int idx)
 	if (idx < 0 || idx >= CALMWM_NGROUPS)
 		errx(1, "group_hidetoggle: index out of range (%d)", idx);
 
-	gc = &sc->groups[idx];
+	TAILQ_FOREACH(gc, &sc->groupq, entry) {
+		if (gc->num == idx)
+			break;
+	}
 
-	if (group_hidden_state(gc))
-		group_show(sc, gc);
+	if (group_holds_only_hidden(gc))
+		group_show(gc);
 	else {
-		group_hide(sc, gc);
+		group_hide(gc);
 		/* make clients stick to empty group */
-		if (TAILQ_EMPTY(&gc->clients))
+		if (TAILQ_EMPTY(&gc->clientq))
 			group_setactive(sc, idx);
 	}
 }
@@ -242,9 +266,9 @@ group_only(struct screen_ctx *sc, int idx)
 
 	TAILQ_FOREACH(gc, &sc->groupq, entry) {
 		if (gc->num == idx)
-			group_show(sc, gc);
+			group_show(gc);
 		else
-			group_hide(sc, gc);
+			group_hide(gc);
 	}
 }
 
@@ -268,19 +292,19 @@ group_cycle(struct screen_ctx *sc, int flags)
 		if (gc == sc->group_active)
 			break;
 
-		if (!TAILQ_EMPTY(&gc->clients) && showgroup == NULL)
+		if (!group_holds_only_sticky(gc) && showgroup == NULL)
 			showgroup = gc;
-		else if (!group_hidden_state(gc))
-			group_hide(sc, gc);
+		else if (!group_holds_only_hidden(gc))
+			group_hide(gc);
 	}
 
 	if (showgroup == NULL)
 		return;
 
-	group_hide(sc, sc->group_active);
+	group_hide(sc->group_active);
 
-	if (group_hidden_state(showgroup))
-		group_show(sc, showgroup);
+	if (group_holds_only_hidden(showgroup))
+		group_show(showgroup);
 	else
 		group_setactive(sc, showgroup->num);
 }
@@ -292,9 +316,9 @@ group_alltoggle(struct screen_ctx *sc)
 
 	TAILQ_FOREACH(gc, &sc->groupq, entry) {
 		if (sc->group_hideall)
-			group_show(sc, gc);
+			group_show(gc);
 		else
-			group_hide(sc, gc);
+			group_hide(gc);
 	}
 	sc->group_hideall = !sc->group_hideall;
 }
diff --git a/kbfunc.c b/kbfunc.c
index 78cb9fd..84164ab 100644
--- a/kbfunc.c
+++ b/kbfunc.c
@@ -60,7 +60,7 @@ kbfunc_client_moveresize(struct client_ctx *cc, union arg *arg)
 	int			 x, y, flags, amt;
 	unsigned int		 mx, my;
 
-	if (cc->flags & CLIENT_FREEZE)
+	if (cc->flags & (CLIENT_FREEZE|CLIENT_STICKY))
 		return;
 
 	mx = my = 0;
@@ -151,7 +151,7 @@ kbfunc_client_search(struct client_ctx *cc, union arg *arg)
 	old_cc = client_current();
 
 	TAILQ_INIT(&menuq);
-	TAILQ_FOREACH(cc, &Clientq, entry)
+	TAILQ_FOREACH(cc, &sc->clientq, entry)
 		menuq_add(&menuq, cc, "%s", cc->name);
 
 	if ((mi = menu_filter(sc, &menuq, "window", NULL, 0,
@@ -281,8 +281,7 @@ kbfunc_exec(struct client_ctx *cc, union arg *arg)
 			(void)memset(tpath, '\0', sizeof(tpath));
 			l = snprintf(tpath, sizeof(tpath), "%s/%s", paths[i],
 			    dp->d_name);
-			/* check for truncation etc */
-			if (l == -1 || l >= (int)sizeof(tpath))
+			if (l == -1 || l >= sizeof(tpath))
 				continue;
 			if (access(tpath, X_OK) == 0)
 				menuq_add(&menuq, NULL, "%s", dp->d_name);
@@ -373,8 +372,9 @@ kbfunc_ssh(struct client_ctx *cc, union arg *arg)
 			goto out;
 		l = snprintf(path, sizeof(path), "%s -T '[ssh] %s' -e ssh %s",
 		    cmd->path, mi->text, mi->text);
-		if (l != -1 && l < sizeof(path))
-			u_spawn(path);
+		if (l == -1 || l >= sizeof(path))
+			goto out;
+		u_spawn(path);
 	}
 out:
 	if (mi != NULL && mi->dummy)
@@ -448,39 +448,39 @@ kbfunc_client_movetogroup(struct client_ctx *cc, union arg *arg)
 }
 
 void
-kbfunc_client_sticky(struct client_ctx *cc, union arg *arg)
+kbfunc_client_toggle_sticky(struct client_ctx *cc, union arg *arg)
 {
-	client_sticky(cc);
+	client_toggle_sticky(cc);
 }
 
 void
-kbfunc_client_fullscreen(struct client_ctx *cc, union arg *arg)
+kbfunc_client_toggle_fullscreen(struct client_ctx *cc, union arg *arg)
 {
-	client_fullscreen(cc);
+	client_toggle_fullscreen(cc);
 }
 
 void
-kbfunc_client_maximize(struct client_ctx *cc, union arg *arg)
+kbfunc_client_toggle_maximize(struct client_ctx *cc, union arg *arg)
 {
-	client_maximize(cc);
+	client_toggle_maximize(cc);
 }
 
 void
-kbfunc_client_vmaximize(struct client_ctx *cc, union arg *arg)
+kbfunc_client_toggle_vmaximize(struct client_ctx *cc, union arg *arg)
 {
-	client_vmaximize(cc);
+	client_toggle_vmaximize(cc);
 }
 
 void
-kbfunc_client_hmaximize(struct client_ctx *cc, union arg *arg)
+kbfunc_client_toggle_hmaximize(struct client_ctx *cc, union arg *arg)
 {
-	client_hmaximize(cc);
+	client_toggle_hmaximize(cc);
 }
 
 void
-kbfunc_client_freeze(struct client_ctx *cc, union arg *arg)
+kbfunc_client_toggle_freeze(struct client_ctx *cc, union arg *arg)
 {
-	client_freeze(cc);
+	client_toggle_freeze(cc);
 }
 
 void
diff --git a/menu.c b/menu.c
index efbf756..0203b33 100644
--- a/menu.c
+++ b/menu.c
@@ -126,7 +126,7 @@ menu_filter(struct screen_ctx *sc, struct menu_q *menuq, const char *prompt,
 	if (xu_ptr_grab(sc->menuwin, MENUGRABMASK,
 	    Conf.cursor[CF_QUESTION]) < 0) {
 		XUnmapWindow(X_Dpy, sc->menuwin);
-		return (NULL);
+		return(NULL);
 	}
 
 	XGetInputFocus(X_Dpy, &focuswin, &focusrevert);
@@ -180,7 +180,7 @@ out:
 	XUnmapWindow(X_Dpy, sc->menuwin);
 	XUngrabKeyboard(X_Dpy, CurrentTime);
 
-	return (mi);
+	return(mi);
 }
 
 static struct menu *
@@ -210,7 +210,7 @@ menu_complete_path(struct menu_ctx *mc)
 	else if (!mr->abort)
 		strlcpy(mr->text,  mc->searchstr, sizeof(mr->text));
 	free(path);
-	return (mr);
+	return(mr);
 }
 
 static struct menu *
@@ -225,7 +225,7 @@ menu_handle_key(XEvent *e, struct menu_ctx *mc, struct menu_q *menuq,
 	wchar_t 	 wc;
 
 	if (menu_keycode(&e->xkey, &ctl, chr) < 0)
-		return (NULL);
+		return(NULL);
 
 	switch (ctl) {
 	case CTL_ERASEONE:
@@ -266,7 +266,7 @@ menu_handle_key(XEvent *e, struct menu_ctx *mc, struct menu_q *menuq,
 			mi->dummy = 1;
 		}
 		mi->abort = 0;
-		return (mi);
+		return(mi);
 	case CTL_WIPE:
 		mc->searchstr[0] = '\0';
 		mc->changed = 1;
@@ -281,7 +281,7 @@ menu_handle_key(XEvent *e, struct menu_ctx *mc, struct menu_q *menuq,
 			if ((mc->flags & CWM_MENU_FILE) &&
 			    (strncmp(mc->searchstr, mi->text,
 					strlen(mi->text))) == 0)
-				return (menu_complete_path(mc));
+				return(menu_complete_path(mc));
 
 			/*
 			 * Put common prefix of the results into searchstr
@@ -306,7 +306,7 @@ menu_handle_key(XEvent *e, struct menu_ctx *mc, struct menu_q *menuq,
 		mi->text[0] = '\0';
 		mi->dummy = 1;
 		mi->abort = 1;
-		return (mi);
+		return(mi);
 	default:
 		break;
 	}
@@ -329,7 +329,7 @@ menu_handle_key(XEvent *e, struct menu_ctx *mc, struct menu_q *menuq,
 		mc->listing = 0;
 	}
 
-	return (NULL);
+	return(NULL);
 }
 
 static void
@@ -497,7 +497,7 @@ menu_handle_release(XEvent *e, struct menu_ctx *mc, struct menu_q *resultq)
 		mi->text[0] = '\0';
 		mi->dummy = 1;
 	}
-	return (mi);
+	return(mi);
 }
 
 static int
@@ -517,7 +517,7 @@ menu_calc_entry(struct menu_ctx *mc, int x, int y)
 	if (mc->hasprompt && entry == 0)
 		entry = -1;
 
-	return (entry);
+	return(entry);
 }
 
 static int
@@ -597,12 +597,12 @@ menu_keycode(XKeyEvent *ev, enum ctltype *ctl, char *chr)
 	}
 
 	if (*ctl != CTL_NONE)
-		return (0);
+		return(0);
 
 	if (XLookupString(ev, chr, 32, &ks, NULL) < 0)
-		return (-1);
+		return(-1);
 
-	return (0);
+	return(0);
 }
 
 void
diff --git a/mousefunc.c b/mousefunc.c
index 3442f67..a3d9c6a 100644
--- a/mousefunc.c
+++ b/mousefunc.c
@@ -73,7 +73,7 @@ mousefunc_client_resize(struct client_ctx *cc, union arg *arg)
 	struct screen_ctx	*sc = cc->sc;
 	int			 x = cc->geom.x, y = cc->geom.y;
 
-	if (cc->flags & CLIENT_FREEZE)
+	if (cc->flags & (CLIENT_FREEZE|CLIENT_STICKY))
 		return;
 
 	client_raise(cc);
@@ -90,19 +90,18 @@ mousefunc_client_resize(struct client_ctx *cc, union arg *arg)
 
 		switch (ev.type) {
 		case MotionNotify:
+			/* not more than 60 times / second */
+			if ((ev.xmotion.time - ltime) <= (1000 / 60))
+				continue;
+			ltime = ev.xmotion.time;
+
 			mousefunc_sweep_calc(cc, x, y,
 			    ev.xmotion.x_root, ev.xmotion.y_root);
-
-			/* don't resize more than 60 times / second */
-			if ((ev.xmotion.time - ltime) > (1000 / 60)) {
-				ltime = ev.xmotion.time;
-				client_resize(cc, 1);
-				mousefunc_sweep_draw(cc);
-			}
+			client_resize(cc, 1);
+			mousefunc_sweep_draw(cc);
 			break;
 		case ButtonRelease:
-			if (ltime)
-				client_resize(cc, 1);
+			client_resize(cc, 1);
 			XUnmapWindow(X_Dpy, sc->menuwin);
 			XReparentWindow(X_Dpy, sc->menuwin, sc->rootwin, 0, 0);
 			xu_ptr_ungrab();
@@ -130,7 +129,7 @@ mousefunc_client_move(struct client_ctx *cc, union arg *arg)
 
 	client_raise(cc);
 
-	if (cc->flags & CLIENT_FREEZE)
+	if (cc->flags & (CLIENT_FREEZE|CLIENT_STICKY))
 		return;
 
 	if (xu_ptr_grab(cc->win, MOUSEMASK, Conf.cursor[CF_MOVE]) < 0)
@@ -143,6 +142,11 @@ mousefunc_client_move(struct client_ctx *cc, union arg *arg)
 
 		switch (ev.type) {
 		case MotionNotify:
+			/* not more than 60 times / second */
+			if ((ev.xmotion.time - ltime) <= (1000 / 60))
+				continue;
+			ltime = ev.xmotion.time;
+
 			cc->geom.x = ev.xmotion.x_root - px - cc->bwidth;
 			cc->geom.y = ev.xmotion.y_root - py - cc->bwidth;
 
@@ -156,15 +160,10 @@ mousefunc_client_move(struct client_ctx *cc, union arg *arg)
 			    cc->geom.y + cc->geom.h + (cc->bwidth * 2),
 			    xine.y, xine.y + xine.h, sc->snapdist);
 
-			/* don't move more than 60 times / second */
-			if ((ev.xmotion.time - ltime) > (1000 / 60)) {
-				ltime = ev.xmotion.time;
-				client_move(cc);
-			}
+			client_move(cc);
 			break;
 		case ButtonRelease:
-			if (ltime)
-				client_move(cc);
+			client_move(cc);
 			xu_ptr_ungrab();
 			return;
 		}
@@ -188,10 +187,10 @@ mousefunc_menu_group(struct client_ctx *cc, union arg *arg)
 
 	TAILQ_INIT(&menuq);
 	TAILQ_FOREACH(gc, &sc->groupq, entry) {
-		if (TAILQ_EMPTY(&gc->clients))
+		if (group_holds_only_sticky(gc))
 			continue;
 		menuq_add(&menuq, gc,
-		    group_hidden_state(gc) ? "%d: [%s]" : "%d: %s",
+		    group_holds_only_hidden(gc) ? "%d: [%s]" : "%d: %s",
 		    gc->num, gc->name);
 	}
 	if (TAILQ_EMPTY(&menuq))
@@ -200,8 +199,8 @@ mousefunc_menu_group(struct client_ctx *cc, union arg *arg)
 	if ((mi = menu_filter(sc, &menuq, NULL, NULL, 0,
 	    NULL, NULL)) != NULL) {
 		gc = (struct group_ctx *)mi->ctx;
-		(group_hidden_state(gc)) ?
-		    group_show(sc, gc) : group_hide(sc, gc);
+		(group_holds_only_hidden(gc)) ?
+		    group_show(gc) : group_hide(gc);
 	}
 
 	menuq_clear(&menuq);
@@ -219,7 +218,7 @@ mousefunc_menu_unhide(struct client_ctx *cc, union arg *arg)
 	old_cc = client_current();
 
 	TAILQ_INIT(&menuq);
-	TAILQ_FOREACH(cc, &Clientq, entry) {
+	TAILQ_FOREACH(cc, &sc->clientq, entry) {
 		if (cc->flags & CLIENT_HIDDEN) {
 			wname = (cc->label) ? cc->label : cc->name;
 			if (wname == NULL)
diff --git a/screen.c b/screen.c
index 02aefcc..2eefa0c 100644
--- a/screen.c
+++ b/screen.c
@@ -40,7 +40,7 @@ screen_init(int which)
 
 	sc = xcalloc(1, sizeof(*sc));
 
-	TAILQ_INIT(&sc->mruq);
+	TAILQ_INIT(&sc->clientq);
 	TAILQ_INIT(&sc->regionq);
 
 	sc->which = which;
@@ -79,16 +79,16 @@ screen_init(int which)
 }
 
 struct screen_ctx *
-screen_fromroot(Window rootwin)
+screen_find(Window win)
 {
 	struct screen_ctx	*sc;
 
-	TAILQ_FOREACH(sc, &Screenq, entry)
-		if (sc->rootwin == rootwin)
-			return (sc);
-
+	TAILQ_FOREACH(sc, &Screenq, entry) {
+		if (sc->rootwin == win)
+			return(sc);
+	}
 	/* XXX FAIL HERE */
-	return (TAILQ_FIRST(&Screenq));
+	return(TAILQ_FIRST(&Screenq));
 }
 
 void
@@ -133,7 +133,7 @@ screen_find_xinerama(struct screen_ctx *sc, int x, int y, int flags)
 		geom.w -= (sc->gap.left + sc->gap.right);
 		geom.h -= (sc->gap.top + sc->gap.bottom);
 	}
-	return (geom);
+	return(geom);
 }
 
 void
diff --git a/search.c b/search.c
index 4012400..49e3184 100644
--- a/search.c
+++ b/search.c
@@ -102,7 +102,7 @@ search_match_client(struct menu_q *menuq, struct menu_q *resultq, char *search)
 			tier++;
 
 		/* Clients that are hidden get ranked one up. */
-		if (cc->flags & CLIENT_HIDDEN && tier > 0)
+		if ((cc->flags & CLIENT_HIDDEN) && (tier > 0))
 			tier--;
 
 		assert(tier < nitems(tierp));
@@ -194,13 +194,13 @@ search_match_path(struct menu_q *menuq, struct menu_q *resultq, char *search, in
 static void
 search_match_path_exec(struct menu_q *menuq, struct menu_q *resultq, char *search)
 {
-	return (search_match_path(menuq, resultq, search, PATH_EXEC));
+	return(search_match_path(menuq, resultq, search, PATH_EXEC));
 }
 
 void
 search_match_path_any(struct menu_q *menuq, struct menu_q *resultq, char *search)
 {
-	return (search_match_path(menuq, resultq, search, PATH_ANY));
+	return(search_match_path(menuq, resultq, search, PATH_ANY));
 }
 
 void
@@ -254,13 +254,13 @@ strsubmatch(char *sub, char *str, int zeroidx)
 	unsigned int	 n, flen;
 
 	if (sub == NULL || str == NULL)
-		return (0);
+		return(0);
 
 	len = strlen(str);
 	sublen = strlen(sub);
 
 	if (sublen > len)
-		return (0);
+		return(0);
 
 	if (!zeroidx)
 		flen = len - sublen;
@@ -269,7 +269,7 @@ strsubmatch(char *sub, char *str, int zeroidx)
 
 	for (n = 0; n <= flen; n++)
 		if (strncasecmp(sub, str + n, sublen) == 0)
-			return (1);
+			return(1);
 
-	return (0);
+	return(0);
 }
diff --git a/xevents.c b/xevents.c
index c72bd0c..de6d41b 100644
--- a/xevents.c
+++ b/xevents.c
@@ -82,7 +82,7 @@ xev_handle_maprequest(XEvent *ee)
 	if ((cc = client_find(e->window)) == NULL)
 		cc = client_init(e->window, NULL);
 
-	if ((cc != NULL) && ((cc->flags & CLIENT_IGNORE) == 0))
+	if ((cc != NULL) && (!(cc->flags & CLIENT_IGNORE)))
 		client_ptrwarp(cc);
 }
 
@@ -239,7 +239,7 @@ xev_handle_buttonpress(XEvent *ee)
 		if (e->window != e->root)
 			return;
 		cc = &fakecc;
-		cc->sc = screen_fromroot(e->window);
+		cc->sc = screen_find(e->window);
 	}
 
 	(*mb->callback)(cc, &mb->argument);
@@ -289,7 +289,7 @@ xev_handle_keypress(XEvent *ee)
 			return;
 	} else {
 		cc = &fakecc;
-		cc->sc = screen_fromroot(e->window);
+		cc->sc = screen_find(e->window);
 	}
 
 	(*kb->callback)(cc, &kb->argument);
@@ -306,7 +306,7 @@ xev_handle_keyrelease(XEvent *ee)
 	KeySym			 keysym;
 	unsigned int		 i;
 
-	sc = screen_fromroot(e->root);
+	sc = screen_find(e->root);
 
 	keysym = XkbKeycodeToKeysym(X_Dpy, e->keycode, 0, 0);
 	for (i = 0; i < nitems(modkeys); i++) {
@@ -324,7 +324,7 @@ xev_handle_clientmessage(XEvent *ee)
 	struct client_ctx	*cc, *old_cc;
 	struct screen_ctx       *sc;
 
-	sc = screen_fromroot(e->window);
+	sc = screen_find(e->window);
 
 	if ((cc = client_find(e->window)) == NULL && e->window != sc->rootwin)
 		return;
diff --git a/xmalloc.c b/xmalloc.c
index 675a0ff..cb24c26 100644
--- a/xmalloc.c
+++ b/xmalloc.c
@@ -42,7 +42,7 @@ xmalloc(size_t siz)
 	if ((p = malloc(siz)) == NULL)
 		err(1, "malloc");
 
-	return (p);
+	return(p);
 }
 
 void *
@@ -57,7 +57,7 @@ xcalloc(size_t no, size_t siz)
 	if ((p = calloc(no, siz)) == NULL)
 		err(1, "calloc");
 
-	return (p);
+	return(p);
 }
 
 char *
@@ -68,7 +68,7 @@ xstrdup(const char *str)
 	if ((p = strdup(str)) == NULL)
 		err(1, "strdup");
 
-	return (p);
+	return(p);
 }
 
 int
@@ -84,5 +84,5 @@ xasprintf(char **ret, const char *fmt, ...)
 	if (i < 0 || *ret == NULL)
 		err(1, "asprintf");
 
-	return (i);
+	return(i);
 }
diff --git a/xutil.c b/xutil.c
index dd5bbc1..7765413 100644
--- a/xutil.c
+++ b/xutil.c
@@ -74,7 +74,7 @@ xu_key_ungrab(Window win)
 int
 xu_ptr_grab(Window win, unsigned int mask, Cursor curs)
 {
-	return (XGrabPointer(X_Dpy, win, False, mask,
+	return(XGrabPointer(X_Dpy, win, False, mask,
 	    GrabModeAsync, GrabModeAsync,
 	    None, curs, CurrentTime) == GrabSuccess ? 0 : -1);
 }
@@ -82,7 +82,7 @@ xu_ptr_grab(Window win, unsigned int mask, Cursor curs)
 int
 xu_ptr_regrab(unsigned int mask, Cursor curs)
 {
-	return (XChangeActivePointerGrab(X_Dpy, mask,
+	return(XChangeActivePointerGrab(X_Dpy, mask,
 	    curs, CurrentTime) == GrabSuccess ? 0 : -1);
 }
 
@@ -117,12 +117,12 @@ xu_getprop(Window win, Atom atm, Atom type, long len, unsigned char **p)
 
 	if (XGetWindowProperty(X_Dpy, win, atm, 0L, len, False, type,
 	    &realtype, &format, &n, &extra, p) != Success || *p == NULL)
-		return (-1);
+		return(-1);
 
 	if (n == 0)
 		XFree(*p);
 
-	return (n);
+	return(n);
 }
 
 int
@@ -135,7 +135,7 @@ xu_getstrprop(Window win, Atom atm, char **text) {
 
 	XGetTextProperty(X_Dpy, win, &prop, atm);
 	if (!prop.nitems)
-		return (0);
+		return(0);
 
 	if (Xutf8TextPropertyToTextList(X_Dpy, &prop, &list,
 	    &nitems) == Success && nitems > 0 && *list) {
@@ -154,7 +154,7 @@ xu_getstrprop(Window win, Atom atm, char **text) {
 
 	XFree(prop.value);
 
-	return (nitems);
+	return(nitems);
 }
 
 /* Root Window Properties */
@@ -214,13 +214,13 @@ xu_ewmh_net_client_list(struct screen_ctx *sc)
 	Window			*winlist;
 	int			 i = 0, j = 0;
 
-	TAILQ_FOREACH(cc, &Clientq, entry)
+	TAILQ_FOREACH(cc, &sc->clientq, entry)
 		i++;
 	if (i == 0)
 		return;
 
 	winlist = xcalloc(i, sizeof(*winlist));
-	TAILQ_FOREACH(cc, &Clientq, entry)
+	TAILQ_FOREACH(cc, &sc->clientq, entry)
 		winlist[j++] = cc->win;
 	XChangeProperty(X_Dpy, sc->rootwin, ewmh[_NET_CLIENT_LIST],
 	    XA_WINDOW, 32, PropModeReplace, (unsigned char *)winlist, i);
@@ -351,13 +351,13 @@ xu_ewmh_get_net_wm_state(struct client_ctx *cc, int *n)
 
 	if ((*n = xu_getprop(cc->win, ewmh[_NET_WM_STATE], XA_ATOM, 64L,
 	    (unsigned char **)&p)) <= 0)
-		return (NULL);
+		return(NULL);
 
 	state = xcalloc(*n, sizeof(Atom));
 	(void)memcpy(state, p, *n * sizeof(Atom));
 	XFree((char *)p);
 
-	return (state);
+	return(state);
 }
 
 void
@@ -372,16 +372,19 @@ xu_ewmh_handle_net_wm_state_msg(struct client_ctx *cc, int action,
 	} handlers[] = {
 		{ _NET_WM_STATE_STICKY,
 			CLIENT_STICKY,
-			client_sticky },
+			client_toggle_sticky },
 		{ _NET_WM_STATE_MAXIMIZED_VERT,
 			CLIENT_VMAXIMIZED,
-			client_vmaximize },
+			client_toggle_vmaximize },
 		{ _NET_WM_STATE_MAXIMIZED_HORZ,
 			CLIENT_HMAXIMIZED,
-			client_hmaximize },
+			client_toggle_hmaximize },
+		{ _NET_WM_STATE_HIDDEN,
+			CLIENT_HIDDEN,
+			client_toggle_hidden },
 		{ _NET_WM_STATE_FULLSCREEN,
 			CLIENT_FULLSCREEN,
-			client_fullscreen },
+			client_toggle_fullscreen },
 		{ _NET_WM_STATE_DEMANDS_ATTENTION,
 			CLIENT_URGENCY,
 			client_urgency },
@@ -393,7 +396,7 @@ xu_ewmh_handle_net_wm_state_msg(struct client_ctx *cc, int action,
 			continue;
 		switch (action) {
 		case _NET_WM_STATE_ADD:
-			if ((cc->flags & handlers[i].property) == 0)
+			if (!(cc->flags & handlers[i].property))
 				handlers[i].toggle(cc);
 			break;
 		case _NET_WM_STATE_REMOVE:
@@ -415,13 +418,15 @@ xu_ewmh_restore_net_wm_state(struct client_ctx *cc)
 	atoms = xu_ewmh_get_net_wm_state(cc, &n);
 	for (i = 0; i < n; i++) {
 		if (atoms[i] == ewmh[_NET_WM_STATE_STICKY])
-			client_sticky(cc);
+			client_toggle_sticky(cc);
 		if (atoms[i] == ewmh[_NET_WM_STATE_MAXIMIZED_HORZ])
-			client_hmaximize(cc);
+			client_toggle_hmaximize(cc);
 		if (atoms[i] == ewmh[_NET_WM_STATE_MAXIMIZED_VERT])
-			client_vmaximize(cc);
+			client_toggle_vmaximize(cc);
+		if (atoms[i] == ewmh[_NET_WM_STATE_HIDDEN])
+			client_toggle_hidden(cc);
 		if (atoms[i] == ewmh[_NET_WM_STATE_FULLSCREEN])
-			client_fullscreen(cc);
+			client_toggle_fullscreen(cc);
 		if (atoms[i] == ewmh[_NET_WM_STATE_DEMANDS_ATTENTION])
 			client_urgency(cc);
 	}
@@ -437,16 +442,19 @@ xu_ewmh_set_net_wm_state(struct client_ctx *cc)
 	oatoms = xu_ewmh_get_net_wm_state(cc, &n);
 	atoms = xcalloc((n + _NET_WM_STATES_NITEMS), sizeof(Atom));
 	for (i = j = 0; i < n; i++) {
-		if (oatoms[i] != ewmh[_NET_WM_STATE_MAXIMIZED_HORZ] &&
+		if (oatoms[i] != ewmh[_NET_WM_STATE_STICKY] &&
+		    oatoms[i] != ewmh[_NET_WM_STATE_MAXIMIZED_HORZ] &&
 		    oatoms[i] != ewmh[_NET_WM_STATE_MAXIMIZED_VERT] &&
+		    oatoms[i] != ewmh[_NET_WM_STATE_HIDDEN] &&
 		    oatoms[i] != ewmh[_NET_WM_STATE_FULLSCREEN] &&
-		    oatoms[i] != ewmh[_NET_WM_STATE_STICKY] &&
 		    oatoms[i] != ewmh[_NET_WM_STATE_DEMANDS_ATTENTION])
 			atoms[j++] = oatoms[i];
 	}
 	free(oatoms);
 	if (cc->flags & CLIENT_STICKY)
 		atoms[j++] = ewmh[_NET_WM_STATE_STICKY];
+	if (cc->flags & CLIENT_HIDDEN)
+		atoms[j++] = ewmh[_NET_WM_STATE_HIDDEN];
 	if (cc->flags & CLIENT_FULLSCREEN)
 		atoms[j++] = ewmh[_NET_WM_STATE_FULLSCREEN];
 	else {
@@ -483,7 +491,7 @@ xu_xft_width(XftFont *xftfont, const char *text, int len)
 	XftTextExtentsUtf8(X_Dpy, xftfont, (const FcChar8*)text,
 	    len, &extents);
 
-	return (extents.xOff);
+	return(extents.xOff);
 }
 
 void