add embedding support with -w option

This commit is contained in:
Quentin Rameau 2016-10-08 14:08:28 +02:00 committed by Hiltjo Posthuma
parent a97f550aa7
commit a9a5c6cc2d
2 changed files with 58 additions and 12 deletions

View file

@ -20,6 +20,8 @@ dmenu \- dynamic menu
.IR color ] .IR color ]
.RB [ \-sf .RB [ \-sf
.IR color ] .IR color ]
.RB [ \-w
.IR windowid ]
.P .P
.BR dmenu_run " ..." .BR dmenu_run " ..."
.SH DESCRIPTION .SH DESCRIPTION
@ -75,6 +77,9 @@ defines the selected foreground color.
.TP .TP
.B \-v .B \-v
prints version information to stdout, then exits. prints version information to stdout, then exits.
.TP
.BI \-w " windowid"
embed into windowid.
.SH USAGE .SH USAGE
dmenu is completely controlled by the keyboard. Items are selected using the dmenu is completely controlled by the keyboard. Items are selected using the
arrow keys, page up, page down, home, and end. arrow keys, page up, page down, home, and end.

65
dmenu.c
View file

@ -34,8 +34,8 @@ struct item {
}; };
static char text[BUFSIZ] = ""; static char text[BUFSIZ] = "";
static char *embed;
static int bh, mw, mh; static int bh, mw, mh;
static int sw, sh; /* X display screen geometry width, height */
static int inputw = 0, promptw; static int inputw = 0, promptw;
static int lrpad; /* sum of left and right padding */ static int lrpad; /* sum of left and right padding */
static size_t cursor; static size_t cursor;
@ -46,7 +46,7 @@ static int mon = -1, screen;
static Atom clip, utf8; static Atom clip, utf8;
static Display *dpy; static Display *dpy;
static Window root, win; static Window root, parentwin, win;
static XIC xic; static XIC xic;
static Drw *drw; static Drw *drw;
@ -174,12 +174,31 @@ drawmenu(void)
drw_map(drw, win, 0, 0, mw, mh); drw_map(drw, win, 0, 0, mw, mh);
} }
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 static void
grabkeyboard(void) grabkeyboard(void)
{ {
struct timespec ts = { .tv_sec = 0, .tv_nsec = 1000000 }; struct timespec ts = { .tv_sec = 0, .tv_nsec = 1000000 };
int i; int i;
if (embed)
return;
/* try to grab keyboard, we may have to wait for another process to ungrab */ /* try to grab keyboard, we may have to wait for another process to ungrab */
for (i = 0; i < 1000; i++) { for (i = 0; i < 1000; i++) {
if (XGrabKeyboard(dpy, DefaultRootWindow(dpy), True, GrabModeAsync, if (XGrabKeyboard(dpy, DefaultRootWindow(dpy), True, GrabModeAsync,
@ -497,6 +516,11 @@ run(void)
if (ev.xexpose.count == 0) if (ev.xexpose.count == 0)
drw_map(drw, win, 0, 0, mw, mh); drw_map(drw, win, 0, 0, mw, mh);
break; break;
case FocusIn:
/* regrab focus from parent window */
if (ev.xfocus.window != win)
grabfocus();
break;
case KeyPress: case KeyPress:
keypress(&ev.xkey); keypress(&ev.xkey);
break; break;
@ -539,7 +563,7 @@ setup(void)
lines = MAX(lines, 0); lines = MAX(lines, 0);
mh = (lines + 1) * bh; mh = (lines + 1) * bh;
#ifdef XINERAMA #ifdef XINERAMA
if ((info = XineramaQueryScreens(dpy, &n))) { if (parentwin == root && (info = XineramaQueryScreens(dpy, &n))) {
XGetInputFocus(dpy, &w, &di); XGetInputFocus(dpy, &w, &di);
if (mon >= 0 && mon < n) if (mon >= 0 && mon < n)
i = mon; i = mon;
@ -570,9 +594,12 @@ setup(void)
} else } else
#endif #endif
{ {
if (!XGetWindowAttributes(dpy, parentwin, &wa))
die("could not get embedding window attributes: 0x%lx",
parentwin);
x = 0; x = 0;
y = topbar ? 0 : sh - mh; y = topbar ? 0 : wa.height - mh;
mw = sw; mw = wa.width;
} }
promptw = (prompt && *prompt) ? TEXTW(prompt) - lrpad / 4 : 0; promptw = (prompt && *prompt) ? TEXTW(prompt) - lrpad / 4 : 0;
inputw = MIN(inputw, mw/3); inputw = MIN(inputw, mw/3);
@ -582,9 +609,8 @@ setup(void)
swa.override_redirect = True; swa.override_redirect = True;
swa.background_pixel = scheme[SchemeNorm][ColBg].pixel; swa.background_pixel = scheme[SchemeNorm][ColBg].pixel;
swa.event_mask = ExposureMask | KeyPressMask | VisibilityChangeMask; swa.event_mask = ExposureMask | KeyPressMask | VisibilityChangeMask;
win = XCreateWindow(dpy, root, x, y, mw, mh, 0, win = XCreateWindow(dpy, parentwin, x, y, mw, mh, 0,
DefaultDepth(dpy, screen), CopyFromParent, CopyFromParent, CopyFromParent, CopyFromParent,
DefaultVisual(dpy, screen),
CWOverrideRedirect | CWBackPixel | CWEventMask, &swa); CWOverrideRedirect | CWBackPixel | CWEventMask, &swa);
/* open input methods */ /* open input methods */
@ -593,6 +619,15 @@ setup(void)
XNClientWindow, win, XNFocusWindow, win, NULL); XNClientWindow, win, XNFocusWindow, win, NULL);
XMapRaised(dpy, win); 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); drw_resize(drw, mw, mh);
drawmenu(); drawmenu();
} }
@ -601,13 +636,14 @@ static void
usage(void) usage(void)
{ {
fputs("usage: dmenu [-bfiv] [-l lines] [-p prompt] [-fn font] [-m monitor]\n" 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); exit(1);
} }
int int
main(int argc, char *argv[]) main(int argc, char *argv[])
{ {
XWindowAttributes wa;
int i, fast = 0; int i, fast = 0;
for (i = 1; i < argc; i++) for (i = 1; i < argc; i++)
@ -641,6 +677,8 @@ main(int argc, char *argv[])
colors[SchemeSel][ColBg] = argv[++i]; colors[SchemeSel][ColBg] = argv[++i];
else if (!strcmp(argv[i], "-sf")) /* selected foreground color */ else if (!strcmp(argv[i], "-sf")) /* selected foreground color */
colors[SchemeSel][ColFg] = argv[++i]; colors[SchemeSel][ColFg] = argv[++i];
else if (!strcmp(argv[i], "-w")) /* embedding window id */
embed = argv[++i];
else else
usage(); usage();
@ -650,9 +688,12 @@ main(int argc, char *argv[])
die("cannot open display"); die("cannot open display");
screen = DefaultScreen(dpy); screen = DefaultScreen(dpy);
root = RootWindow(dpy, screen); root = RootWindow(dpy, screen);
sw = DisplayWidth(dpy, screen); if (!embed || !(parentwin = strtol(embed, NULL, 0)))
sh = DisplayHeight(dpy, screen); parentwin = root;
drw = drw_create(dpy, screen, root, sw, sh); 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))) if (!drw_fontset_create(drw, fonts, LENGTH(fonts)))
die("no fonts could be loaded."); die("no fonts could be loaded.");
lrpad = drw->fonts->h; lrpad = drw->fonts->h;