add embedding support with -w option
authorQuentin Rameau <quinq@fifth.space>
Sat, 8 Oct 2016 12:08:28 +0000 (14:08 +0200)
committerHiltjo Posthuma <hiltjo@codemadness.org>
Fri, 14 Oct 2016 13:26:35 +0000 (15:26 +0200)
dmenu.1
dmenu.c

diff --git a/dmenu.1 b/dmenu.1
index 8bbd79d..9eab758 100644 (file)
--- a/dmenu.1
+++ b/dmenu.1
@@ -20,6 +20,8 @@ dmenu \- dynamic menu
 .IR color ]
 .RB [ \-sf
 .IR color ]
 .IR color ]
 .RB [ \-sf
 .IR color ]
+.RB [ \-w
+.IR windowid ]
 .P
 .BR dmenu_run " ..."
 .SH DESCRIPTION
 .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
 .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.
 .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 (file)
--- a/dmenu.c
+++ b/dmenu.c
@@ -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 lrpad; /* sum of left and right padding */
 static size_t cursor;
 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 Atom clip, utf8;
 static Display *dpy;
-static Window root, win;
+static Window root, parentwin, win;
 static XIC xic;
 
 static Drw *drw;
 static XIC xic;
 
 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
 grabkeyboard(void)
 {
        struct timespec ts = { .tv_sec = 0, .tv_nsec = 1000000  };
        int i;
 
 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,
        /* 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;
                        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;
                case KeyPress:
                        keypress(&ev.xkey);
                        break;
@@ -539,7 +563,7 @@ setup(void)
        lines = MAX(lines, 0);
        mh = (lines + 1) * bh;
 #ifdef XINERAMA
        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;
                XGetInputFocus(dpy, &w, &di);
                if (mon >= 0 && mon < n)
                        i = mon;
@@ -570,9 +594,12 @@ setup(void)
        } else
 #endif
        {
        } else
 #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;
-               mw = sw;
+               y = topbar ? 0 : wa.height - mh;
+               mw = wa.width;
        }
        promptw = (prompt && *prompt) ? TEXTW(prompt) - lrpad / 4 : 0;
        inputw = MIN(inputw, mw/3);
        }
        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;
        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 */
                            CWOverrideRedirect | CWBackPixel | CWEventMask, &swa);
 
        /* open input methods */
@@ -593,6 +619,15 @@ setup(void)
                        XNClientWindow, win, XNFocusWindow, win, NULL);
 
        XMapRaised(dpy, win);
                        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();
 }
        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"
 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[])
 {
        exit(1);
 }
 
 int
 main(int argc, char *argv[])
 {
+       XWindowAttributes wa;
        int i, fast = 0;
 
        for (i = 1; i < argc; i++)
        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];
                        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();
 
                else
                        usage();
 
@@ -650,9 +688,12 @@ main(int argc, char *argv[])
                die("cannot open display");
        screen = DefaultScreen(dpy);
        root = RootWindow(dpy, screen);
                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;
        if (!drw_fontset_create(drw, fonts, LENGTH(fonts)))
                die("no fonts could be loaded.");
        lrpad = drw->fonts->h;