diff options
Diffstat (limited to 'dmenu.c')
-rw-r--r-- | dmenu.c | 207 |
1 files changed, 88 insertions, 119 deletions
@@ -24,8 +24,6 @@ /* macros */ #define INTERSECT(x,y,w,h,r) (MAX(0, MIN((x)+(w),(r).x_org+(r).width) - MAX((x),(r).x_org)) \ * MAX(0, MIN((y)+(h),(r).y_org+(r).height) - MAX((y),(r).y_org))) -#define BOOL_INTERSECT(x,y,w,h,r) (MAX(0, MIN((x)+(w),(r).x_org+(r).width) - MAX((x),(r).x_org)) \ - && MAX(0, MIN((y)+(h),(r).y_org+(r).height) - MAX((y),(r).y_org))) #define LENGTH(X) (sizeof X / sizeof X[0]) #define TEXTW(X) (drw_fontset_getwidth(drw, (X)) + lrpad) @@ -36,7 +34,7 @@ enum { SchemeNorm, SchemeSel, SchemeNormHighlight, SchemeSelHighlight, struct item { char *text; - char *text_output; + char *text_output; struct item *left, *right; int out; double distance; @@ -44,9 +42,8 @@ struct item { static char text[BUFSIZ] = ""; static char *embed; -static char separator; -static int separator_greedy; -static int separator_reverse; +static char separator, separator_reverse; +static char * (*sepchr)(const char *, int); static int bh, mw, mh; static int inputw = 0, promptw, passwd = 0; static int lrpad; /* sum of left and right padding */ @@ -66,7 +63,7 @@ static Drw *drw; static Clr *scheme[SchemeLast]; /* Temporary arrays to allow overriding xresources values */ -static char *colortemp[4]; +static char *colortemp[8]; static char *tempfonts; #include "config.h" @@ -74,6 +71,13 @@ static char *tempfonts; static int (*fstrncmp)(const char *, const char *, size_t) = strncmp; static char *(*fstrstr)(const char *, const char *) = strstr; +static unsigned int +textw_clamp(const char *str, unsigned int n) +{ + unsigned int w = drw_fontset_getwidth_clamp(drw, str, n) + lrpad; + return MIN(w, n); +} + static void appenditem(struct item *item, struct item **list, struct item **last) { @@ -98,10 +102,10 @@ calcoffsets(void) n = mw - (promptw + inputw + TEXTW("<") + TEXTW(">")); /* calculate which items will begin the next page and previous page */ for (i = 0, next = curr; next; next = next->right) - if ((i += (lines > 0) ? bh : MIN(TEXTW(next->text), n)) > n) + if ((i += (lines > 0) ? bh : textw_clamp(next->text, n)) > n) break; for (i = 0, prev = curr; prev && prev->left; prev = prev->left) - if ((i += (lines > 0) ? bh : MIN(TEXTW(prev->left->text), n)) > n) + if ((i += (lines > 0) ? bh : textw_clamp(prev->left->text, n)) > n) break; } @@ -122,6 +126,9 @@ cleanup(void) XUngrabKey(dpy, AnyKey, AnyModifier, root); for (i = 0; i < SchemeLast; i++) free(scheme[i]); + for (i = 0; items && items[i].text; ++i) + free(separator_reverse ? items[i].text_output : items[i].text); + free(items); drw_free(drw); XSync(dpy, False); XCloseDisplay(dpy); @@ -159,19 +166,17 @@ drawhighlights(struct item *item, int x, int y, int maxw) ? SchemeSelHighlight : SchemeNormHighlight]); for (i = 0, highlight = item->text; *highlight && text[i];) { - if (!fstrncmp(&(*highlight), &text[i], 1)) { + if (!fstrncmp(&text[i], highlight, 1)) { + c = highlight[1]; + highlight[1] = '\0'; + /* get indentation */ - c = *highlight; - *highlight = '\0'; indent = TEXTW(item->text); - *highlight = c; /* highlight character */ - c = highlight[1]; - highlight[1] = '\0'; drw_text( drw, - x + indent - (lrpad / 2), + x + indent - lrpad, y, MIN(maxw - indent, TEXTW(highlight) - lrpad), bh, 0, highlight, 0 @@ -220,7 +225,7 @@ drawmenu(void) drw_setscheme(drw, scheme[SchemeNorm]); if (passwd) { censort = ecalloc(1, sizeof(text)); - memset(censort, '.', strlen(text)); + memset(censort, '*', strlen(text)); drw_text(drw, x, 0, w, bh, lrpad / 2, censort, 0); free(censort); } else drw_text(drw, x, 0, w, bh, lrpad / 2, text, 0); @@ -245,7 +250,7 @@ drawmenu(void) } x += w; for (item = curr; item != next; item = item->right) - x = drawitem(item, x, 0, MIN(TEXTW(item->text), mw - x - TEXTW(">"))); + x = drawitem(item, x, 0, textw_clamp(item->text, mw - x - TEXTW(">"))); if (next) { w = TEXTW(">"); drw_setscheme(drw, scheme[SchemeNorm]); @@ -390,7 +395,7 @@ match(void) /* separate input text into tokens to be matched individually */ for (s = strtok(buf, " "); s; tokv[tokc - 1] = s, s = strtok(NULL, " ")) if (++tokc > tokn && !(tokv = realloc(tokv, ++tokn * sizeof *tokv))) - die("cannot realloc %u bytes:", tokn * sizeof *tokv); + die("cannot realloc %zu bytes:", tokn * sizeof *tokv); len = tokc ? strlen(tokv[0]) : 0; matches = lprefix = lsubstr = matchend = prefixend = substrend = NULL; @@ -577,7 +582,7 @@ keypress(XKeyEvent *ev) switch(ksym) { default: insert: - if (!iscntrl(*buf)) + if (!iscntrl((unsigned char)*buf)) insert(buf, len); break; case XK_Delete: @@ -679,9 +684,9 @@ insert: case XK_Tab: if (!sel) return; - strncpy(text, sel->text, sizeof text - 1); - text[sizeof text - 1] = '\0'; - cursor = strlen(text); + cursor = strnlen(sel->text, sizeof text - 1); + memcpy(text, sel->text, cursor); + text[cursor] = '\0'; match(); break; } @@ -744,11 +749,8 @@ buttonpress(XEvent *e) } if (ev->button != Button1) return; - /* disabled below, needs to be fixed */ - /* if (ev->state & ~ControlMask) return; - */ if (lines > 0) { /* vertical list: (ctrl)left-click on item */ w = mw - x; @@ -807,40 +809,6 @@ buttonpress(XEvent *e) } static void -mousemove(XEvent *e) -{ - struct item *item; - XPointerMovedEvent *ev = &e->xmotion; - int x = 0, y = 0, h = bh, w; - - if (lines > 0) { - w = mw - x; - for (item = curr; item != next; item = item->right) { - y += h; - if (ev->y >= y && ev->y <= (y + h)) { - sel = item; - calcoffsets(); - drawmenu(); - return; - } - } - } else if (matches) { - x += inputw; - w = TEXTW("<"); - for (item = curr; item != next; item = item->right) { - x += w; - w = MIN(TEXTW(item->text), mw - x - TEXTW(">")); - if (ev->x >= x && ev->x <= x + w) { - sel = item; - calcoffsets(); - drawmenu(); - return; - } - } - } -} - -static void paste(void) { char *p, *q; @@ -861,26 +829,25 @@ paste(void) static void readstdin(void) { - char buf[sizeof text], *p; - size_t i, imax = 0, size = 0; - unsigned int tmpmax = 0; - if(passwd){ - inputw = lines = 0; - return; - } + char *p, *line = NULL; + size_t i, junk, size = 0; + ssize_t len; + if(passwd) { + inputw = lines = 0; + return; + } /* read each line from stdin and add it to the item list */ - for (i = 0; fgets(buf, sizeof buf, stdin); i++) { + for (i = 0; (len = getline(&line, &junk, stdin)) != -1; i++, line = NULL) { if (i + 1 >= size / sizeof *items) if (!(items = realloc(items, (size += BUFSIZ)))) - die("cannot realloc %u bytes:", size); - if ((p = strchr(buf, '\n'))) - *p = '\0'; - if (!(items[i].text = strdup(buf))) - die("cannot strdup %u bytes:", strlen(buf) + 1); - if (separator && (p = separator_greedy ? - strrchr(items[i].text, separator) : strchr(items[i].text, separator))) { + die("cannot realloc %zu bytes:", size); + if (line[len - 1] == '\n') + line[len - 1] = '\0'; + items[i].text = line; + + if (separator && (p = sepchr(items[i].text, separator)) != NULL) { *p = '\0'; items[i].text_output = ++p; } else { @@ -891,16 +858,11 @@ readstdin(void) items[i].text = items[i].text_output; items[i].text_output = p; } + items[i].out = 0; - drw_font_getexts(drw->fonts, buf, strlen(buf), &tmpmax, NULL); - if (tmpmax > inputw) { - inputw = tmpmax; - imax = i; - } } if (items) items[i].text = NULL; - inputw = items ? TEXTW(items[imax].text) : 0; lines = MIN(lines, i); } @@ -921,9 +883,6 @@ run(void) case ButtonPress: buttonpress(&ev); break; - case MotionNotify: - mousemove(&ev); - break; case Expose: if (ev.xexpose.count == 0) drw_map(drw, win, 0, 0, mw, mh); @@ -1004,7 +963,7 @@ setup(void) /* no focused window is on screen, so use pointer location instead */ if (mon < 0 && !area && XQueryPointer(dpy, root, &dw, &dw, &x, &y, &di, &di, &du)) for (i = 0; i < n; i++) - if (BOOL_INTERSECT(x, y, 1, 1, info[i])) + if (INTERSECT(x, y, 1, 1, info[i]) != 0) break; if (centered) { @@ -1035,14 +994,15 @@ setup(void) mw = wa.width; } } - inputw = MIN(inputw, mw/3); + promptw = (prompt && *prompt) ? TEXTW(prompt) - lrpad / 4 : 0; + inputw = mw / 3; /* input width: ~33% of monitor width */ match(); /* create menu window */ swa.override_redirect = True; swa.background_pixel = scheme[SchemeNorm][ColBg].pixel; swa.event_mask = ExposureMask | KeyPressMask | VisibilityChangeMask | - ButtonPressMask | PointerMotionMask; + ButtonPressMask; win = XCreateWindow(dpy, parentwin, x, y, mw, mh, border_width, CopyFromParent, CopyFromParent, CopyFromParent, CWOverrideRedirect | CWBackPixel | CWEventMask, &swa); @@ -1075,11 +1035,10 @@ setup(void) static void usage(void) { - fputs("usage: dmenu [-bfirvP] [-l lines] [-p prompt] [-fn font] [-m monitor]\n" - " [-nb color] [-nf color] [-sb color] [-sf color] [-bw width]\n" - " [-nhb color] [-nhf color] [-shb color] [-shf color] [-w windowid]\n" - " [-d separator] [-D separator]\n", stderr); - exit(1); + die("usage: dmenu [-bfirvP] [-l lines] [-p prompt] [-fn font] [-m monitor]\n" + " [-nb color] [-nf color] [-sb color] [-sf color] [-w windowid]\n" + " [-nhb color] [-nhf color] [-shb color] [-shf color]\n" + " [-d separator] [-D separator] [-h height]"); } void @@ -1112,22 +1071,22 @@ readxresources(void) { colors[SchemeSel][ColFg] = strdup(xval.addr); else colors[SchemeSel][ColFg] = strdup(colors[SchemeSel][ColFg]); + if (XrmGetResource(xdb, "dmenu.hibackground", "*", &type, &xval)) + colors[SchemeNormHighlight][ColBg] = strdup(xval.addr); + else + colors[SchemeNormHighlight][ColBg] = strdup(colors[SchemeSel][ColFg]); + if (XrmGetResource(xdb, "dmenu.hiforeground", "*", &type, &xval)) + colors[SchemeNormHighlight][ColFg] = strdup(xval.addr); + else + colors[SchemeNormHighlight][ColFg] = strdup(colors[SchemeSel][ColFg]); if (XrmGetResource(xdb, "dmenu.selhibackground", "*", &type, &xval)) colors[SchemeSelHighlight][ColBg] = strdup(xval.addr); else - colors[SchemeSelHighlight][ColBg] = strdup(colors[SchemeSel][ColBg]); + colors[SchemeSelHighlight][ColBg] = strdup(colors[SchemeSel][ColFg]); if (XrmGetResource(xdb, "dmenu.selhiforeground", "*", &type, &xval)) colors[SchemeSelHighlight][ColFg] = strdup(xval.addr); else colors[SchemeSelHighlight][ColFg] = strdup(colors[SchemeSel][ColFg]); - if (XrmGetResource(xdb, "dmenu.hibackground", "*", &type, &xval)) - colors[SchemeNormHighlight][ColBg] = strdup(xval.addr); - else - colors[SchemeNormHighlight][ColBg] = strdup(colors[SchemeNorm][ColBg]); - if (XrmGetResource(xdb, "dmenu.hiforeground", "*", &type, &xval)) - colors[SchemeNormHighlight][ColFg] = strdup(xval.addr); - else - colors[SchemeNormHighlight][ColFg] = strdup(colors[SchemeNorm][ColFg]); XrmDestroyDatabase(xdb); } @@ -1148,14 +1107,14 @@ main(int argc, char *argv[]) topbar = 0; else if (!strcmp(argv[i], "-f")) /* grabs keyboard before reading stdin */ fast = 1; - else if (!strcmp(argv[i], "-c")) /* centers dmenu on screen */ - centered = 1; - else if (!strcmp(argv[i], "-F")) /* grabs keyboard before reading stdin */ - fuzzy = 1; + else if (!strcmp(argv[i], "-F")) /* toggles fuzzy matching */ + fuzzy = fuzzy ? 0 : 1; + else if (!strcmp(argv[i], "-c")) /* centers dmenu on screen */ + centered = 1; else if (!strcmp(argv[i], "-i")) { /* case-insensitive item matching */ fstrncmp = strncasecmp; fstrstr = cistrstr; - } else if (!strcmp(argv[i], "-P")) /* is the input a password */ + } else if (!strcmp(argv[i], "-P")) /* is the input a password */ passwd = 1; else if (!strcmp(argv[i], "-r")) /* reject input which results in no match */ reject_no_match = 1; @@ -1182,22 +1141,24 @@ main(int argc, char *argv[]) colortemp[2] = argv[++i]; else if (!strcmp(argv[i], "-sf")) /* selected foreground color */ colortemp[3] = argv[++i]; - else if (!strcmp(argv[i], "-nhb")) /* normal hi background color */ - colors[SchemeNormHighlight][ColBg] = argv[++i]; - else if (!strcmp(argv[i], "-nhf")) /* normal hi foreground color */ - colors[SchemeNormHighlight][ColFg] = argv[++i]; - else if (!strcmp(argv[i], "-shb")) /* selected hi background color */ - colors[SchemeSelHighlight][ColBg] = argv[++i]; - else if (!strcmp(argv[i], "-shf")) /* selected hi foreground color */ - colors[SchemeSelHighlight][ColFg] = argv[++i]; + else if (!strcmp(argv[i], "-nhb")) /* normal hi background color */ + colortemp[4] = argv[++i]; + else if (!strcmp(argv[i], "-nhf")) /* normal hi foreground color */ + colortemp[5] = argv[++i]; + else if (!strcmp(argv[i], "-shb")) /* selected hi background color */ + colortemp[6] = argv[++i]; + else if (!strcmp(argv[i], "-shf")) /* selected hi foreground color */ + colortemp[7] = argv[++i]; else if (!strcmp(argv[i], "-w")) /* embedding window id */ embed = argv[++i]; + else if (!strcmp(argv[i], "-bw")) + border_width = atoi(argv[++i]); /* border width */ else if (!strcmp(argv[i], "-d") || /* field separator */ - (separator_greedy = !strcmp(argv[i], "-D"))) { - separator = argv[++i][0]; - separator_reverse = argv[i][1] == '|'; - } else if (!strcmp(argv[i], "-bw")) - border_width = atoi(argv[++i]); /* border width */ + !strcmp(argv[i], "-D")) { + sepchr = argv[i][1] == 'D' ? strrchr : strchr; + separator = argv[++i][0]; + separator_reverse = argv[i][1] == '|'; + } else usage(); @@ -1225,6 +1186,14 @@ main(int argc, char *argv[]) colors[SchemeSel][ColBg] = strdup(colortemp[2]); if ( colortemp[3]) colors[SchemeSel][ColFg] = strdup(colortemp[3]); + if ( colortemp[4]) + colors[SchemeNormHighlight][ColBg] = strdup(colortemp[4]); + if ( colortemp[5]) + colors[SchemeNormHighlight][ColFg] = strdup(colortemp[5]); + if ( colortemp[6]) + colors[SchemeSelHighlight][ColBg] = strdup(colortemp[6]); + if ( colortemp[7]) + colors[SchemeSelHighlight][ColFg] = strdup(colortemp[7]); if (!drw_fontset_create(drw, (const char**)fonts, LENGTH(fonts))) die("no fonts could be loaded."); |