summary refs log tree commit diff
diff options
context:
space:
mode:
authoroga <oga>2008-05-20 14:50:51 +0000
committeroga <oga>2008-05-20 14:50:51 +0000
commit1e46ba72f706d7ab2b0f7a6a14054b908348d10e (patch)
tree0efe57cdad018b6a29f0c0b65113ef08589f953d
parent3bb0b451f78d13b4624e52b726f51e4847a84a2f (diff)
downloadcwm-1e46ba72f706d7ab2b0f7a6a14054b908348d10e.tar.gz
cwm-1e46ba72f706d7ab2b0f7a6a14054b908348d10e.tar.xz
cwm-1e46ba72f706d7ab2b0f7a6a14054b908348d10e.zip
Pull out the behaviour in grab_label and search_start into one utility
function menu_filter(). The plan is to eventually merge in grab_menu too.
Shrinks the code a fair bit.

Also, change XMaskEvent for XWindowEvent to prevent getting exposes for other
windows. This is particuarly noticable on slow machines with a LOT of xterms
(todd, you're an odd man).

ok okan@, todd@.
-rw-r--r--Makefile4
-rw-r--r--calmwm.c7
-rw-r--r--calmwm.h12
-rw-r--r--client.c12
-rw-r--r--grab.c97
-rw-r--r--kbfunc.c36
-rw-r--r--menu.c296
-rw-r--r--search.c265
8 files changed, 340 insertions, 389 deletions
diff --git a/Makefile b/Makefile
index 721f437..b0be0e4 100644
--- a/Makefile
+++ b/Makefile
@@ -4,8 +4,8 @@
 
 PROG=		cwm
 
-SRCS=		calmwm.c screen.c xmalloc.c client.c grab.c search.c \
-		util.c xutil.c conf.c input.c xevents.c group.c \
+SRCS=		calmwm.c screen.c xmalloc.c client.c grab.c menu.c \
+		search.c util.c xutil.c conf.c input.c xevents.c group.c \
 		kbfunc.c font.c parse.y
 
 CPPFLAGS+=	-I${X11BASE}/include -I${X11BASE}/include/freetype2 -I${.CURDIR}
diff --git a/calmwm.c b/calmwm.c
index 582c10a..db055c0 100644
--- a/calmwm.c
+++ b/calmwm.c
@@ -152,6 +152,10 @@ x_setupscreen(struct screen_ctx *sc, u_int which)
 	sc->display = x_screenname(which);
 	sc->which = which;
 	sc->rootwin = RootWindow(X_Dpy, which);
+
+	sc->xmax = DisplayWidth(X_Dpy, sc->which);
+	sc->ymax = DisplayHeight(X_Dpy, sc->which);
+
 	XAllocNamedColor(X_Dpy, DefaultColormap(X_Dpy, which),
 	    "black", &sc->fgcolor, &tmp);
 	XAllocNamedColor(X_Dpy, DefaultColormap(X_Dpy, which),
@@ -204,6 +208,8 @@ x_setupscreen(struct screen_ctx *sc, u_int which)
 
 	font_init(sc);
 	DefaultFont = font_getx(sc, Conf.DefaultFontName);
+	sc->fontheight = font_ascent(DefaultFont) +
+	    font_descent(DefaultFont) + 1;
 
 	/*
 	 * XXX - this should *really* be in screen_init().  ordering
@@ -213,7 +219,6 @@ x_setupscreen(struct screen_ctx *sc, u_int which)
 
 	/* Initialize menu window. */
 	grab_menuinit(sc);
-	search_init(sc);
 
 	/* Deal with existing clients. */
 	XQueryTree(X_Dpy, sc->rootwin, &w0, &w1, &wins, &nwins);
diff --git a/calmwm.h b/calmwm.h
index fa49d6c..e1a5b0e 100644
--- a/calmwm.h
+++ b/calmwm.h
@@ -60,7 +60,6 @@ struct screen_ctx {
 	u_int		 which;
 	Window		 rootwin;
 	Window		 menuwin;
-	Window		 searchwin;
 	Colormap	 colormap;
 	XColor		 bgcolor, fgcolor, fccolor, redcolor, cyancolor,
 			 whitecolor, blackcolor;
@@ -72,13 +71,13 @@ struct screen_ctx {
 
 	int		 altpersist;
 
-	int		 maxinitialised;
 	int		 xmax;
 	int		 ymax;
 
 	struct cycle_entry_q mruq;
 
 	struct fonthash	 fonthash;
+	u_int		 fontheight;
 	XftDraw		*xftdraw;
 	XftColor	 xftcolor;
 };
@@ -354,6 +353,10 @@ void			 client_gethints(struct client_ctx *);
 void			 client_freehints(struct client_ctx *);
 void			 client_do_shape(struct client_ctx *);
 
+struct menu  		*menu_filter(struct menu_q *, char *, char *, int,
+			     void (*)(struct menu_q *, struct menu_q *, char *),
+			     void (*)(struct menu *, int));
+
 void			 xev_handle_maprequest(struct xevent *, XEvent *);
 void			 xev_handle_unmapnotify(struct xevent *, XEvent *);
 void			 xev_handle_destroynotify(struct xevent *, XEvent *);
@@ -449,11 +452,6 @@ void			 kbfunc_ssh(struct client_ctx *, void *);
 void			 kbfunc_term(struct client_ctx *, void *);
 void			 kbfunc_lock(struct client_ctx *, void *);
 
-void			 search_init(struct screen_ctx *);
-struct menu	*search_start(struct menu_q *,
-		    void (*)(struct menu_q *, struct menu_q *, char *),
-		    void (*)(struct menu *, int),
-		    char *, int);
 void			 search_match_client(struct menu_q *, struct menu_q *,
 			     char *);
 void			 search_print_client(struct menu *, int);
diff --git a/client.c b/client.c
index 087d212..5026ac6 100644
--- a/client.c
+++ b/client.c
@@ -657,7 +657,7 @@ client_placecalc(struct client_ctx *cc)
 {
 	struct screen_ctx *sc = CCTOSC(cc);
 	int yslack, xslack;
-	int x, y, height, width, ymax, xmax, mousex, mousey;
+	int x, y, height, width, mousex, mousey;
 
 	y = cc->geom.y;
 	x = cc->geom.x;
@@ -665,11 +665,9 @@ client_placecalc(struct client_ctx *cc)
 	height = cc->geom.height;
 	width = cc->geom.width;
 
-	ymax = DisplayHeight(X_Dpy, sc->which) - cc->bwidth;
-	xmax = DisplayWidth(X_Dpy, sc->which) - cc->bwidth;
 
-	yslack = ymax - cc->geom.height;
-	xslack = xmax - cc->geom.width;
+	yslack = sc->ymax - cc->geom.height;
+	xslack = sc->xmax - cc->geom.width;
 
 	xu_ptr_getpos(sc->rootwin, &mousex, &mousey);
 
@@ -695,7 +693,7 @@ client_placecalc(struct client_ctx *cc)
 	} else {
 		if (yslack < 0) {
 			y = cc->bwidth;
-			height = ymax;
+			height = sc->ymax;
 		} else {
 			if (y == 0 || y > yslack)
 				y = MIN(mousey, yslack);
@@ -704,7 +702,7 @@ client_placecalc(struct client_ctx *cc)
 
 		if (xslack < 0) {
 			x = cc->bwidth;
-			width = xmax;
+			width = sc->xmax;
 		} else {
 			if (x == 0 || x > xslack)
 				x = MIN(mousex, xslack);
diff --git a/grab.c b/grab.c
index 6f0e56a..e27eb28 100644
--- a/grab.c
+++ b/grab.c
@@ -171,11 +171,6 @@ grab_menu(XButtonEvent *e, struct menu_q *menuq)
 		no++;
 	}
 
-	if (!sc->maxinitialised) {
-		sc->xmax = DisplayWidth(X_Dpy, sc->which);
-		sc->ymax = DisplayHeight(X_Dpy, sc->which);
-	}
-
 	height = font_ascent(font) + font_descent(font) + 1;
 	tothigh = height * no;
 
@@ -261,98 +256,6 @@ grab_menuinit(struct screen_ctx *sc)
 	    1, 1, 1, sc->blackpixl, sc->whitepixl);
 }
 
-#define LABEL_MAXLEN 256
-#define LabelMask (KeyPressMask|ExposureMask)
-
-void
-grab_label(struct client_ctx *cc)
-{
-	struct screen_ctx *sc = screen_current();
-	int x, y, dx, dy, fontheight, focusrevert;
-	XEvent e;
-	char labelstr[LABEL_MAXLEN];
-	char dispstr[LABEL_MAXLEN + sizeof("label>") - 1];
-	Window focuswin;
-	char chr;
-	enum ctltype ctl;
-	size_t len;
-	struct fontdesc *font = DefaultFont;
-
-	if (cc->label != NULL)
-		strlcpy(labelstr, cc->label, sizeof(labelstr));
-	else
-		labelstr[0] = '\0';
-
-	xu_ptr_getpos(sc->rootwin, &x, &y);
-
-	dy = fontheight = font_ascent(font) + font_descent(font) + 1;
-	dx = font_width(font, "label>", 6);
-
-	XMoveResizeWindow(X_Dpy, sc->searchwin, x, y, dx, dy);
-	XSelectInput(X_Dpy, sc->searchwin, LabelMask);
-	XMapRaised(X_Dpy, sc->searchwin);
-
-	XGetInputFocus(X_Dpy, &focuswin, &focusrevert);
-	XSetInputFocus(X_Dpy, sc->searchwin, RevertToPointerRoot, CurrentTime);
-
-	for (;;) {
-		XMaskEvent(X_Dpy, LabelMask, &e);
-
-		switch (e.type) {
-		case KeyPress:
-			if (input_keycodetrans(e.xkey.keycode, e.xkey.state,
-			    &ctl, &chr) < 0)
-				continue;
-
-			switch (ctl) {
-			case CTL_ERASEONE:
-				if ((len = strlen(labelstr)) > 0)
-					labelstr[len - 1] = '\0';
-				break;
-			case CTL_RETURN:
-				/* Done */
-				if (strlen(labelstr) == 0)
-					goto out;
-
-				if (cc->label != NULL)
-					xfree(cc->label);
-
-				cc->label = xstrdup(labelstr);
-				/* FALLTHROUGH */
-			case CTL_ABORT:
-				goto out;
-			default:
-				break;
-			}
-
-			if (chr != '\0') {
-				char str[2];
-
-				str[0] = chr;
-				str[1] = '\0';
-				strlcat(labelstr, str, sizeof(labelstr));
-			}
-
-		case Expose:
-			snprintf(dispstr, sizeof(dispstr), "label>%s",
-			    labelstr);
-			dx = font_width(font, dispstr, strlen(dispstr));
-			dy = fontheight;
-
-			XClearWindow(X_Dpy, sc->searchwin);
-			XResizeWindow(X_Dpy, sc->searchwin, dx, dy);
-
-			font_draw(font, dispstr, strlen(dispstr),
-			    sc->searchwin, 0, font_ascent(font) + 1);
-			break;
-		}
-	}
-
-out:
-	XSetInputFocus(X_Dpy, focuswin, focusrevert, CurrentTime);
-	XUnmapWindow(X_Dpy, sc->searchwin);
-}
-
 static int
 _sweepcalc(struct client_ctx *cc, int x0, int y0, int motionx, int motiony)
 {
diff --git a/kbfunc.c b/kbfunc.c
index 0446cb7..e006d34 100644
--- a/kbfunc.c
+++ b/kbfunc.c
@@ -128,9 +128,8 @@ kbfunc_client_search(struct client_ctx *scratch, void *arg)
 		TAILQ_INSERT_TAIL(&menuq, mi, entry);
 	}
 
-	if ((mi = search_start(&menuq,
-	    search_match_client, search_print_client,
-	    "window", 0)) != NULL) {
+	if ((mi = menu_filter(&menuq, "window", NULL, 0,
+	    search_match_client, search_print_client)) != NULL) {
 		cc = (struct client_ctx *)mi->ctx;
 		if (cc->flags & CLIENT_HIDDEN)
 			client_unhide(cc);
@@ -163,8 +162,8 @@ kbfunc_menu_search(struct client_ctx *scratch, void *arg)
 		TAILQ_INSERT_TAIL(&menuq, mi, entry);
 	}
 
-	if ((mi = search_start(&menuq,
-	    search_match_text, NULL, "application", 0)) != NULL)
+	if ((mi = menu_filter(&menuq, "application", NULL, 0,
+	    search_match_text, NULL)) != NULL)
 		u_spawn(((struct cmd *)mi->ctx)->image);
 
 	while ((mi = TAILQ_FIRST(&menuq)) != NULL) {
@@ -301,8 +300,8 @@ kbfunc_exec(struct client_ctx *scratch, void *arg)
 	}
 	xfree(path);
 
-	if ((mi = search_start(&menuq,
-	    search_match_exec, NULL, label, 1)) != NULL) {
+	if ((mi = menu_filter(&menuq, label, NULL, 1,
+	    search_match_exec, NULL)) != NULL) {
 		switch (cmd) {
 			case CWM_EXEC_PROGRAM:
 				u_spawn(mi->text);
@@ -376,8 +375,8 @@ kbfunc_ssh(struct client_ctx *scratch, void *arg)
 	fclose(fp);
 
 
-	if ((mi = search_start(&menuq,
-	    search_match_exec, NULL, "ssh", 1)) != NULL) {
+	if ((mi = menu_filter(&menuq, "ssh", NULL, 1,
+	    search_match_exec, NULL)) != NULL) {
 		conf_reload(&Conf);
 		l = snprintf(cmd, sizeof(cmd), "%s -e ssh %s", Conf.termpath,
 		    mi->text);
@@ -396,7 +395,24 @@ kbfunc_ssh(struct client_ctx *scratch, void *arg)
 void
 kbfunc_client_label(struct client_ctx *cc, void *arg)
 {
-	grab_label(cc);
+	struct menu	*mi;
+	char		*current;
+	struct menu_q	 menuq;
+
+	TAILQ_INIT(&menuq);
+	
+	if (cc->label != NULL)
+		current = cc->label;
+	else
+		current = NULL;
+
+	if ((mi = menu_filter(&menuq, "label", current, 1,
+	    search_match_text, NULL)) != NULL) {
+		if (cc->label != NULL)
+			xfree(cc->label);
+		cc->label = xstrdup(mi->text);
+		xfree(mi);
+	}
 }
 
 void
diff --git a/menu.c b/menu.c
new file mode 100644
index 0000000..a022f84
--- /dev/null
+++ b/menu.c
@@ -0,0 +1,296 @@
+/*
+ * Copyright (c) 2008 Owain G. Ainsworth <oga@openbsd.org>
+ * Copyright (c) 2004 Marius Aamodt Eriksen <marius@monkey.org>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include "headers.h"
+#include "calmwm.h"
+
+#define KeyMask (KeyPressMask|ExposureMask)
+
+struct menu_ctx {
+	char			 searchstr[MENU_MAXENTRY + 1];
+	char			 dispstr[MENU_MAXENTRY*2 + 1];
+	char			 promptstr[MENU_MAXENTRY + 1];
+	int			 list;
+	int			 listing;
+	int			 changed;
+	int			 noresult;
+	int			 x;
+	int			 y; /* location */
+    	void (*match)(struct menu_q *, struct menu_q *, char *);
+    	void (*print)(struct menu *, int);
+};
+static struct menu	*menu_handle_key(XEvent *, struct menu_ctx *,
+			     struct menu_q *, struct menu_q *);
+static void		 menu_draw(struct screen_ctx *, struct menu_ctx *,
+			     struct menu_q *, struct menu_q *);
+
+struct menu *
+menu_filter(struct menu_q *menuq, char *prompt, char *initial, int dummy,
+    void (*match)(struct menu_q *, struct menu_q *, char *),
+    void (*print)(struct menu *, int))
+{
+	struct screen_ctx	*sc = screen_current();
+	struct menu_ctx		 mc;
+	struct menu_q		 resultq;
+	struct menu		*mi = NULL;
+	XEvent			 e;
+	Window			 focuswin;
+	int			 dx, dy, focusrevert;
+	char			 endchar = '«';
+	struct fontdesc		*font = DefaultFont;
+
+	TAILQ_INIT(&resultq);
+
+	bzero(&mc, sizeof(mc));
+
+	xu_ptr_getpos(sc->rootwin, &mc.x, &mc.y);
+
+	if (prompt == NULL)
+		prompt = "search";
+
+	if (initial != NULL)
+		strlcpy(mc.searchstr, initial, sizeof(mc.searchstr));
+	else
+		mc.searchstr[0] = '\0';
+
+	mc.match = match;
+	mc.print = print;
+
+	snprintf(mc.promptstr, sizeof(mc.promptstr), "%s»", prompt);
+	snprintf(mc.dispstr, sizeof(mc.dispstr), "%s%s%c", mc.promptstr,
+	    mc.searchstr, endchar);
+	dx = font_width(font, mc.dispstr, strlen(mc.dispstr));
+	dy = sc->fontheight;
+
+	XMoveResizeWindow(X_Dpy, sc->menuwin, mc.x, mc.y, dx, dy);
+	XSelectInput(X_Dpy, sc->menuwin, KeyMask);
+	XMapRaised(X_Dpy, sc->menuwin);
+
+	if (xu_ptr_grab(sc->menuwin, 0, Cursor_question) < 0) {
+		XUnmapWindow(X_Dpy, sc->menuwin);
+		return (NULL);
+	}
+
+	XGetInputFocus(X_Dpy, &focuswin, &focusrevert);
+	XSetInputFocus(X_Dpy, sc->menuwin, RevertToPointerRoot, CurrentTime);
+
+	for (;;) {
+		mc.changed = 0;
+
+		XWindowEvent(X_Dpy, sc->menuwin, KeyMask, &e);
+
+		switch (e.type) {
+		case KeyPress:
+			if ((mi = menu_handle_key(&e, &mc, menuq, &resultq))
+			    != NULL)
+				goto out;
+			/* FALLTHROUGH */
+		case Expose:
+			menu_draw(sc, &mc, menuq, &resultq);
+			break;
+		}
+	}
+out:
+	if (dummy == 0 && mi->dummy) { /* no match */
+		xfree (mi);
+		mi = NULL;
+		xu_ptr_ungrab();
+		XSetInputFocus(X_Dpy, focuswin, focusrevert, CurrentTime);
+	}
+
+	XUnmapWindow(X_Dpy, sc->menuwin);
+
+	return (mi);
+}
+
+static struct menu *
+menu_handle_key(XEvent *e, struct menu_ctx *mc, struct menu_q *menuq,
+    struct menu_q *resultq)
+{
+	struct menu	*mi;
+	enum ctltype	 ctl;
+	char		 chr;
+	size_t		 len;
+
+	if (input_keycodetrans(e->xkey.keycode, e->xkey.state,
+	    &ctl, &chr) < 0)
+		return (NULL);
+
+	switch (ctl) {
+	case CTL_ERASEONE:
+		if ((len = strlen(mc->searchstr)) > 0) {
+			mc->searchstr[len - 1] = '\0';
+			mc->changed = 1;
+		}
+		break;
+	case CTL_UP:
+		mi = TAILQ_LAST(resultq, menu_q);
+		if (mi == NULL)
+			break;
+
+		TAILQ_REMOVE(resultq, mi, resultentry);
+		TAILQ_INSERT_HEAD(resultq, mi, resultentry);
+		break;
+	case CTL_DOWN:
+		mi = TAILQ_FIRST(resultq);
+		if (mi == NULL)
+			break;
+
+		TAILQ_REMOVE(resultq, mi, resultentry);
+		TAILQ_INSERT_TAIL(resultq, mi, resultentry);
+		break;
+	case CTL_RETURN:
+		/*
+		 * Return whatever the cursor is currently on. Else
+		 * even if dummy is zero, we need to return something.
+		 */
+		if ((mi = TAILQ_FIRST(resultq)) == NULL) {
+			mi = xmalloc(sizeof *mi);
+			(void)strlcpy(mi->text,
+			    mc->searchstr, sizeof(mi->text));
+			mi->dummy = 1;
+		}
+		return (mi);
+	case CTL_WIPE:
+		mc->searchstr[0] = '\0';
+		mc->changed = 1;
+		break;
+	case CTL_ALL:
+		mc->list = !mc->list;
+		break;
+	case CTL_ABORT:
+		mi = xmalloc(sizeof *mi);
+		mi->text[0] = '\0';
+		mi->dummy = 1;
+		return (mi);
+	default:
+		break;
+	}
+
+	if (chr != '\0') {
+		char str[2];
+
+		str[0] = chr;
+		str[1] = '\0';
+		mc->changed = 1;
+		strlcat(mc->searchstr, str, sizeof(mc->searchstr));
+	}
+
+	mc->noresult = 0;
+	if (mc->changed && strlen(mc->searchstr) > 0) {
+		(*mc->match)(menuq, resultq, mc->searchstr);
+		/* If menuq is empty, never show we've failed */
+		mc->noresult = TAILQ_EMPTY(resultq) && !TAILQ_EMPTY(menuq);
+	} else if (mc->changed)
+		TAILQ_INIT(resultq);
+
+	 if (!mc->list && mc->listing && !mc->changed) {
+		TAILQ_INIT(resultq);
+		mc->listing = 0;
+	}
+
+	return (NULL);
+}
+
+static void
+menu_draw(struct screen_ctx *sc, struct menu_ctx *mc, struct menu_q *menuq,
+    struct menu_q *resultq)
+{
+	struct menu	*mi;
+	char		 endchar = '«';
+	int		 n = 0;
+	int		 dx, dy;
+	int		 xsave, ysave;
+	int		 warp;
+	struct fontdesc	*font = DefaultFont;
+
+	if (mc->list) {
+		if (TAILQ_EMPTY(resultq) && mc->list) {
+			/* Copy them all over. */
+			TAILQ_FOREACH(mi, menuq, entry)
+				TAILQ_INSERT_TAIL(resultq, mi,
+				    resultentry);
+
+			mc->listing = 1;
+		} else if (mc->changed)
+			mc->listing = 0;
+	}
+
+	snprintf(mc->dispstr, sizeof(mc->dispstr), "%s%s%c",
+	    mc->promptstr, mc->searchstr, endchar);
+	dx = font_width(font, mc->dispstr, strlen(mc->dispstr));
+	dy = sc->fontheight;
+
+	TAILQ_FOREACH(mi, resultq, resultentry) {
+		char *text;
+
+		if (mc->print != NULL) {
+			(*mc->print)(mi, mc->listing);
+			text = mi->print;
+		} else {
+			mi->print[0] = '\0';
+			text = mi->text;
+		}
+
+		dx = MAX(dx, font_width(font, text,
+		    MIN(strlen(text), MENU_MAXENTRY)));
+		dy += sc->fontheight;
+	}
+
+	xsave = mc->x;
+	ysave = mc->y;
+	if (mc->x < 0)
+		mc->x = 0;
+	else if (mc->x + dx >= sc->xmax)
+		mc->x = sc->xmax - dx;
+
+	if (mc->y + dy >= sc->ymax)
+		mc->y = sc->ymax - dy;
+	/* never hide the top of the menu */
+        if (mc->y < 0)
+                mc->y = 0;
+
+	if (mc->x != xsave || mc->y != ysave)
+		xu_ptr_setpos(sc->rootwin, mc->x, mc->y);
+
+	XClearWindow(X_Dpy, sc->menuwin);
+	XMoveResizeWindow(X_Dpy, sc->menuwin, mc->x, mc->y, dx, dy);
+
+	font_draw(font, mc->dispstr, strlen(mc->dispstr), sc->menuwin,
+	    0, font_ascent(font) + 1);
+
+	n = 1;
+	TAILQ_FOREACH(mi, resultq, resultentry) {
+		char *text = mi->print[0] != '\0' ?
+		    mi->print : mi->text;
+
+		font_draw(font, text,
+		    MIN(strlen(text), MENU_MAXENTRY),
+		    sc->menuwin,
+		    0, n*sc->fontheight + font_ascent(font) + 1);
+		n++;
+	}
+
+	if (n > 1)
+		XFillRectangle(X_Dpy, sc->menuwin, sc->gc,
+		    0, sc->fontheight, dx, sc->fontheight);
+
+	if (mc->noresult)
+		XFillRectangle(X_Dpy, sc->menuwin, sc->gc,
+		    0, 0, dx, sc->fontheight);
+
+}
diff --git a/search.c b/search.c
index 15e7e64..ac108d9 100644
--- a/search.c
+++ b/search.c
@@ -24,271 +24,6 @@
 
 static int	_strsubmatch(char *, char *, int);
 
-void
-search_init(struct screen_ctx *sc)
-{
-	sc->searchwin = XCreateSimpleWindow(X_Dpy, sc->rootwin, 0, 0,
-	    1, 1, 1, sc->blackpixl, sc->whitepixl);
-}
-
-/*
- * Input: list of items,
- * Output: choose one
- * so, exactly like menus
- */
-
-struct menu *
-search_start(struct menu_q *menuq,
-    void (*match)(struct menu_q *, struct menu_q *, char *),
-    void (*print)(struct menu *mi, int print),
-    char *prompt, int dummy)
-{
-	struct screen_ctx *sc = screen_current();
-	int x, y, dx, dy, fontheight,
-	    focusrevert, mutated, xmax, ymax, warp, added, beobnoxious = 0;
-	XEvent e;
-	char searchstr[MENU_MAXENTRY + 1];
-	char dispstr[MENU_MAXENTRY*2 + 1];
-	char promptstr[MENU_MAXENTRY + 1];
-	Window focuswin;
-	struct menu *mi = NULL, *dummy_mi = NULL;
-	struct menu_q resultq;
-	char chr;
-	enum ctltype ctl;
-	size_t len;
-	u_int n;
-	static int list = 0;
-	int listing = 0;
-	char endchar = '«';
-	struct fontdesc *font = DefaultFont;
-
-	if (prompt == NULL)
-		prompt = "search";
-
-	TAILQ_INIT(&resultq);
-
-	xmax = DisplayWidth(X_Dpy, sc->which);
-	ymax = DisplayHeight(X_Dpy, sc->which);
-
-	xu_ptr_getpos(sc->rootwin, &x, &y);
-
-	searchstr[0] = '\0';
-
-	snprintf(promptstr, sizeof(promptstr), "%s »", prompt);
-	dy = fontheight = font_ascent(font) + font_descent(font) + 1;
-	snprintf(dispstr, sizeof(dispstr), "%s%c", promptstr, endchar);
-	dx = font_width(font, dispstr, strlen(dispstr));
-
-	XMoveResizeWindow(X_Dpy, sc->searchwin, x, y, dx, dy);
-	XSelectInput(X_Dpy, sc->searchwin, SearchMask);
-	XMapRaised(X_Dpy, sc->searchwin);
-
-	/*
-	 * TODO: eventually, the mouse should be able to select
-	 * results as well.  Right now we grab it only to set a fancy
-	 * cursor.
-	 */
-	if (xu_ptr_grab(sc->searchwin, 0, Cursor_question) < 0) {
-		XUnmapWindow(X_Dpy, sc->searchwin);
-		return (NULL);
-	}
-
-	XGetInputFocus(X_Dpy, &focuswin, &focusrevert);
-	XSetInputFocus(X_Dpy, sc->searchwin, RevertToPointerRoot, CurrentTime);
-
-	for (;;) {
-		added = mutated = 0;
-
-		XMaskEvent(X_Dpy, SearchMask, &e);
-
-		switch (e.type) {
-		case KeyPress:
-			if (input_keycodetrans(e.xkey.keycode, e.xkey.state,
-			    &ctl, &chr) < 0)
-				continue;
-
-			switch (ctl) {
-			case CTL_ERASEONE:
-				if ((len = strlen(searchstr)) > 0) {
-					searchstr[len - 1] = '\0';
-					mutated = 1;
-				}
-				break;
-			case CTL_UP:
-				mi = TAILQ_LAST(&resultq, menu_q);
-				if (mi == NULL)
-					break;
-
-				TAILQ_REMOVE(&resultq, mi, resultentry);
-				TAILQ_INSERT_HEAD(&resultq, mi, resultentry);
-				break;
-			case CTL_DOWN:
-				mi = TAILQ_FIRST(&resultq);
-				if (mi == NULL)
-					break;
-
-				TAILQ_REMOVE(&resultq, mi, resultentry);
-				TAILQ_INSERT_TAIL(&resultq, mi, resultentry);
-				break;
-			case CTL_RETURN:
-				/* This is just picking the match the
-				 * cursor is over. */
-				if ((mi = TAILQ_FIRST(&resultq)) != NULL) {
-					goto found;
-				} else if (dummy) {
-					dummy_mi = xmalloc(sizeof *dummy_mi);
-					(void) strlcpy(dummy_mi->text,
-					    searchstr, sizeof(dummy_mi->text));
-					dummy_mi->dummy = 1;
-					goto found;
-				}
-				goto out;
-			case CTL_WIPE:
-				searchstr[0] = '\0';
-				mutated = 1;
-				break;
-			case CTL_ALL:
-				list = !list;
-				break;
-			case CTL_ABORT:
-				goto out;
-			default:
-				break;
-			}
-
-			if (chr != '\0') {
-				char str[2];
-
-				str[0] = chr;
-				str[1] = '\0';
-				mutated = 1;
-				added =
-				    strlcat(searchstr, str, sizeof(searchstr));
-			}
-
-			beobnoxious = 0;
-			if (mutated && strlen(searchstr) > 0) {
-				(*match)(menuq, &resultq, searchstr);
-				beobnoxious = TAILQ_EMPTY(&resultq);
-			} else if (mutated)
-				TAILQ_INIT(&resultq);
-
-
-			 if (!list && listing && !mutated) {
-				TAILQ_INIT(&resultq);
-				listing = 0;
-			}
-
-		case Expose:
-			if (list) {
-				if (TAILQ_EMPTY(&resultq) && list) {
-					/* Copy them all over. */
-					TAILQ_FOREACH(mi, menuq, entry)
-						TAILQ_INSERT_TAIL(&resultq, mi,
-						    resultentry);
-
-					listing = 1;
-				} else if (mutated)
-					listing = 0;
-			}
-
-			snprintf(dispstr, sizeof(dispstr), "%s%s%c",
-			    promptstr, searchstr, endchar);
-			dx = font_width(font, dispstr, strlen(dispstr));
-			dy = fontheight;
-
-			TAILQ_FOREACH(mi, &resultq, resultentry) {
-				char *text;
-
-				if (print != NULL) {
-					(*print)(mi, listing);
-					text = mi->print;
-				} else {
-					mi->print[0] = '\0';
-					text = mi->text;
-				}
-
-				dx = MAX(dx, font_width(font, text,
-				    MIN(strlen(text), MENU_MAXENTRY)));
-				dy += fontheight;
-			}
-
-			/*
-			 * Calculate new geometry.
-			 *
-			 * XXX - put this into a util function -- it's
-			 * used elsewhere, too.
-			 */
-			warp = 0;
-			if (x < 0) {
-				x = 0;
-				warp = 1;
-			}
-			if (x + dx >= xmax) {
-				x = xmax - dx;
-				warp = 1;
-			}
-
-			if (y < 0) {
-				y = 0;
-				warp = 1;
-			}
-			if (y + dy >= ymax) {
-				y = ymax - dy;
-				/* If the menu is too high, never hide the
-				 * top of the menu.
-				 */
-				if (y < 0)
-					y = 0;
-				warp = 1;
-			}
-
-			if (warp)
-				xu_ptr_setpos(sc->rootwin, x, y);
-
-			XClearWindow(X_Dpy, sc->searchwin);
-			XMoveResizeWindow(X_Dpy, sc->searchwin, x, y, dx, dy);
-
-			font_draw(font, dispstr, strlen(dispstr), sc->searchwin,
-			    0, font_ascent(font) + 1);
-
-			n = 1;
-			TAILQ_FOREACH(mi, &resultq, resultentry) {
-				char *text = mi->print[0] != '\0' ?
-				    mi->print : mi->text;
-
-				font_draw(font, text,
-				    MIN(strlen(text), MENU_MAXENTRY),
-				    sc->searchwin,
-				    0, n*fontheight + font_ascent(font) + 1);
-				n++;
-			}
-
-			if (n > 1)
-				XFillRectangle(X_Dpy, sc->searchwin, sc->gc,
-				    0, fontheight, dx, fontheight);
-
-			if (beobnoxious)
-				XFillRectangle(X_Dpy, sc->searchwin, sc->gc,
-				    0, 0, dx, fontheight);
-
-			break;
-		}
-	}
-
-out:
-	/* (if no match) */
-	xu_ptr_ungrab();
-	XSetInputFocus(X_Dpy, focuswin, focusrevert, CurrentTime);
-
-found:
-	XUnmapWindow(X_Dpy, sc->searchwin);
-
-	if (dummy && dummy_mi != NULL)
-		return (dummy_mi);
-	return (mi);
-}
-
 /*
  * Match: label, title, class.
  */