diff options
-rw-r--r-- | .hgtags | 1 | ||||
-rw-r--r-- | Makefile | 4 | ||||
-rw-r--r-- | config.mk | 2 | ||||
-rw-r--r-- | dmenu.1 | 15 | ||||
-rw-r--r-- | dmenu.c | 186 | ||||
-rwxr-xr-x | dmenu_run | 2 | ||||
-rw-r--r-- | draw.c | 22 | ||||
-rw-r--r-- | draw.h | 1 | ||||
-rw-r--r-- | lsx.c | 4 |
9 files changed, 118 insertions, 119 deletions
@@ -46,3 +46,4 @@ e4c81a78ffbad6ba4d1ad119cc654da6eca63a4c 3.2 | |||
46 | abb6579a324fffdf6a23c2fa4c32911277da594a 4.2.1 | 46 | abb6579a324fffdf6a23c2fa4c32911277da594a 4.2.1 |
47 | 14c79f054bdf43ff3213af8e60a783192e92a018 4.3 | 47 | 14c79f054bdf43ff3213af8e60a783192e92a018 4.3 |
48 | 34a2d77049a95b02f3332a0b88f9370965ebcfad 4.3.1 | 48 | 34a2d77049a95b02f3332a0b88f9370965ebcfad 4.3.1 |
49 | 2b105eaae8315b076da93056da9ecd60de5a7ac9 4.4 | ||
@@ -30,12 +30,12 @@ lsx: lsx.o | |||
30 | 30 | ||
31 | clean: | 31 | clean: |
32 | @echo cleaning | 32 | @echo cleaning |
33 | @rm -f dmenu ${OBJ} dmenu-${VERSION}.tar.gz | 33 | @rm -f dmenu lsx ${OBJ} dmenu-${VERSION}.tar.gz |
34 | 34 | ||
35 | dist: clean | 35 | dist: clean |
36 | @echo creating dist tarball | 36 | @echo creating dist tarball |
37 | @mkdir -p dmenu-${VERSION} | 37 | @mkdir -p dmenu-${VERSION} |
38 | @cp LICENSE Makefile README config.mk dmenu.1 draw.h dmenu_run ${SRC} dmenu-${VERSION} | 38 | @cp LICENSE Makefile README config.mk dmenu.1 draw.h dmenu_run lsx.1 ${SRC} dmenu-${VERSION} |
39 | @tar -cf dmenu-${VERSION}.tar dmenu-${VERSION} | 39 | @tar -cf dmenu-${VERSION}.tar dmenu-${VERSION} |
40 | @gzip dmenu-${VERSION}.tar | 40 | @gzip dmenu-${VERSION}.tar |
41 | @rm -rf dmenu-${VERSION} | 41 | @rm -rf dmenu-${VERSION} |
@@ -1,5 +1,5 @@ | |||
1 | # dmenu version | 1 | # dmenu version |
2 | VERSION = 4.3.1 | 2 | VERSION = hg |
3 | 3 | ||
4 | # paths | 4 | # paths |
5 | PREFIX = /usr/local | 5 | PREFIX = /usr/local |
@@ -25,13 +25,10 @@ dmenu \- dynamic menu | |||
25 | .BR dmenu_run " ..." | 25 | .BR dmenu_run " ..." |
26 | .SH DESCRIPTION | 26 | .SH DESCRIPTION |
27 | .B dmenu | 27 | .B dmenu |
28 | is a dynamic menu for X, originally designed for | 28 | is a dynamic menu for X, which reads a list of newline\-separated items from |
29 | .IR dwm (1). | 29 | stdin. When the user selects an item and presses Return, their choice is printed |
30 | It manages huge numbers of user\-defined menu items efficiently. | 30 | to stdout and dmenu terminates. Entering text will narrow the items to those |
31 | .P | 31 | matching the tokens in the input. |
32 | dmenu reads a list of newline\-separated items from stdin and creates a menu. | ||
33 | When the user selects an item or enters any text and presses Return, their | ||
34 | choice is printed to stdout and dmenu terminates. | ||
35 | .P | 32 | .P |
36 | .B dmenu_run | 33 | .B dmenu_run |
37 | is a dmenu script used by dwm which lists programs in the user's $PATH and | 34 | is a dmenu script used by dwm which lists programs in the user's $PATH and |
@@ -42,8 +39,8 @@ executes the selected item. | |||
42 | dmenu appears at the bottom of the screen. | 39 | dmenu appears at the bottom of the screen. |
43 | .TP | 40 | .TP |
44 | .B \-f | 41 | .B \-f |
45 | dmenu grabs the keyboard before reading stdin. This is faster, but may lock up | 42 | dmenu grabs the keyboard before reading stdin. This is faster, but will lock up |
46 | X if stdin is from a terminal. | 43 | X until stdin reaches end\-of\-file. |
47 | .TP | 44 | .TP |
48 | .B \-i | 45 | .B \-i |
49 | dmenu matches menu items case insensitively. | 46 | dmenu matches menu items case insensitively. |
@@ -25,12 +25,12 @@ struct Item { | |||
25 | 25 | ||
26 | static void appenditem(Item *item, Item **list, Item **last); | 26 | static void appenditem(Item *item, Item **list, Item **last); |
27 | static void calcoffsets(void); | 27 | static void calcoffsets(void); |
28 | static char *cistrstr(const char *s, const char *sub); | ||
28 | static void drawmenu(void); | 29 | static void drawmenu(void); |
29 | static char *fstrstr(const char *s, const char *sub); | ||
30 | static void grabkeyboard(void); | 30 | static void grabkeyboard(void); |
31 | static void insert(const char *str, ssize_t n); | 31 | static void insert(const char *str, ssize_t n); |
32 | static void keypress(XKeyEvent *ev); | 32 | static void keypress(XKeyEvent *ev); |
33 | static void match(Bool sub); | 33 | static void match(void); |
34 | static size_t nextrune(int inc); | 34 | static size_t nextrune(int inc); |
35 | static void paste(void); | 35 | static void paste(void); |
36 | static void readstdin(void); | 36 | static void readstdin(void); |
@@ -60,6 +60,7 @@ static Item *prev, *curr, *next, *sel; | |||
60 | static Window win; | 60 | static Window win; |
61 | 61 | ||
62 | static int (*fstrncmp)(const char *, const char *, size_t) = strncmp; | 62 | static int (*fstrncmp)(const char *, const char *, size_t) = strncmp; |
63 | static char *(*fstrstr)(const char *, const char *) = strstr; | ||
63 | 64 | ||
64 | int | 65 | int |
65 | main(int argc, char *argv[]) { | 66 | main(int argc, char *argv[]) { |
@@ -76,8 +77,10 @@ main(int argc, char *argv[]) { | |||
76 | topbar = False; | 77 | topbar = False; |
77 | else if(!strcmp(argv[i], "-f")) | 78 | else if(!strcmp(argv[i], "-f")) |
78 | fast = True; | 79 | fast = True; |
79 | else if(!strcmp(argv[i], "-i")) | 80 | else if(!strcmp(argv[i], "-i")) { |
80 | fstrncmp = strncasecmp; | 81 | fstrncmp = strncasecmp; |
82 | fstrstr = cistrstr; | ||
83 | } | ||
81 | else if(i+1 == argc) | 84 | else if(i+1 == argc) |
82 | usage(); | 85 | usage(); |
83 | /* double flags */ | 86 | /* double flags */ |
@@ -112,15 +115,16 @@ main(int argc, char *argv[]) { | |||
112 | setup(); | 115 | setup(); |
113 | run(); | 116 | run(); |
114 | 117 | ||
115 | return EXIT_FAILURE; /* should not reach */ | 118 | return EXIT_FAILURE; /* unreachable */ |
116 | } | 119 | } |
117 | 120 | ||
118 | void | 121 | void |
119 | appenditem(Item *item, Item **list, Item **last) { | 122 | appenditem(Item *item, Item **list, Item **last) { |
120 | if(!*last) | 123 | if(*last) |
121 | *list = item; | ||
122 | else | ||
123 | (*last)->right = item; | 124 | (*last)->right = item; |
125 | else | ||
126 | *list = item; | ||
127 | |||
124 | item->left = *last; | 128 | item->left = *last; |
125 | item->right = NULL; | 129 | item->right = NULL; |
126 | *last = item; | 130 | *last = item; |
@@ -143,6 +147,16 @@ calcoffsets(void) { | |||
143 | break; | 147 | break; |
144 | } | 148 | } |
145 | 149 | ||
150 | char * | ||
151 | cistrstr(const char *s, const char *sub) { | ||
152 | size_t len; | ||
153 | |||
154 | for(len = strlen(sub); *s; s++) | ||
155 | if(!strncasecmp(s, sub, len)) | ||
156 | return (char *)s; | ||
157 | return NULL; | ||
158 | } | ||
159 | |||
146 | void | 160 | void |
147 | drawmenu(void) { | 161 | drawmenu(void) { |
148 | int curpos; | 162 | int curpos; |
@@ -188,16 +202,6 @@ drawmenu(void) { | |||
188 | mapdc(dc, win, mw, mh); | 202 | mapdc(dc, win, mw, mh); |
189 | } | 203 | } |
190 | 204 | ||
191 | char * | ||
192 | fstrstr(const char *s, const char *sub) { | ||
193 | size_t len; | ||
194 | |||
195 | for(len = strlen(sub); *s; s++) | ||
196 | if(!fstrncmp(s, sub, len)) | ||
197 | return (char *)s; | ||
198 | return NULL; | ||
199 | } | ||
200 | |||
201 | void | 205 | void |
202 | grabkeyboard(void) { | 206 | grabkeyboard(void) { |
203 | int i; | 207 | int i; |
@@ -219,7 +223,7 @@ insert(const char *str, ssize_t n) { | |||
219 | if(n > 0) | 223 | if(n > 0) |
220 | memcpy(&text[cursor], str, n); | 224 | memcpy(&text[cursor], str, n); |
221 | cursor += n; | 225 | cursor += n; |
222 | match(n > 0 && text[cursor] == '\0'); | 226 | match(); |
223 | } | 227 | } |
224 | 228 | ||
225 | void | 229 | void |
@@ -233,58 +237,37 @@ keypress(XKeyEvent *ev) { | |||
233 | 237 | ||
234 | XConvertCase(ksym, &lower, &upper); | 238 | XConvertCase(ksym, &lower, &upper); |
235 | switch(lower) { | 239 | switch(lower) { |
236 | default: | 240 | case XK_a: ksym = XK_Home; break; |
237 | return; | 241 | case XK_b: ksym = XK_Left; break; |
238 | case XK_a: | 242 | case XK_c: ksym = XK_Escape; break; |
239 | ksym = XK_Home; | 243 | case XK_d: ksym = XK_Delete; break; |
240 | break; | 244 | case XK_e: ksym = XK_End; break; |
241 | case XK_b: | 245 | case XK_f: ksym = XK_Right; break; |
242 | ksym = XK_Left; | 246 | case XK_h: ksym = XK_BackSpace; break; |
243 | break; | 247 | case XK_i: ksym = XK_Tab; break; |
244 | case XK_c: | 248 | case XK_j: ksym = XK_Return; break; |
245 | ksym = XK_Escape; | 249 | case XK_m: ksym = XK_Return; break; |
246 | break; | 250 | case XK_n: ksym = XK_Up; break; |
247 | case XK_d: | 251 | case XK_p: ksym = XK_Down; break; |
248 | ksym = XK_Delete; | 252 | |
249 | break; | 253 | case XK_k: /* delete right */ |
250 | case XK_e: | ||
251 | ksym = XK_End; | ||
252 | break; | ||
253 | case XK_f: | ||
254 | ksym = XK_Right; | ||
255 | break; | ||
256 | case XK_h: | ||
257 | ksym = XK_BackSpace; | ||
258 | break; | ||
259 | case XK_i: | ||
260 | ksym = XK_Tab; | ||
261 | break; | ||
262 | case XK_j: | ||
263 | case XK_m: | ||
264 | ksym = XK_Return; | ||
265 | break; | ||
266 | case XK_k: /* delete right */ | ||
267 | text[cursor] = '\0'; | 254 | text[cursor] = '\0'; |
268 | match(False); | 255 | match(); |
269 | break; | ||
270 | case XK_n: | ||
271 | ksym = XK_Down; | ||
272 | break; | ||
273 | case XK_p: | ||
274 | ksym = XK_Up; | ||
275 | break; | 256 | break; |
276 | case XK_u: /* delete left */ | 257 | case XK_u: /* delete left */ |
277 | insert(NULL, 0 - cursor); | 258 | insert(NULL, 0 - cursor); |
278 | break; | 259 | break; |
279 | case XK_w: /* delete word */ | 260 | case XK_w: /* delete word */ |
280 | while(cursor > 0 && text[nextrune(-1)] == ' ') | 261 | while(cursor > 0 && text[nextrune(-1)] == ' ') |
281 | insert(NULL, nextrune(-1) - cursor); | 262 | insert(NULL, nextrune(-1) - cursor); |
282 | while(cursor > 0 && text[nextrune(-1)] != ' ') | 263 | while(cursor > 0 && text[nextrune(-1)] != ' ') |
283 | insert(NULL, nextrune(-1) - cursor); | 264 | insert(NULL, nextrune(-1) - cursor); |
284 | break; | 265 | break; |
285 | case XK_y: /* paste selection */ | 266 | case XK_y: /* paste selection */ |
286 | XConvertSelection(dc->dpy, XA_PRIMARY, utf8, utf8, win, CurrentTime); | 267 | XConvertSelection(dc->dpy, XA_PRIMARY, utf8, utf8, win, CurrentTime); |
287 | return; | 268 | return; |
269 | default: | ||
270 | return; | ||
288 | } | 271 | } |
289 | } | 272 | } |
290 | switch(ksym) { | 273 | switch(ksym) { |
@@ -296,9 +279,11 @@ keypress(XKeyEvent *ev) { | |||
296 | if(text[cursor] == '\0') | 279 | if(text[cursor] == '\0') |
297 | return; | 280 | return; |
298 | cursor = nextrune(+1); | 281 | cursor = nextrune(+1); |
282 | /* fallthrough */ | ||
299 | case XK_BackSpace: | 283 | case XK_BackSpace: |
300 | if(cursor > 0) | 284 | if(cursor == 0) |
301 | insert(NULL, nextrune(-1) - cursor); | 285 | return; |
286 | insert(NULL, nextrune(-1) - cursor); | ||
302 | break; | 287 | break; |
303 | case XK_End: | 288 | case XK_End: |
304 | if(text[cursor] != '\0') { | 289 | if(text[cursor] != '\0') { |
@@ -330,8 +315,7 @@ keypress(XKeyEvent *ev) { | |||
330 | cursor = nextrune(-1); | 315 | cursor = nextrune(-1); |
331 | break; | 316 | break; |
332 | } | 317 | } |
333 | else if(lines > 0) | 318 | /* fallthrough */ |
334 | return; | ||
335 | case XK_Up: | 319 | case XK_Up: |
336 | if(sel && sel->left && (sel = sel->left)->right == curr) { | 320 | if(sel && sel->left && (sel = sel->left)->right == curr) { |
337 | curr = prev; | 321 | curr = prev; |
@@ -352,15 +336,14 @@ keypress(XKeyEvent *ev) { | |||
352 | break; | 336 | break; |
353 | case XK_Return: | 337 | case XK_Return: |
354 | case XK_KP_Enter: | 338 | case XK_KP_Enter: |
355 | fputs((sel && !(ev->state & ShiftMask)) ? sel->text : text, stdout); | 339 | puts((sel && !(ev->state & ShiftMask)) ? sel->text : text); |
356 | exit(EXIT_SUCCESS); | 340 | exit(EXIT_SUCCESS); |
357 | case XK_Right: | 341 | case XK_Right: |
358 | if(text[cursor] != '\0') { | 342 | if(text[cursor] != '\0') { |
359 | cursor = nextrune(+1); | 343 | cursor = nextrune(+1); |
360 | break; | 344 | break; |
361 | } | 345 | } |
362 | else if(lines > 0) | 346 | /* fallthrough */ |
363 | return; | ||
364 | case XK_Down: | 347 | case XK_Down: |
365 | if(sel && sel->right && (sel = sel->right) == next) { | 348 | if(sel && sel->right && (sel = sel->right) == next) { |
366 | curr = next; | 349 | curr = next; |
@@ -372,33 +355,44 @@ keypress(XKeyEvent *ev) { | |||
372 | return; | 355 | return; |
373 | strncpy(text, sel->text, sizeof text); | 356 | strncpy(text, sel->text, sizeof text); |
374 | cursor = strlen(text); | 357 | cursor = strlen(text); |
375 | match(True); | 358 | match(); |
376 | break; | 359 | break; |
377 | } | 360 | } |
378 | drawmenu(); | 361 | drawmenu(); |
379 | } | 362 | } |
380 | 363 | ||
381 | void | 364 | void |
382 | match(Bool sub) { | 365 | match(void) { |
383 | size_t len = strlen(text); | 366 | static char **tokv = NULL; |
384 | Item *lexact, *lprefix, *lsubstr, *exactend, *prefixend, *substrend; | 367 | static int tokn = 0; |
385 | Item *item, *lnext; | 368 | |
386 | 369 | char buf[sizeof text], *s; | |
387 | lexact = lprefix = lsubstr = exactend = prefixend = substrend = NULL; | 370 | int i, tokc = 0; |
388 | for(item = sub ? matches : items; item && item->text; item = lnext) { | 371 | size_t len; |
389 | lnext = sub ? item->right : item + 1; | 372 | Item *item, *lprefix, *lsubstr, *prefixend, *substrend; |
390 | if(!fstrncmp(text, item->text, len + 1)) | 373 | |
391 | appenditem(item, &lexact, &exactend); | 374 | strcpy(buf, text); |
392 | else if(!fstrncmp(text, item->text, len)) | 375 | for(s = strtok(buf, " "); s; tokv[tokc-1] = s, s = strtok(NULL, " ")) |
376 | if(++tokc > tokn && !(tokv = realloc(tokv, ++tokn * sizeof *tokv))) | ||
377 | eprintf("cannot realloc %u bytes\n", tokn * sizeof *tokv); | ||
378 | len = tokc ? strlen(tokv[0]) : 0; | ||
379 | |||
380 | matches = lprefix = lsubstr = matchend = prefixend = substrend = NULL; | ||
381 | for(item = items; item && item->text; item++) { | ||
382 | for(i = 0; i < tokc; i++) | ||
383 | if(!fstrstr(item->text, tokv[i])) | ||
384 | break; | ||
385 | if(i != tokc) | ||
386 | continue; | ||
387 | if(!tokc || !fstrncmp(tokv[0], item->text, len+1)) | ||
388 | appenditem(item, &matches, &matchend); | ||
389 | else if(!fstrncmp(tokv[0], item->text, len)) | ||
393 | appenditem(item, &lprefix, &prefixend); | 390 | appenditem(item, &lprefix, &prefixend); |
394 | else if(fstrstr(item->text, text)) | 391 | else |
395 | appenditem(item, &lsubstr, &substrend); | 392 | appenditem(item, &lsubstr, &substrend); |
396 | } | 393 | } |
397 | matches = lexact; | ||
398 | matchend = exactend; | ||
399 | |||
400 | if(lprefix) { | 394 | if(lprefix) { |
401 | if(matchend) { | 395 | if(matches) { |
402 | matchend->right = lprefix; | 396 | matchend->right = lprefix; |
403 | lprefix->left = matchend; | 397 | lprefix->left = matchend; |
404 | } | 398 | } |
@@ -407,7 +401,7 @@ match(Bool sub) { | |||
407 | matchend = prefixend; | 401 | matchend = prefixend; |
408 | } | 402 | } |
409 | if(lsubstr) { | 403 | if(lsubstr) { |
410 | if(matchend) { | 404 | if(matches) { |
411 | matchend->right = lsubstr; | 405 | matchend->right = lsubstr; |
412 | lsubstr->left = matchend; | 406 | lsubstr->left = matchend; |
413 | } | 407 | } |
@@ -460,6 +454,7 @@ readstdin(void) { | |||
460 | if(items) | 454 | if(items) |
461 | items[i].text = NULL; | 455 | items[i].text = NULL; |
462 | inputw = maxstr ? textw(dc, maxstr) : 0; | 456 | inputw = maxstr ? textw(dc, maxstr) : 0; |
457 | lines = MIN(lines, i); | ||
463 | } | 458 | } |
464 | 459 | ||
465 | void | 460 | void |
@@ -470,7 +465,7 @@ run(void) { | |||
470 | switch(ev.type) { | 465 | switch(ev.type) { |
471 | case Expose: | 466 | case Expose: |
472 | if(ev.xexpose.count == 0) | 467 | if(ev.xexpose.count == 0) |
473 | drawmenu(); | 468 | mapdc(dc, win, mw, mh); |
474 | break; | 469 | break; |
475 | case KeyPress: | 470 | case KeyPress: |
476 | keypress(&ev.xkey); | 471 | keypress(&ev.xkey); |
@@ -490,7 +485,7 @@ void | |||
490 | setup(void) { | 485 | setup(void) { |
491 | int x, y, screen = DefaultScreen(dc->dpy); | 486 | int x, y, screen = DefaultScreen(dc->dpy); |
492 | Window root = RootWindow(dc->dpy, screen); | 487 | Window root = RootWindow(dc->dpy, screen); |
493 | XSetWindowAttributes wa; | 488 | XSetWindowAttributes swa; |
494 | #ifdef XINERAMA | 489 | #ifdef XINERAMA |
495 | int n; | 490 | int n; |
496 | XineramaScreenInfo *info; | 491 | XineramaScreenInfo *info; |
@@ -511,9 +506,14 @@ setup(void) { | |||
511 | if((info = XineramaQueryScreens(dc->dpy, &n))) { | 506 | if((info = XineramaQueryScreens(dc->dpy, &n))) { |
512 | int i, di; | 507 | int i, di; |
513 | unsigned int du; | 508 | unsigned int du; |
514 | Window dw; | 509 | Window w, dw; |
510 | XWindowAttributes wa; | ||
515 | 511 | ||
516 | XQueryPointer(dc->dpy, root, &dw, &dw, &x, &y, &di, &di, &du); | 512 | XGetInputFocus(dc->dpy, &w, &di); |
513 | if(w != root && w != PointerRoot && w != None && XGetWindowAttributes(dc->dpy, w, &wa)) | ||
514 | XTranslateCoordinates(dc->dpy, w, root, wa.x, wa.y, &x, &y, &dw); | ||
515 | else | ||
516 | XQueryPointer(dc->dpy, root, &dw, &dw, &x, &y, &di, &di, &du); | ||
517 | for(i = 0; i < n-1; i++) | 517 | for(i = 0; i < n-1; i++) |
518 | if(INRECT(x, y, info[i].x_org, info[i].y_org, info[i].width, info[i].height)) | 518 | if(INRECT(x, y, info[i].x_org, info[i].y_org, info[i].width, info[i].height)) |
519 | break; | 519 | break; |
@@ -531,16 +531,16 @@ setup(void) { | |||
531 | } | 531 | } |
532 | promptw = prompt ? textw(dc, prompt) : 0; | 532 | promptw = prompt ? textw(dc, prompt) : 0; |
533 | inputw = MIN(inputw, mw/3); | 533 | inputw = MIN(inputw, mw/3); |
534 | match(False); | 534 | match(); |
535 | 535 | ||
536 | /* menu window */ | 536 | /* menu window */ |
537 | wa.override_redirect = True; | 537 | swa.override_redirect = True; |
538 | wa.background_pixmap = ParentRelative; | 538 | swa.background_pixmap = ParentRelative; |
539 | wa.event_mask = ExposureMask | KeyPressMask | VisibilityChangeMask; | 539 | swa.event_mask = ExposureMask | KeyPressMask | VisibilityChangeMask; |
540 | win = XCreateWindow(dc->dpy, root, x, y, mw, mh, 0, | 540 | win = XCreateWindow(dc->dpy, root, x, y, mw, mh, 0, |
541 | DefaultDepth(dc->dpy, screen), CopyFromParent, | 541 | DefaultDepth(dc->dpy, screen), CopyFromParent, |
542 | DefaultVisual(dc->dpy, screen), | 542 | DefaultVisual(dc->dpy, screen), |
543 | CWOverrideRedirect | CWBackPixmap | CWEventMask, &wa); | 543 | CWOverrideRedirect | CWBackPixmap | CWEventMask, &swa); |
544 | 544 | ||
545 | XMapRaised(dc->dpy, win); | 545 | XMapRaised(dc->dpy, win); |
546 | resizedc(dc, mw, mh); | 546 | resizedc(dc, mw, mh); |
@@ -6,4 +6,4 @@ CACHE=${XDG_CACHE_HOME:-"$HOME/.cache"}/dmenu_run | |||
6 | mkdir -p "`dirname "$CACHE"`" && lsx $PATH | sort -u > "$CACHE" | 6 | mkdir -p "`dirname "$CACHE"`" && lsx $PATH | sort -u > "$CACHE" |
7 | fi | 7 | fi |
8 | ) | 8 | ) |
9 | cmd=`dmenu "$@" < "$CACHE"` && exec $cmd | 9 | cmd=`dmenu "$@" < "$CACHE"` && exec sh -c "$cmd" |
@@ -96,7 +96,7 @@ initdc(void) { | |||
96 | DC *dc; | 96 | DC *dc; |
97 | 97 | ||
98 | if(!setlocale(LC_CTYPE, "") || !XSupportsLocale()) | 98 | if(!setlocale(LC_CTYPE, "") || !XSupportsLocale()) |
99 | fprintf(stderr, "no locale support\n"); | 99 | fputs("no locale support\n", stderr); |
100 | if(!(dc = calloc(1, sizeof *dc))) | 100 | if(!(dc = calloc(1, sizeof *dc))) |
101 | eprintf("cannot malloc %u bytes:", sizeof *dc); | 101 | eprintf("cannot malloc %u bytes:", sizeof *dc); |
102 | if(!(dc->dpy = XOpenDisplay(NULL))) | 102 | if(!(dc->dpy = XOpenDisplay(NULL))) |
@@ -120,28 +120,28 @@ initfont(DC *dc, const char *fontstr) { | |||
120 | 120 | ||
121 | Bool | 121 | Bool |
122 | loadfont(DC *dc, const char *fontstr) { | 122 | loadfont(DC *dc, const char *fontstr) { |
123 | char *def, **missing; | 123 | char *def, **missing, **names; |
124 | int i, n; | 124 | int i, n; |
125 | XFontStruct **xfonts; | ||
125 | 126 | ||
126 | if(!*fontstr) | 127 | if(!*fontstr) |
127 | return False; | 128 | return False; |
128 | if((dc->font.set = XCreateFontSet(dc->dpy, fontstr, &missing, &n, &def))) { | 129 | if((dc->font.set = XCreateFontSet(dc->dpy, fontstr, &missing, &n, &def))) { |
129 | char **names; | ||
130 | XFontStruct **xfonts; | ||
131 | |||
132 | n = XFontsOfFontSet(dc->font.set, &xfonts, &names); | 130 | n = XFontsOfFontSet(dc->font.set, &xfonts, &names); |
133 | for(i = dc->font.ascent = dc->font.descent = 0; i < n; i++) { | 131 | for(i = 0; i < n; i++) { |
134 | dc->font.ascent = MAX(dc->font.ascent, xfonts[i]->ascent); | 132 | dc->font.ascent = MAX(dc->font.ascent, xfonts[i]->ascent); |
135 | dc->font.descent = MAX(dc->font.descent, xfonts[i]->descent); | 133 | dc->font.descent = MAX(dc->font.descent, xfonts[i]->descent); |
134 | dc->font.width = MAX(dc->font.width, xfonts[i]->max_bounds.width); | ||
136 | } | 135 | } |
137 | } | 136 | } |
138 | else if((dc->font.xfont = XLoadQueryFont(dc->dpy, fontstr))) { | 137 | else if((dc->font.xfont = XLoadQueryFont(dc->dpy, fontstr))) { |
139 | dc->font.ascent = dc->font.xfont->ascent; | 138 | dc->font.ascent = dc->font.xfont->ascent; |
140 | dc->font.descent = dc->font.xfont->descent; | 139 | dc->font.descent = dc->font.xfont->descent; |
140 | dc->font.width = dc->font.xfont->max_bounds.width; | ||
141 | } | 141 | } |
142 | if(missing) | 142 | if(missing) |
143 | XFreeStringList(missing); | 143 | XFreeStringList(missing); |
144 | return (dc->font.set || dc->font.xfont); | 144 | return dc->font.set || dc->font.xfont; |
145 | } | 145 | } |
146 | 146 | ||
147 | void | 147 | void |
@@ -154,10 +154,10 @@ resizedc(DC *dc, unsigned int w, unsigned int h) { | |||
154 | if(dc->canvas) | 154 | if(dc->canvas) |
155 | XFreePixmap(dc->dpy, dc->canvas); | 155 | XFreePixmap(dc->dpy, dc->canvas); |
156 | 156 | ||
157 | dc->canvas = XCreatePixmap(dc->dpy, DefaultRootWindow(dc->dpy), w, h, | ||
158 | DefaultDepth(dc->dpy, DefaultScreen(dc->dpy))); | ||
159 | dc->w = w; | 157 | dc->w = w; |
160 | dc->h = h; | 158 | dc->h = h; |
159 | dc->canvas = XCreatePixmap(dc->dpy, DefaultRootWindow(dc->dpy), w, h, | ||
160 | DefaultDepth(dc->dpy, DefaultScreen(dc->dpy))); | ||
161 | } | 161 | } |
162 | 162 | ||
163 | int | 163 | int |
@@ -15,6 +15,7 @@ typedef struct { | |||
15 | int ascent; | 15 | int ascent; |
16 | int descent; | 16 | int descent; |
17 | int height; | 17 | int height; |
18 | int width; | ||
18 | XFontSet set; | 19 | XFontSet set; |
19 | XFontStruct *xfont; | 20 | XFontStruct *xfont; |
20 | } font; | 21 | } font; |
@@ -1,8 +1,8 @@ | |||
1 | /* See LICENSE file for copyright and license details. */ | 1 | /* See LICENSE file for copyright and license details. */ |
2 | #include <dirent.h> | 2 | #include <dirent.h> |
3 | #include <limits.h> | ||
3 | #include <stdio.h> | 4 | #include <stdio.h> |
4 | #include <stdlib.h> | 5 | #include <stdlib.h> |
5 | #include <string.h> | ||
6 | #include <unistd.h> | 6 | #include <unistd.h> |
7 | #include <sys/stat.h> | 7 | #include <sys/stat.h> |
8 | 8 | ||
@@ -31,7 +31,7 @@ lsx(const char *dir) { | |||
31 | return; | 31 | return; |
32 | } | 32 | } |
33 | while((d = readdir(dp))) | 33 | while((d = readdir(dp))) |
34 | if(snprintf(buf, sizeof buf, "%s/%s", dir, d->d_name) < sizeof buf | 34 | if(snprintf(buf, sizeof buf, "%s/%s", dir, d->d_name) < (int)sizeof buf |
35 | && !stat(buf, &st) && S_ISREG(st.st_mode) && access(buf, X_OK) == 0) | 35 | && !stat(buf, &st) && S_ISREG(st.st_mode) && access(buf, X_OK) == 0) |
36 | puts(d->d_name); | 36 | puts(d->d_name); |
37 | closedir(dp); | 37 | closedir(dp); |