From: Po Lu Date: Sun, 27 Feb 2022 02:37:17 +0000 (+0800) Subject: Fix Motif menu and menu bar dismissal on XI2 X-Git-Tag: emacs-29.0.90~2099 X-Git-Url: http://git.eshelyaron.com/gitweb/?a=commitdiff_plain;h=16702f183f34cba880a04e08db9d6b644b38b424;p=emacs.git 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. --- diff --git a/src/xmenu.c b/src/xmenu.c index 21e8f0f9ec7..2bc9f5a93a0 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 040397777b6..33a6613e145 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 ? © : (XEvent *) event); +#else + XtDispatchEvent ((XEvent *) event); +#endif + } } unblock_input (); #endif /* USE_X_TOOLKIT */