Commit Diff


commit - 9ff10a0f897bf216fbea6b2bf5c8ccfb9d1b0d9b
commit + 844addbb3803e8f077087ce69fdaaf32b0ea4395
blob - 7aa4f86701101cbc050057c97db8c9d85a4c54a5
blob + 30172d531c4e6ecb5843222e3dd95f94a1ce98f2
--- mymenu.1
+++ mymenu.1
@@ -11,19 +11,20 @@
 .Op Fl p Ar prompt
 .Op Fl x Ar coord
 .Op Fl y Ar coord
-.Op Fl w Ar width
-.Op Fl h Ar height
+.Op Fl W Ar width
+.Op Fl H Ar height
 .Op Fl P Ar padding
 .Op Fl l Ar layout
 .Op Fl f Ar font
 .Op Fl b Ar borders
-.Op Fl B Ar color
+.Op Fl B Ar colors
 .Op Fl t Ar color
 .Op Fl T Ar color
 .Op Fl c Ar color
 .Op Fl C Ar color
 .Op Fl s Ar color
 .Op Fl S Ar color
+.Op Fl w Ar window
 .Ek
 .Sh DESCRIPTION
 The
@@ -76,6 +77,8 @@ Override the completion background color. See MyMenu.c
 Override the highlighted completion foreground color. See MyMenu.completion_highlighted.foreground.
 .It Fl S Ar color
 Override the highlighted completion background color. See MyMenu.completion_highlighted.background.
+.It Fl w Ar window
+Embed into the given window id.
 .El
 .Sh RESOURCES
 .Bl -tag -width Ds
blob - a3799a212afaf7e478c6c183efd87a9b0d36f9d6
blob + 11461dc55c32d53b0ec151ac8ee391cf9ef1ade8
--- mymenu.1.md
+++ mymenu.1.md
@@ -11,19 +11,20 @@ MYMENU(1) - General Commands Manual
 \[**-p** *prompt*]
 \[**-x** *coord*]
 \[**-y** *coord*]
-\[**-w** *width*]
-\[**-h** *height*]
+\[**-W** *width*]
+\[**-H** *height*]
 \[**-P** *padding*]
 \[**-l** *layout*]
 \[**-f** *font*]
 \[**-b** *borders*]
-\[**-B** *color*]
+\[**-B** *colors*]
 \[**-t** *color*]
 \[**-T** *color*]
 \[**-c** *color*]
 \[**-C** *color*]
 \[**-s** *color*]
 \[**-S** *color*]
+\[**-w** *window*]
 
 # DESCRIPTION
 
@@ -115,6 +116,10 @@ over the (respective) ones defined in the
 
 > Override the highlighted completion background color. See MyMenu.completion\_highlighted.background.
 
+**-w** *window*
+
+> Embed into the given window id.
+
 # RESOURCES
 
 MyMenu.font
@@ -326,4 +331,4 @@ sysexits(3)
 
 Omar Polo <omar.polo@europecom.net>
 
-OpenBSD 6.3 - July 13, 2018
+OpenBSD 6.3 - July 15, 2018
blob - a8792fdcffe280276c3b1dacc1740b5d5d395ed8
blob + e4558fc6d4f892c6bb22a6710c205cdb3ced7dcd
--- mymenu.c
+++ mymenu.c
@@ -41,7 +41,7 @@
 # define default_fontname "fixed"
 #endif
 
-#define ARGS "hvap:P:l:f:w:h:x:y:b:B:t:T:c:C:s:S:"
+#define ARGS "hvae:p:P:l:f:W:H:x:y:b:B:t:T:c:C:s:S:"
 
 #define MIN(a, b) ((a) < (b) ? (a) : (b))
 #define MAX(a, b) ((a) > (b) ? (a) : (b))
