aboutsummaryrefslogtreecommitdiff
path: root/dmenu.c
diff options
context:
space:
mode:
Diffstat (limited to 'dmenu.c')
-rw-r--r--dmenu.c147
1 files changed, 68 insertions, 79 deletions
diff --git a/dmenu.c b/dmenu.c
index e0c2f80..0e7b70b 100644
--- a/dmenu.c
+++ b/dmenu.c
@@ -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 */
29enum { SchemeNorm, SchemeSel, SchemeOut, SchemeLast }; /* color schemes */ 28enum { SchemeNorm, SchemeSel, SchemeOut, SchemeLast }; /* color schemes */
@@ -37,7 +36,8 @@ struct item {
37static char text[BUFSIZ] = ""; 36static char text[BUFSIZ] = "";
38static int bh, mw, mh; 37static int bh, mw, mh;
39static int sw, sh; /* X display screen geometry width, height */ 38static int sw, sh; /* X display screen geometry width, height */
40static int inputw, promptw; 39static int inputw = 0, promptw;
40static int lrpad; /* sum of left and right padding */
41static size_t cursor; 41static size_t cursor;
42static struct item *items = NULL; 42static struct item *items = NULL;
43static struct item *matches, *matchend; 43static struct item *matches, *matchend;
@@ -49,8 +49,8 @@ static Display *dpy;
49static Window root, win; 49static Window root, win;
50static XIC xic; 50static XIC xic;
51 51
52static ClrScheme scheme[SchemeLast];
53static Drw *drw; 52static Drw *drw;
53static 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
115static int
116drawitem(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
117static void 128static void
118drawmenu(void) 129drawmenu(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)
469static void 458static void
470readstdin(void) 459readstdin(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();