]> git.eshelyaron.com Git - emacs.git/commitdiff
Fix Motif menu and menu bar dismissal on XI2
authorPo Lu <luangruo@yahoo.com>
Sun, 27 Feb 2022 02:37:17 +0000 (10:37 +0800)
committerPo Lu <luangruo@yahoo.com>
Sun, 27 Feb 2022 02:37:43 +0000 (10:37 +0800)
* src/xmenu.c (x_activate_menubar): Improve ungrabbing logic on
XI2.
(server_timestamp_predicate): New function.
(create_and_show_popup_menu): If the display supports XI2, make
sure the timestamps are correct by dispatching a PropertyNotify
event to Xt.
* src/xterm.c (handle_one_xevent): Translate XI_ButtonRelease
events into core events before dispatching them to Xt.

src/xmenu.c
src/xterm.c

index 21e8f0f9ec70389baef2c61e31a32ac806f92173..2bc9f5a93a0d4119e1301f58bc1ca8c5e64f0d68 100644 (file)
@@ -572,11 +572,11 @@ x_activate_menubar (struct frame *f)
     {
       for (int i = 0; i < dpyinfo->num_devices; ++i)
        {
-#ifndef USE_MOTIF
          if (dpyinfo->devices[i].grab)
-#endif
-           XIUngrabDevice (dpyinfo->display, dpyinfo->devices[i].device_id,
-                           CurrentTime);
+           {
+             XIUngrabDevice (dpyinfo->display, dpyinfo->devices[i].device_id,
+                             CurrentTime);
+           }
        }
     }
 #endif
@@ -1514,6 +1514,23 @@ pop_down_menu (int id)
   popup_activated_flag = 0;
 }
 
+#ifdef HAVE_XINPUT2
+static Bool
+server_timestamp_predicate (Display *display,
+                           XEvent *xevent,
+                           XPointer arg)
+{
+  XID *args = (XID *) arg;
+
+  if (xevent->type == PropertyNotify
+      && xevent->xproperty.window == args[0]
+      && xevent->xproperty.atom == args[1])
+    return True;
+
+  return False;
+}
+#endif
+
 /* Pop up the menu for frame F defined by FIRST_WV at X/Y and loop until the
    menu pops down.
    menu_item_selection will be set to the selection.  */
