From 09101e36f81541d5b9c1c94a4a37ba1bca32d4f0 Mon Sep 17 00:00:00 2001 From: Carlos Garnacho Date: Fri, 10 Nov 2023 13:14:49 +0100 Subject: [PATCH] wayland: Handle pointer focus inhibition at the Clutter level The MetaWaylandPointer used to put this together through MetaCursorTracker cursor visibility, and ClutterSeat-level inhibition API, applying the pointer focus changes due to visibility logically to Wayland clients. In order to make this work over all Clutter widgetry instead of just Wayland clients, make the ClutterSeat-level inhibition API control this feature at the ClutterStage picking level, and leave/enter the seat pointer as appropriate. By default, the seat pointer has (un)focus inhibited. The MetaCursorTracker has been made another player in unfocus inhibition, simply asking for the pointer to get its focus while the cursor is visible. This in practice means that picking code may return a NULL actor, some asserts and preconditions had to be changed to handle this, plus some test code slightly. Part-of: --- clutter/clutter/clutter-stage.c | 58 +++++++++++++++++++++--------- src/backends/meta-cursor-tracker.c | 9 +++++ src/tests/clutter/conform/grab.c | 2 +- src/wayland/meta-wayland-pointer.c | 34 +----------------- 4 files changed, 52 insertions(+), 51 deletions(-) diff --git a/clutter/clutter/clutter-stage.c b/clutter/clutter/clutter-stage.c index 793597104..26dba059c 100644 --- a/clutter/clutter/clutter-stage.c +++ b/clutter/clutter/clutter-stage.c @@ -1626,6 +1626,13 @@ clutter_stage_class_init (ClutterStageClass *klass) klass->deactivate = clutter_stage_real_deactivate; } +static void +on_seat_unfocus_inhibited_changed (ClutterStage *stage, + ClutterSeat *seat) +{ + clutter_stage_repick_device (stage, clutter_seat_get_pointer (seat)); +} + static void clutter_stage_init (ClutterStage *self) { @@ -1633,6 +1640,7 @@ clutter_stage_init (ClutterStage *self) ClutterStagePrivate *priv; ClutterStageWindow *impl; ClutterBackend *backend; + ClutterSeat *seat; GError *error; /* a stage is a top-level object */ @@ -1686,6 +1694,12 @@ clutter_stage_init (ClutterStage *self) clutter_stage_set_title (self, g_get_prgname ()); clutter_stage_set_key_focus (self, NULL); clutter_stage_set_viewport (self, geom.width, geom.height); + + seat = clutter_backend_get_default_seat (backend); + g_signal_connect_object (seat, "is-unfocus-inhibited-changed", + G_CALLBACK (on_seat_unfocus_inhibited_changed), + self, + G_CONNECT_SWAPPED); } static void @@ -3568,29 +3582,37 @@ clutter_stage_pick_and_update_device (ClutterStage *stage, graphene_point_t point, uint32_t time_ms) { - ClutterActor *new_actor; + ClutterActor *new_actor = NULL; MtkRegion *clear_area = NULL; + ClutterSeat *seat; - if ((flags & CLUTTER_DEVICE_UPDATE_IGNORE_CACHE) == 0) + seat = clutter_input_device_get_seat (device); + + if (sequence || + device != clutter_seat_get_pointer (seat) || + clutter_seat_is_unfocus_inhibited (seat)) { - if (clutter_stage_check_in_clear_area (stage, device, - sequence, point)) + if ((flags & CLUTTER_DEVICE_UPDATE_IGNORE_CACHE) == 0) { - clutter_stage_set_device_coords (stage, device, - sequence, point); - return clutter_stage_get_device_actor (stage, device, sequence); + if (clutter_stage_check_in_clear_area (stage, device, + sequence, point)) + { + clutter_stage_set_device_coords (stage, device, + sequence, point); + return clutter_stage_get_device_actor (stage, device, sequence); + } } + + new_actor = _clutter_stage_do_pick (stage, + point.x, + point.y, + CLUTTER_PICK_REACTIVE, + &clear_area); + + /* Picking should never fail, but if it does, we bail out here */ + g_return_val_if_fail (new_actor != NULL, NULL); } - new_actor = _clutter_stage_do_pick (stage, - point.x, - point.y, - CLUTTER_PICK_REACTIVE, - &clear_area); - - /* Picking should never fail, but if it does, we bail out here */ - g_return_val_if_fail (new_actor != NULL, NULL); - clutter_stage_update_device (stage, device, sequence, source_device, @@ -4393,7 +4415,9 @@ clutter_stage_emit_event (ClutterStage *self, } } - g_assert (target_actor != NULL); + if (!target_actor) + return; + seat_grab_actor = priv->topmost_grab ? priv->topmost_grab->actor : CLUTTER_ACTOR (self); is_sequence_begin = diff --git a/src/backends/meta-cursor-tracker.c b/src/backends/meta-cursor-tracker.c index 99c4c5f3f..cea4fae7b 100644 --- a/src/backends/meta-cursor-tracker.c +++ b/src/backends/meta-cursor-tracker.c @@ -55,6 +55,7 @@ typedef struct _MetaCursorTrackerPrivate MetaBackend *backend; gboolean is_showing; + gboolean pointer_focus; int track_position_count; @@ -531,6 +532,7 @@ meta_cursor_tracker_set_pointer_visible (MetaCursorTracker *tracker, { MetaCursorTrackerPrivate *priv = meta_cursor_tracker_get_instance_private (tracker); + ClutterSeat *seat; if (visible == priv->is_showing) return; @@ -539,6 +541,13 @@ meta_cursor_tracker_set_pointer_visible (MetaCursorTracker *tracker, sync_cursor (tracker); g_signal_emit (tracker, signals[VISIBILITY_CHANGED], 0); + + seat = clutter_backend_get_default_seat (clutter_get_default_backend ()); + + if (priv->is_showing) + clutter_seat_inhibit_unfocus (seat); + else + clutter_seat_uninhibit_unfocus (seat); } MetaBackend * diff --git a/src/tests/clutter/conform/grab.c b/src/tests/clutter/conform/grab.c index 21524fc4a..1eb239832 100644 --- a/src/tests/clutter/conform/grab.c +++ b/src/tests/clutter/conform/grab.c @@ -662,6 +662,7 @@ grab_input_only (void) } CLUTTER_TEST_SUITE ( + CLUTTER_TEST_UNIT ("/grab/input-only", grab_input_only); CLUTTER_TEST_UNIT ("/grab/grab-under-pointer", grab_under_pointer) CLUTTER_TEST_UNIT ("/grab/grab-under-pointers-parent", grab_under_pointers_parent) CLUTTER_TEST_UNIT ("/grab/grab-outside-pointer", grab_outside_pointer) @@ -672,5 +673,4 @@ CLUTTER_TEST_SUITE ( CLUTTER_TEST_UNIT ("/grab/grab-unordered-ungrab-2", grab_unordered_ungrab_2) CLUTTER_TEST_UNIT ("/grab/key-focus-in-grab", grab_key_focus_in_grab); CLUTTER_TEST_UNIT ("/grab/key-focus-outside-grab", grab_key_focus_outside_grab); - CLUTTER_TEST_UNIT ("/grab/input-only", grab_input_only); ) diff --git a/src/wayland/meta-wayland-pointer.c b/src/wayland/meta-wayland-pointer.c index 9969c75f5..c4da3681d 100644 --- a/src/wayland/meta-wayland-pointer.c +++ b/src/wayland/meta-wayland-pointer.c @@ -302,14 +302,9 @@ static void sync_focus_surface (MetaWaylandPointer *pointer) { MetaBackend *backend = backend_from_pointer (pointer); - MetaCursorTracker *cursor_tracker = meta_backend_get_cursor_tracker (backend); - ClutterBackend *clutter_backend = clutter_get_default_backend (); - ClutterSeat *clutter_seat = clutter_backend_get_default_seat (clutter_backend); ClutterStage *stage = CLUTTER_STAGE (meta_backend_get_stage (backend)); - if (clutter_stage_get_grab_actor (stage) != NULL || - (!meta_cursor_tracker_get_pointer_visible (cursor_tracker) && - !clutter_seat_is_unfocus_inhibited (clutter_seat))) + if (clutter_stage_get_grab_actor (stage) != NULL) { meta_wayland_pointer_set_focus (pointer, NULL); return; @@ -457,9 +452,6 @@ default_grab_focus (MetaWaylandPointerGrab *grab, MetaWaylandPointer *pointer = grab->pointer; MetaWaylandSeat *seat = meta_wayland_pointer_get_seat (pointer); MetaBackend *backend = backend_from_pointer (pointer); - MetaCursorTracker *cursor_tracker = meta_backend_get_cursor_tracker (backend); - ClutterBackend *clutter_backend = clutter_get_default_backend (); - ClutterSeat *clutter_seat = clutter_backend_get_default_seat (clutter_backend); ClutterStage *stage = CLUTTER_STAGE (meta_backend_get_stage (backend)); if (!meta_wayland_seat_has_pointer (seat)) @@ -468,10 +460,6 @@ default_grab_focus (MetaWaylandPointerGrab *grab, if (clutter_stage_get_grab_actor (stage) != NULL) return; - if (!meta_cursor_tracker_get_pointer_visible (cursor_tracker) && - !clutter_seat_is_unfocus_inhibited (clutter_seat)) - return; - if (pointer->button_count > 0) return; @@ -537,16 +525,6 @@ meta_wayland_pointer_enable (MetaWaylandPointer *pointer) "cursor-changed", G_CALLBACK (meta_wayland_pointer_on_cursor_changed), pointer); - - g_signal_connect_swapped (cursor_tracker, - "visibility-changed", - G_CALLBACK (sync_focus_surface), - pointer); - - g_signal_connect_swapped (clutter_seat, - "is-unfocus-inhibited-changed", - G_CALLBACK (sync_focus_surface), - pointer); } void @@ -554,8 +532,6 @@ meta_wayland_pointer_disable (MetaWaylandPointer *pointer) { MetaBackend *backend = backend_from_pointer (pointer); MetaCursorTracker *cursor_tracker = meta_backend_get_cursor_tracker (backend); - ClutterBackend *clutter_backend = clutter_get_default_backend (); - ClutterSeat *clutter_seat = clutter_backend_get_default_seat (clutter_backend); g_hash_table_foreach (pointer->pointer_clients, make_resources_inert_foreach, @@ -565,14 +541,6 @@ meta_wayland_pointer_disable (MetaWaylandPointer *pointer) (gpointer) meta_wayland_pointer_on_cursor_changed, pointer); - g_signal_handlers_disconnect_by_func (cursor_tracker, - sync_focus_surface, - pointer); - - g_signal_handlers_disconnect_by_func (clutter_seat, - sync_focus_surface, - pointer); - if (pointer->cursor_surface) { g_clear_signal_handler (&pointer->cursor_surface_destroy_id,