summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--calmwm.c97
-rw-r--r--calmwm.h64
-rw-r--r--client.c28
-rw-r--r--conf.c58
-rw-r--r--cwmrc.56
-rw-r--r--font.c47
-rw-r--r--group.c29
-rw-r--r--kbfunc.c36
-rw-r--r--menu.c93
-rw-r--r--mousefunc.c17
-rw-r--r--parse.y25
-rw-r--r--screen.c57
-rw-r--r--xevents.c6
-rw-r--r--xutil.c12
14 files changed, 308 insertions, 267 deletions
diff --git a/calmwm.c b/calmwm.c
index 08d0b53..58cb768 100644
--- a/calmwm.c
+++ b/calmwm.c
@@ -26,6 +26,7 @@
 #include <errno.h>
 #include <getopt.h>
 #include <locale.h>
+#include <pwd.h>
 #include <signal.h>
 #include <stdio.h>
 #include <stdlib.h>
@@ -48,21 +49,22 @@ struct client_ctx_q		 Clientq = TAILQ_HEAD_INITIALIZER(Clientq);
 
 int				 HasRandr, Randr_ev;
 struct conf			 Conf;
+char				*homedir;
 
 static void	sigchld_cb(int);
 static void	dpy_init(const char *);
 static int	x_errorhandler(Display *, XErrorEvent *);
 static int	x_wmerrorhandler(Display *, XErrorEvent *);
 static void	x_setup(void);
-static void	x_setupscreen(struct screen_ctx *, u_int);
 static void	x_teardown(void);
 
 int
 main(int argc, char **argv)
 {
 	const char	*conf_file = NULL;
-	char		*display_name = NULL;
+	char		*conf_path, *display_name = NULL;
 	int		 ch;
+	struct passwd	*pw;
 
 	if (!setlocale(LC_CTYPE, "") || !XSupportsLocale())
 		warnx("no locale support");
@@ -87,15 +89,36 @@ main(int argc, char **argv)
 	if (signal(SIGCHLD, sigchld_cb) == SIG_ERR)
 		err(1, "signal");
 
+	if ((homedir = getenv("HOME")) == NULL || *homedir == '\0') {
+		pw = getpwuid(getuid());
+		if (pw != NULL && pw->pw_dir != NULL && *pw->pw_dir != '\0')
+			homedir = pw->pw_dir;
+		else
+			homedir = "/";
+	}
+
+	if (conf_file == NULL)
+		xasprintf(&conf_path, "%s/%s", homedir, CONFFILE);
+	else
+		conf_path = xstrdup(conf_file);
+
+	if (access(conf_path, R_OK) != 0) {
+		if (conf_file != NULL)
+			warn("%s", conf_file);
+		free(conf_path);
+		conf_path = NULL;
+	}
+
 	dpy_init(display_name);
 
-	bzero(&Conf, sizeof(Conf));
-	conf_setup(&Conf, conf_file);
+	conf_init(&Conf);
+	if (conf_path && (parse_config(conf_path, &Conf) == -1))
+		warnx("config file %s has errors, not loading", conf_path);
+	free(conf_path);
+
 	xu_getatoms();
 	x_setup();
-
 	xev_loop();
-
 	x_teardown();
 
 	return (0);
@@ -135,7 +158,7 @@ x_setup(void)
 
 	for (i = 0; i < ScreenCount(X_Dpy); i++) {
 		sc = xcalloc(1, sizeof(*sc));
-		x_setupscreen(sc, i);
+		screen_init(sc, i);
 		TAILQ_INSERT_TAIL(&Screenq, sc, entry);
 	}
 
@@ -150,69 +173,9 @@ x_setup(void)
 static void
 x_teardown(void)
 {
-	struct screen_ctx	*sc;
-
-	TAILQ_FOREACH(sc, &Screenq, entry)
-		XFreeGC(X_Dpy, sc->gc);
-
 	XCloseDisplay(X_Dpy);
 }
 
-static void
-x_setupscreen(struct screen_ctx *sc, u_int which)
-{
-	Window			*wins, w0, w1;
-	XWindowAttributes	 winattr;
-	XSetWindowAttributes	 rootattr;
-	u_int			 nwins, i;
-
-	sc->which = which;
-	sc->rootwin = RootWindow(X_Dpy, sc->which);
-
-	xu_ewmh_net_supported(sc);
-	xu_ewmh_net_supported_wm_check(sc);
-
-	conf_gap(&Conf, sc);
-
-	screen_update_geometry(sc);
-
-	conf_color(&Conf, sc);
-
-	group_init(sc);
-	conf_font(&Conf, sc);
-
-	TAILQ_INIT(&sc->mruq);
-
-	/* Initialize menu window. */
-	menu_init(sc);
-
-	rootattr.cursor = Cursor_normal;
-	rootattr.event_mask = CHILDMASK|PropertyChangeMask|EnterWindowMask|
-	    LeaveWindowMask|ColormapChangeMask|BUTTONMASK;
-
-	XChangeWindowAttributes(X_Dpy, sc->rootwin,
-	    CWEventMask|CWCursor, &rootattr);
-
-	/* Deal with existing clients. */
-	XQueryTree(X_Dpy, sc->rootwin, &w0, &w1, &wins, &nwins);
-
-	for (i = 0; i < nwins; i++) {
-		XGetWindowAttributes(X_Dpy, wins[i], &winattr);
-		if (winattr.override_redirect ||
-		    winattr.map_state != IsViewable)
-			continue;
-		(void)client_new(wins[i], sc, winattr.map_state != IsUnmapped);
-	}
-	XFree(wins);
-
-	screen_updatestackingorder(sc);
-
-	if (HasRandr)
-		XRRSelectInput(X_Dpy, sc->rootwin, RRScreenChangeNotifyMask);
-
-	XSync(X_Dpy, False);
-}
-
 static int
 x_wmerrorhandler(Display *dpy, XErrorEvent *e)
 {
diff --git a/calmwm.h b/calmwm.h
index 7bbe0f9..cf63a64 100644
--- a/calmwm.h
+++ b/calmwm.h
@@ -56,15 +56,12 @@ size_t strlcat(char *, const char *, size_t);
 #define	CONFFILE	".cwmrc"
 #define	WMNAME	 	"CWM"
 
-#define CHILDMASK	(SubstructureRedirectMask|SubstructureNotifyMask)
 #define BUTTONMASK	(ButtonPressMask|ButtonReleaseMask)
 #define MOUSEMASK	(BUTTONMASK|PointerMotionMask)
+#define MENUMASK 	(MOUSEMASK|ButtonMotionMask|ExposureMask)
+#define MENUGRABMASK	(MOUSEMASK|ButtonMotionMask|StructureNotifyMask)
 #define KEYMASK		(KeyPressMask|ExposureMask)
-#define MENUMASK 	(BUTTONMASK|ButtonMotionMask|ExposureMask| \
-			PointerMotionMask)
-#define MENUGRABMASK	(BUTTONMASK|ButtonMotionMask|StructureNotifyMask|\
-			PointerMotionMask)
-#define SEARCHMASK	(KeyPressMask|ExposureMask)
+#define IGNOREMODMASK	(LockMask|Mod2Mask)
 
 /* kb movement */
 #define CWM_MOVE		0x0001
