aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--dmenu.15
-rw-r--r--dmenu.c65
2 files changed, 58 insertions, 12 deletions
diff --git a/dmenu.1 b/dmenu.1
index 8bbd79d..9eab758 100644
--- a/dmenu.1
+++ b/dmenu.1
@@ -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
77prints version information to stdout, then exits. 79prints version information to stdout, then exits.
80.TP
81.BI \-w " windowid"
82embed into windowid.
78.SH USAGE 83.SH USAGE
79dmenu is completely controlled by the keyboard. Items are selected using the 84dmenu is completely controlled by the keyboard. Items are selected using the
80arrow keys, page up, page down, home, and end. 85arrow keys, page up, page down, home, and end.
diff --git a/dmenu.c b/dmenu.c
index ff74369..9278e91 100644
--- a/dmenu.c
+++ b/dmenu.c
@@ -34,8 +34,8 @@ struct item {
34}; 34};
35 35
36static char text[BUFSIZ] = ""; 36static char text[BUFSIZ] = "";
37static char *embed;
37static int bh, mw, mh; 38static int bh, mw, mh;
38static int sw, sh; /* X display screen geometry width, height */
39static int inputw = 0, promptw; 39static int inputw = 0, promptw;
40static int lrpad; /* sum of left and right padding */ 40static int lrpad; /* sum of left and right padding */
41static size_t cursor; 41static size_t cursor;
@@ -46,7 +46,7 @@ static int mon = -1, screen;
46 46
47static Atom clip, utf8; 47static Atom clip, utf8;
48static Display *dpy; 48static Display *dpy;
49static Window root, win; 49static Window root, parentwin, win;
50static XIC xic; 50static XIC xic;
51 51
52static Drw *drw; 52static Drw *drw;
@@ -175,11 +175,30 @@ drawmenu(void)
175} 175}
176 176
177static void 177static void
178grabfocus(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
194static void
178grabkeyboard(void) 195grabkeyboard(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
601usage(void) 636usage(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
608int 643int
609main(int argc, char *argv[]) 644main(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;