diff options
| author | Po Lu | 2022-02-27 10:37:17 +0800 |
|---|---|---|
| committer | Po Lu | 2022-02-27 10:37:43 +0800 |
| commit | 16702f183f34cba880a04e08db9d6b644b38b424 (patch) | |
| tree | eb207e70aaeeae2d49bf2d31256c252e51c144ff /src | |
| parent | a2768c2f745eb4203a006ad86d6cccd160c7a3c8 (diff) | |
| download | emacs-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.c | 70 | ||||
| -rw-r--r-- | src/xterm.c | 49 |
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 | ||
| 1518 | static Bool | ||
| 1519 | server_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 ? © : (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 */ |