@@ -96,14 +93,19 @@ union arg {
 	int	 i;
 };
 
+enum menucolor {
+	CWM_COLOR_MENU_FG,
+	CWM_COLOR_MENU_BG,
+	CWM_COLOR_MENU_FONT,
+	CWM_COLOR_MENU_FONT_SEL,
+	CWM_COLOR_MENU_MAX
+};
+
 enum cwmcolor {
 	CWM_COLOR_BORDER_ACTIVE,
 	CWM_COLOR_BORDER_INACTIVE,
 	CWM_COLOR_BORDER_GROUP,
 	CWM_COLOR_BORDER_UNGROUP,
-	CWM_COLOR_FG_MENU,
-	CWM_COLOR_BG_MENU,
-	CWM_COLOR_FONT,
 	CWM_COLOR_MAX
 };
 
@@ -139,7 +141,7 @@ struct client_ctx {
 	struct screen_ctx	*sc;
 	Window			 win;
 	XSizeHints		*size;
-	Colormap		 cmap;
+	Colormap		 colormap;
 	u_int			 bwidth; /* border width */
 	struct geom		 geom, savegeom;
 	struct {
@@ -166,16 +168,16 @@ struct client_ctx {
 #define CLIENT_VMAXIMIZED		0x0004
 #define CLIENT_HMAXIMIZED		0x0008
 #define CLIENT_FREEZE			0x0010
+#define CLIENT_GROUP			0x0020
+#define CLIENT_UNGROUP			0x0040
 
+#define CLIENT_HIGHLIGHT		(CLIENT_GROUP | CLIENT_UNGROUP)
 #define CLIENT_MAXFLAGS			(CLIENT_VMAXIMIZED | CLIENT_HMAXIMIZED)
 #define CLIENT_MAXIMIZED		(CLIENT_VMAXIMIZED | CLIENT_HMAXIMIZED)
 	int			 flags;
 	int			 state;
 	int			 active;
 	int			 stackingorder;
-#define CLIENT_HIGHLIGHT_GROUP		0x0001
-#define CLIENT_HIGHLIGHT_UNGROUP	0x0002
-	int			 highlight;
 	struct winname_q	 nameq;
 #define CLIENT_MAXNAMEQLEN		5
 	int			 nameqlen;
@@ -217,18 +219,19 @@ TAILQ_HEAD(autogroupwin_q, autogroupwin);
 struct screen_ctx {
 	TAILQ_ENTRY(screen_ctx)	 entry;
 	u_int			 which;
+	Visual			*visual;
+	Colormap		 colormap;
 	Window			 rootwin;
 	Window			 menuwin;
 	struct color		 color[CWM_COLOR_MAX];
-	GC			 gc;
 	int			 cycling;
 	struct geom		 view; /* viewable area */
 	struct geom		 work; /* workable area, gap-applied */
 	struct gap		 gap;
 	struct cycle_entry_q	 mruq;
-	XftColor		 xftcolor;
+	XftColor		 xftcolor[CWM_COLOR_MENU_MAX];
 	XftDraw			*xftdraw;
-	XftFont			*font;
+	XftFont			*xftfont;
 	int			 xinerama_no;
 	XineramaScreenInfo	*xinerama;
 #define CALMWM_NGROUPS		 9
@@ -266,7 +269,6 @@ TAILQ_HEAD(mousebinding_q, mousebinding);
 
 struct cmd {
 	TAILQ_ENTRY(cmd)	entry;
-	int			flags;
 	char			image[MAXPATHLEN];
 #define CMD_MAXLABELLEN		256
 	char			label[CMD_MAXLABELLEN];
@@ -301,8 +303,10 @@ struct conf {
 	int			 snapdist;
 	struct gap		 gap;
 	struct color		 color[CWM_COLOR_MAX];
+	char		 	*menucolor[CWM_COLOR_MENU_MAX];
 	char			 termpath[MAXPATHLEN];
 	char			 lockpath[MAXPATHLEN];
+	char			 known_hosts[MAXPATHLEN];
 #define	CONF_FONT			"sans-serif:pixelsize=14:bold"
 	char			*font;
 };
@@ -324,7 +328,8 @@ __dead void		 usage(void);
 void			 client_applysizehints(struct client_ctx *);
 struct client_ctx	*client_current(void);
 void			 client_cycle(struct screen_ctx *, int);
-void			 client_cycle_leave(struct screen_ctx *, struct client_ctx *);
+void			 client_cycle_leave(struct screen_ctx *,
+			     struct client_ctx *);
 void			 client_delete(struct client_ctx *);
 void			 client_draw_border(struct client_ctx *);
 struct client_ctx	*client_find(Window);
@@ -337,7 +342,6 @@ void			 client_lower(struct client_ctx *);
 void			 client_map(struct client_ctx *);
 void			 client_maximize(struct client_ctx *);
 void			 client_move(struct client_ctx *);
-void			 client_mtf(struct client_ctx *);
 struct client_ctx	*client_new(Window, struct screen_ctx *, int);
 void			 client_ptrsave(struct client_ctx *);
 void			 client_ptrwarp(struct client_ctx *);
@@ -371,8 +375,8 @@ void			 search_match_client(struct menu_q *, struct menu_q *,
 			     char *);
 void			 search_match_exec(struct menu_q *, struct menu_q *,
 			     char *);
-void			 search_match_exec_path(struct menu_q *, struct menu_q *,
-			     char *);
+void			 search_match_exec_path(struct menu_q *,
+			     struct menu_q *, char *);
 void			 search_match_path_any(struct menu_q *, struct menu_q *,
 			     char *);
 void			 search_match_text(struct menu_q *, struct menu_q *,
@@ -381,6 +385,7 @@ void			 search_print_client(struct menu *, int);
 
 XineramaScreenInfo	*screen_find_xinerama(struct screen_ctx *, int, int);
 struct screen_ctx	*screen_fromroot(Window);
+void			 screen_init(struct screen_ctx *, u_int);
 void			 screen_update_geometry(struct screen_ctx *);
 void			 screen_updatestackingorder(struct screen_ctx *);
 
@@ -436,13 +441,14 @@ struct menu  		*menu_filter(struct screen_ctx *, struct menu_q *,
 			     void (*)(struct menu_q *, struct menu_q *, char *),
 			     void (*)(struct menu *, int));
 void			 menu_init(struct screen_ctx *);
+void			 menuq_clear(struct menu_q *);
 
 int			 parse_config(const char *, struct conf *);
 
 void			 conf_bindname(struct conf *, char *, char *);
 void			 conf_clear(struct conf *);
 void			 conf_client(struct client_ctx *);
-void			 conf_cmd_add(struct conf *, char *, char *, int);
+void			 conf_cmd_add(struct conf *, char *, char *);
 void			 conf_color(struct conf *, struct screen_ctx *);
 void			 conf_font(struct conf *, struct screen_ctx *);
 void			 conf_gap(struct conf *, struct screen_ctx *);
@@ -450,16 +456,15 @@ void			 conf_grab(struct conf *, struct keybinding *);
 void			 conf_grab_mouse(struct client_ctx *);
 void			 conf_init(struct conf *);
 void			 conf_mousebind(struct conf *, char *, char *);
-void			 conf_setup(struct conf *, const char *);
 void			 conf_ungrab(struct conf *, struct keybinding *);
 
 int			 font_ascent(struct screen_ctx *);
 int			 font_descent(struct screen_ctx *);
 void			 font_draw(struct screen_ctx *, const char *, int,
-			     Drawable, int, int);
+			     Drawable, int, int, int);
 u_int			 font_height(struct screen_ctx *);
 void			 font_init(struct screen_ctx *, const char *,
-			     const char *);
+			     const char **);
 int			 font_width(struct screen_ctx *, const char *, int);
 
 void			 xev_loop(void);
@@ -481,6 +486,8 @@ void			 xu_ptr_setpos(Window, int, int);
 void			 xu_ptr_ungrab(void);
 void			 xu_sendmsg(Window, Atom, long);
 void			 xu_setstate(struct client_ctx *, int);
+void 			 xu_xorcolor(XRenderColor, XRenderColor,
+			     XRenderColor *);
 
 void			 xu_ewmh_net_supported(struct screen_ctx *);
 void			 xu_ewmh_net_supported_wm_check(struct screen_ctx *);
@@ -493,11 +500,11 @@ void			 xu_ewmh_net_wm_number_of_desktops(struct screen_ctx *);
 void			 xu_ewmh_net_showing_desktop(struct screen_ctx *);
 void			 xu_ewmh_net_virtual_roots(struct screen_ctx *);
 void			 xu_ewmh_net_current_desktop(struct screen_ctx *, long);
-void			 xu_ewmh_net_desktop_names(struct screen_ctx *, char *, int);
+void			 xu_ewmh_net_desktop_names(struct screen_ctx *, char *,
+			     int);
 
 void			 xu_ewmh_net_wm_desktop(struct client_ctx *);
 
-
 void			 u_exec(char *);
 void			 u_spawn(char *);
 
@@ -520,8 +527,9 @@ extern Cursor				 Cursor_resize;
 extern struct screen_ctx_q		 Screenq;
 extern struct client_ctx_q		 Clientq;
 extern struct conf			 Conf;
+extern char				*homedir;
 
-extern int				 HasXinerama, HasRandr, Randr_ev;
+extern int				 HasRandr, Randr_ev;
 
 enum {
 	WM_STATE,
diff --git a/client.c b/client.c
index 455f5ef..2394d2d 100644
--- a/client.c
+++ b/client.c
@@ -33,6 +33,7 @@
 
 static struct client_ctx	*client_mrunext(struct client_ctx *);
 static struct client_ctx	*client_mruprev(struct client_ctx *);
+static void			 client_mtf(struct client_ctx *);
 static void			 client_none(struct screen_ctx *);
 static void			 client_placecalc(struct client_ctx *);
 static void			 client_update(struct client_ctx *);
@@ -91,7 +92,7 @@ client_new(Window win, struct screen_ctx *sc, int mapped)
 	cc->geom.y = wattr.y;
 	cc->geom.w = wattr.width;
 	cc->geom.h = wattr.height;
-	cc->cmap = wattr.colormap;
+	cc->colormap = wattr.colormap;
 
 	if (wattr.map_state != IsViewable) {
 		client_placecalc(cc);
@@ -158,7 +159,7 @@ client_delete(struct client_ctx *cc)
 
 	xu_ewmh_net_client_list(sc);
 
-	if (_curcc == cc)
+	if (cc == client_current())
 		client_none(sc);
 
 	XFree(cc->size);
@@ -180,7 +181,7 @@ client_leave(struct client_ctx *cc)
 	struct screen_ctx	*sc;
 
 	if (cc == NULL)
-		cc = _curcc;
+		cc = client_current();
 	if (cc == NULL)
 		return;
 
@@ -194,14 +195,14 @@ client_setactive(struct client_ctx *cc, int fg)
 	struct screen_ctx	*sc;
 
 	if (cc == NULL)
-		cc = _curcc;
+		cc = client_current();
 	if (cc == NULL)
 		return;
 
 	sc = cc->sc;
 
 	if (fg) {
-		XInstallColormap(X_Dpy, cc->cmap);
+		XInstallColormap(X_Dpy, cc->colormap);
 		XSetInputFocus(X_Dpy, cc->win,
 		    RevertToPointerRoot, CurrentTime);
 		conf_grab_mouse(cc);
@@ -214,7 +215,7 @@ client_setactive(struct client_ctx *cc, int fg)
 	} else
 		client_leave(cc);
 
-	if (fg && _curcc != cc) {
+	if (fg && cc != client_current()) {
 		client_setactive(NULL, 0);
 		_curcc = cc;
 		xu_ewmh_net_active_window(sc, cc->win);
@@ -480,7 +481,7 @@ client_hide(struct client_ctx *cc)
 	cc->flags |= CLIENT_HIDDEN;
 	xu_setstate(cc, IconicState);
 
-	if (cc == _curcc)
+	if (cc == client_current())
 		client_none(cc->sc);
 }
 
@@ -489,7 +490,6 @@ client_unhide(struct client_ctx *cc)
 {
 	XMapRaised(X_Dpy, cc->win);
 
-	cc->highlight = 0;
 	cc->flags &= ~CLIENT_HIDDEN;
 	xu_setstate(cc, NormalState);
 	client_draw_border(cc);
@@ -502,11 +502,11 @@ client_draw_border(struct client_ctx *cc)
 	unsigned long		 pixel;
 
 	if (cc->active)
-		switch (cc->highlight) {
-		case CLIENT_HIGHLIGHT_GROUP:
+		switch (cc->flags & CLIENT_HIGHLIGHT) {
+		case CLIENT_GROUP:
 			pixel = sc->color[CWM_COLOR_BORDER_GROUP].pixel;
 			break;
-		case CLIENT_HIGHLIGHT_UNGROUP:
+		case CLIENT_UNGROUP:
 			pixel = sc->color[CWM_COLOR_BORDER_UNGROUP].pixel;
 			break;
 		default:
@@ -731,19 +731,17 @@ client_placecalc(struct client_ctx *cc)
 	}
 }
 
-void
+static void
 client_mtf(struct client_ctx *cc)
 {
 	struct screen_ctx	*sc;
 
 	if (cc == NULL)
-		cc = _curcc;
+		cc = client_current();
 	if (cc == NULL)
 		return;
 
 	sc = cc->sc;
-
-	/* Move to front. */
 	TAILQ_REMOVE(&sc->mruq, cc, mru_entry);
 	TAILQ_INSERT_HEAD(&sc->mruq, cc, mru_entry);
 }
diff --git a/conf.c b/conf.c
index 4f50039..88c5fd9 100644
--- a/conf.c
+++ b/conf.c
@@ -36,7 +36,7 @@ static void	 conf_unbind(struct conf *, struct keybinding *);
 
 /* Add an command menu entry to the end of the menu */
 void
-conf_cmd_add(struct conf *c, char *image, char *label, int flags)
+conf_cmd_add(struct conf *c, char *image, char *label)
 {
 	/* "term" and "lock" have special meanings. */
 
@@ -46,7 +46,6 @@ conf_cmd_add(struct conf *c, char *image, char *label, int flags)
 		(void)strlcpy(c->lockpath, image, sizeof(c->lockpath));
 	else {
 		struct cmd *cmd = xmalloc(sizeof(*cmd));
-		cmd->flags = flags;
 		(void)strlcpy(cmd->image, image, sizeof(cmd->image));
 		(void)strlcpy(cmd->label, label, sizeof(cmd->label));
 		TAILQ_INSERT_TAIL(&c->cmdq, cmd, entry);
@@ -62,17 +61,21 @@ conf_gap(struct conf *c, struct screen_ctx *sc)
 void
 conf_font(struct conf *c, struct screen_ctx *sc)
 {
-	font_init(sc, c->font, c->color[CWM_COLOR_FONT].name);
+	font_init(sc, c->font, (const char **)c->menucolor);
 }
 
-static struct color color_binds[] = {
+static char *menu_color_binds[CWM_COLOR_MENU_MAX] = {
+	"black", /* CWM_COLOR_MENU_FG */
+	"white", /* CWM_COLOR_MENU_BG */
+	"black", /* CWM_COLOR_MENU_FONT */
+	"",  	 /* CWM_COLOR_MENU_FONT_SEL */
+};
+
+static struct color color_binds[CWM_COLOR_MAX] = {
 	{ "#CCCCCC",	0 }, /* CWM_COLOR_BORDER_ACTIVE */
 	{ "#666666",	0 }, /* CWM_COLOR_BORDER_INACTIVE */
 	{ "blue",	0 }, /* CWM_COLOR_BORDER_GROUP */
 	{ "red",	0 }, /* CWM_COLOR_BORDER_UNGROUP */
-	{ "black",	0 }, /* CWM_COLOR_FG_MENU */
-	{ "white",	0 }, /* CWM_COLOR_BG_MENU */
-	{ "black",	0 }, /* CWM_COLOR_FONT */
 };
 
 void
@@ -162,7 +165,8 @@ conf_init(struct conf *c)
 {
 	int	i;
 
-	c->flags = 0;
+	bzero(c, sizeof(*c));
+
 	c->bwidth = CONF_BWIDTH;
 	c->mamount = CONF_MAMOUNT;
 	c->snapdist = CONF_SNAPDIST;
@@ -182,10 +186,16 @@ conf_init(struct conf *c)
 	for (i = 0; i < nitems(color_binds); i++)
 		c->color[i].name = xstrdup(color_binds[i].name);
 
+	for (i = 0; i < nitems(menu_color_binds); i++)
+		c->menucolor[i] = xstrdup(menu_color_binds[i]);
+
 	/* Default term/lock */
 	(void)strlcpy(c->termpath, "xterm", sizeof(c->termpath));
 	(void)strlcpy(c->lockpath, "xlock", sizeof(c->lockpath));
 
+	(void)snprintf(c->known_hosts, sizeof(c->known_hosts), "%s/%s",
+	    homedir, ".ssh/known_hosts");
+
 	c->font = xstrdup(CONF_FONT);
 }
 
@@ -233,38 +243,6 @@ conf_clear(struct conf *c)
 }
 
 void
-conf_setup(struct conf *c, const char *conf_file)
-{
-	char		 conf_path[MAXPATHLEN];
-	char		*home;
-	struct stat	 sb;
-	int		 parse = 0;
-
-	conf_init(c);
-
-	if (conf_file == NULL) {
-		if ((home = getenv("HOME")) == NULL)
-			errx(1, "No HOME directory.");
-
-		(void)snprintf(conf_path, sizeof(conf_path), "%s/%s",
-		    home, CONFFILE);
-
-		if (stat(conf_path, &sb) == 0 && (sb.st_mode & S_IFREG))
-			parse = 1;
-	} else {
-		if (stat(conf_file, &sb) == -1 || !(sb.st_mode & S_IFREG))
-			errx(1, "%s: %s", conf_file, strerror(errno));
-		else {
-			(void)strlcpy(conf_path, conf_file, sizeof(conf_path));
-			parse = 1;
-		}
-	}
-
-	if (parse && (parse_config(conf_path, c) == -1))
-		warnx("config file %s has errors, not loading", conf_path);
-}
-
-void
 conf_client(struct client_ctx *cc)
 {
 	struct winmatch	*wm;
diff --git a/cwmrc.5 b/cwmrc.5
index 39ab221..c8ea841 100644
--- a/cwmrc.5
+++ b/cwmrc.5
@@ -14,7 +14,7 @@
 .\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
 .\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 .\"
-.Dd $Mdocdate: November 7 2012 $
+.Dd $Mdocdate: November 29 2012 $
 .Dt CWMRC 5
 .Os
 .Sh NAME
@@ -50,6 +50,7 @@ or if their name and class properties match
 and
 .Ar windowclass ,
 respectively.
+The more specific last match wins.
 .Ar group
 is a number between 0 and 9.
 If
@@ -111,6 +112,9 @@ Set the color of the active border.
 .It Ic color font Ar color
 Set menu font color.
 .Pp
+.It Ic color selfont Ar color
+Set font color for selected menu item.
+.Pp
 .It Ic color groupborder Ar color
 Set the color of the border while grouping a window.
 .Pp
diff --git a/font.c b/font.c
index 4267e91..648450e 100644
--- a/font.c
+++ b/font.c
@@ -33,36 +33,52 @@
 int
 font_ascent(struct screen_ctx *sc)
 {
-	return (sc->font->ascent);
+	return (sc->xftfont->ascent);
 }
 
 int
 font_descent(struct screen_ctx *sc)
 {
-	return (sc->font->descent);
+	return (sc->xftfont->descent);
 }
 
 u_int
 font_height(struct screen_ctx *sc)
 {
-	return (sc->font->height + 1);
+	return (sc->xftfont->height + 1);
 }
 
 void
-font_init(struct screen_ctx *sc, const char *name, const char *color)
+font_init(struct screen_ctx *sc, const char *name, const char **color)
 {
+	int		 i;
+	XRenderColor	 c;
+
 	sc->xftdraw = XftDrawCreate(X_Dpy, sc->rootwin,
-	    DefaultVisual(X_Dpy, sc->which), DefaultColormap(X_Dpy, sc->which));
+	    sc->visual, sc->colormap);
 	if (sc->xftdraw == NULL)
 		errx(1, "XftDrawCreate");
 
-	if (!XftColorAllocName(X_Dpy, DefaultVisual(X_Dpy, sc->which),
-	    DefaultColormap(X_Dpy, sc->which), color, &sc->xftcolor))
-		errx(1, "XftColorAllocName");
-
-	sc->font = XftFontOpenName(X_Dpy, sc->which, name);
-	if (sc->font == NULL)
+	sc->xftfont = XftFontOpenName(X_Dpy, sc->which, name);
+	if (sc->xftfont == NULL)
 		errx(1, "XftFontOpenName");
+
+	for (i = 0; i < CWM_COLOR_MENU_MAX; i++) {
+		if (*color[i] == '\0')
+			break;
+		if (!XftColorAllocName(X_Dpy, sc->visual, sc->colormap,
+			color[i], &sc->xftcolor[i]))
+			errx(1, "XftColorAllocName");
+	}
+	if (i == CWM_COLOR_MENU_MAX)
+		return;
+
+	xu_xorcolor(sc->xftcolor[CWM_COLOR_MENU_BG].color,
+		    sc->xftcolor[CWM_COLOR_MENU_FG].color, &c);
+	xu_xorcolor(sc->xftcolor[CWM_COLOR_MENU_FONT].color, c, &c);
+	if (!XftColorAllocValue(X_Dpy, sc->visual, sc->colormap,
+		&c, &sc->xftcolor[CWM_COLOR_MENU_FONT_SEL]))
+		errx(1, "XftColorAllocValue");
 }
 
 int
@@ -70,7 +86,7 @@ font_width(struct screen_ctx *sc, const char *text, int len)
 {
 	XGlyphInfo	 extents;
 
-	XftTextExtentsUtf8(X_Dpy, sc->font, (const FcChar8*)text,
+	XftTextExtentsUtf8(X_Dpy, sc->xftfont, (const FcChar8*)text,
 	    len, &extents);
 
 	return (extents.xOff);
@@ -78,9 +94,12 @@ font_width(struct screen_ctx *sc, const char *text, int len)
 
 void
 font_draw(struct screen_ctx *sc, const char *text, int len,
-    Drawable d, int x, int y)
+    Drawable d, int active, int x, int y)
 {
+	int	 color;
+
+	color = active ? CWM_COLOR_MENU_FONT_SEL : CWM_COLOR_MENU_FONT;
 	XftDrawChange(sc->xftdraw, d);
-	XftDrawStringUtf8(sc->xftdraw, &sc->xftcolor, sc->font, x, y,
+	XftDrawStringUtf8(sc->xftdraw, &sc->xftcolor[color], sc->xftfont, x, y,
 	    (const FcChar8*)text, len);
 }
diff --git a/group.c b/group.c
index 834fac4..ab72eef 100644
--- a/group.c
+++ b/group.c
@@ -218,16 +218,14 @@ void
 group_sticky_toggle_enter(struct client_ctx *cc)
 {
 	struct screen_ctx	*sc = cc->sc;
-	struct group_ctx	*gc;
-
-	gc = sc->group_active;
+	struct group_ctx	*gc = sc->group_active;
 
 	if (gc == cc->group) {
 		group_remove(cc);
-		cc->highlight = CLIENT_HIGHLIGHT_UNGROUP;
+		cc->flags |= CLIENT_UNGROUP;
 	} else {
 		group_add(gc, cc);
-		cc->highlight = CLIENT_HIGHLIGHT_GROUP;
+		cc->flags |= CLIENT_GROUP;
 	}
 
 	client_draw_border(cc);
@@ -236,7 +234,7 @@ group_sticky_toggle_enter(struct client_ctx *cc)
 void
 group_sticky_toggle_exit(struct client_ctx *cc)
 {
-	cc->highlight = 0;
+	cc->flags &= ~CLIENT_HIGHLIGHT;
 	client_draw_border(cc);
 }
 
@@ -385,10 +383,7 @@ group_menu(XButtonEvent *e)
 	(gc->hidden) ? group_show(sc, gc) : group_hide(sc, gc);
 
 cleanup:
-	while ((mi = TAILQ_FIRST(&menuq)) != NULL) {
-		TAILQ_REMOVE(&menuq, mi, entry);
-		free(mi);
-	}
+	menuq_clear(&menuq);
 }
 
 void
@@ -412,7 +407,7 @@ group_autogroup(struct client_ctx *cc)
 	struct screen_ctx	*sc = cc->sc;
 	struct autogroupwin	*aw;
 	struct group_ctx	*gc;
-	int			 no = -1;
+	int			 no = -1, both_match = 0;
 	long			*grpno;
 
 	if (cc->app_class == NULL || cc->app_name == NULL)
@@ -429,11 +424,13 @@ group_autogroup(struct client_ctx *cc)
 		XFree(grpno);
 	} else {
 		TAILQ_FOREACH(aw, &Conf.autogroupq, entry) {
-			if (strcmp(aw->class, cc->app_class) == 0 &&
-			    (aw->name == NULL ||
-			    strcmp(aw->name, cc->app_name) == 0)) {
-				no = aw->num;
-				break;
+			if (strcmp(aw->class, cc->app_class) == 0) {
+				if ((aw->name != NULL) &&
+				    (strcmp(aw->name, cc->app_name) == 0)) {
+					no = aw->num;
+					both_match = 1;
+				} else if (aw->name == NULL && !both_match)
+					no = aw->num;
 			}
 		}
 	}
diff --git a/kbfunc.c b/kbfunc.c
index c110a9f..d574878 100644
--- a/kbfunc.c
+++ b/kbfunc.c
@@ -33,7 +33,6 @@
 
 #include "calmwm.h"
 
-#define KNOWN_HOSTS	".ssh/known_hosts"
 #define HASH_MARKER	"|1|"
 
 extern char		**cwm_argv;
@@ -168,10 +167,7 @@ kbfunc_client_search(struct client_ctx *cc, union arg *arg)
 		client_ptrwarp(cc);
 	}
 
-	while ((mi = TAILQ_FIRST(&menuq)) != NULL) {
-		TAILQ_REMOVE(&menuq, mi, entry);
-		free(mi);
-	}
+	menuq_clear(&menuq);
 }
 
 void
@@ -195,10 +191,7 @@ kbfunc_menu_search(struct client_ctx *cc, union arg *arg)
 	    search_match_text, NULL)) != NULL)
 		u_spawn(((struct cmd *)mi->ctx)->image);
 
-	while ((mi = TAILQ_FIRST(&menuq)) != NULL) {
-		TAILQ_REMOVE(&menuq, mi, entry);
-		free(mi);
-	}
+	menuq_clear(&menuq);
 }
 
 void
@@ -320,10 +313,7 @@ kbfunc_exec(struct client_ctx *cc, union arg *arg)
 out:
 	if (mi != NULL && mi->dummy)
 		free(mi);
-	while ((mi = TAILQ_FIRST(&menuq)) != NULL) {
-		TAILQ_REMOVE(&menuq, mi, entry);
-		free(mi);
-	}
+	menuq_clear(&menuq);
 }
 
 void
@@ -333,21 +323,16 @@ kbfunc_ssh(struct client_ctx *cc, union arg *arg)
 	struct menu		*mi;
 	struct menu_q		 menuq;
 	FILE			*fp;
-	char			*buf, *lbuf, *p, *home;
-	char			 hostbuf[MAXHOSTNAMELEN], filename[MAXPATHLEN];
+	char			*buf, *lbuf, *p;
+	char			 hostbuf[MAXHOSTNAMELEN];
 	char			 cmd[256];
 	int			 l;
 	size_t			 len;
 
-	if ((home = getenv("HOME")) == NULL)
-		return;
-
-	l = snprintf(filename, sizeof(filename), "%s/%s", home, KNOWN_HOSTS);
-	if (l == -1 || l >= sizeof(filename))
-		return;
-
-	if ((fp = fopen(filename, "r")) == NULL)
+	if ((fp = fopen(Conf.known_hosts, "r")) == NULL) {
+		warn("kbfunc_ssh: %s", Conf.known_hosts);
 		return;
+	}
 
 	TAILQ_INIT(&menuq);
 	lbuf = NULL;
@@ -390,10 +375,7 @@ kbfunc_ssh(struct client_ctx *cc, union arg *arg)
 out:
 	if (mi != NULL && mi->dummy)
 		free(mi);
-	while ((mi = TAILQ_FIRST(&menuq)) != NULL) {
-		TAILQ_REMOVE(&menuq, mi, entry);
-		free(mi);
-	}
+	menuq_clear(&menuq);
 }
 
 void
diff --git a/menu.c b/menu.c
index dcf801d..87c04d6 100644
--- a/menu.c
+++ b/menu.c
@@ -65,11 +65,13 @@ struct menu_ctx {
 static struct menu	*menu_handle_key(XEvent *, struct menu_ctx *,
 			     struct menu_q *, struct menu_q *);
 static void		 menu_handle_move(XEvent *, struct menu_ctx *,
-			     struct screen_ctx *);
+			     struct screen_ctx *, struct menu_q *);
 static struct menu	*menu_handle_release(XEvent *, struct menu_ctx *,
 			     struct screen_ctx *, struct menu_q *);
 static void		 menu_draw(struct screen_ctx *, struct menu_ctx *,
 			     struct menu_q *, struct menu_q *);
+static void 		 menu_draw_entry(struct screen_ctx *, struct menu_ctx *,
+			     struct menu_q *, int, int);
 static int		 menu_calc_entry(struct screen_ctx *, struct menu_ctx *,
 			     int, int);
 static int		 menu_keycode(XKeyEvent *, enum ctltype *,
@@ -78,20 +80,10 @@ static int		 menu_keycode(XKeyEvent *, enum ctltype *,
 void
 menu_init(struct screen_ctx *sc)
 {
-	XGCValues	 gv;
-
 	sc->menuwin = XCreateSimpleWindow(X_Dpy, sc->rootwin, 0, 0, 1, 1,
 	    Conf.bwidth,
-	    sc->color[CWM_COLOR_FG_MENU].pixel,
-	    sc->color[CWM_COLOR_BG_MENU].pixel);
-
-	gv.foreground =
-	    sc->color[CWM_COLOR_FG_MENU].pixel^sc->color[CWM_COLOR_BG_MENU].pixel;
-	gv.background = sc->color[CWM_COLOR_BG_MENU].pixel;
-	gv.function = GXxor;
-
-	sc->gc = XCreateGC(X_Dpy, sc->menuwin,
-	    GCForeground|GCBackground|GCFunction, &gv);
+	    sc->xftcolor[CWM_COLOR_MENU_FG].pixel,
+	    sc->xftcolor[CWM_COLOR_MENU_BG].pixel);
 }
 
 struct menu *
@@ -174,7 +166,7 @@ menu_filter(struct screen_ctx *sc, struct menu_q *menuq, char *prompt,
 			menu_draw(sc, &mc, menuq, &resultq);
 			break;
 		case MotionNotify:
-			menu_handle_move(&e, &mc, sc);
+			menu_handle_move(&e, &mc, sc, &resultq);
 			break;
 		case ButtonRelease:
 			if ((mi = menu_handle_release(&e, &mc, sc, &resultq))
@@ -223,10 +215,7 @@ menu_complete_path(struct menu_ctx *mc)
 		strlcpy(path, mi->text, sizeof(mi->text));
 	}
 	
-	while ((mi = TAILQ_FIRST(&menuq)) != NULL) {
-		TAILQ_REMOVE(&menuq, mi, entry);
-		free(mi);
-	}
+	menuq_clear(&menuq);
 
 	if (path[0] != '\0') 
 		snprintf(mr->text, sizeof(mr->text), "%s \"%s\"",
@@ -442,8 +431,8 @@ menu_draw(struct screen_ctx *sc, struct menu_ctx *mc, struct menu_q *menuq,
 	    mc->width, mc->height);
 
 	if (mc->hasprompt) {
-		font_draw(sc, mc->dispstr, strlen(mc->dispstr), sc->menuwin,
-		    0, font_ascent(sc) + 1);
+		font_draw(sc, mc->dispstr, strlen(mc->dispstr), sc->menuwin, 0,
+		    0, font_ascent(sc));
 		n = 1;
 	} else
 		n = 0;
@@ -458,34 +447,61 @@ menu_draw(struct screen_ctx *sc, struct menu_ctx *mc, struct menu_q *menuq,
 			break;
 
 		font_draw(sc, text, MIN(strlen(text), MENU_MAXENTRY),
-		    sc->menuwin, 0, y);
+		    sc->menuwin, 0, 0, y);
 		n++;
 	}
+	if (mc->hasprompt && n > 1 && (mc->searchstr[0] != '\0')) {
+		mc->entry = 1;
+		menu_draw_entry(sc, mc, resultq, mc->entry, 1);
+	}
+}
 
-	if (mc->hasprompt && n > 1 && (mc->searchstr[0] != '\0'))
-		XFillRectangle(X_Dpy, sc->menuwin, sc->gc,
-		    0, font_height(sc), mc->width, font_height(sc));
+static void
+menu_draw_entry(struct screen_ctx *sc, struct menu_ctx *mc,
+    struct menu_q *resultq, int entry, int active)
+{
+	struct menu	*mi;
+	char 		*text;
+	int		 color, i = 0;
 
-	if (mc->noresult)
-		XFillRectangle(X_Dpy, sc->menuwin, sc->gc,
-		    0, 0, mc->width, font_height(sc));
+	if (mc->hasprompt)
+		i = 1;
+
+	TAILQ_FOREACH(mi, resultq, resultentry)
+		if (entry == i++)
+			break;
+	if (mi == NULL)
+		return;
+
+	color = active ? CWM_COLOR_MENU_FG : CWM_COLOR_MENU_BG;
+	text = mi->print[0] != '\0' ?  mi->print : mi->text;
+	XftDrawRect(sc->xftdraw, &sc->xftcolor[color], 0,
+	    font_height(sc) * entry, mc->width,
+	    font_height(sc) + font_descent(sc));
+	font_draw(sc, text, strlen(text), sc->menuwin, active,
+	    0, font_height(sc) * entry + font_ascent(sc) + 1);
 }
 
 static void
-menu_handle_move(XEvent *e, struct menu_ctx *mc, struct screen_ctx *sc)
+menu_handle_move(XEvent *e, struct menu_ctx *mc, struct screen_ctx *sc,
+    struct menu_q *resultq)
 {
 	mc->prev = mc->entry;
 	mc->entry = menu_calc_entry(sc, mc, e->xbutton.x, e->xbutton.y);
 
+	if (mc->prev == mc->entry)
+		return;
+
 	if (mc->prev != -1)
-		XFillRectangle(X_Dpy, sc->menuwin, sc->gc, 0,
-		    font_height(sc) * mc->prev, mc->width, font_height(sc));
+		menu_draw_entry(sc, mc, resultq, mc->prev, 0);
 	if (mc->entry != -1) {
 		(void)xu_ptr_regrab(MENUGRABMASK, Cursor_normal);
-		XFillRectangle(X_Dpy, sc->menuwin, sc->gc, 0,
-		    font_height(sc) * mc->entry, mc->width, font_height(sc));
+		menu_draw_entry(sc, mc, resultq, mc->entry, 1);
 	} else
 		(void)xu_ptr_regrab(MENUGRABMASK, Cursor_default);
+
+	if (mc->hasprompt)
+		menu_draw_entry(sc, mc, resultq, 1, 1);
 }
 
 static struct menu *
@@ -519,7 +535,7 @@ menu_calc_entry(struct screen_ctx *sc, struct menu_ctx *mc, int x, int y)
 	entry = y / font_height(sc);
 
 	/* in bounds? */
-	if (x <= 0 || x > mc->width || y <= 0 ||
+	if (x < 0 || x > mc->width || y < 0 ||
 	    y > font_height(sc) * mc->num || entry < 0 || entry >= mc->num)
 		entry = -1;
 
@@ -613,3 +629,14 @@ menu_keycode(XKeyEvent *ev, enum ctltype *ctl, char *chr)
 
 	return (0);
 }
+
+void
+menuq_clear(struct menu_q *mq)
+{
+	struct menu	*mi;
+
+	while ((mi = TAILQ_FIRST(mq)) != NULL) {
+		TAILQ_REMOVE(mq, mi, entry);
+		free(mi);
+	}
+}
diff --git a/mousefunc.c b/mousefunc.c
index 37dd7a1..7c07a36 100644
--- a/mousefunc.c
+++ b/mousefunc.c
@@ -68,9 +68,9 @@ mousefunc_sweep_draw(struct client_ctx *cc)
 	XMoveResizeWindow(X_Dpy, sc->menuwin, 0, 0, width, font_height(sc) * 2);
 	XMapWindow(X_Dpy, sc->menuwin);
 	XClearWindow(X_Dpy, sc->menuwin);
-	font_draw(sc, cc->name, strlen(cc->name), sc->menuwin,
+	font_draw(sc, cc->name, strlen(cc->name), sc->menuwin, 0,
 	    2, font_ascent(sc) + 1);
-	font_draw(sc, asize, strlen(asize), sc->menuwin,
+	font_draw(sc, asize, strlen(asize), sc->menuwin, 0,
 	    width / 2 - width_size / 2, font_height(sc) + font_ascent(sc) + 1);
 }
 
@@ -250,12 +250,8 @@ mousefunc_menu_unhide(struct client_ctx *cc, void *arg)
 		if (old_cc != NULL)
 			client_ptrsave(old_cc);
 		client_ptrwarp(cc);
-	} else {
-		while ((mi = TAILQ_FIRST(&menuq)) != NULL) {
-			TAILQ_REMOVE(&menuq, mi, entry);
-			free(mi);
-		}
-	}
+	} else
+		menuq_clear(&menuq);
 }
 
 void
@@ -280,8 +276,5 @@ mousefunc_menu_cmd(struct client_ctx *cc, void *arg)
 	if (mi != NULL)
 		u_spawn(((struct cmd *)mi->ctx)->image);
 	else
-		while ((mi = TAILQ_FIRST(&menuq)) != NULL) {
-			TAILQ_REMOVE(&menuq, mi, entry);
-			free(mi);
-		}
+		menuq_clear(&menuq);
 }
diff --git a/parse.y b/parse.y
index 006d1b8..aae8f3c 100644
--- a/parse.y
+++ b/parse.y
@@ -75,7 +75,8 @@ typedef struct {
 %token	COLOR SNAPDIST
 %token	ACTIVEBORDER INACTIVEBORDER
 %token	GROUPBORDER UNGROUPBORDER
-%token	MENUBG MENUFG FONTCOLOR
+%token	MENUBG MENUFG
+%token	FONTCOLOR FONTSELCOLOR
 %token	ERROR
 %token	<v.string>		STRING
 %token	<v.number>		NUMBER
@@ -127,7 +128,7 @@ main		: FONTNAME STRING		{
 			conf->snapdist = $2;
 		}
 		| COMMAND STRING string		{
-			conf_cmd_add(conf, $3, $2, 0);
+			conf_cmd_add(conf, $3, $2);
 			free($2);
 			free($3);
 		}
@@ -188,16 +189,20 @@ colors		: ACTIVEBORDER STRING {
 			conf->color[CWM_COLOR_BORDER_UNGROUP].name = $2;
 		}
 		| MENUBG STRING {
-			free(conf->color[CWM_COLOR_BG_MENU].name);
-			conf->color[CWM_COLOR_BG_MENU].name = $2;
+			free(conf->menucolor[CWM_COLOR_MENU_BG]);
+			conf->menucolor[CWM_COLOR_MENU_BG] = $2;
 		}
 		| MENUFG STRING {
-			free(conf->color[CWM_COLOR_FG_MENU].name);
-			conf->color[CWM_COLOR_FG_MENU].name = $2;
+			free(conf->menucolor[CWM_COLOR_MENU_FG]);
+			conf->menucolor[CWM_COLOR_MENU_FG] = $2;
 		}
 		| FONTCOLOR STRING {
-			free(conf->color[CWM_COLOR_FONT].name);
-			conf->color[CWM_COLOR_FONT].name = $2;
+			free(conf->menucolor[CWM_COLOR_MENU_FONT]);
+			conf->menucolor[CWM_COLOR_MENU_FONT] = $2;
+		}
+		| FONTSELCOLOR STRING {
+			free(conf->menucolor[CWM_COLOR_MENU_FONT_SEL]);
+			conf->menucolor[CWM_COLOR_MENU_FONT_SEL] = $2;
 		}
 		;
 %%
@@ -249,6 +254,7 @@ lookup(char *s)
 		{ "mousebind",		MOUSEBIND},
 		{ "moveamount",		MOVEAMOUNT},
 		{ "no",			NO},
+		{ "selfont", 		FONTSELCOLOR},
 		{ "snapdist",		SNAPDIST},
 		{ "sticky",		STICKY},
 		{ "ungroupborder",	UNGROUPBORDER},
@@ -577,6 +583,9 @@ parse_config(const char *filename, struct conf *xconf)
 		for (i = 0; i < CWM_COLOR_MAX; i++)
 			xconf->color[i].name = conf->color[i].name;
 
+		for (i = 0; i < CWM_COLOR_MENU_MAX; i++)
+			xconf->menucolor[i] = conf->menucolor[i];
+
 		xconf->font = conf->font;
 	}
 
diff --git a/screen.c b/screen.c
index c723378..92ff9a4 100644
--- a/screen.c
+++ b/screen.c
@@ -32,6 +32,63 @@
 
 static void	 screen_init_xinerama(struct screen_ctx *);
 
+void
+screen_init(struct screen_ctx *sc, u_int which)
+{
+	Window			*wins, w0, w1;
+	XWindowAttributes	 winattr;
+	XSetWindowAttributes	 rootattr;
+	u_int			 nwins, i;
+
+	sc->which = which;
+	sc->visual = DefaultVisual(X_Dpy, sc->which);
+	sc->colormap = DefaultColormap(X_Dpy, sc->which);
+	sc->rootwin = RootWindow(X_Dpy, sc->which);
+
+	xu_ewmh_net_supported(sc);
+	xu_ewmh_net_supported_wm_check(sc);
+
+	conf_gap(&Conf, sc);
+
+	screen_update_geometry(sc);
+
+	conf_color(&Conf, sc);
+
+	group_init(sc);
+	conf_font(&Conf, sc);
+
+	TAILQ_INIT(&sc->mruq);
+
+	menu_init(sc);
+
+	rootattr.cursor = Cursor_normal;
+	rootattr.event_mask = SubstructureRedirectMask|SubstructureNotifyMask|
+	    PropertyChangeMask|EnterWindowMask|LeaveWindowMask|
+	    ColormapChangeMask|BUTTONMASK;
+
+	XChangeWindowAttributes(X_Dpy, sc->rootwin,
+	    CWEventMask|CWCursor, &rootattr);
+
+	/* Deal with existing clients. */
+	XQueryTree(X_Dpy, sc->rootwin, &w0, &w1, &wins, &nwins);
+
+	for (i = 0; i < nwins; i++) {
+		XGetWindowAttributes(X_Dpy, wins[i], &winattr);
+		if (winattr.override_redirect ||
+		    winattr.map_state != IsViewable)
+			continue;
+		(void)client_new(wins[i], sc, winattr.map_state != IsUnmapped);
+	}
+	XFree(wins);
+
+	screen_updatestackingorder(sc);
+
+	if (HasRandr)
+		XRRSelectInput(X_Dpy, sc->rootwin, RRScreenChangeNotifyMask);
+
+	XSync(X_Dpy, False);
+}
+
 struct screen_ctx *
 screen_fromroot(Window rootwin)
 {
diff --git a/xevents.c b/xevents.c
index acfb2bc..abfaf0e 100644
--- a/xevents.c
+++ b/xevents.c
@@ -241,8 +241,7 @@ xev_handle_buttonpress(XEvent *ee)
 	sc = screen_fromroot(e->root);
 	cc = client_find(e->window);
 
-	/* Ignore caps lock and numlock */
-	e->state &= ~(Mod2Mask | LockMask);
+	e->state &= ~IGNOREMODMASK;
 
 	TAILQ_FOREACH(mb, &Conf.mousebindingq, entry) {
 		if (e->button == mb->button && e->state == mb->modmask)
@@ -283,8 +282,7 @@ xev_handle_keypress(XEvent *ee)
 	keysym = XkbKeycodeToKeysym(X_Dpy, e->keycode, 0, 0);
 	skeysym = XkbKeycodeToKeysym(X_Dpy, e->keycode, 0, 1);
 
-	/* we don't care about caps lock and numlock here */
-	e->state &= ~(LockMask | Mod2Mask);
+	e->state &= ~IGNOREMODMASK;
 
 	TAILQ_FOREACH(kb, &Conf.keybindingq, entry) {
 		if (keysym != kb->keysym && skeysym == kb->keysym)
diff --git a/xutil.c b/xutil.c
index fa3fc7f..d141766 100644
--- a/xutil.c
+++ b/xutil.c
@@ -422,11 +422,19 @@ xu_getcolor(struct screen_ctx *sc, char *name)
 {
 	XColor	 color, tmp;
 
-	if (!XAllocNamedColor(X_Dpy, DefaultColormap(X_Dpy, sc->which),
-	    name, &color, &tmp)) {
+	if (!XAllocNamedColor(X_Dpy, sc->colormap, name, &color, &tmp)) {
 		warnx("XAllocNamedColor error: '%s'", name);
 		return (0);
 	}
 
 	return (color.pixel);
 }
+
+void
+xu_xorcolor(XRenderColor a, XRenderColor b, XRenderColor *r)
+{
+	r->red = a.red ^ b.red;
+	r->green = a.green ^ b.green;
+	r->blue = a.blue ^ b.blue;
+	r->alpha = 0xffff;
+}