@@ -494,7 +494,7 @@ void draw_horizontally(struct rendering *r, char *text
   start_at = r->x_zero + text_extents("n", 1, r, nil, nil);
   start_at = start_at * prompt_width + r->padding;
 
-  int texty = (height + r->height) >>1;
+  int texty = (inner_height(r) + height + r->y_zero) / 2;
 
   XFillRectangle(r->d, r->w, r->prompt_bg, r->x_zero, r->y_zero, start_at, inner_height(r));
 
@@ -504,7 +504,7 @@ void draw_horizontally(struct rendering *r, char *text
   draw_string(r->ps1, r->ps1len, r->x_zero + r->padding, texty, r, PROMPT);
   draw_string(text, MIN(text_len, prompt_width), r->x_zero + r->padding + ps1xlen, texty, r, PROMPT);
 
-  XFillRectangle(r->d, r->w, r->completion_bg, start_at, r->y_zero, r->width, r->height);
+  XFillRectangle(r->d, r->w, r->completion_bg, start_at, r->y_zero, r->width, inner_height(r));
 
   struct completion *c = cs->completions;
   for (int i = 0; c != nil; ++i) {
@@ -662,6 +662,19 @@ void get_wh(Display *d, Window *w, int *width, int *he
   XGetWindowAttributes(d, *w, &win_attr);
   *height = win_attr.height;
   *width = win_attr.width;
+}
+
+int grabfocus(Display *d, Window w) {
+  for (int i = 0; i < 100; ++i) {
+    Window focuswin;
+    int revert_to_win;
+    XGetInputFocus(d, &focuswin, &revert_to_win);
+    if (focuswin == w)
+      return true;
+    XSetInputFocus(d, w, RevertToParent, CurrentTime);
+    usleep(1000);
+  }
+  return 0;
 }
 
 // I know this may seem a little hackish BUT is the only way I managed
@@ -674,6 +687,7 @@ int take_keyboard(Display *d, Window w) {
       return 1;
     usleep(1000);
   }
+  fprintf(stderr, "Cannot grab keyboard\n");
   return 0;
 }
 
@@ -839,10 +853,10 @@ enum action parse_event(Display *d, XKeyPressedEvent *
 
 // Given the name of the program (argv[0]?) print a small help on stderr
 void usage(char *prgname) {
-  fprintf(stderr, "Usage: %s [flags]\n", prgname);
-  fprintf(stderr, "\t-a: automatic mode, the first completion is "
-          "always selected;\n");
-  fprintf(stderr, "\t-h: print this help.\n");
+  fprintf(stderr, "%s [-hva] [-p prompt] [-x coord] [-y coord] [-W width] [-H height]\n"
+                  "       [-P padding] [-l layout] [-f font] [-b borders] [-B colors]\n"
+                  "       [-t color] [-T color] [-c color] [-C color] [-s color] [-S color]\n"
+                  "       [-w window_id]\n", prgname);
 }
 
 int main(int argc, char **argv) {
@@ -855,19 +869,22 @@ int main(int argc, char **argv) {
   // by default the first completion isn't selected
   bool first_selected = false;
 
-  // first round of args parsing for early terminating options
+  char *parent_window_id = nil;
+
+  // first round of args parsing
   int ch;
   while ((ch = getopt(argc, argv, ARGS)) != -1) {
     switch (ch) {
-      /* case 'a': */
-      /*   first_selected = true; */
-      /*   break; */
-      case 'h':
+      case 'h': // help
         usage(*argv);
         return 0;
-      case 'v':
+      case 'v': // version
         fprintf(stderr, "%s version: %s\n", *argv, VERSION);
         return 0;
+      case 'e': // embed
+        parent_window_id = strdup(optarg);
+        check_allocation(parent_window_id);
+        break;
       default:
         break;
     }
@@ -925,15 +942,22 @@ int main(int argc, char **argv) {
     return EX_UNAVAILABLE;
   }
 
+  Window parent_window;
+  bool embed = true;
+  if (! (parent_window_id && (parent_window = strtol(parent_window_id, nil, 0)))) {
+    parent_window = DefaultRootWindow(d);
+    embed = false;
+  }
+
   // get display size
-  // XXX: is getting the default root window dimension correct?
-  XWindowAttributes xwa;
-  XGetWindowAttributes(d, DefaultRootWindow(d), &xwa);
-  int d_width = xwa.width;
-  int d_height = xwa.height;
+  int d_width;
+  int d_height;
+  get_wh(d, &parent_window, &d_width, &d_height);
 
+  fprintf(stderr, "d_width %d, d_height %d\n", d_width, d_height);
+
 #ifdef USE_XINERAMA
-  if (XineramaIsActive(d)) {
+  if (!embed && XineramaIsActive(d)) {
     // find the mice
     int number_of_screens = XScreenCount(d);
     Window r;
@@ -1119,6 +1143,9 @@ int main(int argc, char **argv) {
       case 'a':
         first_selected = true;
         break;
+      case 'e':
+        // (embedding mymenu) this case was already catched.
+        break;
       case 'p': {
         char *newprompt = strdup(optarg);
         if (newprompt != nil) {
@@ -1147,10 +1174,10 @@ int main(int argc, char **argv) {
         }
         break;
       }
-      case 'w':
+      case 'W':
         width = parse_int_with_percentage(optarg, width, d_width);
         break;
-      case 'h':
+      case 'H':
         height = parse_int_with_percentage(optarg, height, d_height);
         break;
       case 'b': {
@@ -1235,37 +1262,38 @@ int main(int argc, char **argv) {
   // create the window
   XSetWindowAttributes attr;
   attr.override_redirect = true;
+  attr.event_mask = ExposureMask | KeyPressMask | VisibilityChangeMask;
 
   Window w = XCreateWindow(d,                                   // display
-                           DefaultRootWindow(d),                // parent
+                           parent_window,                       // parent
                            x + offset_x, y + offset_y,          // x y
                            width, height,                       // w h
                            0,                                   // border width
-                           DefaultDepth(d, DefaultScreen(d)),   // depth
+                           CopyFromParent,                      // depth
                            InputOutput,                         // class
-                           DefaultVisual(d, DefaultScreen(d)),  // visual
-                           CWOverrideRedirect,                  // value mask
+                           CopyFromParent,                      // visual
+                           CWEventMask | CWOverrideRedirect,    // value mask (CWBackPixel in the future also?)
                            &attr);
 
   set_win_atoms_hints(d, w, width, height);
 
   // we want some events
   XSelectInput(d, w, StructureNotifyMask | KeyPressMask | KeymapStateMask);
+  XMapRaised(d, w);
 
-  // make the window appear on the screen
-  XMapWindow(d, w);
-
-  // wait for the MapNotify event (i.e. the event "window rendered")
-  for (;;) {
-    XEvent e;
-    XNextEvent(d, &e);
-    if (e.type == MapNotify)
-      break;
+  // if embed, listen for other events as well
+  if (embed) {
+    XSelectInput(d, parent_window, FocusChangeMask);
+    Window *children, parent, root;
+    unsigned int children_no;
+    if (XQueryTree(d, parent_window, &root, &parent, &children, &children_no) && children) {
+      for (unsigned int i = 0; i < children_no && children[i] != w; ++i)
+        XSelectInput(d, children[i], FocusChangeMask);
+      XFree(children);
+    }
+    grabfocus(d, w);
   }
 
-  // get the *real* width & height after the window was rendered
-  get_wh(d, &w, &width, &height);
-
   // grab keyboard
   take_keyboard(d, w);
 
@@ -1384,8 +1412,26 @@ int main(int argc, char **argv) {
     switch (e.type) {
       case KeymapNotify:
         XRefreshKeyboardMapping(&e.xmapping);
+        break;
+
+      case FocusIn:
+        // re-grab focus
+        if (e.xfocus.window != w)
+          grabfocus(d, w);
         break;
 
+      case VisibilityNotify:
+        if (e.xvisibility.state != VisibilityUnobscured)
+          XRaiseWindow(d, w);
+        break;
+
+      case MapNotify:
+        /* fprintf(stderr, "Map Notify!\n"); */
+        /* TODO: update the computed window and height! */
+        /* get_wh(d, &w, width, height); */
+        draw(&r, text, cs);
+        break;
+
       case KeyPress: {
         XKeyPressedEvent *ev = (XKeyPressedEvent*)&e;