X-Git-Url: https://git.danieliu.xyz/?a=blobdiff_plain;f=main.c;h=b733feb5fc76a6c20578feab338b1fc4409a41e2;hb=03c2b05bb2265e0ef7ba33b7f6df36bd6e0ce54d;hp=573d7c368692dadf13197979df83343662c27dad;hpb=08420a935b96bf1bd8531c3a9cda66ee87e31855;p=dmenu.git diff --git a/main.c b/main.c index 573d7c3..b733feb 100644 --- a/main.c +++ b/main.c @@ -3,18 +3,17 @@ * See LICENSE file for license details. */ #include "dmenu.h" - #include #include #include #include #include #include -#include -#include #include #include +#define CLEANMASK(mask) (mask & ~(numlockmask | LockMask)) + typedef struct Item Item; struct Item { Item *next; /* traverses all items */ @@ -26,11 +25,12 @@ struct Item { static char text[4096]; static char *prompt = NULL; -static int mx, my, mw, mh; +static int mw, mh; static int ret = 0; static int nitem = 0; static unsigned int cmdw = 0; static unsigned int promptw = 0; +static unsigned int numlockmask = 0; static Bool running = True; static Item *allitems = NULL; /* first of all items */ static Item *item = NULL; /* first of pattern matching items */ @@ -108,6 +108,61 @@ drawmenu(void) { XFlush(dpy); } +static void +grabkeyboard(void) { + while(XGrabKeyboard(dpy, root, True, GrabModeAsync, + GrabModeAsync, CurrentTime) != GrabSuccess) + usleep(1000); +} + +static unsigned long +initcolor(const char *colstr) { + Colormap cmap = DefaultColormap(dpy, screen); + XColor color; + + if(!XAllocNamedColor(dpy, cmap, colstr, &color, &color)) + eprint("error, cannot allocate color '%s'\n", colstr); + return color.pixel; +} + +static void +initfont(const char *fontstr) { + char *def, **missing; + int i, n; + + missing = NULL; + if(dc.font.set) + XFreeFontSet(dpy, dc.font.set); + dc.font.set = XCreateFontSet(dpy, fontstr, &missing, &n, &def); + if(missing) + XFreeStringList(missing); + if(dc.font.set) { + XFontSetExtents *font_extents; + XFontStruct **xfonts; + char **font_names; + dc.font.ascent = dc.font.descent = 0; + font_extents = XExtentsOfFontSet(dc.font.set); + n = XFontsOfFontSet(dc.font.set, &xfonts, &font_names); + for(i = 0, dc.font.ascent = 0, dc.font.descent = 0; i < n; i++) { + if(dc.font.ascent < (*xfonts)->ascent) + dc.font.ascent = (*xfonts)->ascent; + if(dc.font.descent < (*xfonts)->descent) + dc.font.descent = (*xfonts)->descent; + xfonts++; + } + } + else { + if(dc.font.xfont) + XFreeFont(dpy, dc.font.xfont); + dc.font.xfont = NULL; + if(!(dc.font.xfont = XLoadQueryFont(dpy, fontstr))) + eprint("error, cannot load font: '%s'\n", fontstr); + dc.font.ascent = dc.font.xfont->ascent; + dc.font.descent = dc.font.xfont->descent; + } + dc.font.height = dc.font.ascent + dc.font.descent; +} + static void match(char *pattern) { unsigned int plen; @@ -148,8 +203,8 @@ match(char *pattern) { static void kpress(XKeyEvent * e) { char buf[32]; - int num, prev_nitem; - unsigned int i, len; + int i, num, prev_nitem; + unsigned int len; KeySym ksym; len = strlen(text); @@ -164,21 +219,42 @@ kpress(XKeyEvent * e) { switch (ksym) { default: /* ignore other control sequences */ return; + case XK_bracketleft: + ksym = XK_Escape; break; case XK_h: case XK_H: ksym = XK_BackSpace; break; + case XK_i: + case XK_I: + ksym = XK_Tab; + break; + case XK_j: + case XK_J: + ksym = XK_Return; + break; case XK_u: case XK_U: text[0] = 0; match(text); drawmenu(); return; - break; + case XK_w: + case XK_W: + if(len) { + i = len - 1; + while(i >= 0 && text[i] == ' ') + text[i--] = 0; + while(i >= 0 && text[i] != ' ') + text[i--] = 0; + match(text); + drawmenu(); + } + return; } } - if(e->state & Mod1Mask) { + if(CLEANMASK(e->state) & Mod1Mask) { switch(ksym) { default: return; case XK_h: @@ -213,12 +289,8 @@ kpress(XKeyEvent * e) { } break; case XK_BackSpace: - if((i = len)) { - prev_nitem = nitem; - do { - text[--i] = 0; - match(text); - } while(i && nitem && prev_nitem == nitem); + if(len) { + text[--len] = 0; match(text); } break; @@ -322,6 +394,12 @@ readstdin(void) { return maxname; } +static void +usage(void) { + eprint("usage: dmenu [-b] [-fn ] [-nb ] [-nf ]\n" + " [-p ] [-sb ] [-sf ] [-v]\n"); +} + /* extern */ int screen; @@ -337,15 +415,12 @@ main(int argc, char *argv[]) { char *normfg = NORMFGCOLOR; char *selbg = SELBGCOLOR; char *selfg = SELFGCOLOR; - fd_set rd; - int i; - struct timeval timeout; + int i, j; Item *itm; XEvent ev; + XModifierKeymap *modmap; XSetWindowAttributes wa; - timeout.tv_usec = 0; - timeout.tv_sec = 3; /* command line args */ for(i = 1; i < argc; i++) if(!strncmp(argv[i], "-b", 3)) { @@ -369,52 +444,48 @@ main(int argc, char *argv[]) { else if(!strncmp(argv[i], "-sf", 4)) { if(++i < argc) selfg = argv[i]; } - else if(!strncmp(argv[i], "-t", 3)) { - if(++i < argc) timeout.tv_sec = atoi(argv[i]); - } - else if(!strncmp(argv[i], "-v", 3)) { - fputs("dmenu-"VERSION", (C)opyright MMVI-MMVII Anselm R. Garbe\n", stdout); - exit(EXIT_SUCCESS); - } + else if(!strncmp(argv[i], "-v", 3)) + eprint("dmenu-"VERSION", (C)opyright MMVI-MMVII Anselm R. Garbe\n"); else - eprint("usage: dmenu [-b] [-fn ] [-nb ] [-nf ] [-p ]\n" - " [-sb ] [-sf ] [-t ] [-v]\n", stdout); + usage(); setlocale(LC_CTYPE, ""); dpy = XOpenDisplay(0); if(!dpy) eprint("dmenu: cannot open display\n"); screen = DefaultScreen(dpy); root = RootWindow(dpy, screen); - - /* Note, the select() construction allows to grab all keypresses as - * early as possible, to not loose them. But if there is no standard - * input supplied, we will make sure to exit after MAX_WAIT_STDIN - * seconds. This is convenience behavior for rapid typers. - */ - while(XGrabKeyboard(dpy, root, True, GrabModeAsync, - GrabModeAsync, CurrentTime) != GrabSuccess) - usleep(1000); - FD_ZERO(&rd); - FD_SET(STDIN_FILENO, &rd); - if(select(ConnectionNumber(dpy) + 1, &rd, NULL, NULL, &timeout) < 1) - goto UninitializedEnd; - maxname = readstdin(); + if(isatty(STDIN_FILENO)) { + maxname = readstdin(); + grabkeyboard(); + } + else { /* prevent keypress loss */ + grabkeyboard(); + maxname = readstdin(); + } + /* init modifier map */ + modmap = XGetModifierMapping(dpy); + for (i = 0; i < 8; i++) { + for (j = 0; j < modmap->max_keypermod; j++) { + if(modmap->modifiermap[i * modmap->max_keypermod + j] + == XKeysymToKeycode(dpy, XK_Num_Lock)) + numlockmask = (1 << i); + } + } + XFreeModifiermap(modmap); /* style */ - dc.norm[ColBG] = getcolor(normbg); - dc.norm[ColFG] = getcolor(normfg); - dc.sel[ColBG] = getcolor(selbg); - dc.sel[ColFG] = getcolor(selfg); - setfont(font); + dc.norm[ColBG] = initcolor(normbg); + dc.norm[ColFG] = initcolor(normfg); + dc.sel[ColBG] = initcolor(selbg); + dc.sel[ColFG] = initcolor(selfg); + initfont(font); /* menu window */ wa.override_redirect = 1; wa.background_pixmap = ParentRelative; wa.event_mask = ExposureMask | ButtonPressMask | KeyPressMask; - mx = my = 0; mw = DisplayWidth(dpy, screen); mh = dc.font.height + 2; - if(bottom) - my += DisplayHeight(dpy, screen) - mh; - win = XCreateWindow(dpy, root, mx, my, mw, mh, 0, + win = XCreateWindow(dpy, root, 0, + bottom ? DisplayHeight(dpy, screen) - mh : 0, mw, mh, 0, DefaultDepth(dpy, screen), CopyFromParent, DefaultVisual(dpy, screen), CWOverrideRedirect | CWBackPixmap | CWEventMask, &wa); @@ -464,7 +535,6 @@ main(int argc, char *argv[]) { XFreePixmap(dpy, dc.drawable); XFreeGC(dpy, dc.gc); XDestroyWindow(dpy, win); -UninitializedEnd: XUngrabKeyboard(dpy, CurrentTime); XCloseDisplay(dpy); return ret;