@@ -1529,6 +1546,10 @@ create_and_show_popup_menu (struct frame *f, widget_value *first_wv,
   LWLIB_ID menu_id;
   Widget menu;
   Window dummy_window;
+#ifdef HAVE_XINPUT2
+  XEvent property_dummy;
+  Atom property_atom;
+#endif
 
   eassert (FRAME_X_P (f));
 
@@ -1609,14 +1630,37 @@ create_and_show_popup_menu (struct frame *f, widget_value *first_wv,
     }
 
   if (any_xi_grab_p)
-    XGrabPointer (dpyinfo->display,
-                 FRAME_X_WINDOW (f),
-                 False, (PointerMotionMask
-                         | PointerMotionHintMask
-                         | ButtonReleaseMask
-                         | ButtonPressMask),
-                 GrabModeSync, GrabModeAsync,
-                 None, None, CurrentTime);
+    {
+#ifndef USE_MOTIF
+      XGrabPointer (dpyinfo->display,
+                   FRAME_X_WINDOW (f),
+                   False, (PointerMotionMask
+                           | PointerMotionHintMask
+                           | ButtonReleaseMask
+                           | ButtonPressMask),
+                   GrabModeSync, GrabModeAsync,
+                   None, None, CurrentTime);
+#endif
+    }
+
+  if (dpyinfo->supports_xi2)
+    {
+      /* Dispatch a PropertyNotify to Xt with the current server time.
+        Motif tries to set a grab with the timestamp of the last event
+        processed by Xt, but Xt doesn't consider GenericEvents, so the
+        timestamp is always less than the last grab time.  */
+
+      property_atom = XInternAtom (dpyinfo->display, "EMACS_SERVER_TIME_PROP", False);
+
+      XChangeProperty (dpyinfo->display, FRAME_OUTER_WINDOW (f),
+                      property_atom, XA_ATOM, 32,
+                      PropModeReplace, (unsigned char *) &property_atom, 1);
+
+      XIfEvent (dpyinfo->display, &property_dummy, server_timestamp_predicate,
+               (XPointer) &(XID[]) {(XID) FRAME_OUTER_WINDOW (f), (XID) property_atom});
+
+      XtDispatchEvent (&property_dummy);
+    }
 
   if (dpyinfo->supports_xi2)
     XUngrabServer (dpyinfo->display);
@@ -1626,7 +1670,7 @@ create_and_show_popup_menu (struct frame *f, widget_value *first_wv,
   lw_popup_menu (menu, &dummy);
   popup_activated_flag = 1;
 
-#ifdef HAVE_XINPUT2
+#if defined HAVE_XINPUT2 && !defined USE_MOTIF
   if (any_xi_grab_p)
     XAllowEvents (dpyinfo->display, AsyncPointer, CurrentTime);
 #endif
index 040397777b637b5d528d50b31f074dbad5040be0..33a6613e1457c60401df06c345c7734b9318a72e 100644 (file)
@@ -9513,6 +9513,13 @@ handle_one_xevent (struct x_display_info *dpyinfo,
   XEvent configureEvent;
   XEvent next_event;
   Lisp_Object coding;
+#ifdef USE_MOTIF
+  /* Some XInput 2 events are important for Motif menu bars to work
+     correctly, so they must be translated into core events before
+     being passed to XtDispatchEvent.  */
+  bool use_copy = false;
+  XEvent copy;
+#endif
 
   *finish = X_EVENT_NORMAL;
 
@@ -10924,7 +10931,7 @@ handle_one_xevent (struct x_display_info *dpyinfo,
          x_display_set_last_user_time (dpyinfo, event->xbutton.time);
 
 #ifdef HAVE_XWIDGETS
-       struct xwidget_view *xvw = xwidget_view_from_window (event->xmotion.window);
+       struct xwidget_view *xvw = xwidget_view_from_window (event->xbutton.window);
 
        if (xvw)
          {
@@ -11659,6 +11666,38 @@ handle_one_xevent (struct x_display_info *dpyinfo,
              struct xwidget_view *xvw;
 #endif
 
+#ifdef USE_MOTIF
+             if (popup_activated ())
+               {
+                 use_copy = true;
+                 copy.xbutton.type = ButtonRelease;
+                 copy.xbutton.serial = xev->serial;
+                 copy.xbutton.send_event = xev->send_event;
+                 copy.xbutton.display = dpyinfo->display;
+                 copy.xbutton.window = xev->event;
+                 copy.xbutton.root = xev->root;
+                 copy.xbutton.subwindow = xev->child;
+                 copy.xbutton.time = xev->time;
+                 copy.xbutton.x = lrint (xev->event_x);
+                 copy.xbutton.y = lrint (xev->event_y);
+                 copy.xbutton.x_root = lrint (xev->root_x);
+                 copy.xbutton.y_root = lrint (xev->root_y);
+                 copy.xbutton.state = xev->mods.effective;
+                 copy.xbutton.button = xev->detail;
+                 copy.xbutton.same_screen = True;
+
+                 if (xev->buttons.mask_len)
+                   {
+                     if (XIMaskIsSet (xev->buttons.mask, 1))
+                       copy.xbutton.state |= Button1Mask;
+                     if (XIMaskIsSet (xev->buttons.mask, 2))
+                       copy.xbutton.state |= Button2Mask;
+                     if (XIMaskIsSet (xev->buttons.mask, 3))
+                       copy.xbutton.state |= Button3Mask;
+                   }
+               }
+#endif
+
 #ifdef HAVE_XINPUT2_1
              /* Ignore emulated scroll events when XI2 native
                 scroll events are present.  */
@@ -12699,7 +12738,13 @@ handle_one_xevent (struct x_display_info *dpyinfo,
          if (event->type != ConfigureNotify
              || (event->xconfigure.width != 0
                  && event->xconfigure.height != 0))
-           XtDispatchEvent ((XEvent *) event);
+           {
+#ifdef USE_MOTIF
+             XtDispatchEvent (use_copy ? &copy : (XEvent *) event);
+#else
+             XtDispatchEvent ((XEvent *) event);
+#endif
+           }
        }
       unblock_input ();
 #endif /* USE_X_TOOLKIT */