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  .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. @@ -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; | 
