diff options
Diffstat (limited to 'dmenu.c')
| -rw-r--r-- | dmenu.c | 147 |
1 files changed, 68 insertions, 79 deletions
| @@ -22,8 +22,7 @@ | |||
| 22 | #define INTERSECT(x,y,w,h,r) (MAX(0, MIN((x)+(w),(r).x_org+(r).width) - MAX((x),(r).x_org)) \ | 22 | #define INTERSECT(x,y,w,h,r) (MAX(0, MIN((x)+(w),(r).x_org+(r).width) - MAX((x),(r).x_org)) \ |
| 23 | * MAX(0, MIN((y)+(h),(r).y_org+(r).height) - MAX((y),(r).y_org))) | 23 | * MAX(0, MIN((y)+(h),(r).y_org+(r).height) - MAX((y),(r).y_org))) |
| 24 | #define LENGTH(X) (sizeof X / sizeof X[0]) | 24 | #define LENGTH(X) (sizeof X / sizeof X[0]) |
| 25 | #define TEXTNW(X,N) (drw_font_getexts_width(drw->fonts[0], (X), (N))) | 25 | #define TEXTW(X) (drw_fontset_getwidth(drw, (X)) + lrpad) |
| 26 | #define TEXTW(X) (drw_text(drw, 0, 0, 0, 0, (X), 0) + drw->fonts[0]->h) | ||
| 27 | 26 | ||
| 28 | /* enums */ | 27 | /* enums */ |
| 29 | enum { SchemeNorm, SchemeSel, SchemeOut, SchemeLast }; /* color schemes */ | 28 | enum { SchemeNorm, SchemeSel, SchemeOut, SchemeLast }; /* color schemes */ |
| @@ -37,7 +36,8 @@ struct item { | |||
| 37 | static char text[BUFSIZ] = ""; | 36 | static char text[BUFSIZ] = ""; |
| 38 | static int bh, mw, mh; | 37 | static int bh, mw, mh; |
| 39 | static int sw, sh; /* X display screen geometry width, height */ | 38 | static int sw, sh; /* X display screen geometry width, height */ |
| 40 | static int inputw, promptw; | 39 | static int inputw = 0, promptw; |
| 40 | static int lrpad; /* sum of left and right padding */ | ||
| 41 | static size_t cursor; | 41 | static size_t cursor; |
| 42 | static struct item *items = NULL; | 42 | static struct item *items = NULL; |
| 43 | static struct item *matches, *matchend; | 43 | static struct item *matches, *matchend; |
| @@ -49,8 +49,8 @@ static Display *dpy; | |||
| 49 | static Window root, win; | 49 | static Window root, win; |
| 50 | static XIC xic; | 50 | static XIC xic; |
| 51 | 51 | ||
| 52 | static ClrScheme scheme[SchemeLast]; | ||
| 53 | static Drw *drw; | 52 | static Drw *drw; |
| 53 | static Clr *scheme[SchemeLast]; | ||
| 54 | 54 | ||
| 55 | #include "config.h" | 55 | #include "config.h" |
| 56 | 56 | ||
| @@ -81,10 +81,10 @@ calcoffsets(void) | |||
| 81 | n = mw - (promptw + inputw + TEXTW("<") + TEXTW(">")); | 81 | n = mw - (promptw + inputw + TEXTW("<") + TEXTW(">")); |
| 82 | /* calculate which items will begin the next page and previous page */ | 82 | /* calculate which items will begin the next page and previous page */ |
| 83 | for (i = 0, next = curr; next; next = next->right) | 83 | for (i = 0, next = curr; next; next = next->right) |
| 84 | if ((i += (lines > 0) ? bh : MIN(TEXTW(next->text), n)) > n) | 84 | if ((i += (lines > 0) ? bh : TEXTW(next->text)) > n) |
| 85 | break; | 85 | break; |
| 86 | for (i = 0, prev = curr; prev && prev->left; prev = prev->left) | 86 | for (i = 0, prev = curr; prev && prev->left; prev = prev->left) |
| 87 | if ((i += (lines > 0) ? bh : MIN(TEXTW(prev->left->text), n)) > n) | 87 | if ((i += (lines > 0) ? bh : TEXTW(prev->left->text)) > n) |
| 88 | break; | 88 | break; |
| 89 | } | 89 | } |
| 90 | 90 | ||
| @@ -94,10 +94,8 @@ cleanup(void) | |||
| 94 | size_t i; | 94 | size_t i; |
| 95 | 95 | ||
| 96 | XUngrabKey(dpy, AnyKey, AnyModifier, root); | 96 | XUngrabKey(dpy, AnyKey, AnyModifier, root); |
| 97 | for (i = 0; i < SchemeLast; i++) { | 97 | for (i = 0; i < SchemeLast; i++) |
| 98 | drw_clr_free(scheme[i].bg); | 98 | free(scheme[i]); |
| 99 | drw_clr_free(scheme[i].fg); | ||
| 100 | } | ||
| 101 | drw_free(drw); | 99 | drw_free(drw); |
| 102 | XSync(dpy, False); | 100 | XSync(dpy, False); |
| 103 | XCloseDisplay(dpy); | 101 | XCloseDisplay(dpy); |
| @@ -114,70 +112,63 @@ cistrstr(const char *s, const char *sub) | |||
| 114 | return NULL; | 112 | return NULL; |
| 115 | } | 113 | } |
| 116 | 114 | ||
| 115 | static int | ||
| 116 | drawitem(struct item *item, int x, int y, int w) | ||
| 117 | { | ||
| 118 | if (item == sel) | ||
| 119 | drw_setscheme(drw, scheme[SchemeSel]); | ||
| 120 | else if (item->out) | ||
| 121 | drw_setscheme(drw, scheme[SchemeOut]); | ||
| 122 | else | ||
| 123 | drw_setscheme(drw, scheme[SchemeNorm]); | ||
| 124 | |||
| 125 | return drw_text(drw, x, y, w, bh, lrpad / 2, item->text, 0); | ||
| 126 | } | ||
| 127 | |||
| 117 | static void | 128 | static void |
| 118 | drawmenu(void) | 129 | drawmenu(void) |
| 119 | { | 130 | { |
| 120 | int curpos; | 131 | unsigned int curpos; |
| 121 | struct item *item; | 132 | struct item *item; |
| 122 | int x = 0, y = 0, h = bh, w; | 133 | int x = 0, y = 0, w; |
| 123 | 134 | ||
| 124 | drw_setscheme(drw, &scheme[SchemeNorm]); | 135 | drw_setscheme(drw, scheme[SchemeNorm]); |
| 125 | drw_rect(drw, 0, 0, mw, mh, 1, 1, 1); | 136 | drw_rect(drw, 0, 0, mw, mh, 1, 1); |
| 126 | 137 | ||
| 127 | if (prompt && *prompt) { | 138 | if (prompt && *prompt) { |
| 128 | drw_setscheme(drw, &scheme[SchemeSel]); | 139 | drw_setscheme(drw, scheme[SchemeSel]); |
| 129 | drw_text(drw, x, 0, promptw, bh, prompt, 0); | 140 | x = drw_text(drw, x, 0, promptw, bh, lrpad / 2, prompt, 0); |
| 130 | x += promptw; | ||
| 131 | } | 141 | } |
| 132 | /* draw input field */ | 142 | /* draw input field */ |
| 133 | w = (lines > 0 || !matches) ? mw - x : inputw; | 143 | w = (lines > 0 || !matches) ? mw - x : inputw; |
| 134 | drw_setscheme(drw, &scheme[SchemeNorm]); | 144 | drw_setscheme(drw, scheme[SchemeNorm]); |
| 135 | drw_text(drw, x, 0, w, bh, text, 0); | 145 | drw_text(drw, x, 0, w, bh, lrpad / 2, text, 0); |
| 136 | 146 | ||
| 137 | if ((curpos = TEXTNW(text, cursor) + bh / 2 - 2) < w) { | 147 | drw_font_getexts(drw->fonts, text, cursor, &curpos, NULL); |
| 138 | drw_setscheme(drw, &scheme[SchemeNorm]); | 148 | if ((curpos += lrpad / 2 - 1) < w) { |
| 139 | drw_rect(drw, x + curpos + 2, 2, 1, bh - 4, 1, 1, 0); | 149 | drw_setscheme(drw, scheme[SchemeNorm]); |
| 150 | drw_rect(drw, x + curpos, 2, 2, bh - 4, 1, 0); | ||
| 140 | } | 151 | } |
| 141 | 152 | ||
| 142 | if (lines > 0) { | 153 | if (lines > 0) { |
| 143 | /* draw vertical list */ | 154 | /* draw vertical list */ |
| 144 | w = mw - x; | 155 | for (item = curr; item != next; item = item->right) |
| 145 | for (item = curr; item != next; item = item->right) { | 156 | drawitem(item, x, y += bh, mw - x); |
| 146 | y += h; | ||
| 147 | if (item == sel) | ||
| 148 | drw_setscheme(drw, &scheme[SchemeSel]); | ||
| 149 | else if (item->out) | ||
| 150 | drw_setscheme(drw, &scheme[SchemeOut]); | ||
| 151 | else | ||
| 152 | drw_setscheme(drw, &scheme[SchemeNorm]); | ||
| 153 | |||
| 154 | drw_text(drw, x, y, w, bh, item->text, 0); | ||
| 155 | } | ||
| 156 | } else if (matches) { | 157 | } else if (matches) { |
| 157 | /* draw horizontal list */ | 158 | /* draw horizontal list */ |
| 158 | x += inputw; | 159 | x += inputw; |
| 159 | w = TEXTW("<"); | 160 | w = TEXTW("<"); |
| 160 | if (curr->left) { | 161 | if (curr->left) { |
| 161 | drw_setscheme(drw, &scheme[SchemeNorm]); | 162 | drw_setscheme(drw, scheme[SchemeNorm]); |
| 162 | drw_text(drw, x, 0, w, bh, "<", 0); | 163 | drw_text(drw, x, 0, w, bh, lrpad / 2, "<", 0); |
| 163 | } | 164 | } |
| 164 | for (item = curr; item != next; item = item->right) { | 165 | x += w; |
| 165 | x += w; | 166 | for (item = curr; item != next; item = item->right) |
| 166 | w = MIN(TEXTW(item->text), mw - x - TEXTW(">")); | 167 | x = drawitem(item, x, 0, MIN(TEXTW(item->text), mw - x - TEXTW(">"))); |
| 167 | |||
| 168 | if (item == sel) | ||
| 169 | drw_setscheme(drw, &scheme[SchemeSel]); | ||
| 170 | else if (item->out) | ||
| 171 | drw_setscheme(drw, &scheme[SchemeOut]); | ||
| 172 | else | ||
| 173 | drw_setscheme(drw, &scheme[SchemeNorm]); | ||
| 174 | drw_text(drw, x, 0, w, bh, item->text, 0); | ||
| 175 | } | ||
| 176 | w = TEXTW(">"); | ||
| 177 | x = mw - w; | ||
| 178 | if (next) { | 168 | if (next) { |
| 179 | drw_setscheme(drw, &scheme[SchemeNorm]); | 169 | w = TEXTW(">"); |
| 180 | drw_text(drw, x, 0, w, bh, ">", 0); | 170 | drw_setscheme(drw, scheme[SchemeNorm]); |
| 171 | drw_text(drw, mw - w, 0, w, bh, lrpad / 2, ">", 0); | ||
| 181 | } | 172 | } |
| 182 | } | 173 | } |
| 183 | drw_map(drw, win, 0, 0, mw, mh); | 174 | drw_map(drw, win, 0, 0, mw, mh); |
| @@ -191,8 +182,8 @@ grabkeyboard(void) | |||
| 191 | 182 | ||
| 192 | /* try to grab keyboard, we may have to wait for another process to ungrab */ | 183 | /* try to grab keyboard, we may have to wait for another process to ungrab */ |
| 193 | for (i = 0; i < 1000; i++) { | 184 | for (i = 0; i < 1000; i++) { |
| 194 | if (XGrabKeyboard(dpy, DefaultRootWindow(dpy), True, | 185 | if (XGrabKeyboard(dpy, DefaultRootWindow(dpy), True, GrabModeAsync, |
| 195 | GrabModeAsync, GrabModeAsync, CurrentTime) == GrabSuccess) | 186 | GrabModeAsync, CurrentTime) == GrabSuccess) |
| 196 | return; | 187 | return; |
| 197 | nanosleep(&ts, NULL); | 188 | nanosleep(&ts, NULL); |
| 198 | } | 189 | } |
| @@ -314,11 +305,9 @@ keypress(XKeyEvent *ev) | |||
| 314 | insert(NULL, 0 - cursor); | 305 | insert(NULL, 0 - cursor); |
| 315 | break; | 306 | break; |
| 316 | case XK_w: /* delete word */ | 307 | case XK_w: /* delete word */ |
| 317 | while (cursor > 0 && strchr(worddelimiters, | 308 | while (cursor > 0 && strchr(worddelimiters, text[nextrune(-1)])) |
| 318 | text[nextrune(-1)])) | ||
| 319 | insert(NULL, nextrune(-1) - cursor); | 309 | insert(NULL, nextrune(-1) - cursor); |
| 320 | while (cursor > 0 && !strchr(worddelimiters, | 310 | while (cursor > 0 && !strchr(worddelimiters, text[nextrune(-1)])) |
| 321 | text[nextrune(-1)])) | ||
| 322 | insert(NULL, nextrune(-1) - cursor); | 311 | insert(NULL, nextrune(-1) - cursor); |
| 323 | break; | 312 | break; |
| 324 | case XK_y: /* paste selection */ | 313 | case XK_y: /* paste selection */ |
| @@ -469,8 +458,9 @@ paste(void) | |||
| 469 | static void | 458 | static void |
| 470 | readstdin(void) | 459 | readstdin(void) |
| 471 | { | 460 | { |
| 472 | char buf[sizeof text], *p, *maxstr = NULL; | 461 | char buf[sizeof text], *p; |
| 473 | size_t i, max = 0, size = 0; | 462 | size_t i, imax = 0, size = 0; |
| 463 | unsigned int tmpmax = 0; | ||
| 474 | 464 | ||
| 475 | /* read each line from stdin and add it to the item list */ | 465 | /* read each line from stdin and add it to the item list */ |
| 476 | for (i = 0; fgets(buf, sizeof buf, stdin); i++) { | 466 | for (i = 0; fgets(buf, sizeof buf, stdin); i++) { |
| @@ -482,12 +472,15 @@ readstdin(void) | |||
| 482 | if (!(items[i].text = strdup(buf))) | 472 | if (!(items[i].text = strdup(buf))) |
| 483 | die("cannot strdup %u bytes:", strlen(buf) + 1); | 473 | die("cannot strdup %u bytes:", strlen(buf) + 1); |
| 484 | items[i].out = 0; | 474 | items[i].out = 0; |
| 485 | if (strlen(items[i].text) > max) | 475 | drw_font_getexts(drw->fonts, buf, strlen(buf), &tmpmax, NULL); |
| 486 | max = strlen(maxstr = items[i].text); | 476 | if (tmpmax > inputw) { |
| 477 | inputw = tmpmax; | ||
| 478 | imax = i; | ||
| 479 | } | ||
| 487 | } | 480 | } |
| 488 | if (items) | 481 | if (items) |
| 489 | items[i].text = NULL; | 482 | items[i].text = NULL; |
| 490 | inputw = maxstr ? TEXTW(maxstr) : 0; | 483 | inputw = TEXTW(items[imax].text); |
| 491 | lines = MIN(lines, i); | 484 | lines = MIN(lines, i); |
| 492 | } | 485 | } |
| 493 | 486 | ||
| @@ -534,18 +527,15 @@ setup(void) | |||
| 534 | #endif | 527 | #endif |
| 535 | 528 | ||
| 536 | /* init appearance */ | 529 | /* init appearance */ |
| 537 | scheme[SchemeNorm].bg = drw_clr_create(drw, normbgcolor); | 530 | scheme[SchemeNorm] = drw_scm_create(drw, colors[SchemeNorm], 2); |
| 538 | scheme[SchemeNorm].fg = drw_clr_create(drw, normfgcolor); | 531 | scheme[SchemeSel] = drw_scm_create(drw, colors[SchemeSel], 2); |
| 539 | scheme[SchemeSel].bg = drw_clr_create(drw, selbgcolor); | 532 | scheme[SchemeOut] = drw_scm_create(drw, colors[SchemeOut], 2); |
| 540 | scheme[SchemeSel].fg = drw_clr_create(drw, selfgcolor); | ||
| 541 | scheme[SchemeOut].bg = drw_clr_create(drw, outbgcolor); | ||
| 542 | scheme[SchemeOut].fg = drw_clr_create(drw, outfgcolor); | ||
| 543 | 533 | ||
| 544 | clip = XInternAtom(dpy, "CLIPBOARD", False); | 534 | clip = XInternAtom(dpy, "CLIPBOARD", False); |
| 545 | utf8 = XInternAtom(dpy, "UTF8_STRING", False); | 535 | utf8 = XInternAtom(dpy, "UTF8_STRING", False); |
| 546 | 536 | ||
| 547 | /* calculate menu geometry */ | 537 | /* calculate menu geometry */ |
| 548 | bh = drw->fonts[0]->h + 2; | 538 | bh = drw->fonts->h + 2; |
| 549 | lines = MAX(lines, 0); | 539 | lines = MAX(lines, 0); |
| 550 | mh = (lines + 1) * bh; | 540 | mh = (lines + 1) * bh; |
| 551 | #ifdef XINERAMA | 541 | #ifdef XINERAMA |
| @@ -584,13 +574,13 @@ setup(void) | |||
| 584 | y = topbar ? 0 : sh - mh; | 574 | y = topbar ? 0 : sh - mh; |
| 585 | mw = sw; | 575 | mw = sw; |
| 586 | } | 576 | } |
| 587 | promptw = (prompt && *prompt) ? TEXTW(prompt) : 0; | 577 | promptw = (prompt && *prompt) ? TEXTW(prompt) - lrpad / 4 : 0; |
| 588 | inputw = MIN(inputw, mw/3); | 578 | inputw = MIN(inputw, mw/3); |
| 589 | match(); | 579 | match(); |
| 590 | 580 | ||
| 591 | /* create menu window */ | 581 | /* create menu window */ |
| 592 | swa.override_redirect = True; | 582 | swa.override_redirect = True; |
| 593 | swa.background_pixel = scheme[SchemeNorm].bg->pix; | 583 | swa.background_pixel = scheme[SchemeNorm][ColBg].pixel; |
| 594 | swa.event_mask = ExposureMask | KeyPressMask | VisibilityChangeMask; | 584 | swa.event_mask = ExposureMask | KeyPressMask | VisibilityChangeMask; |
| 595 | win = XCreateWindow(dpy, root, x, y, mw, mh, 0, | 585 | win = XCreateWindow(dpy, root, x, y, mw, mh, 0, |
| 596 | DefaultDepth(dpy, screen), CopyFromParent, | 586 | DefaultDepth(dpy, screen), CopyFromParent, |
| @@ -644,13 +634,13 @@ main(int argc, char *argv[]) | |||
| 644 | else if (!strcmp(argv[i], "-fn")) /* font or font set */ | 634 | else if (!strcmp(argv[i], "-fn")) /* font or font set */ |
| 645 | fonts[0] = argv[++i]; | 635 | fonts[0] = argv[++i]; |
| 646 | else if (!strcmp(argv[i], "-nb")) /* normal background color */ | 636 | else if (!strcmp(argv[i], "-nb")) /* normal background color */ |
| 647 | normbgcolor = argv[++i]; | 637 | colors[SchemeNorm][ColBg] = argv[++i]; |
| 648 | else if (!strcmp(argv[i], "-nf")) /* normal foreground color */ | 638 | else if (!strcmp(argv[i], "-nf")) /* normal foreground color */ |
| 649 | normfgcolor = argv[++i]; | 639 | colors[SchemeNorm][ColFg] = argv[++i]; |
| 650 | else if (!strcmp(argv[i], "-sb")) /* selected background color */ | 640 | else if (!strcmp(argv[i], "-sb")) /* selected background color */ |
| 651 | selbgcolor = argv[++i]; | 641 | colors[SchemeSel][ColBg] = argv[++i]; |
| 652 | else if (!strcmp(argv[i], "-sf")) /* selected foreground color */ | 642 | else if (!strcmp(argv[i], "-sf")) /* selected foreground color */ |
| 653 | selfgcolor = argv[++i]; | 643 | colors[SchemeSel][ColFg] = argv[++i]; |
| 654 | else | 644 | else |
| 655 | usage(); | 645 | usage(); |
| 656 | 646 | ||
| @@ -663,10 +653,9 @@ main(int argc, char *argv[]) | |||
| 663 | sw = DisplayWidth(dpy, screen); | 653 | sw = DisplayWidth(dpy, screen); |
| 664 | sh = DisplayHeight(dpy, screen); | 654 | sh = DisplayHeight(dpy, screen); |
| 665 | drw = drw_create(dpy, screen, root, sw, sh); | 655 | drw = drw_create(dpy, screen, root, sw, sh); |
| 666 | drw_load_fonts(drw, fonts, LENGTH(fonts)); | 656 | if (!drw_fontset_create(drw, fonts, LENGTH(fonts))) |
| 667 | if (!drw->fontcount) | ||
| 668 | die("no fonts could be loaded.\n"); | 657 | die("no fonts could be loaded.\n"); |
| 669 | drw_setscheme(drw, &scheme[SchemeNorm]); | 658 | lrpad = drw->fonts->h; |
| 670 | 659 | ||
| 671 | if (fast) { | 660 | if (fast) { |
| 672 | grabkeyboard(); | 661 | grabkeyboard(); |
