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