emacs-diffs
[Top][All Lists]
Advanced

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

master 759d337b0d: Fix key navigation of Lucid menus on XI2


From: Po Lu
Subject: master 759d337b0d: Fix key navigation of Lucid menus on XI2
Date: Sat, 23 Apr 2022 07:59:06 -0400 (EDT)

branch: master
commit 759d337b0d05f3164bf90dd980a079cd412f9de1
Author: Po Lu <luangruo@yahoo.com>
Commit: Po Lu <luangruo@yahoo.com>

    Fix key navigation of Lucid menus on XI2
    
    * src/xmenu.c (popup_get_selection): Fix cookie claiming of
    input extension events.
    (Fx_menu_bar_open_internal): Use right timestamps on XI2.
    * src/xterm.c (handle_one_xevent): Dispatch XI2 key events via
    Xt when popup is active.
---
 src/xmenu.c | 47 +++++++++++++++++++++++++++++-------
 src/xterm.c | 79 ++++++++++++++++++++++++++++++++++++++++++++++++++-----------
 2 files changed, 104 insertions(+), 22 deletions(-)

diff --git a/src/xmenu.c b/src/xmenu.c
index 94cd9dab69..316dacee5b 100644
--- a/src/xmenu.c
+++ b/src/xmenu.c
@@ -365,16 +365,16 @@ popup_get_selection (XEvent *initial_event, struct 
x_display_info *dpyinfo,
               && event.xgeneric.display == dpyinfo->display
               && event.xgeneric.extension == dpyinfo->xi2_opcode)
        {
+         if (!event.xcookie.data
+             && XGetEventData (dpyinfo->display, &event.xcookie))
+           cookie_claimed_p = true;
+
          if (event.xcookie.data)
            {
              switch (event.xgeneric.evtype)
                {
                case XI_ButtonRelease:
                  {
-                   if (!event.xcookie.data
-                       && XGetEventData (dpyinfo->display, &event.xcookie))
-                     cookie_claimed_p = true;
-
                    xev = (XIDeviceEvent *) event.xcookie.data;
                    device = xi_device_from_id (dpyinfo, xev->deviceid);
 
@@ -424,10 +424,6 @@ popup_get_selection (XEvent *initial_event, struct 
x_display_info *dpyinfo,
                  {
                    KeySym keysym;
 
-                   if (!event.xcookie.data
-                       && XGetEventData (dpyinfo->display, &event.xcookie))
-                     cookie_claimed_p = true;
-
                    xev = (XIDeviceEvent *) event.xcookie.data;
 
                    copy.xkey.type = KeyPress;
@@ -473,6 +469,9 @@ DEFUN ("x-menu-bar-open-internal", 
Fx_menu_bar_open_internal, Sx_menu_bar_open_i
 {
   XEvent ev;
   struct frame *f = decode_window_system_frame (frame);
+#if defined USE_X_TOOLKIT && defined HAVE_XINPUT2
+  struct x_display_info *dpyinfo = FRAME_DISPLAY_INFO (f);
+#endif
   Widget menubar;
   block_input ();
 
@@ -485,12 +484,44 @@ DEFUN ("x-menu-bar-open-internal", 
Fx_menu_bar_open_internal, Sx_menu_bar_open_i
       Window child;
       bool error_p = false;
 
+#if defined USE_X_TOOLKIT && defined HAVE_XINPUT2
+      /* Clear the XI2 grab so Motif or lwlib can set a core grab.
+        Otherwise some versions of Motif will emit a warning and hang,
+        and lwlib will fail to destroy the menu window.  */
+
+      if (dpyinfo->supports_xi2
+         && xi_frame_selected_for (f, XI_ButtonPress))
+       {
+         for (int i = 0; i < dpyinfo->num_devices; ++i)
+           {
+             /* The keyboard grab matters too, in this specific
+                case.  */
+#ifndef USE_LUCID
+             if (dpyinfo->devices[i].grab)
+#endif
+               {
+                 XIUngrabDevice (dpyinfo->display,
+                                 dpyinfo->devices[i].device_id,
+                                 CurrentTime);
+                 dpyinfo->devices[i].grab = 0;
+               }
+           }
+       }
+#endif
+
       x_catch_errors (FRAME_X_DISPLAY (f));
       memset (&ev, 0, sizeof ev);
       ev.xbutton.display = FRAME_X_DISPLAY (f);
       ev.xbutton.window = XtWindow (menubar);
       ev.xbutton.root = FRAME_DISPLAY_INFO (f)->root_window;
+#ifndef HAVE_XINPUT2
       ev.xbutton.time = XtLastTimestampProcessed (FRAME_X_DISPLAY (f));
+#else
+      ev.xbutton.time = ((dpyinfo->supports_xi2
+                         && xi_frame_selected_for (f, XI_KeyPress))
+                        ? dpyinfo->last_user_time
+                        : XtLastTimestampProcessed (dpyinfo->display));
+#endif
       ev.xbutton.button = Button1;
       ev.xbutton.x = ev.xbutton.y = FRAME_MENUBAR_HEIGHT (f) / 2;
       ev.xbutton.same_screen = True;
diff --git a/src/xterm.c b/src/xterm.c
index 1b1074b2f4..8b813210b7 100644
--- a/src/xterm.c
+++ b/src/xterm.c
@@ -13833,10 +13833,10 @@ handle_one_xevent (struct x_display_info *dpyinfo,
   XEvent configureEvent;
   XEvent next_event;
   Lisp_Object coding;
-#if defined USE_MOTIF && defined HAVE_XINPUT2
-  /* 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.  */
+#if defined USE_X_TOOLKIT && defined HAVE_XINPUT2
+  /* Some XInput 2 events are important for Motif and Lucid menu bars
+     to work correctly, so they must be translated into core events
+     before being passed to XtDispatchEvent.  */
   bool use_copy = false;
   XEvent copy;
 #elif defined USE_GTK && !defined HAVE_GTK3 && defined HAVE_XINPUT2
@@ -17746,7 +17746,41 @@ handle_one_xevent (struct x_display_info *dpyinfo,
 #if defined (USE_X_TOOLKIT) || defined (USE_GTK)
              /* Dispatch XI_KeyPress events when in menu.  */
              if (popup_activated ())
-               goto XI_OTHER;
+               {
+#ifdef USE_LUCID
+                 /* This makes key navigation work inside menus.  */
+                 use_copy = true;
+                 copy.xkey.type = KeyPress;
+                 copy.xkey.serial = xev->serial;
+                 copy.xkey.send_event = xev->send_event;
+                 copy.xkey.display = dpyinfo->display;
+                 copy.xkey.window = xev->event;
+                 copy.xkey.root = xev->root;
+                 copy.xkey.subwindow = xev->child;
+                 copy.xkey.time = xev->time;
+                 copy.xkey.state = ((xev->mods.effective & ~(1 << 13 | 1 << 
14))
+                                    | (xev->group.effective << 13));
+
+                 copy.xkey.x = lrint (xev->event_x);
+                 copy.xkey.y = lrint (xev->event_y);
+                 copy.xkey.x_root = lrint (xev->root_x);
+                 copy.xkey.y_root = lrint (xev->root_y);
+
+                 if (xev->buttons.mask_len)
+                   {
+                     if (XIMaskIsSet (xev->buttons.mask, 1))
+                       copy.xkey.state |= Button1Mask;
+                     if (XIMaskIsSet (xev->buttons.mask, 2))
+                       copy.xkey.state |= Button2Mask;
+                     if (XIMaskIsSet (xev->buttons.mask, 3))
+                       copy.xkey.state |= Button3Mask;
+                   }
+
+                 copy.xkey.keycode = xev->detail;
+                 copy.xkey.same_screen = True;
+#endif
+                 goto XI_OTHER;
+               }
 #endif
 
              x_display_set_last_user_time (dpyinfo, xev->time);
@@ -18193,7 +18227,7 @@ handle_one_xevent (struct x_display_info *dpyinfo,
 #endif
 
          case XI_KeyRelease:
-#if defined HAVE_X_I18N || defined USE_GTK
+#if defined HAVE_X_I18N || defined USE_GTK || defined USE_LUCID
            {
              XKeyPressedEvent xkey;
 
@@ -18229,14 +18263,31 @@ handle_one_xevent (struct x_display_info *dpyinfo,
              xkey.keycode = xev->detail;
              xkey.same_screen = True;
 
+#ifdef USE_LUCID
+             if (!popup_activated ())
+               {
+#endif
 #ifdef HAVE_X_I18N
-             if (x_filter_event (dpyinfo, (XEvent *) &xkey))
-               *finish = X_EVENT_DROP;
-#else
-             f = x_any_window_to_frame (xkey->event);
+                 if (x_filter_event (dpyinfo, (XEvent *) &xkey))
+                   *finish = X_EVENT_DROP;
+#elif defined USE_GTK
+                 f = x_any_window_to_frame (xkey->event);
 
-             if (f && xg_filter_key (f, event))
-               *finish = X_EVENT_DROP;
+                 if (f && xg_filter_key (f, event))
+                   *finish = X_EVENT_DROP;
+#endif
+#ifdef USE_LUCID
+               }
+             else
+               {
+                 /* FIXME: the Lucid menu bar pops down upon any key
+                    release event, so we don't dispatch these events
+                    at all, which doesn't seem to be the right
+                    solution.
+
+                    use_copy = true;
+                    copy.xkey = xkey; */
+               }
 #endif
            }
 #endif
@@ -19009,12 +19060,12 @@ handle_one_xevent (struct x_display_info *dpyinfo,
        {
          /* Ignore some obviously bogus ConfigureNotify events that
             other clients have been known to send Emacs.
-            (bug#54051)*/
+            (bug#54051) */
          if (event->type != ConfigureNotify
              || (event->xconfigure.width != 0
                  && event->xconfigure.height != 0))
            {
-#if defined USE_MOTIF && defined HAVE_XINPUT2
+#if defined USE_X_TOOLKIT && defined HAVE_XINPUT2
              XtDispatchEvent (use_copy ? &copy : (XEvent *) event);
 #else
              XtDispatchEvent ((XEvent *) event);



reply via email to

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