mirror of
https://github.com/leahneukirchen/cwm.git
synced 2023-08-10 21:13:12 +03:00
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:
parent
3bb0b451f7
commit
1e46ba72f7
4
Makefile
4
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}
|
||||
|
7
calmwm.c
7
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);
|
||||
|
12
calmwm.h
12
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);
|
||||
|
12
client.c
12
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);
|
||||
|
97
grab.c
97
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)
|
||||
{
|
||||
|
36
kbfunc.c
36
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
|
||||
|
296
menu.c
Normal file
296
menu.c
Normal 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
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.
|
||||
*/
|
||||
|
Loading…
Reference in New Issue
Block a user