diff options
| author | Po Lu | 2022-08-05 10:18:18 +0800 |
|---|---|---|
| committer | Po Lu | 2022-08-05 10:18:18 +0800 |
| commit | 0dbe0fd4104f4a58908324c1ead365461a4daa16 (patch) | |
| tree | 1df736fccd0f7ddc0df1628fc7ccfd56bc1b87bf | |
| parent | 8ea7506d724903008910bc47e88212da55549ede (diff) | |
| download | emacs-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.c | 235 | ||||
| -rw-r--r-- | src/xterm.h | 36 |
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, | |||
| 5394 | static void | 5394 | static void |
| 5395 | x_cache_xi_devices (struct x_display_info *dpyinfo) | 5395 | x_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 | |||
| 12459 | static void | ||
| 12460 | xi_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 | |||
| 12554 | static void | ||
| 12555 | xi_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 | |||
| 12600 | static void | ||
| 12601 | xi_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 | ||
| 239 | struct xi_device_t | 239 | struct 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. */ |