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:
265
search.c
265
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.
|
||||
*/
|
||||
|
||||
Reference in New Issue
Block a user