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:
parent
7dab52dfbc
commit
16b8948d79
38
src/xfns.c
38
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);
|
||||
|
171
src/xterm.c
171
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))
|
||||
|
31
src/xterm.h
31
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
|
||||
|
Loading…
Reference in New Issue
Block a user