1
0
mirror of https://git.savannah.gnu.org/git/emacs.git synced 2025-01-01 11:14:55 +00:00

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'.
This commit is contained in:
Po Lu 2022-08-08 11:44:53 +08:00
parent 7dab52dfbc
commit 16b8948d79
3 changed files with 186 additions and 54 deletions

View File

@ -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);

View File

@ -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))

View File

@ -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