{
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
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. */
LWLIB_ID menu_id;
Widget menu;
Window dummy_window;
+#ifdef HAVE_XINPUT2
+ XEvent property_dummy;
+ Atom property_atom;
+#endif
eassert (FRAME_X_P (f));
}
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);
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
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;
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)
{
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. */
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 */