block_input ();
- XQueryPointer (FRAME_X_DISPLAY (f),
- FRAME_DISPLAY_INFO (f)->root_window,
+ x_query_pointer (FRAME_X_DISPLAY (f),
+ FRAME_DISPLAY_INFO (f)->root_window,
- /* The root window which contains the pointer. */
- &root,
+ /* The root window which contains the pointer. */
+ &root,
- /* Window pointer is on, not used */
- &dummy_window,
+ /* Window pointer is on, not used */
+ &dummy_window,
- /* The position on that root window. */
- x, y,
+ /* The position on that root window. */
+ x, y,
- /* x/y in dummy_window coordinates, not used. */
- &dummy, &dummy,
+ /* x/y in dummy_window coordinates, not used. */
+ &dummy, &dummy,
- /* Modifier keys and pointer buttons, about which
- we don't care. */
- (unsigned int *) &dummy);
+ /* Modifier keys and pointer buttons, about which
+ we don't care. */
+ (unsigned int *) &dummy);
XTranslateCoordinates (FRAME_X_DISPLAY (f),
return Qnil;
block_input ();
- XQueryPointer (FRAME_X_DISPLAY (f),
- FRAME_DISPLAY_INFO (f)->root_window,
- &root, &dummy_window, &x, &y, &dummy, &dummy,
- (unsigned int *) &dummy);
+ x_query_pointer (FRAME_X_DISPLAY (f),
+ FRAME_DISPLAY_INFO (f)->root_window,
+ &root, &dummy_window, &x, &y, &dummy, &dummy,
+ (unsigned int *) &dummy);
unblock_input ();
return Fcons (make_fixnum (x), make_fixnum (y));
Lisp_Object frame, attributes, monitor, geometry;
block_input ();
- XQueryPointer (FRAME_X_DISPLAY (f), FRAME_DISPLAY_INFO (f)->root_window,
- &root, &child, root_x, root_y, &win_x, &win_y, &pmask);
+ x_query_pointer (FRAME_X_DISPLAY (f), FRAME_DISPLAY_INFO (f)->root_window,
+ &root, &child, root_x, root_y, &win_x, &win_y, &pmask);
unblock_input ();
XSETFRAME (frame, f);
xi_device->direct_p = false;
#endif
xi_device->name = build_string (device->name);
+ xi_device->attachment = device->attachment;
for (c = 0; c < device->num_classes; ++c)
{
focus is switched to a given frame. This situation is handled by
keeping track of each master device's focus frame, the time of the
last interaction with that frame, and always keeping the focus on
- the most recently selected frame. */
+ the most recently selected frame. We also use the pointer of the
+ device that is keeping the current frame focused in functions like
+ `mouse-position'. */
static void
xi_handle_focus_change (struct x_display_info *dpyinfo)
new = NULL;
time = 0;
+ dpyinfo->client_pointer_device = -1;
+
for (i = 0; i < dpyinfo->num_devices; ++i)
{
device = &dpyinfo->devices[i];
new = device->focus_frame;
time = device->focus_frame_time;
source = device;
+
+ /* Use this device for future calls to `mouse-position' etc.
+ If it is a keyboard, use its attached pointer. */
+
+ if (device->use == XIMasterKeyboard)
+ dpyinfo->client_pointer_device = device->attachment;
+ else
+ dpyinfo->client_pointer_device = device->device_id;
}
if (device->focus_implicit_frame
new = device->focus_implicit_frame;
time = device->focus_implicit_time;
source = device;
+
+ /* Use this device for future calls to `mouse-position' etc.
+ If it is a keyboard, use its attached pointer. */
+
+ if (device->use == XIMasterKeyboard)
+ dpyinfo->client_pointer_device = device->attachment;
+ else
+ dpyinfo->client_pointer_device = device->device_id;
}
}
if (!event->focus)
break;
+ if (device->use == XIMasterPointer)
+ device = xi_device_from_id (dpyinfo, device->attachment);
+
+ if (!device)
+ break;
+
device->focus_implicit_frame = mentioned_frame;
device->focus_implicit_time = event->time;
break;
if (!event->focus)
break;
+ if (device->use == XIMasterPointer)
+ device = xi_device_from_id (dpyinfo, device->attachment);
+
+ if (!device)
+ break;
+
device->focus_implicit_frame = NULL;
break;
}
{
bool change;
+ /* If DEVICE is a pointer, use its attached keyboard device. */
+ if (device->use == XIMasterPointer)
+ device = xi_device_from_id (dpyinfo, device->attachment);
+
+ if (!device)
+ return;
+
change = false;
if (device->focus_frame == f)
return value;
}
+/* Like XQueryPointer, but always use the right client pointer
+ device. */
+
+Bool
+x_query_pointer (Display *dpy, Window w, Window *root_return,
+ Window *child_return, int *root_x_return,
+ int *root_y_return, int *win_x_return,
+ int *win_y_return, unsigned int *mask_return)
+{
+ struct x_display_info *dpyinfo;
+ Bool rc;
+ bool had_errors;
+#ifdef HAVE_XINPUT2
+ XIModifierState modifiers;
+ XIButtonState buttons;
+ XIGroupState group; /* Unused. */
+ double root_x, root_y, win_x, win_y;
+ unsigned int state;
+#endif
+
+ dpyinfo = x_display_info_for_display (dpy);
+#ifdef HAVE_XINPUT2
+ if (dpyinfo && dpyinfo->client_pointer_device != -1)
+ {
+ /* Catch errors caused by the device going away. This is not
+ very expensive, since XIQueryPointer will sync anyway. */
+ x_catch_errors (dpy);
+ rc = XIQueryPointer (dpyinfo->display,
+ dpyinfo->client_pointer_device,
+ w, root_return, child_return,
+ &root_x, &root_y, &win_x, &win_y,
+ &buttons, &modifiers, &group);
+ had_errors = x_had_errors_p (dpy);
+ x_uncatch_errors_after_check ();
+
+ if (had_errors)
+ rc = XQueryPointer (dpyinfo->display, w, root_return,
+ child_return, root_x_return,
+ root_y_return, win_x_return,
+ win_y_return, mask_return);
+ else
+ {
+ state = 0;
+
+ xi_convert_button_state (&buttons, &state);
+ *mask_return = state | modifiers.effective;
+
+ *root_x_return = lrint (root_x);
+ *root_y_return = lrint (root_y);
+ *win_x_return = lrint (win_x);
+ *win_y_return = lrint (win_y);
+ }
+ }
+ else
+#endif
+ rc = XQueryPointer (dpy, w, root_return, child_return,
+ root_x_return, root_y_return, win_x_return,
+ win_y_return, mask_return);
+
+ return rc;
+}
+
/* Mouse clicks and mouse movement. Rah.
Formerly, we used PointerMotionHintMask (in standard_event_mask)
dpyinfo->last_mouse_scroll_bar = NULL;
/* Figure out which root window we're on. */
- XQueryPointer (FRAME_X_DISPLAY (*fp),
- DefaultRootWindow (FRAME_X_DISPLAY (*fp)),
- /* The root window which contains the pointer. */
- &root,
- /* Trash which we can't trust if the pointer is on
- a different screen. */
- &dummy_window,
- /* The position on that root window. */
- &root_x, &root_y,
- /* More trash we can't trust. */
- &dummy, &dummy,
- /* Modifier keys and pointer buttons, about which
- we don't care. */
- (unsigned int *) &dummy);
+ x_query_pointer (FRAME_X_DISPLAY (*fp),
+ DefaultRootWindow (FRAME_X_DISPLAY (*fp)),
+ /* The root window which contains the pointer. */
+ &root,
+ /* Trash which we can't trust if the pointer is on
+ a different screen. */
+ &dummy_window,
+ /* The position on that root window. */
+ &root_x, &root_y,
+ /* More trash we can't trust. */
+ &dummy, &dummy,
+ /* Modifier keys and pointer buttons, about which
+ we don't care. */
+ (unsigned int *) &dummy);
/* Now we have a position on the root; find the innermost window
containing the pointer. */
/* Get the mouse's position relative to the scroll bar window, and
report that. */
- if (XQueryPointer (FRAME_X_DISPLAY (f), w,
+ if (x_query_pointer (FRAME_X_DISPLAY (f), w,
- /* Root, child, root x and root y. */
- &dummy_window, &dummy_window,
- &dummy_coord, &dummy_coord,
+ /* Root, child, root x and root y. */
+ &dummy_window, &dummy_window,
+ &dummy_coord, &dummy_coord,
- /* Position relative to scroll bar. */
- &win_x, &win_y,
+ /* Position relative to scroll bar. */
+ &win_x, &win_y,
- /* Mouse buttons and modifier keys. */
- &dummy_mask))
+ /* Mouse buttons and modifier keys. */
+ &dummy_mask))
{
int top_range = VERTICAL_SCROLL_BAR_TOP_RANGE (f, bar->height);
/* Get the mouse's position relative to the scroll bar window, and
report that. */
- if (XQueryPointer (FRAME_X_DISPLAY (f), w,
+ if (x_query_pointer (FRAME_X_DISPLAY (f), w,
- /* Root, child, root x and root y. */
- &dummy_window, &dummy_window,
- &dummy_coord, &dummy_coord,
+ /* Root, child, root x and root y. */
+ &dummy_window, &dummy_window,
+ &dummy_coord, &dummy_coord,
- /* Position relative to scroll bar. */
- &win_x, &win_y,
+ /* Position relative to scroll bar. */
+ &win_x, &win_y,
- /* Mouse buttons and modifier keys. */
- &dummy_mask))
+ /* Mouse buttons and modifier keys. */
+ &dummy_mask))
{
int left_range = HORIZONTAL_SCROLL_BAR_LEFT_RANGE (f, bar->width);
if (info)
{
if (device && info->enabled)
- device->use = info->use;
+ {
+ device->use = info->use;
+ device->attachment = info->attachment;
+ }
else if (device)
disabled[n_disabled++] = hev->info[i].deviceid;
int minor = 0;
#endif
+ dpyinfo->client_pointer_device = -1;
+
if (XQueryExtension (dpyinfo->display, "XInputExtension",
&dpyinfo->xi2_opcode, &xi_first_event,
&xi_first_error))
/* Whether or not the device is grabbed and its use. */
int grab, use;
+ /* The attached device. Only valid if USE is some kind of master
+ device. */
+ int attachment;
+
#ifdef HAVE_XINPUT2_2
/* Whether or not this device is a direct touch device. */
bool direct_p;
#ifdef HAVE_XINPUT2
bool supports_xi2;
+
+ /* The minor version of the input extension. (Major is always
+ 2.x.) */
int xi2_version;
+
+ /* The generic event opcode of XI2 events. */
int xi2_opcode;
+ /* The number of devices on this display known to Emacs. */
int num_devices;
+
+ /* Array of all input extension devices on this display known to
+ Emacs. */
struct xi_device_t *devices;
+ /* Pending keystroke time. */
Time pending_keystroke_time;
+
+ /* Pending keystroke source. If a core KeyPress event arrives with
+ the same timestamp as pending_keystroke_time, it will be treated
+ as originating from this device. */
int pending_keystroke_source;
#if defined USE_GTK && !defined HAVE_GTK3
input method) core key event. */
bool pending_keystroke_time_special_p;
#endif
+
+ /* The client pointer. We keep a record client-side to avoid
+ calling XISetClientPointer all the time. */
+ int client_pointer_device;
#endif
#ifdef HAVE_XKB
#ifdef HAVE_XRENDER
extern void x_xrender_color_from_gc_background (struct frame *, GC,
XRenderColor *, bool);
-extern void x_xr_ensure_picture (struct frame *f);
-extern void x_xr_apply_ext_clip (struct frame *f, GC gc);
-extern void x_xr_reset_ext_clip (struct frame *f);
+extern void x_xr_ensure_picture (struct frame *);
+extern void x_xr_apply_ext_clip (struct frame *, GC);
+extern void x_xr_reset_ext_clip (struct frame *);
#endif
+extern Bool x_query_pointer (Display *, Window, Window *, Window *, int *,
+ int *, int *, int *, unsigned int *);
+
#ifdef HAVE_GTK3
extern void x_scroll_bar_configure (GdkEvent *);
#endif