diff options
| -rw-r--r-- | dmenu.c | 587 |
1 files changed, 299 insertions, 288 deletions
| @@ -40,134 +40,55 @@ struct Item { | |||
| 40 | }; | 40 | }; |
| 41 | 41 | ||
| 42 | /* forward declarations */ | 42 | /* forward declarations */ |
| 43 | static void *emalloc(unsigned int size); | 43 | void calcoffsets(void); |
| 44 | static void eprint(const char *errstr, ...); | 44 | void cleanup(void); |
| 45 | static char *estrdup(const char *str); | 45 | void drawmenu(void); |
| 46 | static void drawtext(const char *text, unsigned long col[ColLast]); | 46 | void drawtext(const char *text, unsigned long col[ColLast]); |
| 47 | static unsigned int textw(const char *text); | 47 | void *emalloc(unsigned int size); |
| 48 | static unsigned int textnw(const char *text, unsigned int len); | 48 | void eprint(const char *errstr, ...); |
| 49 | static void calcoffsets(void); | 49 | char *estrdup(const char *str); |
| 50 | static void drawmenu(void); | 50 | unsigned long getcolor(const char *colstr); |
| 51 | static Bool grabkeyboard(void); | 51 | Bool grabkeyboard(void); |
| 52 | static unsigned long getcolor(const char *colstr); | 52 | void initfont(const char *fontstr); |
| 53 | static void initfont(const char *fontstr); | 53 | void kpress(XKeyEvent * e); |
| 54 | static int strido(const char *text, const char *pattern); | 54 | void match(char *pattern); |
| 55 | static void match(char *pattern); | 55 | void readstdin(void); |
| 56 | static void kpress(XKeyEvent * e); | 56 | void run(void); |
| 57 | static char *readstdin(void); | 57 | void setup(Bool bottom); |
| 58 | static void usage(void); | 58 | int strido(const char *text, const char *pattern); |
| 59 | 59 | unsigned int textnw(const char *text, unsigned int len); | |
| 60 | 60 | unsigned int textw(const char *text); | |
| 61 | /* variables */ | ||
| 62 | static int screen; | ||
| 63 | static Display *dpy; | ||
| 64 | static DC dc = {0}; | ||
| 65 | static char text[4096]; | ||
| 66 | static char *prompt = NULL; | ||
| 67 | static int mw, mh; | ||
| 68 | static int ret = 0; | ||
| 69 | static int nitem = 0; | ||
| 70 | static unsigned int cmdw = 0; | ||
| 71 | static unsigned int promptw = 0; | ||
| 72 | static unsigned int numlockmask = 0; | ||
| 73 | static Bool running = True; | ||
| 74 | static Item *allitems = NULL; /* first of all items */ | ||
| 75 | static Item *item = NULL; /* first of pattern matching items */ | ||
| 76 | static Item *sel = NULL; | ||
| 77 | static Item *next = NULL; | ||
| 78 | static Item *prev = NULL; | ||
| 79 | static Item *curr = NULL; | ||
| 80 | static Window root; | ||
| 81 | static Window win; | ||
| 82 | 61 | ||
| 83 | #include "config.h" | 62 | #include "config.h" |
| 84 | 63 | ||
| 85 | static void * | 64 | /* variables */ |
| 86 | emalloc(unsigned int size) { | 65 | char *font = FONT; |
| 87 | void *res = malloc(size); | 66 | char *maxname = NULL; |
| 88 | 67 | char *normbg = NORMBGCOLOR; | |
| 89 | if(!res) | 68 | char *normfg = NORMFGCOLOR; |
| 90 | eprint("fatal: could not malloc() %u bytes\n", size); | 69 | char *prompt = NULL; |
| 91 | return res; | 70 | char *selbg = SELBGCOLOR; |
| 92 | } | 71 | char *selfg = SELFGCOLOR; |
| 93 | 72 | char text[4096]; | |
| 94 | static void | 73 | int screen; |
| 95 | eprint(const char *errstr, ...) { | 74 | int ret = 0; |
| 96 | va_list ap; | 75 | unsigned int cmdw = 0; |
| 97 | 76 | unsigned int mw, mh; | |
| 98 | va_start(ap, errstr); | 77 | unsigned int promptw = 0; |
| 99 | vfprintf(stderr, errstr, ap); | 78 | unsigned int nitem = 0; |
| 100 | va_end(ap); | 79 | unsigned int numlockmask = 0; |
| 101 | exit(EXIT_FAILURE); | 80 | Bool running = True; |
| 102 | } | 81 | Display *dpy; |
| 103 | 82 | DC dc = {0}; | |
| 104 | static char * | 83 | Item *allitems = NULL; /* first of all items */ |
| 105 | estrdup(const char *str) { | 84 | Item *item = NULL; /* first of pattern matching items */ |
| 106 | void *res = strdup(str); | 85 | Item *sel = NULL; |
| 107 | 86 | Item *next = NULL; | |
| 108 | if(!res) | 87 | Item *prev = NULL; |
| 109 | eprint("fatal: could not malloc() %u bytes\n", strlen(str)); | 88 | Item *curr = NULL; |
| 110 | return res; | 89 | Window root, win; |
| 111 | } | 90 | |
| 112 | 91 | void | |
| 113 | |||
| 114 | static void | ||
| 115 | drawtext(const char *text, unsigned long col[ColLast]) { | ||
| 116 | int x, y, w, h; | ||
| 117 | static char buf[256]; | ||
| 118 | unsigned int len, olen; | ||
| 119 | XRectangle r = { dc.x, dc.y, dc.w, dc.h }; | ||
| 120 | |||
| 121 | XSetForeground(dpy, dc.gc, col[ColBG]); | ||
| 122 | XFillRectangles(dpy, dc.drawable, dc.gc, &r, 1); | ||
| 123 | if(!text) | ||
| 124 | return; | ||
| 125 | w = 0; | ||
| 126 | olen = len = strlen(text); | ||
| 127 | if(len >= sizeof buf) | ||
| 128 | len = sizeof buf - 1; | ||
| 129 | memcpy(buf, text, len); | ||
| 130 | buf[len] = 0; | ||
| 131 | h = dc.font.ascent + dc.font.descent; | ||
| 132 | y = dc.y + (dc.h / 2) - (h / 2) + dc.font.ascent; | ||
| 133 | x = dc.x + (h / 2); | ||
| 134 | /* shorten text if necessary */ | ||
| 135 | while(len && (w = textnw(buf, len)) > dc.w - h) | ||
| 136 | buf[--len] = 0; | ||
| 137 | if(len < olen) { | ||
| 138 | if(len > 1) | ||
| 139 | buf[len - 1] = '.'; | ||
| 140 | if(len > 2) | ||
| 141 | buf[len - 2] = '.'; | ||
| 142 | if(len > 3) | ||
| 143 | buf[len - 3] = '.'; | ||
| 144 | } | ||
| 145 | if(w > dc.w) | ||
| 146 | return; /* too long */ | ||
| 147 | XSetForeground(dpy, dc.gc, col[ColFG]); | ||
| 148 | if(dc.font.set) | ||
| 149 | XmbDrawString(dpy, dc.drawable, dc.font.set, dc.gc, x, y, buf, len); | ||
| 150 | else | ||
| 151 | XDrawString(dpy, dc.drawable, dc.gc, x, y, buf, len); | ||
| 152 | } | ||
| 153 | |||
| 154 | static unsigned int | ||
| 155 | textw(const char *text) { | ||
| 156 | return textnw(text, strlen(text)) + dc.font.height; | ||
| 157 | } | ||
| 158 | |||
| 159 | static unsigned int | ||
| 160 | textnw(const char *text, unsigned int len) { | ||
| 161 | XRectangle r; | ||
| 162 | |||
| 163 | if(dc.font.set) { | ||
| 164 | XmbTextExtents(dc.font.set, text, len, NULL, &r); | ||
| 165 | return r.width; | ||
| 166 | } | ||
| 167 | return XTextWidth(dc.font.xfont, text, len); | ||
| 168 | } | ||
| 169 | |||
| 170 | static void | ||
| 171 | calcoffsets(void) { | 92 | calcoffsets(void) { |
| 172 | unsigned int tw, w; | 93 | unsigned int tw, w; |
| 173 | 94 | ||
| @@ -193,7 +114,27 @@ calcoffsets(void) { | |||
| 193 | } | 114 | } |
| 194 | } | 115 | } |
| 195 | 116 | ||
| 196 | static void | 117 | void |
| 118 | cleanup(void) { | ||
| 119 | Item *itm; | ||
| 120 | |||
| 121 | while(allitems) { | ||
| 122 | itm = allitems->next; | ||
| 123 | free(allitems->text); | ||
| 124 | free(allitems); | ||
| 125 | allitems = itm; | ||
| 126 | } | ||
| 127 | if(dc.font.set) | ||
| 128 | XFreeFontSet(dpy, dc.font.set); | ||
| 129 | else | ||
| 130 | XFreeFont(dpy, dc.font.xfont); | ||
| 131 | XFreePixmap(dpy, dc.drawable); | ||
| 132 | XFreeGC(dpy, dc.gc); | ||
| 133 | XDestroyWindow(dpy, win); | ||
| 134 | XUngrabKeyboard(dpy, CurrentTime); | ||
| 135 | } | ||
| 136 | |||
| 137 | void | ||
| 197 | drawmenu(void) { | 138 | drawmenu(void) { |
| 198 | Item *i; | 139 | Item *i; |
| 199 | 140 | ||
| @@ -234,20 +175,75 @@ drawmenu(void) { | |||
| 234 | XFlush(dpy); | 175 | XFlush(dpy); |
| 235 | } | 176 | } |
| 236 | 177 | ||
| 237 | static Bool | 178 | void |
| 238 | grabkeyboard(void) { | 179 | drawtext(const char *text, unsigned long col[ColLast]) { |
| 239 | unsigned int len; | 180 | int x, y, w, h; |
| 181 | static char buf[256]; | ||
| 182 | unsigned int len, olen; | ||
| 183 | XRectangle r = { dc.x, dc.y, dc.w, dc.h }; | ||
| 240 | 184 | ||
| 241 | for(len = 1000; len; len--) { | 185 | XSetForeground(dpy, dc.gc, col[ColBG]); |
| 242 | if(XGrabKeyboard(dpy, root, True, GrabModeAsync, GrabModeAsync, CurrentTime) | 186 | XFillRectangles(dpy, dc.drawable, dc.gc, &r, 1); |
| 243 | == GrabSuccess) | 187 | if(!text) |
| 244 | break; | 188 | return; |
| 245 | usleep(1000); | 189 | w = 0; |
| 190 | olen = len = strlen(text); | ||
| 191 | if(len >= sizeof buf) | ||
| 192 | len = sizeof buf - 1; | ||
| 193 | memcpy(buf, text, len); | ||
| 194 | buf[len] = 0; | ||
| 195 | h = dc.font.ascent + dc.font.descent; | ||
| 196 | y = dc.y + (dc.h / 2) - (h / 2) + dc.font.ascent; | ||
| 197 | x = dc.x + (h / 2); | ||
| 198 | /* shorten text if necessary */ | ||
| 199 | while(len && (w = textnw(buf, len)) > dc.w - h) | ||
| 200 | buf[--len] = 0; | ||
| 201 | if(len < olen) { | ||
| 202 | if(len > 1) | ||
| 203 | buf[len - 1] = '.'; | ||
| 204 | if(len > 2) | ||
| 205 | buf[len - 2] = '.'; | ||
| 206 | if(len > 3) | ||
| 207 | buf[len - 3] = '.'; | ||
| 246 | } | 208 | } |
| 247 | return len > 0; | 209 | if(w > dc.w) |
| 210 | return; /* too long */ | ||
| 211 | XSetForeground(dpy, dc.gc, col[ColFG]); | ||
| 212 | if(dc.font.set) | ||
| 213 | XmbDrawString(dpy, dc.drawable, dc.font.set, dc.gc, x, y, buf, len); | ||
| 214 | else | ||
| 215 | XDrawString(dpy, dc.drawable, dc.gc, x, y, buf, len); | ||
| 216 | } | ||
| 217 | |||
| 218 | void * | ||
| 219 | emalloc(unsigned int size) { | ||
| 220 | void *res = malloc(size); | ||
| 221 | |||
| 222 | if(!res) | ||
| 223 | eprint("fatal: could not malloc() %u bytes\n", size); | ||
| 224 | return res; | ||
| 225 | } | ||
| 226 | |||
| 227 | void | ||
| 228 | eprint(const char *errstr, ...) { | ||
| 229 | va_list ap; | ||
| 230 | |||
| 231 | va_start(ap, errstr); | ||
| 232 | vfprintf(stderr, errstr, ap); | ||
| 233 | va_end(ap); | ||
| 234 | exit(EXIT_FAILURE); | ||
| 235 | } | ||
| 236 | |||
| 237 | char * | ||
| 238 | estrdup(const char *str) { | ||
| 239 | void *res = strdup(str); | ||
| 240 | |||
| 241 | if(!res) | ||
| 242 | eprint("fatal: could not malloc() %u bytes\n", strlen(str)); | ||
| 243 | return res; | ||
| 248 | } | 244 | } |
| 249 | 245 | ||
| 250 | static unsigned long | 246 | unsigned long |
| 251 | getcolor(const char *colstr) { | 247 | getcolor(const char *colstr) { |
| 252 | Colormap cmap = DefaultColormap(dpy, screen); | 248 | Colormap cmap = DefaultColormap(dpy, screen); |
| 253 | XColor color; | 249 | XColor color; |
| @@ -257,7 +253,20 @@ getcolor(const char *colstr) { | |||
| 257 | return color.pixel; | 253 | return color.pixel; |
| 258 | } | 254 | } |
| 259 | 255 | ||
| 260 | static void | 256 | Bool |
| 257 | grabkeyboard(void) { | ||
| 258 | unsigned int len; | ||
| 259 | |||
| 260 | for(len = 1000; len; len--) { | ||
| 261 | if(XGrabKeyboard(dpy, root, True, GrabModeAsync, GrabModeAsync, CurrentTime) | ||
| 262 | == GrabSuccess) | ||
| 263 | break; | ||
| 264 | usleep(1000); | ||
| 265 | } | ||
| 266 | return len > 0; | ||
| 267 | } | ||
| 268 | |||
| 269 | void | ||
| 261 | initfont(const char *fontstr) { | 270 | initfont(const char *fontstr) { |
| 262 | char *def, **missing; | 271 | char *def, **missing; |
| 263 | int i, n; | 272 | int i, n; |
| @@ -299,65 +308,7 @@ initfont(const char *fontstr) { | |||
| 299 | dc.font.height = dc.font.ascent + dc.font.descent; | 308 | dc.font.height = dc.font.ascent + dc.font.descent; |
| 300 | } | 309 | } |
| 301 | 310 | ||
| 302 | static int | 311 | void |
| 303 | strido(const char *text, const char *pattern) { | ||
| 304 | for(; *text && *pattern; text++) | ||
| 305 | if (*text == *pattern) | ||
| 306 | pattern++; | ||
| 307 | return !*pattern; | ||
| 308 | } | ||
| 309 | |||
| 310 | static void | ||
| 311 | match(char *pattern) { | ||
| 312 | unsigned int plen; | ||
| 313 | Item *i, *j; | ||
| 314 | |||
| 315 | if(!pattern) | ||
| 316 | return; | ||
| 317 | plen = strlen(pattern); | ||
| 318 | item = j = NULL; | ||
| 319 | nitem = 0; | ||
| 320 | for(i = allitems; i; i=i->next) | ||
| 321 | if(!plen || !strncmp(pattern, i->text, plen)) { | ||
| 322 | if(!j) | ||
| 323 | item = i; | ||
| 324 | else | ||
| 325 | j->right = i; | ||
| 326 | i->left = j; | ||
| 327 | i->right = NULL; | ||
| 328 | j = i; | ||
| 329 | nitem++; | ||
| 330 | } | ||
| 331 | for(i = allitems; i; i=i->next) | ||
| 332 | if(plen && strncmp(pattern, i->text, plen) | ||
| 333 | && strstr(i->text, pattern)) { | ||
| 334 | if(!j) | ||
| 335 | item = i; | ||
| 336 | else | ||
| 337 | j->right = i; | ||
| 338 | i->left = j; | ||
| 339 | i->right = NULL; | ||
| 340 | j = i; | ||
| 341 | nitem++; | ||
| 342 | } | ||
| 343 | for(i = allitems; i; i=i->next) | ||
| 344 | if(plen && strncmp(pattern, i->text, plen) | ||
| 345 | && !strstr(i->text, pattern) | ||
| 346 | && strido(i->text,pattern)) { | ||
| 347 | if(!j) | ||
| 348 | item = i; | ||
| 349 | else | ||
| 350 | j->right = i; | ||
| 351 | i->left = j; | ||
| 352 | i->right = NULL; | ||
| 353 | j = i; | ||
| 354 | nitem++; | ||
| 355 | } | ||
| 356 | curr = prev = next = sel = item; | ||
| 357 | calcoffsets(); | ||
| 358 | } | ||
| 359 | |||
| 360 | static void | ||
| 361 | kpress(XKeyEvent * e) { | 312 | kpress(XKeyEvent * e) { |
| 362 | char buf[32]; | 313 | char buf[32]; |
| 363 | int i, num; | 314 | int i, num; |
| @@ -528,9 +479,58 @@ kpress(XKeyEvent * e) { | |||
| 528 | drawmenu(); | 479 | drawmenu(); |
| 529 | } | 480 | } |
| 530 | 481 | ||
| 531 | static char * | 482 | void |
| 483 | match(char *pattern) { | ||
| 484 | unsigned int plen; | ||
| 485 | Item *i, *j; | ||
| 486 | |||
| 487 | if(!pattern) | ||
| 488 | return; | ||
| 489 | plen = strlen(pattern); | ||
| 490 | item = j = NULL; | ||
| 491 | nitem = 0; | ||
| 492 | for(i = allitems; i; i=i->next) | ||
| 493 | if(!plen || !strncmp(pattern, i->text, plen)) { | ||
| 494 | if(!j) | ||
| 495 | item = i; | ||
| 496 | else | ||
| 497 | j->right = i; | ||
| 498 | i->left = j; | ||
| 499 | i->right = NULL; | ||
| 500 | j = i; | ||
| 501 | nitem++; | ||
| 502 | } | ||
| 503 | for(i = allitems; i; i=i->next) | ||
| 504 | if(plen && strncmp(pattern, i->text, plen) | ||
| 505 | && strstr(i->text, pattern)) { | ||
| 506 | if(!j) | ||
| 507 | item = i; | ||
| 508 | else | ||
| 509 | j->right = i; | ||
| 510 | i->left = j; | ||
| 511 | i->right = NULL; | ||
| 512 | j = i; | ||
| 513 | nitem++; | ||
| 514 | } | ||
| 515 | for(i = allitems; i; i=i->next) | ||
| 516 | if(plen && strncmp(pattern, i->text, plen) | ||
| 517 | && !strstr(i->text, pattern) | ||
| 518 | && strido(i->text,pattern)) { | ||
| 519 | if(!j) | ||
| 520 | item = i; | ||
| 521 | else | ||
| 522 | j->right = i; | ||
| 523 | i->left = j; | ||
| 524 | i->right = NULL; | ||
| 525 | j = i; | ||
| 526 | nitem++; | ||
| 527 | } | ||
| 528 | curr = prev = next = sel = item; | ||
| 529 | calcoffsets(); | ||
| 530 | } | ||
| 531 | |||
| 532 | void | ||
| 532 | readstdin(void) { | 533 | readstdin(void) { |
| 533 | static char *maxname = NULL; | ||
| 534 | char *p, buf[1024]; | 534 | char *p, buf[1024]; |
| 535 | unsigned int len = 0, max = 0; | 535 | unsigned int len = 0, max = 0; |
| 536 | Item *i, *new; | 536 | Item *i, *new; |
| @@ -554,88 +554,50 @@ readstdin(void) { | |||
| 554 | i->next = new; | 554 | i->next = new; |
| 555 | i = new; | 555 | i = new; |
| 556 | } | 556 | } |
| 557 | |||
| 558 | return maxname; | ||
| 559 | } | 557 | } |
| 560 | 558 | ||
| 561 | static void | 559 | void |
| 562 | usage(void) { | 560 | run(void) { |
| 563 | eprint("usage: dmenu [-b] [-fn <font>] [-nb <color>] [-nf <color>]\n" | 561 | XEvent ev; |
| 564 | " [-p <prompt>] [-sb <color>] [-sf <color>] [-v]\n"); | 562 | |
| 563 | /* main event loop */ | ||
| 564 | while(running && !XNextEvent(dpy, &ev)) | ||
| 565 | switch (ev.type) { | ||
| 566 | default: /* ignore all crap */ | ||
| 567 | break; | ||
| 568 | case KeyPress: | ||
| 569 | kpress(&ev.xkey); | ||
| 570 | break; | ||
| 571 | case Expose: | ||
| 572 | if(ev.xexpose.count == 0) | ||
| 573 | drawmenu(); | ||
| 574 | break; | ||
| 575 | } | ||
| 565 | } | 576 | } |
| 566 | 577 | ||
| 567 | int | 578 | void |
| 568 | main(int argc, char *argv[]) { | 579 | setup(Bool bottom) { |
| 569 | Bool bottom = False; | 580 | unsigned int i, j; |
| 570 | char *font = FONT; | ||
| 571 | char *maxname; | ||
| 572 | char *normbg = NORMBGCOLOR; | ||
| 573 | char *normfg = NORMFGCOLOR; | ||
| 574 | char *selbg = SELBGCOLOR; | ||
| 575 | char *selfg = SELFGCOLOR; | ||
| 576 | int i, j; | ||
| 577 | Item *itm; | ||
| 578 | XEvent ev; | ||
| 579 | XModifierKeymap *modmap; | 581 | XModifierKeymap *modmap; |
| 580 | XSetWindowAttributes wa; | 582 | XSetWindowAttributes wa; |
| 581 | 583 | ||
| 582 | /* command line args */ | ||
| 583 | for(i = 1; i < argc; i++) | ||
| 584 | if(!strcmp(argv[i], "-b")) { | ||
| 585 | bottom = True; | ||
| 586 | } | ||
| 587 | else if(!strcmp(argv[i], "-fn")) { | ||
| 588 | if(++i < argc) font = argv[i]; | ||
| 589 | } | ||
| 590 | else if(!strcmp(argv[i], "-nb")) { | ||
| 591 | if(++i < argc) normbg = argv[i]; | ||
| 592 | } | ||
| 593 | else if(!strcmp(argv[i], "-nf")) { | ||
| 594 | if(++i < argc) normfg = argv[i]; | ||
| 595 | } | ||
| 596 | else if(!strcmp(argv[i], "-p")) { | ||
| 597 | if(++i < argc) prompt = argv[i]; | ||
| 598 | } | ||
| 599 | else if(!strcmp(argv[i], "-sb")) { | ||
| 600 | if(++i < argc) selbg = argv[i]; | ||
| 601 | } | ||
| 602 | else if(!strcmp(argv[i], "-sf")) { | ||
| 603 | if(++i < argc) selfg = argv[i]; | ||
| 604 | } | ||
| 605 | else if(!strcmp(argv[i], "-v")) | ||
| 606 | eprint("dmenu-"VERSION", © 2006-2007 Anselm R. Garbe, Sander van Dijk\n"); | ||
| 607 | else | ||
| 608 | usage(); | ||
| 609 | setlocale(LC_CTYPE, ""); | ||
| 610 | dpy = XOpenDisplay(0); | ||
| 611 | if(!dpy) | ||
| 612 | eprint("dmenu: cannot open display\n"); | ||
| 613 | screen = DefaultScreen(dpy); | ||
| 614 | root = RootWindow(dpy, screen); | ||
| 615 | if(isatty(STDIN_FILENO)) { | ||
| 616 | maxname = readstdin(); | ||
| 617 | running = grabkeyboard(); | ||
| 618 | } | ||
| 619 | else { /* prevent keypress loss */ | ||
| 620 | running = grabkeyboard(); | ||
| 621 | maxname = readstdin(); | ||
| 622 | } | ||
| 623 | /* init modifier map */ | 584 | /* init modifier map */ |
| 624 | modmap = XGetModifierMapping(dpy); | 585 | modmap = XGetModifierMapping(dpy); |
| 625 | for (i = 0; i < 8; i++) { | 586 | for(i = 0; i < 8; i++) |
| 626 | for (j = 0; j < modmap->max_keypermod; j++) { | 587 | for(j = 0; j < modmap->max_keypermod; j++) { |
| 627 | if(modmap->modifiermap[i * modmap->max_keypermod + j] | 588 | if(modmap->modifiermap[i * modmap->max_keypermod + j] |
| 628 | == XKeysymToKeycode(dpy, XK_Num_Lock)) | 589 | == XKeysymToKeycode(dpy, XK_Num_Lock)) |
| 629 | numlockmask = (1 << i); | 590 | numlockmask = (1 << i); |
| 630 | } | 591 | } |
| 631 | } | ||
| 632 | XFreeModifiermap(modmap); | 592 | XFreeModifiermap(modmap); |
| 593 | |||
| 633 | /* style */ | 594 | /* style */ |
| 634 | dc.norm[ColBG] = getcolor(normbg); | 595 | dc.norm[ColBG] = getcolor(normbg); |
| 635 | dc.norm[ColFG] = getcolor(normfg); | 596 | dc.norm[ColFG] = getcolor(normfg); |
| 636 | dc.sel[ColBG] = getcolor(selbg); | 597 | dc.sel[ColBG] = getcolor(selbg); |
| 637 | dc.sel[ColFG] = getcolor(selfg); | 598 | dc.sel[ColFG] = getcolor(selfg); |
| 638 | initfont(font); | 599 | initfont(font); |
| 600 | |||
| 639 | /* menu window */ | 601 | /* menu window */ |
| 640 | wa.override_redirect = 1; | 602 | wa.override_redirect = 1; |
| 641 | wa.background_pixmap = ParentRelative; | 603 | wa.background_pixmap = ParentRelative; |
| @@ -647,6 +609,7 @@ main(int argc, char *argv[]) { | |||
| 647 | DefaultDepth(dpy, screen), CopyFromParent, | 609 | DefaultDepth(dpy, screen), CopyFromParent, |
| 648 | DefaultVisual(dpy, screen), | 610 | DefaultVisual(dpy, screen), |
| 649 | CWOverrideRedirect | CWBackPixmap | CWEventMask, &wa); | 611 | CWOverrideRedirect | CWBackPixmap | CWEventMask, &wa); |
| 612 | |||
| 650 | /* pixmap */ | 613 | /* pixmap */ |
| 651 | dc.drawable = XCreatePixmap(dpy, root, mw, mh, DefaultDepth(dpy, screen)); | 614 | dc.drawable = XCreatePixmap(dpy, root, mw, mh, DefaultDepth(dpy, screen)); |
| 652 | dc.gc = XCreateGC(dpy, root, 0, 0); | 615 | dc.gc = XCreateGC(dpy, root, 0, 0); |
| @@ -664,38 +627,86 @@ main(int argc, char *argv[]) { | |||
| 664 | text[0] = 0; | 627 | text[0] = 0; |
| 665 | match(text); | 628 | match(text); |
| 666 | XMapRaised(dpy, win); | 629 | XMapRaised(dpy, win); |
| 667 | drawmenu(); | 630 | } |
| 668 | XSync(dpy, False); | ||
| 669 | 631 | ||
| 670 | /* main event loop */ | 632 | int |
| 671 | while(running && !XNextEvent(dpy, &ev)) | 633 | strido(const char *text, const char *pattern) { |
| 672 | switch (ev.type) { | 634 | for(; *text && *pattern; text++) |
| 673 | default: /* ignore all crap */ | 635 | if (*text == *pattern) |
| 674 | break; | 636 | pattern++; |
| 675 | case KeyPress: | 637 | return !*pattern; |
| 676 | kpress(&ev.xkey); | 638 | } |
| 677 | break; | 639 | |
| 678 | case Expose: | 640 | unsigned int |
| 679 | if(ev.xexpose.count == 0) | 641 | textnw(const char *text, unsigned int len) { |
| 680 | drawmenu(); | 642 | XRectangle r; |
| 681 | break; | 643 | |
| 644 | if(dc.font.set) { | ||
| 645 | XmbTextExtents(dc.font.set, text, len, NULL, &r); | ||
| 646 | return r.width; | ||
| 647 | } | ||
| 648 | return XTextWidth(dc.font.xfont, text, len); | ||
| 649 | } | ||
| 650 | |||
| 651 | unsigned int | ||
| 652 | textw(const char *text) { | ||
| 653 | return textnw(text, strlen(text)) + dc.font.height; | ||
| 654 | } | ||
| 655 | |||
| 656 | int | ||
| 657 | main(int argc, char *argv[]) { | ||
| 658 | Bool bottom = False; | ||
| 659 | unsigned int i; | ||
| 660 | |||
| 661 | /* command line args */ | ||
| 662 | for(i = 1; i < argc; i++) | ||
| 663 | if(!strcmp(argv[i], "-b")) { | ||
| 664 | bottom = True; | ||
| 665 | } | ||
| 666 | else if(!strcmp(argv[i], "-fn")) { | ||
| 667 | if(++i < argc) font = argv[i]; | ||
| 668 | } | ||
| 669 | else if(!strcmp(argv[i], "-nb")) { | ||
| 670 | if(++i < argc) normbg = argv[i]; | ||
| 671 | } | ||
| 672 | else if(!strcmp(argv[i], "-nf")) { | ||
| 673 | if(++i < argc) normfg = argv[i]; | ||
| 674 | } | ||
| 675 | else if(!strcmp(argv[i], "-p")) { | ||
| 676 | if(++i < argc) prompt = argv[i]; | ||
| 677 | } | ||
| 678 | else if(!strcmp(argv[i], "-sb")) { | ||
| 679 | if(++i < argc) selbg = argv[i]; | ||
| 680 | } | ||
| 681 | else if(!strcmp(argv[i], "-sf")) { | ||
| 682 | if(++i < argc) selfg = argv[i]; | ||
| 682 | } | 683 | } |
| 684 | else if(!strcmp(argv[i], "-v")) | ||
| 685 | eprint("dmenu-"VERSION", © 2006-2007 Anselm R. Garbe, Sander van Dijk\n"); | ||
| 686 | else | ||
| 687 | eprint("usage: dmenu [-b] [-fn <font>] [-nb <color>] [-nf <color>]\n" | ||
| 688 | " [-p <prompt>] [-sb <color>] [-sf <color>] [-v]\n"); | ||
| 689 | setlocale(LC_CTYPE, ""); | ||
| 690 | dpy = XOpenDisplay(0); | ||
| 691 | if(!dpy) | ||
| 692 | eprint("dmenu: cannot open display\n"); | ||
| 693 | screen = DefaultScreen(dpy); | ||
| 694 | root = RootWindow(dpy, screen); | ||
| 683 | 695 | ||
| 684 | /* cleanup */ | 696 | if(isatty(STDIN_FILENO)) { |
| 685 | while(allitems) { | 697 | readstdin(); |
| 686 | itm = allitems->next; | 698 | running = grabkeyboard(); |
| 687 | free(allitems->text); | ||
| 688 | free(allitems); | ||
| 689 | allitems = itm; | ||
| 690 | } | 699 | } |
| 691 | if(dc.font.set) | 700 | else { /* prevent keypress loss */ |
| 692 | XFreeFontSet(dpy, dc.font.set); | 701 | running = grabkeyboard(); |
| 693 | else | 702 | readstdin(); |
| 694 | XFreeFont(dpy, dc.font.xfont); | 703 | } |
| 695 | XFreePixmap(dpy, dc.drawable); | 704 | |
| 696 | XFreeGC(dpy, dc.gc); | 705 | setup(bottom); |
| 697 | XDestroyWindow(dpy, win); | 706 | drawmenu(); |
| 698 | XUngrabKeyboard(dpy, CurrentTime); | 707 | XSync(dpy, False); |
| 708 | run(); | ||
| 709 | cleanup(); | ||
| 699 | XCloseDisplay(dpy); | 710 | XCloseDisplay(dpy); |
| 700 | return ret; | 711 | return ret; |
| 701 | } | 712 | } |
