about summary refs log tree commit diff
diff options
context:
space:
mode:
authorQuentin Rameau <quinq@fifth.space>2016-10-08 14:08:28 +0200
committerHiltjo Posthuma <hiltjo@codemadness.org>2016-10-14 15:26:35 +0200
commita9a5c6cc2d7d55ed7e556a4fe9d75307c6df2e84 (patch)
treecab8480da582def31a1853ab8204d721dc325c27
parentdmenu.1: group single options (diff)
downloaddmenu-a9a5c6cc2d7d55ed7e556a4fe9d75307c6df2e84.tar.gz
dmenu-a9a5c6cc2d7d55ed7e556a4fe9d75307c6df2e84.tar.bz2
dmenu-a9a5c6cc2d7d55ed7e556a4fe9d75307c6df2e84.zip
add embedding support with -w option
Diffstat (limited to '')
-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
 .IR color ]
 .RB [ \-sf
 .IR color ]
+.RB [ \-w
+.IR windowid ]
 .P
 .BR dmenu_run " ..."
 .SH DESCRIPTION
@@ -75,6 +77,9 @@ defines the selected foreground color.
 .TP
 .B \-v
 prints version information to stdout, then exits.
+.TP
+.BI \-w " windowid"
+embed into windowid.
 .SH USAGE
 dmenu is completely controlled by the keyboard.  Items are selected using the
 arrow 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 {
 };
 
 static char text[BUFSIZ] = "";
+static char *embed;
 static int bh, mw, mh;
-static int sw, sh; /* X display screen geometry width, height */
 static int inputw = 0, promptw;
 static int lrpad; /* sum of left and right padding */
 static size_t cursor;
@@ -46,7 +46,7 @@ static int mon = -1, screen;
 
 static Atom clip, utf8;
 static Display *dpy;
-static Window root, win;
+static Window root, parentwin, win;
 static XIC xic;
 
 static Drw *drw;
@@ -175,11 +175,30 @@ drawmenu(void)
 }
 
 static void
+grabfocus(void)
+{
+	struct timespec ts = { .tv_sec = 0, .tv_nsec = 10000000  };
+	Window focuswin;
+	int i, revertwin;
+
+	for (i = 0; i < 100; ++i) {
+		XGetInputFocus(dpy, &focuswin, &revertwin);
+		if (focuswin == win)
+			return;
+		XSetInputFocus(dpy, win, RevertToParent, CurrentTime);
+		nanosleep(&ts, NULL);
+	}
+	die("cannot grab focus");
+}
+
+static void
 grabkeyboard(void)
 {
 	struct timespec ts = { .tv_sec = 0, .tv_nsec = 1000000  };
 	int i;
 
+	if (embed)
+		return;
 	/* try to grab keyboard, we may have to wait for another process to ungrab */
 	for (i = 0; i < 1000; i++) {
 		if (XGrabKeyboard(dpy, DefaultRootWindow(dpy), True, GrabModeAsync,
@@ -497,6 +516,11 @@ run(void)
 			if (ev.xexpose.count == 0)
 				drw_map(drw, win, 0, 0, mw, mh);
 			break;
+		case FocusIn:
+			/* regrab focus from parent window */
+			if (ev.xfocus.window != win)
+				grabfocus();
+			break;
 		case KeyPress:
 			keypress(&ev.xkey);
 			break;
@@ -539,7 +563,7 @@ setup(void)
 	lines = MAX(lines, 0);
 	mh = (lines + 1) * bh;
 #ifdef XINERAMA
-	if ((info = XineramaQueryScreens(dpy, &n))) {
+	if (parentwin == root && (info = XineramaQueryScreens(dpy, &n))) {
 		XGetInputFocus(dpy, &w, &di);
 		if (mon >= 0 && mon < n)
 			i = mon;
@@ -570,9 +594,12 @@ setup(void)
 	} else
 #endif
 	{
+		if (!XGetWindowAttributes(dpy, parentwin, &wa))
+			die("could not get embedding window attributes: 0x%lx",
+			    parentwin);
 		x = 0;
-		y = topbar ? 0 : sh - mh;
-		mw = sw;
+		y = topbar ? 0 : wa.height - mh;
+		mw = wa.width;
 	}
 	promptw = (prompt && *prompt) ? TEXTW(prompt) - lrpad / 4 : 0;
 	inputw = MIN(inputw, mw/3);
@@ -582,9 +609,8 @@ setup(void)
 	swa.override_redirect = True;
 	swa.background_pixel = scheme[SchemeNorm][ColBg].pixel;
 	swa.event_mask = ExposureMask | KeyPressMask | VisibilityChangeMask;
-	win = XCreateWindow(dpy, root, x, y, mw, mh, 0,
-	                    DefaultDepth(dpy, screen), CopyFromParent,
-	                    DefaultVisual(dpy, screen),
+	win = XCreateWindow(dpy, parentwin, x, y, mw, mh, 0,
+	                    CopyFromParent, CopyFromParent, CopyFromParent,
 	                    CWOverrideRedirect | CWBackPixel | CWEventMask, &swa);
 
 	/* open input methods */
@@ -593,6 +619,15 @@ setup(void)
 	                XNClientWindow, win, XNFocusWindow, win, NULL);
 
 	XMapRaised(dpy, win);
+	if (embed) {
+		XSelectInput(dpy, parentwin, FocusChangeMask);
+		if (XQueryTree(dpy, parentwin, &dw, &w, &dws, &du) && dws) {
+			for (i = 0; i < du && dws[i] != win; ++i)
+				XSelectInput(dpy, dws[i], FocusChangeMask);
+			XFree(dws);
+		}
+		grabfocus();
+	}
 	drw_resize(drw, mw, mh);
 	drawmenu();
 }
@@ -601,13 +636,14 @@ static void
 usage(void)
 {
 	fputs("usage: dmenu [-bfiv] [-l lines] [-p prompt] [-fn font] [-m monitor]\n"
-	      "             [-nb color] [-nf color] [-sb color] [-sf color]\n", stderr);
+	      "             [-nb color] [-nf color] [-sb color] [-sf color] [-w windowid]\n", stderr);
 	exit(1);
 }
 
 int
 main(int argc, char *argv[])
 {
+	XWindowAttributes wa;
 	int i, fast = 0;
 
 	for (i = 1; i < argc; i++)
@@ -641,6 +677,8 @@ main(int argc, char *argv[])
 			colors[SchemeSel][ColBg] = argv[++i];
 		else if (!strcmp(argv[i], "-sf"))  /* selected foreground color */
 			colors[SchemeSel][ColFg] = argv[++i];
+		else if (!strcmp(argv[i], "-w"))   /* embedding window id */
+			embed = argv[++i];
 		else
 			usage();
 
@@ -650,9 +688,12 @@ main(int argc, char *argv[])
 		die("cannot open display");
 	screen = DefaultScreen(dpy);
 	root = RootWindow(dpy, screen);
-	sw = DisplayWidth(dpy, screen);
-	sh = DisplayHeight(dpy, screen);
-	drw = drw_create(dpy, screen, root, sw, sh);
+	if (!embed || !(parentwin = strtol(embed, NULL, 0)))
+		parentwin = root;
+	if (!XGetWindowAttributes(dpy, parentwin, &wa))
+		die("could not get embedding window attributes: 0x%lx",
+		    parentwin);
+	drw = drw_create(dpy, screen, root, wa.width, wa.height);
 	if (!drw_fontset_create(drw, fonts, LENGTH(fonts)))
 		die("no fonts could be loaded.");
 	lrpad = drw->fonts->h;