Skip to content

Commit

Permalink
Fix segfault during Alt-Tab when window focus mode is either 'Sloppy'…
Browse files Browse the repository at this point in the history
… 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=<optimized out>) at ../src/wayland/meta-wayland-pointer.c:967
 #\5  0x00007fba6070f573 in repick_for_event (pointer=0x564387be1670, for_event=<optimized out>) at ../src/wayland/meta-wayland-pointer.c:640
 #\6  0x00007fba6070f6df in meta_wayland_pointer_repick (pointer=<optimized out>) at ../src/wayland/meta-wayland-pointer.c:1048
 #\7  0x00007fba60712799 in meta_wayland_seat_repick (seat=<optimized out>) at ../src/wayland/meta-wayland-seat.c:441
 #\8  0x00007fba606b09a0 in meta_display_sync_wayland_input_focus (display=<optimized out>) 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=<optimized out>, timestamp=<optimized out>) 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()
  • Loading branch information
rcalixte authored May 8, 2024
1 parent 28be835 commit b15de53
Show file tree
Hide file tree
Showing 6 changed files with 116 additions and 12 deletions.
5 changes: 5 additions & 0 deletions clutter/clutter/clutter-mutter.h
Original file line number Diff line number Diff line change
Expand Up @@ -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__ */
89 changes: 89 additions & 0 deletions clutter/clutter/clutter-stage.c
Original file line number Diff line number Diff line change
Expand Up @@ -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 */
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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);

Expand Down Expand Up @@ -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;
}
1 change: 1 addition & 0 deletions debian/libmuffin0.symbols
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
2 changes: 1 addition & 1 deletion meson.build
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
18 changes: 12 additions & 6 deletions src/wayland/meta-wayland-pointer.c
Original file line number Diff line number Diff line change
Expand Up @@ -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))
{
Expand Down Expand Up @@ -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;
Expand All @@ -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)
Expand All @@ -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);
Expand Down Expand Up @@ -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);
Expand Down
13 changes: 8 additions & 5 deletions src/wayland/meta-wayland-surface.c
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down

0 comments on commit b15de53

Please sign in to comment.