From b15de53d7bc43dbcd0136cd7f845eb7ec9d89e6a Mon Sep 17 00:00:00 2001 From: Rick Calixte <10281587+rcalixte@users.noreply.github.com> Date: Wed, 8 May 2024 13:47:07 -0400 Subject: [PATCH] Fix segfault during Alt-Tab when window focus mode is either 'Sloppy' or 'Mouse' (gdb backtrace attached) (#680) (gdb) bt #\0 meta_wayland_surface_get_relative_coordinates (surface=0x0, abs_x=719, abs_y=405, sx=0x7ffe15cea768, sy=0x7ffe15cea76c) at ../src/wayland/meta-wayland-surface.c:1569 #\1 0x00007fba6070ec62 in meta_wayland_pointer_get_relative_coordinates (pointer=pointer@entry=0x564387be1670, surface=surface@entry=0x0, sx=sx@entry=0x7ffe15cea7a8, sy=sy@entry=0x7ffe15cea7ac) at ../src/wayland/meta-wayland-pointer.c:1061 #\2 0x00007fba6070ef13 in meta_wayland_pointer_send_enter (surface=0x0, serial=38, pointer_resource=0x56438b2179e0, pointer=0x564387be1670) at ../src/wayland/meta-wayland-pointer.c:850 #\3 meta_wayland_pointer_broadcast_enter (surface=0x0, serial=38, pointer=0x564387be1670) at ../src/wayland/meta-wayland-pointer.c:875 #\4 meta_wayland_pointer_set_focus (pointer=0x564387be1670, surface=) at ../src/wayland/meta-wayland-pointer.c:967 #\5 0x00007fba6070f573 in repick_for_event (pointer=0x564387be1670, for_event=) at ../src/wayland/meta-wayland-pointer.c:640 #\6 0x00007fba6070f6df in meta_wayland_pointer_repick (pointer=) at ../src/wayland/meta-wayland-pointer.c:1048 #\7 0x00007fba60712799 in meta_wayland_seat_repick (seat=) at ../src/wayland/meta-wayland-seat.c:441 #\8 0x00007fba606b09a0 in meta_display_sync_wayland_input_focus (display=) at ../src/core/display.c:1457 #\9 0x00007fba606942a0 in meta_end_modal_for_plugin (compositor=0x564387f6fe10, plugin=0x564387beeae0, timestamp=140036) at ../src/compositor/compositor.c:495 #\10 0x00007fba6069bef8 in meta_plugin_end_modal (plugin=, timestamp=) at ../src/compositor/meta-plugin.c:187 #\11 0x00007fba60e719eb in cinnamon_global_end_modal (global=0x564387fef940, timestamp=140036) at ../src/cinnamon-global.c:1000 Soft rebase from Mutter 40.10: * Adding clutter_stage_get_device_coords() * Adding PointerDeviceEntry struct * Updating _ClutterStagePrivate struct * Cherry-pick for repick_for_event() * Cherry-pick and adding null-pointer check for meta_wayland_pointer_set_focus() * Cherry-pick for meta_wayland_pointer_get_relative_coordinates() * Add null checks for meta_wayland_surface_get_relative_coordinates() Fix meson.build warning: * path() -> full_path() --- clutter/clutter/clutter-mutter.h | 5 ++ clutter/clutter/clutter-stage.c | 89 ++++++++++++++++++++++++++++++ debian/libmuffin0.symbols | 1 + meson.build | 2 +- src/wayland/meta-wayland-pointer.c | 18 ++++-- src/wayland/meta-wayland-surface.c | 13 +++-- 6 files changed, 116 insertions(+), 12 deletions(-) diff --git a/clutter/clutter/clutter-mutter.h b/clutter/clutter/clutter-mutter.h index d61746d5f..489e93f93 100644 --- a/clutter/clutter/clutter-mutter.h +++ b/clutter/clutter/clutter-mutter.h @@ -78,6 +78,11 @@ void clutter_stage_update_resource_scales (ClutterStage *stage); CLUTTER_EXPORT gboolean clutter_actor_has_damage (ClutterActor *actor); +CLUTTER_EXPORT +void clutter_stage_get_device_coords (ClutterStage *stage, + ClutterInputDevice *device, + ClutterEventSequence *sequence, + graphene_point_t *coords); #undef __CLUTTER_H_INSIDE__ #endif /* __CLUTTER_MUTTER_H__ */ diff --git a/clutter/clutter/clutter-stage.c b/clutter/clutter/clutter-stage.c index fa20b8e28..585bc5ead 100644 --- a/clutter/clutter/clutter-stage.c +++ b/clutter/clutter/clutter-stage.c @@ -99,6 +99,15 @@ typedef struct _PickClipRecord graphene_point_t vertex[4]; } PickClipRecord; +typedef struct _PointerDeviceEntry +{ + ClutterStage *stage; + ClutterInputDevice *device; + ClutterEventSequence *sequence; + graphene_point_t coords; + ClutterActor *current_actor; +} PointerDeviceEntry; + struct _ClutterStagePrivate { /* the stage implementation */ @@ -147,6 +156,9 @@ struct _ClutterStagePrivate gboolean needs_update; + GHashTable *pointer_devices; + GHashTable *touch_sequences; + guint redraw_pending : 1; guint is_cursor_visible : 1; guint throttle_motion_events : 1; @@ -195,6 +207,7 @@ static const ClutterColor default_stage_color = { 255, 255, 255, 255 }; static void clutter_stage_maybe_finish_queue_redraws (ClutterStage *stage); static void free_queue_redraw_entry (ClutterStageQueueRedrawEntry *entry); +static void free_pointer_device_entry (PointerDeviceEntry *entry); static void capture_view_into (ClutterStage *stage, gboolean paint, ClutterStageView *view, @@ -2010,6 +2023,9 @@ clutter_stage_finalize (GObject *object) g_queue_foreach (priv->event_queue, (GFunc) clutter_event_free, NULL); g_queue_free (priv->event_queue); + g_hash_table_destroy (priv->pointer_devices); + g_hash_table_destroy (priv->touch_sequences); + g_free (priv->title); g_array_free (priv->paint_volume_stack, TRUE); @@ -2387,6 +2403,13 @@ clutter_stage_init (ClutterStage *self) priv->sync_delay = -1; priv->motion_events_enabled = TRUE; + priv->pointer_devices = + g_hash_table_new_full (NULL, NULL, + NULL, (GDestroyNotify) free_pointer_device_entry); + priv->touch_sequences = + g_hash_table_new_full (NULL, NULL, + NULL, (GDestroyNotify) free_pointer_device_entry); + clutter_actor_set_background_color (CLUTTER_ACTOR (self), &default_stage_color); @@ -4796,3 +4819,69 @@ _clutter_stage_get_max_view_scale_factor_for_rect (ClutterStage *stage, *view_scale = scale; return TRUE; } + +static void +on_device_actor_reactive_changed (ClutterActor *actor, + GParamSpec *pspec, + PointerDeviceEntry *entry) +{ +} + +static void +on_device_actor_destroyed (ClutterActor *actor, + PointerDeviceEntry *entry) +{ + /* Simply unset the current_actor pointer here, there's no need to + * unset has_pointer or to disconnect any signals because the actor + * is gone anyway. + * Also, as soon as the next repaint happens, a repick should be triggered + * and the PointerDeviceEntry will get updated again, so no need to + * trigger a repick here. + */ + entry->current_actor = NULL; +} + + +static void +free_pointer_device_entry (PointerDeviceEntry *entry) +{ + if (entry->current_actor) + { + ClutterActor *actor = entry->current_actor; + + g_signal_handlers_disconnect_by_func (actor, + G_CALLBACK (on_device_actor_reactive_changed), + entry); + g_signal_handlers_disconnect_by_func (actor, + G_CALLBACK (on_device_actor_destroyed), + entry); + + _clutter_actor_set_has_pointer (actor, FALSE); + } + + g_free (entry); +} + +/** + * clutter_stage_get_device_coords: (skip): + */ +void +clutter_stage_get_device_coords (ClutterStage *stage, + ClutterInputDevice *device, + ClutterEventSequence *sequence, + graphene_point_t *coords) +{ + ClutterStagePrivate *priv = stage->priv; + PointerDeviceEntry *entry = NULL; + + g_return_if_fail (CLUTTER_IS_STAGE (stage)); + g_return_if_fail (device != NULL); + + if (sequence != NULL) + entry = g_hash_table_lookup (priv->touch_sequences, sequence); + else + entry = g_hash_table_lookup (priv->pointer_devices, device); + + if (entry && coords) + *coords = entry->coords; +} diff --git a/debian/libmuffin0.symbols b/debian/libmuffin0.symbols index 8b48b95cb..9ccc4eac4 100644 --- a/debian/libmuffin0.symbols +++ b/debian/libmuffin0.symbols @@ -1115,6 +1115,7 @@ libmuffin-clutter-0.so.0 libmuffin0 #MINVER# clutter_stage_get_capture_final_size@Base 5.3.0 clutter_stage_get_color@Base 5.3.0 clutter_stage_get_default@Base 5.3.0 + clutter_stage_get_device_coords@Base 6.0.1 clutter_stage_get_frame_counter@Base 5.3.0 clutter_stage_get_key_focus@Base 5.3.0 clutter_stage_get_minimum_size@Base 5.3.0 diff --git a/meson.build b/meson.build index 5660cccb6..4f1a646da 100644 --- a/meson.build +++ b/meson.build @@ -388,7 +388,7 @@ if have_wayland if xwayland_dep.found() xwayland_path = xwayland_dep.get_pkgconfig_variable('xwayland') else - xwayland_path = find_program('Xwayland').path() + xwayland_path = find_program('Xwayland').full_path() endif endif cdata.set_quoted('XWAYLAND_PATH', xwayland_path) diff --git a/src/wayland/meta-wayland-pointer.c b/src/wayland/meta-wayland-pointer.c index d30085202..397128b3c 100644 --- a/src/wayland/meta-wayland-pointer.c +++ b/src/wayland/meta-wayland-pointer.c @@ -618,10 +618,13 @@ repick_for_event (MetaWaylandPointer *pointer, ClutterActor *actor; MetaWaylandSurface *surface; - if (for_event) - actor = clutter_event_get_source (for_event); + if (!for_event) + return; + + if (clutter_event_type (for_event) == CLUTTER_LEAVE) + actor = clutter_event_get_related (for_event); else - actor = clutter_input_device_get_pointer_actor (pointer->device); + actor = clutter_event_get_source (for_event); if (META_IS_SURFACE_ACTOR_WAYLAND (actor)) { @@ -938,6 +941,7 @@ meta_wayland_pointer_set_focus (MetaWaylandPointer *pointer, if (surface != NULL) { + ClutterStage *stage = CLUTTER_STAGE (meta_backend_get_stage (backend)); struct wl_client *client = wl_resource_get_client (surface->resource); graphene_point_t pos; MetaWindow *focus_window; @@ -949,7 +953,7 @@ meta_wayland_pointer_set_focus (MetaWaylandPointer *pointer, G_CALLBACK (focus_surface_destroyed), pointer); - clutter_input_device_get_coords (pointer->device, NULL, &pos); + clutter_stage_get_device_coords (stage, pointer->device, NULL, &pos); focus_window = meta_wayland_surface_get_window (pointer->focus_surface); if (focus_window) @@ -960,7 +964,7 @@ meta_wayland_pointer_set_focus (MetaWaylandPointer *pointer, pointer->focus_client = meta_wayland_pointer_get_pointer_client (pointer, client); - if (pointer->focus_client) + if (pointer->focus_client && pointer->focus_surface) { pointer->focus_serial = meta_wayland_input_device_next_serial (input_device); @@ -1054,10 +1058,12 @@ meta_wayland_pointer_get_relative_coordinates (MetaWaylandPointer *pointer, wl_fixed_t *sx, wl_fixed_t *sy) { + MetaBackend *backend = meta_get_backend (); + ClutterStage *stage = CLUTTER_STAGE (meta_backend_get_stage (backend)); float xf = 0.0f, yf = 0.0f; graphene_point_t pos; - clutter_input_device_get_coords (pointer->device, NULL, &pos); + clutter_stage_get_device_coords (stage, pointer->device, NULL, &pos); meta_wayland_surface_get_relative_coordinates (surface, pos.x, pos.y, &xf, &yf); *sx = wl_fixed_from_double (xf); diff --git a/src/wayland/meta-wayland-surface.c b/src/wayland/meta-wayland-surface.c index aecaac4ce..befac4f84 100644 --- a/src/wayland/meta-wayland-surface.c +++ b/src/wayland/meta-wayland-surface.c @@ -1566,12 +1566,15 @@ meta_wayland_surface_get_relative_coordinates (MetaWaylandSurface *surface, float *sx, float *sy) { - MetaWaylandSurfaceRoleClass *surface_role_class = - META_WAYLAND_SURFACE_ROLE_GET_CLASS (surface->role); + if (surface != NULL && surface->role) + { + MetaWaylandSurfaceRoleClass *surface_role_class = + META_WAYLAND_SURFACE_ROLE_GET_CLASS (surface->role); - surface_role_class->get_relative_coordinates (surface->role, - abs_x, abs_y, - sx, sy); + surface_role_class->get_relative_coordinates (surface->role, + abs_x, abs_y, + sx, sy); + } } void