add embedding support with -w option
a9a5c6cc
2 file(s) · +58 −12
| 20 | 20 | .IR color ] |
|
| 21 | 21 | .RB [ \-sf |
|
| 22 | 22 | .IR color ] |
|
| 23 | + | .RB [ \-w |
|
| 24 | + | .IR windowid ] |
|
| 23 | 25 | .P |
|
| 24 | 26 | .BR dmenu_run " ..." |
|
| 25 | 27 | .SH DESCRIPTION |
|
| 75 | 77 | .TP |
|
| 76 | 78 | .B \-v |
|
| 77 | 79 | prints version information to stdout, then exits. |
|
| 80 | + | .TP |
|
| 81 | + | .BI \-w " windowid" |
|
| 82 | + | embed into windowid. |
|
| 78 | 83 | .SH USAGE |
|
| 79 | 84 | dmenu is completely controlled by the keyboard. Items are selected using the |
|
| 80 | 85 | arrow keys, page up, page down, home, and end. |
|
| 34 | 34 | }; |
|
| 35 | 35 | ||
| 36 | 36 | static char text[BUFSIZ] = ""; |
|
| 37 | + | static char *embed; |
|
| 37 | 38 | static int bh, mw, mh; |
|
| 38 | - | static int sw, sh; /* X display screen geometry width, height */ |
|
| 39 | 39 | static int inputw = 0, promptw; |
|
| 40 | 40 | static int lrpad; /* sum of left and right padding */ |
|
| 41 | 41 | static size_t cursor; |
|
| 46 | 46 | ||
| 47 | 47 | static Atom clip, utf8; |
|
| 48 | 48 | static Display *dpy; |
|
| 49 | - | static Window root, win; |
|
| 49 | + | static Window root, parentwin, win; |
|
| 50 | 50 | static XIC xic; |
|
| 51 | 51 | ||
| 52 | 52 | static Drw *drw; |
|
| 175 | 175 | } |
|
| 176 | 176 | ||
| 177 | 177 | static void |
|
| 178 | + | grabfocus(void) |
|
| 179 | + | { |
|
| 180 | + | struct timespec ts = { .tv_sec = 0, .tv_nsec = 10000000 }; |
|
| 181 | + | Window focuswin; |
|
| 182 | + | int i, revertwin; |
|
| 183 | + | ||
| 184 | + | for (i = 0; i < 100; ++i) { |
|
| 185 | + | XGetInputFocus(dpy, &focuswin, &revertwin); |
|
| 186 | + | if (focuswin == win) |
|
| 187 | + | return; |
|
| 188 | + | XSetInputFocus(dpy, win, RevertToParent, CurrentTime); |
|
| 189 | + | nanosleep(&ts, NULL); |
|
| 190 | + | } |
|
| 191 | + | die("cannot grab focus"); |
|
| 192 | + | } |
|
| 193 | + | ||
| 194 | + | static void |
|
| 178 | 195 | grabkeyboard(void) |
|
| 179 | 196 | { |
|
| 180 | 197 | struct timespec ts = { .tv_sec = 0, .tv_nsec = 1000000 }; |
|
| 181 | 198 | int i; |
|
| 182 | 199 | ||
| 200 | + | if (embed) |
|
| 201 | + | return; |
|
| 183 | 202 | /* try to grab keyboard, we may have to wait for another process to ungrab */ |
|
| 184 | 203 | for (i = 0; i < 1000; i++) { |
|
| 185 | 204 | if (XGrabKeyboard(dpy, DefaultRootWindow(dpy), True, GrabModeAsync, |
|
| 497 | 516 | if (ev.xexpose.count == 0) |
|
| 498 | 517 | drw_map(drw, win, 0, 0, mw, mh); |
|
| 499 | 518 | break; |
|
| 519 | + | case FocusIn: |
|
| 520 | + | /* regrab focus from parent window */ |
|
| 521 | + | if (ev.xfocus.window != win) |
|
| 522 | + | grabfocus(); |
|
| 523 | + | break; |
|
| 500 | 524 | case KeyPress: |
|
| 501 | 525 | keypress(&ev.xkey); |
|
| 502 | 526 | break; |
|
| 539 | 563 | lines = MAX(lines, 0); |
|
| 540 | 564 | mh = (lines + 1) * bh; |
|
| 541 | 565 | #ifdef XINERAMA |
|
| 542 | - | if ((info = XineramaQueryScreens(dpy, &n))) { |
|
| 566 | + | if (parentwin == root && (info = XineramaQueryScreens(dpy, &n))) { |
|
| 543 | 567 | XGetInputFocus(dpy, &w, &di); |
|
| 544 | 568 | if (mon >= 0 && mon < n) |
|
| 545 | 569 | i = mon; |
|
| 570 | 594 | } else |
|
| 571 | 595 | #endif |
|
| 572 | 596 | { |
|
| 597 | + | if (!XGetWindowAttributes(dpy, parentwin, &wa)) |
|
| 598 | + | die("could not get embedding window attributes: 0x%lx", |
|
| 599 | + | parentwin); |
|
| 573 | 600 | x = 0; |
|
| 574 | - | y = topbar ? 0 : sh - mh; |
|
| 575 | - | mw = sw; |
|
| 601 | + | y = topbar ? 0 : wa.height - mh; |
|
| 602 | + | mw = wa.width; |
|
| 576 | 603 | } |
|
| 577 | 604 | promptw = (prompt && *prompt) ? TEXTW(prompt) - lrpad / 4 : 0; |
|
| 578 | 605 | inputw = MIN(inputw, mw/3); |
|
| 582 | 609 | swa.override_redirect = True; |
|
| 583 | 610 | swa.background_pixel = scheme[SchemeNorm][ColBg].pixel; |
|
| 584 | 611 | swa.event_mask = ExposureMask | KeyPressMask | VisibilityChangeMask; |
|
| 585 | - | win = XCreateWindow(dpy, root, x, y, mw, mh, 0, |
|
| 586 | - | DefaultDepth(dpy, screen), CopyFromParent, |
|
| 587 | - | DefaultVisual(dpy, screen), |
|
| 612 | + | win = XCreateWindow(dpy, parentwin, x, y, mw, mh, 0, |
|
| 613 | + | CopyFromParent, CopyFromParent, CopyFromParent, |
|
| 588 | 614 | CWOverrideRedirect | CWBackPixel | CWEventMask, &swa); |
|
| 589 | 615 | ||
| 590 | 616 | /* open input methods */ |
|
| 593 | 619 | XNClientWindow, win, XNFocusWindow, win, NULL); |
|
| 594 | 620 | ||
| 595 | 621 | XMapRaised(dpy, win); |
|
| 622 | + | if (embed) { |
|
| 623 | + | XSelectInput(dpy, parentwin, FocusChangeMask); |
|
| 624 | + | if (XQueryTree(dpy, parentwin, &dw, &w, &dws, &du) && dws) { |
|
| 625 | + | for (i = 0; i < du && dws[i] != win; ++i) |
|
| 626 | + | XSelectInput(dpy, dws[i], FocusChangeMask); |
|
| 627 | + | XFree(dws); |
|
| 628 | + | } |
|
| 629 | + | grabfocus(); |
|
| 630 | + | } |
|
| 596 | 631 | drw_resize(drw, mw, mh); |
|
| 597 | 632 | drawmenu(); |
|
| 598 | 633 | } |
|
| 601 | 636 | usage(void) |
|
| 602 | 637 | { |
|
| 603 | 638 | fputs("usage: dmenu [-bfiv] [-l lines] [-p prompt] [-fn font] [-m monitor]\n" |
|
| 604 | - | " [-nb color] [-nf color] [-sb color] [-sf color]\n", stderr); |
|
| 639 | + | " [-nb color] [-nf color] [-sb color] [-sf color] [-w windowid]\n", stderr); |
|
| 605 | 640 | exit(1); |
|
| 606 | 641 | } |
|
| 607 | 642 | ||
| 608 | 643 | int |
|
| 609 | 644 | main(int argc, char *argv[]) |
|
| 610 | 645 | { |
|
| 646 | + | XWindowAttributes wa; |
|
| 611 | 647 | int i, fast = 0; |
|
| 612 | 648 | ||
| 613 | 649 | for (i = 1; i < argc; i++) |
|
| 641 | 677 | colors[SchemeSel][ColBg] = argv[++i]; |
|
| 642 | 678 | else if (!strcmp(argv[i], "-sf")) /* selected foreground color */ |
|
| 643 | 679 | colors[SchemeSel][ColFg] = argv[++i]; |
|
| 680 | + | else if (!strcmp(argv[i], "-w")) /* embedding window id */ |
|
| 681 | + | embed = argv[++i]; |
|
| 644 | 682 | else |
|
| 645 | 683 | usage(); |
|
| 646 | 684 | ||
| 650 | 688 | die("cannot open display"); |
|
| 651 | 689 | screen = DefaultScreen(dpy); |
|
| 652 | 690 | root = RootWindow(dpy, screen); |
|
| 653 | - | sw = DisplayWidth(dpy, screen); |
|
| 654 | - | sh = DisplayHeight(dpy, screen); |
|
| 655 | - | drw = drw_create(dpy, screen, root, sw, sh); |
|
| 691 | + | if (!embed || !(parentwin = strtol(embed, NULL, 0))) |
|
| 692 | + | parentwin = root; |
|
| 693 | + | if (!XGetWindowAttributes(dpy, parentwin, &wa)) |
|
| 694 | + | die("could not get embedding window attributes: 0x%lx", |
|
| 695 | + | parentwin); |
|
| 696 | + | drw = drw_create(dpy, screen, root, wa.width, wa.height); |
|
| 656 | 697 | if (!drw_fontset_create(drw, fonts, LENGTH(fonts))) |
|
| 657 | 698 | die("no fonts could be loaded."); |
|
| 658 | 699 | lrpad = drw->fonts->h; |
|