add embedding support with -w option - dmenu - dynamic menu | |
git clone git://git.suckless.org/dmenu | |
Log | |
Files | |
Refs | |
README | |
LICENSE | |
--- | |
commit a9a5c6cc2d7d55ed7e556a4fe9d75307c6df2e84 | |
parent a97f550aa7b81d2add1d2a99e594c038da01fc19 | |
Author: Quentin Rameau <[email protected]> | |
Date: Sat, 8 Oct 2016 14:08:28 +0200 | |
add embedding support with -w option | |
Diffstat: | |
M dmenu.1 | 5 +++++ | |
M dmenu.c | 65 +++++++++++++++++++++++++----… | |
2 files changed, 58 insertions(+), 12 deletions(-) | |
--- | |
diff --git 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 | |
@@ -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 un… | |
for (i = 0; i < 1000; i++) { | |
if (XGrabKeyboard(dpy, DefaultRootWindow(dpy), True, GrabModeA… | |
@@ -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, &s… | |
/* 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 moni… | |
- " [-nb color] [-nf color] [-sb color] [-sf color]\n"… | |
+ " [-nb color] [-nf color] [-sb color] [-sf color] [-… | |
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 colo… | |
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; |