diff options
-rw-r--r-- | dmenu.1 | 5 | ||||
-rw-r--r-- | dmenu.c | 65 |
2 files changed, 58 insertions, 12 deletions
@@ -20,6 +20,8 @@ dmenu \- dynamic menu | |||
20 | .IR color ] | 20 | .IR color ] |
21 | .RB [ \-sf | 21 | .RB [ \-sf |
22 | .IR color ] | 22 | .IR color ] |
23 | .RB [ \-w | ||
24 | .IR windowid ] | ||
23 | .P | 25 | .P |
24 | .BR dmenu_run " ..." | 26 | .BR dmenu_run " ..." |
25 | .SH DESCRIPTION | 27 | .SH DESCRIPTION |
@@ -75,6 +77,9 @@ defines the selected foreground color. | |||
75 | .TP | 77 | .TP |
76 | .B \-v | 78 | .B \-v |
77 | prints version information to stdout, then exits. | 79 | prints version information to stdout, then exits. |
80 | .TP | ||
81 | .BI \-w " windowid" | ||
82 | embed into windowid. | ||
78 | .SH USAGE | 83 | .SH USAGE |
79 | dmenu is completely controlled by the keyboard. Items are selected using the | 84 | dmenu is completely controlled by the keyboard. Items are selected using the |
80 | arrow keys, page up, page down, home, and end. | 85 | arrow keys, page up, page down, home, and end. |
@@ -34,8 +34,8 @@ struct item { | |||
34 | }; | 34 | }; |
35 | 35 | ||
36 | static char text[BUFSIZ] = ""; | 36 | static char text[BUFSIZ] = ""; |
37 | static char *embed; | ||
37 | static int bh, mw, mh; | 38 | static int bh, mw, mh; |
38 | static int sw, sh; /* X display screen geometry width, height */ | ||
39 | static int inputw = 0, promptw; | 39 | static int inputw = 0, promptw; |
40 | static int lrpad; /* sum of left and right padding */ | 40 | static int lrpad; /* sum of left and right padding */ |
41 | static size_t cursor; | 41 | static size_t cursor; |
@@ -46,7 +46,7 @@ static int mon = -1, screen; | |||
46 | 46 | ||
47 | static Atom clip, utf8; | 47 | static Atom clip, utf8; |
48 | static Display *dpy; | 48 | static Display *dpy; |
49 | static Window root, win; | 49 | static Window root, parentwin, win; |
50 | static XIC xic; | 50 | static XIC xic; |
51 | 51 | ||
52 | static Drw *drw; | 52 | static Drw *drw; |
@@ -175,11 +175,30 @@ drawmenu(void) | |||
175 | } | 175 | } |
176 | 176 | ||
177 | static void | 177 | static void |
178 | grabfocus(void) | ||
179 | { | ||
180 | struct timespec ts = { .tv_sec = 0, .tv_nsec = 10000000 }; | ||
181 | Window focuswin; | ||
182 | int i, revertwin; | ||
183 | |||
184 | for (i = 0; i < 100; ++i) { | ||
185 | XGetInputFocus(dpy, &focuswin, &revertwin); | ||
186 | if (focuswin == win) | ||
187 | return; | ||
188 | XSetInputFocus(dpy, win, RevertToParent, CurrentTime); | ||
189 | nanosleep(&ts, NULL); | ||
190 | } | ||
191 | die("cannot grab focus"); | ||
192 | } | ||
193 | |||
194 | static void | ||
178 | grabkeyboard(void) | 195 | grabkeyboard(void) |
179 | { | 196 | { |
180 | struct timespec ts = { .tv_sec = 0, .tv_nsec = 1000000 }; | 197 | struct timespec ts = { .tv_sec = 0, .tv_nsec = 1000000 }; |
181 | int i; | 198 | int i; |
182 | 199 | ||
200 | if (embed) | ||
201 | return; | ||
183 | /* try to grab keyboard, we may have to wait for another process to ungrab */ | 202 | /* try to grab keyboard, we may have to wait for another process to ungrab */ |
184 | for (i = 0; i < 1000; i++) { | 203 | for (i = 0; i < 1000; i++) { |
185 | if (XGrabKeyboard(dpy, DefaultRootWindow(dpy), True, GrabModeAsync, | 204 | if (XGrabKeyboard(dpy, DefaultRootWindow(dpy), True, GrabModeAsync, |
@@ -497,6 +516,11 @@ run(void) | |||
497 | if (ev.xexpose.count == 0) | 516 | if (ev.xexpose.count == 0) |
498 | drw_map(drw, win, 0, 0, mw, mh); | 517 | drw_map(drw, win, 0, 0, mw, mh); |
499 | break; | 518 | break; |
519 | case FocusIn: | ||
520 | /* regrab focus from parent window */ | ||
521 | if (ev.xfocus.window != win) | ||
522 | grabfocus(); | ||
523 | break; | ||
500 | case KeyPress: | 524 | case KeyPress: |
501 | keypress(&ev.xkey); | 525 | keypress(&ev.xkey); |
502 | break; | 526 | break; |
@@ -539,7 +563,7 @@ setup(void) | |||
539 | lines = MAX(lines, 0); | 563 | lines = MAX(lines, 0); |
540 | mh = (lines + 1) * bh; | 564 | mh = (lines + 1) * bh; |
541 | #ifdef XINERAMA | 565 | #ifdef XINERAMA |
542 | if ((info = XineramaQueryScreens(dpy, &n))) { | 566 | if (parentwin == root && (info = XineramaQueryScreens(dpy, &n))) { |
543 | XGetInputFocus(dpy, &w, &di); | 567 | XGetInputFocus(dpy, &w, &di); |
544 | if (mon >= 0 && mon < n) | 568 | if (mon >= 0 && mon < n) |
545 | i = mon; | 569 | i = mon; |
@@ -570,9 +594,12 @@ setup(void) | |||
570 | } else | 594 | } else |
571 | #endif | 595 | #endif |
572 | { | 596 | { |
597 | if (!XGetWindowAttributes(dpy, parentwin, &wa)) | ||
598 | die("could not get embedding window attributes: 0x%lx", | ||
599 | parentwin); | ||
573 | x = 0; | 600 | x = 0; |
574 | y = topbar ? 0 : sh - mh; | 601 | y = topbar ? 0 : wa.height - mh; |
575 | mw = sw; | 602 | mw = wa.width; |
576 | } | 603 | } |
577 | promptw = (prompt && *prompt) ? TEXTW(prompt) - lrpad / 4 : 0; | 604 | promptw = (prompt && *prompt) ? TEXTW(prompt) - lrpad / 4 : 0; |
578 | inputw = MIN(inputw, mw/3); | 605 | inputw = MIN(inputw, mw/3); |
@@ -582,9 +609,8 @@ setup(void) | |||
582 | swa.override_redirect = True; | 609 | swa.override_redirect = True; |
583 | swa.background_pixel = scheme[SchemeNorm][ColBg].pixel; | 610 | swa.background_pixel = scheme[SchemeNorm][ColBg].pixel; |
584 | swa.event_mask = ExposureMask | KeyPressMask | VisibilityChangeMask; | 611 | swa.event_mask = ExposureMask | KeyPressMask | VisibilityChangeMask; |
585 | win = XCreateWindow(dpy, root, x, y, mw, mh, 0, | 612 | win = XCreateWindow(dpy, parentwin, x, y, mw, mh, 0, |
586 | DefaultDepth(dpy, screen), CopyFromParent, | 613 | CopyFromParent, CopyFromParent, CopyFromParent, |
587 | DefaultVisual(dpy, screen), | ||
588 | CWOverrideRedirect | CWBackPixel | CWEventMask, &swa); | 614 | CWOverrideRedirect | CWBackPixel | CWEventMask, &swa); |
589 | 615 | ||
590 | /* open input methods */ | 616 | /* open input methods */ |
@@ -593,6 +619,15 @@ setup(void) | |||
593 | XNClientWindow, win, XNFocusWindow, win, NULL); | 619 | XNClientWindow, win, XNFocusWindow, win, NULL); |
594 | 620 | ||
595 | XMapRaised(dpy, win); | 621 | XMapRaised(dpy, win); |
622 | if (embed) { | ||
623 | XSelectInput(dpy, parentwin, FocusChangeMask); | ||
624 | if (XQueryTree(dpy, parentwin, &dw, &w, &dws, &du) && dws) { | ||
625 | for (i = 0; i < du && dws[i] != win; ++i) | ||
626 | XSelectInput(dpy, dws[i], FocusChangeMask); | ||
627 | XFree(dws); | ||
628 | } | ||
629 | grabfocus(); | ||
630 | } | ||
596 | drw_resize(drw, mw, mh); | 631 | drw_resize(drw, mw, mh); |
597 | drawmenu(); | 632 | drawmenu(); |
598 | } | 633 | } |
@@ -601,13 +636,14 @@ static void | |||
601 | usage(void) | 636 | usage(void) |
602 | { | 637 | { |
603 | fputs("usage: dmenu [-bfiv] [-l lines] [-p prompt] [-fn font] [-m monitor]\n" | 638 | fputs("usage: dmenu [-bfiv] [-l lines] [-p prompt] [-fn font] [-m monitor]\n" |
604 | " [-nb color] [-nf color] [-sb color] [-sf color]\n", stderr); | 639 | " [-nb color] [-nf color] [-sb color] [-sf color] [-w windowid]\n", stderr); |
605 | exit(1); | 640 | exit(1); |
606 | } | 641 | } |
607 | 642 | ||
608 | int | 643 | int |
609 | main(int argc, char *argv[]) | 644 | main(int argc, char *argv[]) |
610 | { | 645 | { |
646 | XWindowAttributes wa; | ||
611 | int i, fast = 0; | 647 | int i, fast = 0; |
612 | 648 | ||
613 | for (i = 1; i < argc; i++) | 649 | for (i = 1; i < argc; i++) |
@@ -641,6 +677,8 @@ main(int argc, char *argv[]) | |||
641 | colors[SchemeSel][ColBg] = argv[++i]; | 677 | colors[SchemeSel][ColBg] = argv[++i]; |
642 | else if (!strcmp(argv[i], "-sf")) /* selected foreground color */ | 678 | else if (!strcmp(argv[i], "-sf")) /* selected foreground color */ |
643 | colors[SchemeSel][ColFg] = argv[++i]; | 679 | colors[SchemeSel][ColFg] = argv[++i]; |
680 | else if (!strcmp(argv[i], "-w")) /* embedding window id */ | ||
681 | embed = argv[++i]; | ||
644 | else | 682 | else |
645 | usage(); | 683 | usage(); |
646 | 684 | ||
@@ -650,9 +688,12 @@ main(int argc, char *argv[]) | |||
650 | die("cannot open display"); | 688 | die("cannot open display"); |
651 | screen = DefaultScreen(dpy); | 689 | screen = DefaultScreen(dpy); |
652 | root = RootWindow(dpy, screen); | 690 | root = RootWindow(dpy, screen); |
653 | sw = DisplayWidth(dpy, screen); | 691 | if (!embed || !(parentwin = strtol(embed, NULL, 0))) |
654 | sh = DisplayHeight(dpy, screen); | 692 | parentwin = root; |
655 | drw = drw_create(dpy, screen, root, sw, sh); | 693 | if (!XGetWindowAttributes(dpy, parentwin, &wa)) |
694 | die("could not get embedding window attributes: 0x%lx", | ||
695 | parentwin); | ||
696 | drw = drw_create(dpy, screen, root, wa.width, wa.height); | ||
656 | if (!drw_fontset_create(drw, fonts, LENGTH(fonts))) | 697 | if (!drw_fontset_create(drw, fonts, LENGTH(fonts))) |
657 | die("no fonts could be loaded."); | 698 | die("no fonts could be loaded."); |
658 | lrpad = drw->fonts->h; | 699 | lrpad = drw->fonts->h; |