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 /src/xterm.c | |
| 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.
Diffstat (limited to 'src/xterm.c')
| -rw-r--r-- | src/xterm.c | 235 |
1 files changed, 192 insertions, 43 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) |