emacs-diffs
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

master 16702f183f: Fix Motif menu and menu bar dismissal on XI2


From: Po Lu
Subject: master 16702f183f: Fix Motif menu and menu bar dismissal on XI2
Date: Sat, 26 Feb 2022 21:37:54 -0500 (EST)

branch: master
commit 16702f183f34cba880a04e08db9d6b644b38b424
Author: Po Lu <luangruo@yahoo.com>
Commit: Po Lu <luangruo@yahoo.com>

    Fix Motif menu and menu bar dismissal on XI2
    
    * 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 | 70 +++++++++++++++++++++++++++++++++++++++++++++++++------------
 src/xterm.c | 49 +++++++++++++++++++++++++++++++++++++++++--
 2 files changed, 104 insertions(+), 15 deletions(-)

diff --git a/src/xmenu.c b/src/xmenu.c
index 21e8f0f9ec..2bc9f5a93a 100644
--- a/src/xmenu.c
+++ b/src/xmenu.c
@@ -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
diff --git a/src/xterm.c b/src/xterm.c
index 040397777b..33a6613e14 100644
--- a/src/xterm.c
+++ b/src/xterm.c
@@ -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 */



reply via email to

[Prev in Thread] Current Thread [Next in Thread]