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(); |