[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
master 16b8948d79: Improve handling of pointer focus under the input ext
From: |
Po Lu |
Subject: |
master 16b8948d79: Improve handling of pointer focus under the input extension |
Date: |
Sun, 7 Aug 2022 23:45:48 -0400 (EDT) |
branch: master
commit 16b8948d79e27a37d223eb171c21e6b78d8b5a7a
Author: Po Lu <luangruo@yahoo.com>
Commit: Po Lu <luangruo@yahoo.com>
Improve handling of pointer focus under the input extension
* src/xfns.c (x_relative_mouse_position)
(Fx_mouse_absolute_pixel_position, compute_tip_xy): Use
x_query_pointer instead of XQueryPointer.
* src/xterm.c (xi_populate_device_from_info): Set new attachment
field.
(xi_handle_focus_change): Set client pointer.
(xi_focus_handle_for_device, xi_handle_interaction): Use
attached keyboard device to handle focus.
(x_query_pointer): New function.
(XTmouse_position, x_scroll_bar_report_motion)
(x_horizontal_scroll_bar_report_motion, handle_one_xevent): Use
x_query_pointer instead of XQueryPointer.
(x_term_init): Initialize client pointer device.
* src/xterm.h (struct xi_device_t): New field `attachment'.
(struct x_display_info): New field `client_pointer_device'.
---
src/xfns.c | 38 +++++++-------
src/xterm.c | 171 ++++++++++++++++++++++++++++++++++++++++++++++++------------
src/xterm.h | 31 +++++++++--
3 files changed, 186 insertions(+), 54 deletions(-)
diff --git a/src/xfns.c b/src/xfns.c
index 672097c0d8..2845ecca6a 100644
--- a/src/xfns.c
+++ b/src/xfns.c
@@ -609,24 +609,24 @@ x_relative_mouse_position (struct frame *f, int *x, int
*y)
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),
@@ -6823,10 +6823,10 @@ selected frame's display. */)
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));
@@ -8382,8 +8382,8 @@ compute_tip_xy (struct frame *f, Lisp_Object parms,
Lisp_Object dx,
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);
diff --git a/src/xterm.c b/src/xterm.c
index 54bf656657..c1f74f6866 100644
--- a/src/xterm.c
+++ b/src/xterm.c
@@ -5291,6 +5291,7 @@ xi_populate_device_from_info (struct xi_device_t
*xi_device,
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)
{
@@ -12474,7 +12475,9 @@ x_dnd_begin_drag_and_drop (struct frame *f, Time time,
Atom xaction,
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)
@@ -12493,6 +12496,8 @@ 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];
@@ -12503,6 +12508,14 @@ xi_handle_focus_change (struct x_display_info *dpyinfo)
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
@@ -12511,6 +12524,14 @@ xi_handle_focus_change (struct x_display_info *dpyinfo)
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;
}
}
@@ -12601,6 +12622,12 @@ xi_focus_handle_for_device (struct x_display_info
*dpyinfo,
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;
@@ -12609,6 +12636,12 @@ xi_focus_handle_for_device (struct x_display_info
*dpyinfo,
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;
}
@@ -12646,6 +12679,13 @@ xi_handle_interaction (struct x_display_info *dpyinfo,
{
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)
@@ -13042,6 +13082,68 @@ get_keysym_name (int keysym)
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)
@@ -13308,20 +13410,20 @@ XTmouse_position (struct frame **fp, int insist,
Lisp_Object *bar_window,
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. */
@@ -15894,17 +15996,17 @@ x_scroll_bar_report_motion (struct frame **fp,
Lisp_Object *bar_window,
/* 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);
@@ -15963,17 +16065,17 @@ x_horizontal_scroll_bar_report_motion (struct frame
**fp, Lisp_Object *bar_windo
/* 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);
@@ -22202,7 +22304,10 @@ handle_one_xevent (struct x_display_info *dpyinfo,
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;
@@ -27816,6 +27921,8 @@ x_term_init (Lisp_Object display_name, char
*xrm_option, char *resource_name)
int minor = 0;
#endif
+ dpyinfo->client_pointer_device = -1;
+
if (XQueryExtension (dpyinfo->display, "XInputExtension",
&dpyinfo->xi2_opcode, &xi_first_event,
&xi_first_error))
diff --git a/src/xterm.h b/src/xterm.h
index 7be0f2ede6..e97f3d4c83 100644
--- a/src/xterm.h
+++ b/src/xterm.h
@@ -249,6 +249,10 @@ struct xi_device_t
/* 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;
@@ -708,13 +712,27 @@ struct x_display_info
#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
@@ -724,6 +742,10 @@ struct x_display_info
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
@@ -1599,11 +1621,14 @@ extern Lisp_Object x_cr_export_frames (Lisp_Object,
cairo_surface_type_t);
#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
[Prev in Thread] |
Current Thread |
[Next in Thread] |
- master 16b8948d79: Improve handling of pointer focus under the input extension,
Po Lu <=