aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorPo Lu2022-02-27 10:37:17 +0800
committerPo Lu2022-02-27 10:37:43 +0800
commit16702f183f34cba880a04e08db9d6b644b38b424 (patch)
treeeb207e70aaeeae2d49bf2d31256c252e51c144ff /src
parenta2768c2f745eb4203a006ad86d6cccd160c7a3c8 (diff)
downloademacs-16702f183f34cba880a04e08db9d6b644b38b424.tar.gz
emacs-16702f183f34cba880a04e08db9d6b644b38b424.zip
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.
Diffstat (limited to 'src')
-rw-r--r--src/xmenu.c70
-rw-r--r--src/xterm.c49
2 files changed, 104 insertions, 15 deletions
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)
572 { 572 {
573 for (int i = 0; i < dpyinfo->num_devices; ++i) 573 for (int i = 0; i < dpyinfo->num_devices; ++i)
574 { 574 {
575#ifndef USE_MOTIF
576 if (dpyinfo->devices[i].grab) 575 if (dpyinfo->devices[i].grab)
577#endif 576 {
578 XIUngrabDevice (dpyinfo->display, dpyinfo->devices[i].device_id, 577 XIUngrabDevice (dpyinfo->display, dpyinfo->devices[i].device_id,
579 CurrentTime); 578 CurrentTime);
579 }
580 } 580 }
581 } 581 }
582#endif 582#endif
@@ -1514,6 +1514,23 @@ pop_down_menu (int id)
1514 popup_activated_flag = 0; 1514 popup_activated_flag = 0;
1515} 1515}
1516 1516
1517#ifdef HAVE_XINPUT2
1518static Bool
1519server_timestamp_predicate (Display *display,
1520 XEvent *xevent,
1521 XPointer arg)
1522{
1523 XID *args = (XID *) arg;
1524
1525 if (xevent->type == PropertyNotify
1526 && xevent->xproperty.window == args[0]
1527 && xevent->xproperty.atom == args[1])
1528 return True;
1529
1530 return False;
1531}
1532#endif
1533
1517/* Pop up the menu for frame F defined by FIRST_WV at X/Y and loop until the 1534/* Pop up the menu for frame F defined by FIRST_WV at X/Y and loop until the
1518 menu pops down. 1535 menu pops down.
1519 menu_item_selection will be set to the selection. */ 1536 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,
1529 LWLIB_ID menu_id; 1546 LWLIB_ID menu_id;
1530 Widget menu; 1547 Widget menu;
1531 Window dummy_window; 1548 Window dummy_window;
1549#ifdef HAVE_XINPUT2
1550 XEvent property_dummy;
1551 Atom property_atom;
1552#endif
1532 1553
1533 eassert (FRAME_X_P (f)); 1554 eassert (FRAME_X_P (f));
1534 1555
@@ -1609,14 +1630,37 @@ create_and_show_popup_menu (struct frame *f, widget_value *first_wv,
1609 } 1630 }
1610 1631
1611 if (any_xi_grab_p) 1632 if (any_xi_grab_p)
1612 XGrabPointer (dpyinfo->display, 1633 {
1613 FRAME_X_WINDOW (f), 1634#ifndef USE_MOTIF
1614 False, (PointerMotionMask 1635 XGrabPointer (dpyinfo->display,
1615 | PointerMotionHintMask 1636 FRAME_X_WINDOW (f),
1616 | ButtonReleaseMask 1637 False, (PointerMotionMask
1617 | ButtonPressMask), 1638 | PointerMotionHintMask
1618 GrabModeSync, GrabModeAsync, 1639 | ButtonReleaseMask
1619 None, None, CurrentTime); 1640 | ButtonPressMask),
1641 GrabModeSync, GrabModeAsync,
1642 None, None, CurrentTime);
1643#endif
1644 }
1645
1646 if (dpyinfo->supports_xi2)
1647 {
1648 /* Dispatch a PropertyNotify to Xt with the current server time.
1649 Motif tries to set a grab with the timestamp of the last event
1650 processed by Xt, but Xt doesn't consider GenericEvents, so the
1651 timestamp is always less than the last grab time. */
1652
1653 property_atom = XInternAtom (dpyinfo->display, "EMACS_SERVER_TIME_PROP", False);
1654
1655 XChangeProperty (dpyinfo->display, FRAME_OUTER_WINDOW (f),
1656 property_atom, XA_ATOM, 32,
1657 PropModeReplace, (unsigned char *) &property_atom, 1);
1658
1659 XIfEvent (dpyinfo->display, &property_dummy, server_timestamp_predicate,
1660 (XPointer) &(XID[]) {(XID) FRAME_OUTER_WINDOW (f), (XID) property_atom});
1661
1662 XtDispatchEvent (&property_dummy);
1663 }
1620 1664
1621 if (dpyinfo->supports_xi2) 1665 if (dpyinfo->supports_xi2)
1622 XUngrabServer (dpyinfo->display); 1666 XUngrabServer (dpyinfo->display);
@@ -1626,7 +1670,7 @@ create_and_show_popup_menu (struct frame *f, widget_value *first_wv,
1626 lw_popup_menu (menu, &dummy); 1670 lw_popup_menu (menu, &dummy);
1627 popup_activated_flag = 1; 1671 popup_activated_flag = 1;
1628 1672
1629#ifdef HAVE_XINPUT2 1673#if defined HAVE_XINPUT2 && !defined USE_MOTIF
1630 if (any_xi_grab_p) 1674 if (any_xi_grab_p)
1631 XAllowEvents (dpyinfo->display, AsyncPointer, CurrentTime); 1675 XAllowEvents (dpyinfo->display, AsyncPointer, CurrentTime);
1632#endif 1676#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,
9513 XEvent configureEvent; 9513 XEvent configureEvent;
9514 XEvent next_event; 9514 XEvent next_event;
9515 Lisp_Object coding; 9515 Lisp_Object coding;
9516#ifdef USE_MOTIF
9517 /* Some XInput 2 events are important for Motif menu bars to work
9518 correctly, so they must be translated into core events before
9519 being passed to XtDispatchEvent. */
9520 bool use_copy = false;
9521 XEvent copy;
9522#endif
9516 9523
9517 *finish = X_EVENT_NORMAL; 9524 *finish = X_EVENT_NORMAL;
9518 9525
@@ -10924,7 +10931,7 @@ handle_one_xevent (struct x_display_info *dpyinfo,
10924 x_display_set_last_user_time (dpyinfo, event->xbutton.time); 10931 x_display_set_last_user_time (dpyinfo, event->xbutton.time);
10925 10932
10926#ifdef HAVE_XWIDGETS 10933#ifdef HAVE_XWIDGETS
10927 struct xwidget_view *xvw = xwidget_view_from_window (event->xmotion.window); 10934 struct xwidget_view *xvw = xwidget_view_from_window (event->xbutton.window);
10928 10935
10929 if (xvw) 10936 if (xvw)
10930 { 10937 {
@@ -11659,6 +11666,38 @@ handle_one_xevent (struct x_display_info *dpyinfo,
11659 struct xwidget_view *xvw; 11666 struct xwidget_view *xvw;
11660#endif 11667#endif
11661 11668
11669#ifdef USE_MOTIF
11670 if (popup_activated ())
11671 {
11672 use_copy = true;
11673 copy.xbutton.type = ButtonRelease;
11674 copy.xbutton.serial = xev->serial;
11675 copy.xbutton.send_event = xev->send_event;
11676 copy.xbutton.display = dpyinfo->display;
11677 copy.xbutton.window = xev->event;
11678 copy.xbutton.root = xev->root;
11679 copy.xbutton.subwindow = xev->child;
11680 copy.xbutton.time = xev->time;
11681 copy.xbutton.x = lrint (xev->event_x);
11682 copy.xbutton.y = lrint (xev->event_y);
11683 copy.xbutton.x_root = lrint (xev->root_x);
11684 copy.xbutton.y_root = lrint (xev->root_y);
11685 copy.xbutton.state = xev->mods.effective;
11686 copy.xbutton.button = xev->detail;
11687 copy.xbutton.same_screen = True;
11688
11689 if (xev->buttons.mask_len)
11690 {
11691 if (XIMaskIsSet (xev->buttons.mask, 1))
11692 copy.xbutton.state |= Button1Mask;
11693 if (XIMaskIsSet (xev->buttons.mask, 2))
11694 copy.xbutton.state |= Button2Mask;
11695 if (XIMaskIsSet (xev->buttons.mask, 3))
11696 copy.xbutton.state |= Button3Mask;
11697 }
11698 }
11699#endif
11700
11662#ifdef HAVE_XINPUT2_1 11701#ifdef HAVE_XINPUT2_1
11663 /* Ignore emulated scroll events when XI2 native 11702 /* Ignore emulated scroll events when XI2 native
11664 scroll events are present. */ 11703 scroll events are present. */
@@ -12699,7 +12738,13 @@ handle_one_xevent (struct x_display_info *dpyinfo,
12699 if (event->type != ConfigureNotify 12738 if (event->type != ConfigureNotify
12700 || (event->xconfigure.width != 0 12739 || (event->xconfigure.width != 0
12701 && event->xconfigure.height != 0)) 12740 && event->xconfigure.height != 0))
12702 XtDispatchEvent ((XEvent *) event); 12741 {
12742#ifdef USE_MOTIF
12743 XtDispatchEvent (use_copy ? &copy : (XEvent *) event);
12744#else
12745 XtDispatchEvent ((XEvent *) event);
12746#endif
12747 }
12703 } 12748 }
12704 unblock_input (); 12749 unblock_input ();
12705#endif /* USE_X_TOOLKIT */ 12750#endif /* USE_X_TOOLKIT */