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