X-Git-Url: https://git.danieliu.xyz/?a=blobdiff_plain;f=main.c;h=b733feb5fc76a6c20578feab338b1fc4409a41e2;hb=03c2b05bb2265e0ef7ba33b7f6df36bd6e0ce54d;hp=06b2ca9dc866a592ad15099c9247032bc0f38529;hpb=3dcdbe2a57a19bf727113eca6aa35b1c7cb0ef28;p=dmenu.git diff --git a/main.c b/main.c index 06b2ca9..b733feb 100644 --- a/main.c +++ b/main.c @@ -1,20 +1,19 @@ -/* (C)opyright MMVI Anselm R. Garbe - * (C)opyright MMVI Sander van Dijk +/* (C)opyright MMVI-MMVII Anselm R. Garbe + * (C)opyright MMVI-MMVII Sander van Dijk * 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,41 +219,62 @@ 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: - ksym = XK_Left; - break; + ksym = XK_Left; + break; case XK_l: - ksym = XK_Right; - break; + ksym = XK_Right; + break; case XK_j: - ksym = XK_Next; - break; - case XK_l: - ksym = XK_Prior; - break; + ksym = XK_Next; + break; + case XK_k: + ksym = XK_Prior; + break; case XK_g: - ksym = XK_Home; - break; + ksym = XK_Home; + break; case XK_G: - ksym = XK_End; - break; + ksym = XK_End; + break; } } switch(ksym) { @@ -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; @@ -330,84 +408,84 @@ DC dc = {0}; int main(int argc, char *argv[]) { + Bool bottom = False; char *font = FONT; char *maxname; char *normbg = NORMBGCOLOR; 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], "-font", 6)) { + if(!strncmp(argv[i], "-b", 3)) { + bottom = True; + } + else if(!strncmp(argv[i], "-fn", 4)) { if(++i < argc) font = argv[i]; } - else if(!strncmp(argv[i], "-normbg", 8)) { + else if(!strncmp(argv[i], "-nb", 4)) { if(++i < argc) normbg = argv[i]; } - else if(!strncmp(argv[i], "-normfg", 8)) { + else if(!strncmp(argv[i], "-nf", 4)) { if(++i < argc) normfg = argv[i]; } - else if(!strncmp(argv[i], "-selbg", 7)) { - if(++i < argc) selbg = argv[i]; - } - else if(!strncmp(argv[i], "-selfg", 7)) { - if(++i < argc) selfg = argv[i]; - } else if(!strncmp(argv[i], "-p", 3)) { if(++i < argc) prompt = argv[i]; } - else if(!strncmp(argv[i], "-t", 3)) { - if(++i < argc) timeout.tv_sec = atoi(argv[i]); + else if(!strncmp(argv[i], "-sb", 4)) { + if(++i < argc) selbg = argv[i]; } - else if(!strncmp(argv[i], "-v", 3)) { - fputs("dmenu-"VERSION", (C)opyright MMVI Anselm R. Garbe\n", stdout); - exit(EXIT_SUCCESS); + else if(!strncmp(argv[i], "-sf", 4)) { + if(++i < argc) selfg = argv[i]; } + else if(!strncmp(argv[i], "-v", 3)) + eprint("dmenu-"VERSION", (C)opyright MMVI-MMVII Anselm R. Garbe\n"); else - eprint("usage: dmenu [-font ] [-{norm,sel}{bg,fg} ] [-p ] [-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; - 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); @@ -457,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;