diff options
-rw-r--r-- | calmwm.c | 6 | ||||
-rw-r--r-- | calmwm.h | 5 | ||||
-rw-r--r-- | grab.c | 111 | ||||
-rw-r--r-- | group.c | 2 | ||||
-rw-r--r-- | menu.c | 169 | ||||
-rw-r--r-- | xevents.c | 2 |
6 files changed, 142 insertions, 153 deletions
diff --git a/calmwm.c b/calmwm.c index db055c0..c00e46a 100644 --- a/calmwm.c +++ b/calmwm.c @@ -202,10 +202,6 @@ x_setupscreen(struct screen_ctx *sc, u_int which) GCForeground|GCBackground|GCFunction| GCLineWidth|GCSubwindowMode, &gv); - sc->hlgc = XCreateGC(X_Dpy, sc->rootwin, - GCForeground|GCBackground|GCFunction| - GCLineWidth|GCSubwindowMode, &gv); - font_init(sc); DefaultFont = font_getx(sc, Conf.DefaultFontName); sc->fontheight = font_ascent(DefaultFont) + @@ -218,7 +214,7 @@ x_setupscreen(struct screen_ctx *sc, u_int which) TAILQ_INIT(&sc->mruq); /* Initialize menu window. */ - grab_menuinit(sc); + menu_init(sc); /* Deal with existing clients. */ XQueryTree(X_Dpy, sc->rootwin, &w0, &w1, &wins, &nwins); diff --git a/calmwm.h b/calmwm.h index e1a5b0e..96271e5 100644 --- a/calmwm.h +++ b/calmwm.h @@ -65,7 +65,7 @@ struct screen_ctx { whitecolor, blackcolor; char *display; unsigned long blackpixl, whitepixl, redpixl, bluepixl, cyanpixl; - GC gc, hlgc; + GC gc; Pixmap gray, blue, red; @@ -356,6 +356,7 @@ 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 menu_init(struct screen_ctx *); void xev_handle_maprequest(struct xevent *, XEvent *); void xev_handle_unmapnotify(struct xevent *, XEvent *); @@ -405,8 +406,6 @@ void u_exec(char *); void grab_sweep(struct client_ctx *); void grab_drag(struct client_ctx *); -void grab_menuinit(struct screen_ctx *); -void *grab_menu(XButtonEvent *, struct menu_q *); void grab_label(struct client_ctx *); void xfree(void *); diff --git a/grab.c b/grab.c index e27eb28..8a901c0 100644 --- a/grab.c +++ b/grab.c @@ -145,117 +145,6 @@ grab_drag(struct client_ctx *cc) /* NOTREACHED */ } -#define MenuMask (ButtonMask|ButtonMotionMask|ExposureMask) -#define MenuGrabMask (ButtonMask|ButtonMotionMask|StructureNotifyMask) -#define AllButtonMask (Button1Mask|Button2Mask|Button3Mask|Button4Mask|Button5Mask) - -void * -grab_menu(XButtonEvent *e, struct menu_q *menuq) -{ - struct screen_ctx *sc; - struct menu *mi; - XEvent event; - struct fontdesc *font = DefaultFont; - int x, y, width, height, tothigh, i, no, entry, prev; - int fx, fy; - - no = i = width = 0; - - if ((sc = screen_fromroot(e->root)) == NULL || e->window == sc->menuwin) - return (NULL); - - TAILQ_FOREACH(mi, menuq, entry) { - i = font_width(font, mi->text, strlen(mi->text)) + 4; - if (i > width) - width = i; - no++; - } - - height = font_ascent(font) + font_descent(font) + 1; - tothigh = height * no; - - x = e->x - width/2; - y = e->y - height/2; - - /* does it fit on the screen? */ - if (x < 0) - x = 0; - else if (x+width >= sc->xmax) - x = sc->xmax - width; - - if (y < 0) - y = 0; - else if (y+tothigh >= sc->ymax) - y = sc->ymax - tothigh; - - xu_ptr_setpos(e->root, x + width/2, y + height/2); - - XMoveResizeWindow(X_Dpy, sc->menuwin, x, y, width, tothigh); - XSelectInput(X_Dpy, sc->menuwin, MenuMask); - XMapRaised(X_Dpy, sc->menuwin); - - if (xu_ptr_grab(sc->menuwin, MenuGrabMask, Cursor_select) < 0) { - XUnmapWindow(X_Dpy, sc->menuwin); - return (NULL); - } - - entry = prev = -1; - - for (;;) { - XMaskEvent(X_Dpy, MenuMask, &event); - switch (event.type) { - case Expose: - XClearWindow(X_Dpy, sc->menuwin); - i = 0; - TAILQ_FOREACH(mi, menuq, entry) { - fx = (width - font_width(font, mi->text, - strlen(mi->text)))/2; - fy = height*i + font_ascent(font) + 1; - font_draw(font, mi->text, strlen(mi->text), - sc->menuwin, fx, fy); - i++; - } - /* FALLTHROUGH */ - case MotionNotify: - prev = entry; - entry = menu_calc_entry(event.xbutton.x, - event.xbutton.y, width, height, no); - if (prev != -1) - XFillRectangle(X_Dpy, sc->menuwin, sc->hlgc, - 0, height*prev, width, height); - if (entry != -1) { - xu_ptr_regrab(MenuGrabMask, Cursor_select); - XFillRectangle(X_Dpy, sc->menuwin, sc->hlgc, - 0, height*entry, width, height); - } else - xu_ptr_regrab(MenuGrabMask, Cursor_default); - break; - case ButtonRelease: - if (event.xbutton.button != e->button) - break; - entry = menu_calc_entry(event.xbutton.x, - event.xbutton.y, width, height, no); - xu_ptr_ungrab(); - XUnmapWindow(X_Dpy, sc->menuwin); - - i = 0; - TAILQ_FOREACH(mi, menuq, entry) - if (entry == i++) - break; - return (mi); - default: - break; - } - } -} - -void -grab_menuinit(struct screen_ctx *sc) -{ - sc->menuwin = XCreateSimpleWindow(X_Dpy, sc->rootwin, 0, 0, - 1, 1, 1, sc->blackpixl, sc->whitepixl); -} - static int _sweepcalc(struct client_ctx *cc, int x0, int y0, int motionx, int motiony) { diff --git a/group.c b/group.c index 589015a..ee6af0a 100644 --- a/group.c +++ b/group.c @@ -273,7 +273,7 @@ group_menu(XButtonEvent *e) if (TAILQ_EMPTY(&menuq)) return; - mi = (struct menu *)grab_menu(e, &menuq); + mi = menu_filter(&menuq, NULL, NULL, 0, NULL, NULL); if (mi == NULL || mi->ctx == NULL) goto cleanup; diff --git a/menu.c b/menu.c index a022f84..b3a77cf 100644 --- a/menu.c +++ b/menu.c @@ -18,25 +18,49 @@ #include "headers.h" #include "calmwm.h" -#define KeyMask (KeyPressMask|ExposureMask) +#define KeyMask (KeyPressMask|ExposureMask) +#define MenuMask (ButtonMask|ButtonMotionMask|ExposureMask| \ + PointerMotionMask) +#define MenuGrabMask (ButtonMask|ButtonMotionMask|StructureNotifyMask|\ + PointerMotionMask) +#define PROMPT_SCHAR '»' +#define PROMPT_ECHAR '«' struct menu_ctx { char searchstr[MENU_MAXENTRY + 1]; char dispstr[MENU_MAXENTRY*2 + 1]; char promptstr[MENU_MAXENTRY + 1]; + int hasprompt; int list; int listing; int changed; int noresult; + int prev; + int entry; + int width; + int num; int x; - int y; /* location */ + int y; 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_handle_move(XEvent *, struct menu_ctx *, + struct screen_ctx *); +struct menu *menu_handle_release(XEvent *, struct menu_ctx *, + struct screen_ctx *, struct menu_q *); static void menu_draw(struct screen_ctx *, struct menu_ctx *, struct menu_q *, struct menu_q *); +static int menu_calc_entry(struct screen_ctx *, struct menu_ctx *, + int, int); + +void +menu_init(struct screen_ctx *sc) +{ + sc->menuwin = XCreateSimpleWindow(X_Dpy, sc->rootwin, 0, 0, + 1, 1, 1, sc->blackpixl, sc->whitepixl); +} struct menu * menu_filter(struct menu_q *menuq, char *prompt, char *initial, int dummy, @@ -49,8 +73,7 @@ menu_filter(struct menu_q *menuq, char *prompt, char *initial, int dummy, struct menu *mi = NULL; XEvent e; Window focuswin; - int dx, dy, focusrevert; - char endchar = '«'; + int Mask, focusrevert; struct fontdesc *font = DefaultFont; TAILQ_INIT(&resultq); @@ -59,8 +82,19 @@ menu_filter(struct menu_q *menuq, char *prompt, char *initial, int dummy, xu_ptr_getpos(sc->rootwin, &mc.x, &mc.y); - if (prompt == NULL) - prompt = "search"; + if (prompt == NULL) { + Mask = MenuMask; + mc.promptstr[0] = '\0'; + mc.list = 1; + } else { + Mask = MenuMask | KeyMask; /* only accept keys if prompt */ + snprintf(mc.promptstr, sizeof(mc.promptstr), "%s%c", prompt, + PROMPT_SCHAR); + snprintf(mc.dispstr, sizeof(mc.dispstr), "%s%s%c", mc.promptstr, + mc.searchstr, PROMPT_ECHAR); + mc.width = font_width(font, mc.dispstr, strlen(mc.dispstr)); + mc.hasprompt = 1; + } if (initial != NULL) strlcpy(mc.searchstr, initial, sizeof(mc.searchstr)); @@ -69,18 +103,14 @@ menu_filter(struct menu_q *menuq, char *prompt, char *initial, int dummy, mc.match = match; mc.print = print; + mc.entry = mc.prev = -1; - 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); + XMoveResizeWindow(X_Dpy, sc->menuwin, mc.x, mc.y, mc.width, + sc->fontheight); + XSelectInput(X_Dpy, sc->menuwin, Mask); XMapRaised(X_Dpy, sc->menuwin); - if (xu_ptr_grab(sc->menuwin, 0, Cursor_question) < 0) { + if (xu_ptr_grab(sc->menuwin, MenuGrabMask, Cursor_question) < 0) { XUnmapWindow(X_Dpy, sc->menuwin); return (NULL); } @@ -91,9 +121,11 @@ menu_filter(struct menu_q *menuq, char *prompt, char *initial, int dummy, for (;;) { mc.changed = 0; - XWindowEvent(X_Dpy, sc->menuwin, KeyMask, &e); + XWindowEvent(X_Dpy, sc->menuwin, Mask, &e); switch (e.type) { + default: + break; case KeyPress: if ((mi = menu_handle_key(&e, &mc, menuq, &resultq)) != NULL) @@ -102,6 +134,14 @@ menu_filter(struct menu_q *menuq, char *prompt, char *initial, int dummy, case Expose: menu_draw(sc, &mc, menuq, &resultq); break; + case MotionNotify: + menu_handle_move(&e, &mc, sc); + break; + case ButtonRelease: + if ((mi = menu_handle_release(&e, &mc, sc, &resultq)) + != NULL) + goto out; + break; } } out: @@ -211,9 +251,8 @@ 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 dy; int xsave, ysave; int warp; struct fontdesc *font = DefaultFont; @@ -230,10 +269,16 @@ menu_draw(struct screen_ctx *sc, struct menu_ctx *mc, struct menu_q *menuq, 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; + mc->num = 0; + mc->width = 0; + dy = 0; + if (mc->hasprompt) { + snprintf(mc->dispstr, sizeof(mc->dispstr), "%s%s%c", + mc->promptstr, mc->searchstr, PROMPT_ECHAR); + mc->width = font_width(font, mc->dispstr, strlen(mc->dispstr)); + dy = sc->fontheight; + mc->num = 1; + } TAILQ_FOREACH(mi, resultq, resultentry) { char *text; @@ -246,17 +291,18 @@ menu_draw(struct screen_ctx *sc, struct menu_ctx *mc, struct menu_q *menuq, text = mi->text; } - dx = MAX(dx, font_width(font, text, + mc->width = MAX(mc->width, font_width(font, text, MIN(strlen(text), MENU_MAXENTRY))); dy += sc->fontheight; + mc->num++; } 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; + else if (mc->x + mc->width >= sc->xmax) + mc->x = sc->xmax - mc->width; if (mc->y + dy >= sc->ymax) mc->y = sc->ymax - dy; @@ -268,12 +314,15 @@ menu_draw(struct screen_ctx *sc, struct menu_ctx *mc, struct menu_q *menuq, 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); + XMoveResizeWindow(X_Dpy, sc->menuwin, mc->x, mc->y, mc->width, dy); - font_draw(font, mc->dispstr, strlen(mc->dispstr), sc->menuwin, - 0, font_ascent(font) + 1); + if (mc->hasprompt) { + font_draw(font, mc->dispstr, strlen(mc->dispstr), sc->menuwin, + 0, font_ascent(font) + 1); + n = 1; + } else + n = 0; - n = 1; TAILQ_FOREACH(mi, resultq, resultentry) { char *text = mi->print[0] != '\0' ? mi->print : mi->text; @@ -285,12 +334,68 @@ menu_draw(struct screen_ctx *sc, struct menu_ctx *mc, struct menu_q *menuq, n++; } - if (n > 1) + if (mc->hasprompt && n > 1) XFillRectangle(X_Dpy, sc->menuwin, sc->gc, - 0, sc->fontheight, dx, sc->fontheight); + 0, sc->fontheight, mc->width, sc->fontheight); if (mc->noresult) XFillRectangle(X_Dpy, sc->menuwin, sc->gc, - 0, 0, dx, sc->fontheight); + 0, 0, mc->width, sc->fontheight); +} + +void +menu_handle_move(XEvent *e, struct menu_ctx *mc, struct screen_ctx *sc) +{ + mc->prev = mc->entry; + mc->entry = menu_calc_entry(sc, mc, e->xbutton.x, e->xbutton.y); + + if (mc->prev != -1) + XFillRectangle(X_Dpy, sc->menuwin, sc->gc, 0, + sc->fontheight * mc->prev, mc->width, sc->fontheight); + if (mc->entry != -1) { + xu_ptr_regrab(MenuGrabMask, Cursor_select); + XFillRectangle(X_Dpy, sc->menuwin, sc->gc, 0, + sc->fontheight * mc->entry, mc->width, sc->fontheight); + } else + xu_ptr_regrab(MenuGrabMask, Cursor_default); +} + +struct menu * +menu_handle_release(XEvent *e, struct menu_ctx *mc, struct screen_ctx *sc, + struct menu_q *resultq) +{ + struct menu *mi; + int entry, i = 0; + + entry = menu_calc_entry(sc, mc, e->xbutton.x, e->xbutton.y); + xu_ptr_ungrab(); + + if (mc->hasprompt) + i = 1; + + TAILQ_FOREACH(mi, resultq, resultentry) + if (entry == i++) + break; + if (mi == NULL) { + XMALLOC(mi, struct menu); + mi->text[0] = '\0'; + mi->dummy = 1; + } + return (mi); +} + +static int +menu_calc_entry(struct screen_ctx *sc, struct menu_ctx *mc, int x, int y) +{ + int entry = y / sc->fontheight; + + /* in bounds? */ + if (x < 0 || x > mc->width || y < 0 || y > sc->fontheight*mc->num || + entry < 0 || entry >= mc->num) + entry = -1; + + if (mc->hasprompt && entry == 0) + entry = -1; + return (entry); } diff --git a/xevents.c b/xevents.c index ca3c0d9..32d97e7 100644 --- a/xevents.c +++ b/xevents.c @@ -290,7 +290,7 @@ xev_handle_buttonpress(struct xevent *xev, XEvent *ee) if (TAILQ_EMPTY(&menuq)) goto out; - mi = (struct menu *)grab_menu(e, &menuq); + mi = menu_filter(&menuq, NULL, NULL, 0, NULL, NULL); if (mi == NULL) goto cleanup; |