aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPo Lu2022-08-05 10:18:18 +0800
committerPo Lu2022-08-05 10:18:18 +0800
commit0dbe0fd4104f4a58908324c1ead365461a4daa16 (patch)
tree1df736fccd0f7ddc0df1628fc7ccfd56bc1b87bf
parent8ea7506d724903008910bc47e88212da55549ede (diff)
downloademacs-0dbe0fd4104f4a58908324c1ead365461a4daa16.tar.gz
emacs-0dbe0fd4104f4a58908324c1ead365461a4daa16.zip
Improve input extension focus handling with multiple master devices
* src/xterm.c (x_cache_xi_devices): Initialize device fields to 0. (xi_handle_focus_change, xi_focus_handle_for_device) (xi_handle_delete_frame): New functions; store focus information per-device instead. (x_detect_focus_change): Handle GenericEvents that way instead. (handle_one_xevent): Don't cache XI devices on DeviceChanged. (x_free_frame_resources): Clear any frame focus information. * src/xterm.h (struct xi_device_t): New fields for focus tracking. Add comments describing fields.
-rw-r--r--src/xterm.c235
-rw-r--r--src/xterm.h36
2 files changed, 226 insertions, 45 deletions
diff --git a/src/xterm.c b/src/xterm.c
index 2a453099ee7..ebd27aea069 100644
--- a/src/xterm.c
+++ b/src/xterm.c
@@ -5394,7 +5394,7 @@ xi_populate_device_from_info (struct xi_device_t *xi_device,
5394static void 5394static void
5395x_cache_xi_devices (struct x_display_info *dpyinfo) 5395x_cache_xi_devices (struct x_display_info *dpyinfo)
5396{ 5396{
5397 int ndevices, actual_devices; 5397 int ndevices, actual_devices, i;
5398 XIDeviceInfo *infos; 5398 XIDeviceInfo *infos;
5399 5399
5400 actual_devices = 0; 5400 actual_devices = 0;
@@ -5411,9 +5411,9 @@ x_cache_xi_devices (struct x_display_info *dpyinfo)
5411 return; 5411 return;
5412 } 5412 }
5413 5413
5414 dpyinfo->devices = xmalloc (sizeof *dpyinfo->devices * ndevices); 5414 dpyinfo->devices = xzalloc (sizeof *dpyinfo->devices * ndevices);
5415 5415
5416 for (int i = 0; i < ndevices; ++i) 5416 for (i = 0; i < ndevices; ++i)
5417 { 5417 {
5418 if (infos[i].enabled) 5418 if (infos[i].enabled)
5419 xi_populate_device_from_info (&dpyinfo->devices[actual_devices++], 5419 xi_populate_device_from_info (&dpyinfo->devices[actual_devices++],
@@ -12446,6 +12446,178 @@ x_dnd_begin_drag_and_drop (struct frame *f, Time time, Atom xaction,
12446 return unbind_to (base, Qnil); 12446 return unbind_to (base, Qnil);
12447} 12447}
12448 12448
12449#ifdef HAVE_XINPUT2
12450
12451/* Since the input extension assigns a keyboard focus to each master
12452 device, there is no longer a 1:1 correspondence between the
12453 selected frame and the focus frame immediately after the keyboard
12454 focus is switched to a given frame. This situation is handled by
12455 keeping track of each master device's focus frame, the time of the
12456 last interaction with that frame, and always keeping the focus on
12457 the most recently selected frame. */
12458
12459static void
12460xi_handle_focus_change (struct x_display_info *dpyinfo)
12461{
12462 struct input_event ie;
12463 struct frame *focus, *new;
12464 struct xi_device_t *device, *source;
12465 ptrdiff_t i;
12466 Time time;
12467#ifdef USE_GTK
12468 struct x_output *output;
12469 GtkWidget *widget;
12470#endif
12471
12472 focus = dpyinfo->x_focus_frame;
12473 new = NULL;
12474 time = 0;
12475
12476 for (i = 0; i < dpyinfo->num_devices; ++i)
12477 {
12478 device = &dpyinfo->devices[i];
12479
12480 if (device->focus_frame
12481 && device->focus_frame_time > time)
12482 {
12483 new = device->focus_frame;
12484 time = device->focus_frame_time;
12485 source = device;
12486 }
12487
12488 if (device->focus_implicit_frame
12489 && device->focus_implicit_time > time)
12490 {
12491 new = device->focus_implicit_frame;
12492 time = device->focus_implicit_time;
12493 source = device;
12494 }
12495 }
12496
12497 if (new != focus && focus)
12498 {
12499#ifdef HAVE_X_I18N
12500 if (FRAME_XIC (focus))
12501 XUnsetICFocus (FRAME_XIC (focus));
12502#endif
12503
12504#ifdef USE_GTK
12505 output = FRAME_X_OUTPUT (focus);
12506
12507 if (x_gtk_use_native_input)
12508 {
12509 gtk_im_context_focus_out (output->im_context);
12510 gtk_im_context_set_client_window (output->im_context,
12511 NULL);
12512 }
12513#endif
12514
12515 EVENT_INIT (ie);
12516 ie.kind = FOCUS_OUT_EVENT;
12517 XSETFRAME (ie.frame_or_window, focus);
12518
12519 kbd_buffer_store_event (&ie);
12520 }
12521
12522 if (new != focus && new)
12523 {
12524
12525#ifdef HAVE_X_I18N
12526 if (FRAME_XIC (new))
12527 XSetICFocus (FRAME_XIC (new));
12528#endif
12529
12530#ifdef USE_GTK
12531 output = FRAME_X_OUTPUT (new);
12532
12533 if (x_gtk_use_native_input)
12534 {
12535 widget = FRAME_GTK_OUTER_WIDGET (new);
12536
12537 gtk_im_context_focus_in (output->im_context);
12538 gtk_im_context_set_client_window (output->im_context,
12539 gtk_widget_get_window (widget));
12540 }
12541#endif
12542
12543 EVENT_INIT (ie);
12544 ie.kind = FOCUS_IN_EVENT;
12545 ie.device = source->name;
12546 XSETFRAME (ie.frame_or_window, new);
12547
12548 kbd_buffer_store_event (&ie);
12549 }
12550
12551 x_new_focus_frame (dpyinfo, new);
12552}
12553
12554static void
12555xi_focus_handle_for_device (struct x_display_info *dpyinfo,
12556 struct frame *mentioned_frame,
12557 XIEvent *base_event)
12558{
12559 struct xi_device_t *device;
12560 XIEnterEvent *event;
12561
12562 /* XILeaveEvent, XIFocusInEvent, etc are just synonyms for
12563 XIEnterEvent. */
12564 event = (XIEnterEvent *) base_event;
12565 device = xi_device_from_id (dpyinfo, event->deviceid);
12566
12567 if (!device)
12568 return;
12569
12570 switch (event->evtype)
12571 {
12572 case XI_FocusIn:
12573 device->focus_frame = mentioned_frame;
12574 device->focus_frame_time = event->time;
12575 break;
12576
12577 case XI_FocusOut:
12578 device->focus_frame = NULL;
12579 break;
12580
12581 case XI_Enter:
12582 if (!event->focus)
12583 break;
12584
12585 device->focus_implicit_frame = mentioned_frame;
12586 device->focus_implicit_time = event->time;
12587 break;
12588
12589 case XI_Leave:
12590 if (!event->focus)
12591 break;
12592
12593 device->focus_implicit_frame = NULL;
12594 break;
12595 }
12596
12597 xi_handle_focus_change (dpyinfo);
12598}
12599
12600static void
12601xi_handle_delete_frame (struct x_display_info *dpyinfo,
12602 struct frame *f)
12603{
12604 struct xi_device_t *device;
12605 ptrdiff_t i;
12606
12607 for (i = 0; i < dpyinfo->num_devices; ++i)
12608 {
12609 device = &dpyinfo->devices[i];
12610
12611 if (device->focus_frame == f)
12612 device->focus_frame = NULL;
12613
12614 if (device->focus_implicit_frame == f)
12615 device->focus_implicit_frame = NULL;
12616 }
12617}
12618
12619#endif
12620
12449/* The focus may have changed. Figure out if it is a real focus change, 12621/* The focus may have changed. Figure out if it is a real focus change,
12450 by checking both FocusIn/Out and Enter/LeaveNotify events. 12622 by checking both FocusIn/Out and Enter/LeaveNotify events.
12451 12623
@@ -12478,33 +12650,9 @@ x_detect_focus_change (struct x_display_info *dpyinfo, struct frame *frame,
12478 12650
12479#ifdef HAVE_XINPUT2 12651#ifdef HAVE_XINPUT2
12480 case GenericEvent: 12652 case GenericEvent:
12481 { 12653 xi_focus_handle_for_device (dpyinfo, frame,
12482 XIEvent *xi_event = event->xcookie.data; 12654 event->xcookie.data);
12483 XIEnterEvent *enter_or_focus = event->xcookie.data; 12655 break;
12484
12485 struct frame *focus_frame = dpyinfo->x_focus_event_frame;
12486 int focus_state
12487 = focus_frame ? focus_frame->output_data.x->focus_state : 0;
12488
12489 if (xi_event->evtype == XI_FocusIn
12490 || xi_event->evtype == XI_FocusOut)
12491 x_focus_changed ((xi_event->evtype == XI_FocusIn
12492 ? FocusIn : FocusOut),
12493 ((enter_or_focus->detail
12494 == XINotifyPointer)
12495 ? FOCUS_IMPLICIT : FOCUS_EXPLICIT),
12496 dpyinfo, frame, bufp);
12497 else if ((xi_event->evtype == XI_Enter
12498 || xi_event->evtype == XI_Leave)
12499 && (enter_or_focus->detail != XINotifyInferior)
12500 && enter_or_focus->focus
12501 && !(focus_state & FOCUS_EXPLICIT))
12502 x_focus_changed ((xi_event->evtype == XI_Enter
12503 ? FocusIn : FocusOut),
12504 FOCUS_IMPLICIT,
12505 dpyinfo, frame, bufp);
12506 break;
12507 }
12508#endif 12656#endif
12509 12657
12510 case FocusIn: 12658 case FocusIn:
@@ -21912,7 +22060,7 @@ handle_one_xevent (struct x_display_info *dpyinfo,
21912 if (n_disabled) 22060 if (n_disabled)
21913 { 22061 {
21914 ndevices = 0; 22062 ndevices = 0;
21915 devices = xmalloc (sizeof *devices * dpyinfo->num_devices); 22063 devices = xzalloc (sizeof *devices * dpyinfo->num_devices);
21916 22064
21917 for (i = 0; i < dpyinfo->num_devices; ++i) 22065 for (i = 0; i < dpyinfo->num_devices; ++i)
21918 { 22066 {
@@ -21992,7 +22140,7 @@ handle_one_xevent (struct x_display_info *dpyinfo,
21992 if (n_disabled) 22140 if (n_disabled)
21993 { 22141 {
21994 ndevices = 0; 22142 ndevices = 0;
21995 devices = xmalloc (sizeof *devices * dpyinfo->num_devices); 22143 devices = xzalloc (sizeof *devices * dpyinfo->num_devices);
21996 22144
21997 for (i = 0; i < dpyinfo->num_devices; ++i) 22145 for (i = 0; i < dpyinfo->num_devices; ++i)
21998 { 22146 {
@@ -22027,6 +22175,10 @@ handle_one_xevent (struct x_display_info *dpyinfo,
22027 dpyinfo->num_devices = ndevices; 22175 dpyinfo->num_devices = ndevices;
22028 } 22176 }
22029 22177
22178 /* Now that the device hierarchy has been changed,
22179 recompute focus. */
22180 xi_handle_focus_change (dpyinfo);
22181
22030 goto XI_OTHER; 22182 goto XI_OTHER;
22031 } 22183 }
22032 22184
@@ -22044,17 +22196,9 @@ handle_one_xevent (struct x_display_info *dpyinfo,
22044 22196
22045 device = xi_device_from_id (dpyinfo, device_changed->deviceid); 22197 device = xi_device_from_id (dpyinfo, device_changed->deviceid);
22046 22198
22047 if (!device) 22199 /* If the device isn't enabled, then stop handling this
22048 { 22200 event. A HierarchyChanged event will be sent if it
22049 /* An existing device might have been enabled. */ 22201 is enabled afterwards. */
22050 x_cache_xi_devices (dpyinfo);
22051
22052 /* Now try to find the device again, in case it was
22053 just enabled. */
22054 device = xi_device_from_id (dpyinfo, device_changed->deviceid);
22055 }
22056
22057 /* If it wasn't enabled, then stop handling this event. */
22058 if (!device) 22202 if (!device)
22059 goto XI_OTHER; 22203 goto XI_OTHER;
22060 22204
@@ -26219,6 +26363,11 @@ x_free_frame_resources (struct frame *f)
26219 26363
26220 block_input (); 26364 block_input ();
26221 26365
26366#ifdef HAVE_XINPUT2
26367 /* Remove any record of this frame being focused. */
26368 xi_handle_delete_frame (dpyinfo, f);
26369#endif
26370
26222 /* If a display connection is dead, don't try sending more 26371 /* If a display connection is dead, don't try sending more
26223 commands to the X server. */ 26372 commands to the X server. */
26224 if (dpyinfo->display) 26373 if (dpyinfo->display)
diff --git a/src/xterm.h b/src/xterm.h
index c1a944d3cd6..7be0f2ede65 100644
--- a/src/xterm.h
+++ b/src/xterm.h
@@ -238,23 +238,50 @@ struct xi_touch_point_t
238 238
239struct xi_device_t 239struct xi_device_t
240{ 240{
241 /* The numerical ID of this device. */
241 int device_id; 242 int device_id;
243
242#ifdef HAVE_XINPUT2_1 244#ifdef HAVE_XINPUT2_1
245 /* The number of scroll valuators in `valuators'. */
243 int scroll_valuator_count; 246 int scroll_valuator_count;
244#endif 247#endif
248
249 /* Whether or not the device is grabbed and its use. */
245 int grab, use; 250 int grab, use;
251
246#ifdef HAVE_XINPUT2_2 252#ifdef HAVE_XINPUT2_2
253 /* Whether or not this device is a direct touch device. */
247 bool direct_p; 254 bool direct_p;
248#endif 255#endif
249 256
250#ifdef HAVE_XINPUT2_1 257#ifdef HAVE_XINPUT2_1
258 /* An array of scroll valuators Emacs knows about. */
251 struct xi_scroll_valuator_t *valuators; 259 struct xi_scroll_valuator_t *valuators;
252#endif 260#endif
261
253#ifdef HAVE_XINPUT2_2 262#ifdef HAVE_XINPUT2_2
263 /* An array of in-progress touchscreen events. */
254 struct xi_touch_point_t *touchpoints; 264 struct xi_touch_point_t *touchpoints;
255#endif 265#endif
256 266
267 /* The name of this device. */
257 Lisp_Object name; 268 Lisp_Object name;
269
270 /* The time at which `focus_frame' became the keyboard focus (only
271 applies to master devices). */
272 Time focus_frame_time;
273
274 /* The frame that is currently this device's keyboard focus, or
275 NULL. */
276 struct frame *focus_frame;
277
278 /* The time at which `focus_frame' became the implicit keyboard
279 focus. */
280 Time focus_implicit_time;
281
282 /* The frame that is currently this device's implicit keyboard
283 focus, or NULL. */
284 struct frame *focus_implicit_frame;
258}; 285};
259#endif 286#endif
260 287
@@ -482,7 +509,10 @@ struct x_display_info
482 /* The last frame mentioned in a FocusIn or FocusOut event. This is 509 /* The last frame mentioned in a FocusIn or FocusOut event. This is
483 separate from x_focus_frame, because whether or not LeaveNotify 510 separate from x_focus_frame, because whether or not LeaveNotify
484 events cause us to lose focus depends on whether or not we have 511 events cause us to lose focus depends on whether or not we have
485 received a FocusIn event for it. */ 512 received a FocusIn event for it.
513
514 This field is not used when the input extension is being
515 utilized. */
486 struct frame *x_focus_event_frame; 516 struct frame *x_focus_event_frame;
487 517
488 /* The frame which currently has the visual highlight, and should get 518 /* The frame which currently has the visual highlight, and should get
@@ -1101,7 +1131,9 @@ struct x_output
1101 1131
1102 /* Keep track of focus. May be EXPLICIT if we received a FocusIn for this 1132 /* Keep track of focus. May be EXPLICIT if we received a FocusIn for this
1103 frame, or IMPLICIT if we received an EnterNotify. 1133 frame, or IMPLICIT if we received an EnterNotify.
1104 FocusOut and LeaveNotify clears EXPLICIT/IMPLICIT. */ 1134 FocusOut and LeaveNotify clears EXPLICIT/IMPLICIT.
1135
1136 Not used when the input extension is being utilized. */
1105 int focus_state; 1137 int focus_state;
1106 1138
1107 /* The offset we need to add to compensate for type A WMs. */ 1139 /* The offset we need to add to compensate for type A WMs. */