add embedding support with -w option - dmenu - dynamic menu
  HTML git clone git://git.suckless.org/dmenu
   DIR Log
   DIR Files
   DIR Refs
   DIR README
   DIR LICENSE
       ---
   DIR commit a9a5c6cc2d7d55ed7e556a4fe9d75307c6df2e84
   DIR parent a97f550aa7b81d2add1d2a99e594c038da01fc19
  HTML Author: Quentin Rameau <quinq@fifth.space>
       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(-)
       ---
   DIR 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.
   DIR 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 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;