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@.
This commit is contained in:
oga 2008-05-20 14:50:51 +00:00
parent 3bb0b451f7
commit 1e46ba72f7
8 changed files with 340 additions and 389 deletions

View File

@ -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}

View File

@ -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);

View File

@ -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);

View File

@ -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);

97
grab.c
View File

@ -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)
{

View File

@ -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

296
menu.c Normal file
View File

@ -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);
}

265
search.c
View File

@ -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.
*/