aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authoroga2008-05-20 14:50:51 +0000
committeroga2008-05-20 14:50:51 +0000
commitc4a8f44931713f32f250264ca00520aae30fc0e3 (patch)
tree28a04445e99404bad46b8fbdc9070d8635e0fe72
parent073225cc6903924869d463a1014860a78f73b008 (diff)
downloadcwm-c4a8f44931713f32f250264ca00520aae30fc0e3.tar.gz
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--Makefile6
-rw-r--r--calmwm.c9
-rw-r--r--calmwm.h14
-rw-r--r--client.c14
-rw-r--r--grab.c99
-rw-r--r--kbfunc.c38
-rw-r--r--menu.c296
-rw-r--r--search.c267
8 files changed, 347 insertions, 396 deletions
diff --git a/Makefile b/Makefile
index 9942049..2fb5f2e 100644
--- a/Makefile
+++ b/Makefile
@@ -1,11 +1,11 @@
-# $OpenBSD: Makefile,v 1.6 2008/03/25 23:41:50 matthieu Exp $
+# $OpenBSD: Makefile,v 1.7 2008/05/20 14:50:51 oga Exp $
.include <bsd.xconf.mk>
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 8eb2ad6..79b62ea 100644
--- a/calmwm.c
+++ b/calmwm.c
@@ -15,7 +15,7 @@
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
- * $Id: calmwm.c,v 1.18 2008/05/19 18:53:09 oga Exp $
+ * $Id: calmwm.c,v 1.19 2008/05/20 14:50:51 oga Exp $
*/
#include "headers.h"
@@ -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 c3fac3e..3c9cb3c 100644
--- a/calmwm.h
+++ b/calmwm.h
@@ -15,7 +15,7 @@
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
- * $Id: calmwm.h,v 1.48 2008/05/19 18:07:53 okan Exp $
+ * $Id: calmwm.h,v 1.49 2008/05/20 14:50:51 oga Exp $
*/
#ifndef _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 a5cd9af..691f9bd 100644
--- a/client.c
+++ b/client.c
@@ -15,7 +15,7 @@
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
- * $Id: client.c,v 1.26 2008/05/19 17:24:19 okan Exp $
+ * $Id: client.c,v 1.27 2008/05/20 14:50:51 oga Exp $
*/
#include "headers.h"
@@ -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 90f23b2..d4abc87 100644
--- a/grab.c
+++ b/grab.c
@@ -15,7 +15,7 @@
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
- * $Id: grab.c,v 1.12 2008/05/19 18:07:53 okan Exp $
+ * $Id: grab.c,v 1.13 2008/05/20 14:50:51 oga Exp $
*/
#include "headers.h"
@@ -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 af2fc76..683da5f 100644
--- a/kbfunc.c
+++ b/kbfunc.c
@@ -15,7 +15,7 @@
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
- * $Id: kbfunc.c,v 1.27 2008/05/19 18:53:09 oga Exp $
+ * $Id: kbfunc.c,v 1.28 2008/05/20 14:50:51 oga Exp $
*/
#include <paths.h>
@@ -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 e989f4e..697c4d9 100644
--- a/search.c
+++ b/search.c
@@ -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.
*
- * $Id: search.c,v 1.10 2008/05/19 18:07:53 okan Exp $
+ * $Id: search.c,v 1.11 2008/05/20 14:50:51 oga Exp $
*/
#include "headers.h"
@@ -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.
*/