From 1282a8fc6aecc1328204ef5555e12586c9711438 Mon Sep 17 00:00:00 2001 From: CentOS Sources Date: Fri, 27 Aug 2021 16:20:57 +0000 Subject: [PATCH] import mutter-3.32.2-59.el8 --- SOURCES/wayland-frame-callback-rework.patch | 1045 +++++++++++++++++++ SPECS/mutter.spec | 9 +- 2 files changed, 1053 insertions(+), 1 deletion(-) create mode 100644 SOURCES/wayland-frame-callback-rework.patch diff --git a/SOURCES/wayland-frame-callback-rework.patch b/SOURCES/wayland-frame-callback-rework.patch new file mode 100644 index 0000000..0a6717f --- /dev/null +++ b/SOURCES/wayland-frame-callback-rework.patch @@ -0,0 +1,1045 @@ +From 4232f2056cd31811d047104d1223f3e5ced4b107 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Jonas=20=C3=85dahl?= +Date: Thu, 16 Apr 2020 19:42:03 +0200 +Subject: [PATCH 1/5] clutter/stage: Make clutter_stage_schedule_update() + always schedule + +We could call clutter_stage_schedule_update() and it wouldn't actually +schedule anything, as the master frame clock only tries to reschedule if +1) there is an active timeline, 2) there are pending relayouts, 3) there +are pending redraws, or 4) there are pending events. Thus, a call to +clutter_stage_schedule_update() didn't have any effect if it was called +at the wrong time. + +Fix this by adding a boolean state "needs_update" to the stage, set on +clutter_stage_schedule_update() and cleared on +_clutter_stage_do_update(), that will make the master clock reschedule +an update if it is TRUE. + +https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1218 +(cherry picked from commit b8003807b0772e97354302b5cc2825e0b22c6c83) +--- + clutter/clutter/clutter-stage.c | 10 +++++++++- + 1 file changed, 9 insertions(+), 1 deletion(-) + +diff --git a/clutter/clutter/clutter-stage.c b/clutter/clutter/clutter-stage.c +index aaa77d9ede..5a914a3d0b 100644 +--- a/clutter/clutter/clutter-stage.c ++++ b/clutter/clutter/clutter-stage.c +@@ -152,6 +152,8 @@ struct _ClutterStagePrivate + + int update_freeze_count; + ++ gboolean needs_update; ++ + guint relayout_pending : 1; + guint redraw_pending : 1; + guint is_fullscreen : 1; +@@ -1074,7 +1076,9 @@ _clutter_stage_needs_update (ClutterStage *stage) + + priv = stage->priv; + +- return priv->relayout_pending || priv->redraw_pending; ++ return priv->relayout_pending || ++ priv->needs_update || ++ priv->redraw_pending; + } + + void +@@ -1232,6 +1236,8 @@ _clutter_stage_do_update (ClutterStage *stage) + + priv->stage_was_relayout = FALSE; + ++ priv->needs_update = FALSE; ++ + /* if the stage is being destroyed, or if the destruction already + * happened and we don't have an StageWindow any more, then we + * should bail out +@@ -4080,6 +4086,8 @@ _clutter_stage_schedule_update (ClutterStage *stage) + if (stage_window == NULL) + return; + ++ stage->priv->needs_update = TRUE; ++ + return _clutter_stage_window_schedule_update (stage_window, + stage->priv->sync_delay); + } +-- +2.31.1 + + +From 2d4453cfdcaf0c6a9f492d2c2395dbfc8cf833db Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Jonas=20=C3=85dahl?= +Date: Thu, 16 Apr 2020 19:11:37 +0200 +Subject: [PATCH 2/5] clutter/stage: Make clutter_stage_schedule_update() + public API + +It's effectively used by mutter by abusing a ClutterTimeline to scedule +updates. Timelines are not really suited in places that is done, as it +is really just about getting a single new update scheduled whenever +suitable, so expose the API so we can use it directly. + +https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1218 +(cherry picked from commit 99c9a14bc8058830232cd4e07c7bb897e84a8c9c) +--- + clutter/clutter/clutter-master-clock-default.c | 4 ++-- + clutter/clutter/clutter-stage-private.h | 1 - + clutter/clutter/clutter-stage.c | 16 ++++++++-------- + clutter/clutter/clutter-stage.h | 3 +++ + 4 files changed, 13 insertions(+), 11 deletions(-) + +diff --git a/clutter/clutter/clutter-master-clock-default.c b/clutter/clutter/clutter-master-clock-default.c +index 0647c3a7fd..de7a1e2f4d 100644 +--- a/clutter/clutter/clutter-master-clock-default.c ++++ b/clutter/clutter/clutter-master-clock-default.c +@@ -206,7 +206,7 @@ master_clock_schedule_stage_updates (ClutterMasterClockDefault *master_clock) + stages = clutter_stage_manager_peek_stages (stage_manager); + + for (l = stages; l != NULL; l = l->next) +- _clutter_stage_schedule_update (l->data); ++ clutter_stage_schedule_update (l->data); + } + + static GSList * +@@ -259,7 +259,7 @@ master_clock_reschedule_stage_updates (ClutterMasterClockDefault *master_clock, + if (master_clock->timelines || + _clutter_stage_has_queued_events (l->data) || + _clutter_stage_needs_update (l->data)) +- _clutter_stage_schedule_update (l->data); ++ clutter_stage_schedule_update (l->data); + } + } + +diff --git a/clutter/clutter/clutter-stage-private.h b/clutter/clutter/clutter-stage-private.h +index 42474687ad..ea0ce5ec72 100644 +--- a/clutter/clutter/clutter-stage-private.h ++++ b/clutter/clutter/clutter-stage-private.h +@@ -70,7 +70,6 @@ void _clutter_stage_queue_event (ClutterStage *stage, + gboolean _clutter_stage_has_queued_events (ClutterStage *stage); + void _clutter_stage_process_queued_events (ClutterStage *stage); + void _clutter_stage_update_input_devices (ClutterStage *stage); +-void _clutter_stage_schedule_update (ClutterStage *stage); + gint64 _clutter_stage_get_update_time (ClutterStage *stage); + void _clutter_stage_clear_update_time (ClutterStage *stage); + gboolean _clutter_stage_has_full_redraw_queued (ClutterStage *stage); +diff --git a/clutter/clutter/clutter-stage.c b/clutter/clutter/clutter-stage.c +index 5a914a3d0b..74ff8b1337 100644 +--- a/clutter/clutter/clutter-stage.c ++++ b/clutter/clutter/clutter-stage.c +@@ -921,7 +921,7 @@ _clutter_stage_queue_event (ClutterStage *stage, + { + ClutterMasterClock *master_clock = _clutter_master_clock_get_default (); + _clutter_master_clock_start_running (master_clock); +- _clutter_stage_schedule_update (stage); ++ clutter_stage_schedule_update (stage); + } + + /* if needed, update the state of the input device of the event. +@@ -1295,7 +1295,7 @@ clutter_stage_real_queue_relayout (ClutterActor *self) + + if (!priv->relayout_pending) + { +- _clutter_stage_schedule_update (stage); ++ clutter_stage_schedule_update (stage); + priv->relayout_pending = TRUE; + } + +@@ -3788,7 +3788,7 @@ clutter_stage_ensure_redraw (ClutterStage *stage) + priv = stage->priv; + + if (!priv->relayout_pending && !priv->redraw_pending) +- _clutter_stage_schedule_update (stage); ++ clutter_stage_schedule_update (stage); + + priv->relayout_pending = TRUE; + priv->redraw_pending = TRUE; +@@ -4069,13 +4069,13 @@ clutter_stage_get_minimum_size (ClutterStage *stage, + } + + /** +- * _clutter_stage_schedule_update: +- * @window: a #ClutterStage actor ++ * clutter_stage_schedule_update: ++ * @stage: a #ClutterStage actor + * + * Schedules a redraw of the #ClutterStage at the next optimal timestamp. + */ + void +-_clutter_stage_schedule_update (ClutterStage *stage) ++clutter_stage_schedule_update (ClutterStage *stage) + { + ClutterStageWindow *stage_window; + +@@ -4097,7 +4097,7 @@ _clutter_stage_schedule_update (ClutterStage *stage) + * @stage: a #ClutterStage actor + * + * Returns the earliest time in which the stage is ready to update. The update +- * time is set when _clutter_stage_schedule_update() is called. This can then ++ * time is set when clutter_stage_schedule_update() is called. This can then + * be used by e.g. the #ClutterMasterClock to know when the stage needs to be + * redrawn. + * +@@ -4267,7 +4267,7 @@ _clutter_stage_queue_actor_redraw (ClutterStage *stage, + + CLUTTER_NOTE (PAINT, "First redraw request"); + +- _clutter_stage_schedule_update (stage); ++ clutter_stage_schedule_update (stage); + priv->redraw_pending = TRUE; + + master_clock = _clutter_master_clock_get_default (); +diff --git a/clutter/clutter/clutter-stage.h b/clutter/clutter/clutter-stage.h +index 9da63d211d..53e37ae3bc 100644 +--- a/clutter/clutter/clutter-stage.h ++++ b/clutter/clutter/clutter-stage.h +@@ -265,6 +265,9 @@ CLUTTER_EXPORT + void clutter_stage_skip_sync_delay (ClutterStage *stage); + #endif + ++CLUTTER_EXPORT ++void clutter_stage_schedule_update (ClutterStage *stage); ++ + CLUTTER_EXPORT + gboolean clutter_stage_get_capture_final_size (ClutterStage *stage, + cairo_rectangle_int_t *rect, +-- +2.31.1 + + +From 1c4db591b6bb2ae9d649e8157eae24b875e7a22b Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Jonas=20=C3=85dahl?= +Date: Mon, 28 Oct 2019 18:20:31 +0100 +Subject: [PATCH 3/5] wayland/actor-surface: Always store away frame callbacks + on commit + +We're expected by MetaWaylandSurface to always pick the frame callbacks +out from the pending state when committing (applying) so that no frame +callbacks are unaccounted for. We failed to do this if our actor for +some reason (e.g. associated window was unmanaged) was destroyed. To +handle this situation better, store away the frame callbacks until we +some later point in time need to pass them on forward. + +https://gitlab.gnome.org/GNOME/mutter/merge_requests/893 +--- + src/wayland/meta-wayland-actor-surface.c | 25 +++++++++++++++++++++++- + 1 file changed, 24 insertions(+), 1 deletion(-) + +diff --git a/src/wayland/meta-wayland-actor-surface.c b/src/wayland/meta-wayland-actor-surface.c +index 2471de0a92..264565c575 100644 +--- a/src/wayland/meta-wayland-actor-surface.c ++++ b/src/wayland/meta-wayland-actor-surface.c +@@ -35,6 +35,8 @@ typedef struct _MetaWaylandActorSurfacePrivate MetaWaylandActorSurfacePrivate; + struct _MetaWaylandActorSurfacePrivate + { + MetaSurfaceActor *actor; ++ ++ struct wl_list frame_callback_list; + }; + + G_DEFINE_ABSTRACT_TYPE_WITH_PRIVATE (MetaWaylandActorSurface, +@@ -56,6 +58,7 @@ meta_wayland_actor_surface_dispose (GObject *object) + meta_wayland_actor_surface_get_instance_private (META_WAYLAND_ACTOR_SURFACE (object)); + MetaWaylandSurface *surface = + meta_wayland_surface_role_get_surface (META_WAYLAND_SURFACE_ROLE (object)); ++ MetaWaylandFrameCallback *cb, *next; + + if (priv->actor) + { +@@ -66,6 +69,9 @@ meta_wayland_actor_surface_dispose (GObject *object) + g_clear_object (&priv->actor); + } + ++ wl_list_for_each_safe (cb, next, &priv->frame_callback_list, link) ++ wl_resource_destroy (cb->resource); ++ + G_OBJECT_CLASS (meta_wayland_actor_surface_parent_class)->dispose (object); + } + +@@ -99,6 +105,9 @@ meta_wayland_actor_surface_queue_frame_callbacks (MetaWaylandActorSurface *actor + MetaSurfaceActorWayland *surface_actor_wayland = + META_SURFACE_ACTOR_WAYLAND (priv->actor); + ++ meta_surface_actor_wayland_add_frame_callbacks (surface_actor_wayland, ++ &priv->frame_callback_list); ++ wl_list_init (&priv->frame_callback_list); + meta_surface_actor_wayland_add_frame_callbacks (surface_actor_wayland, + &pending->frame_callback_list); + wl_list_init (&pending->frame_callback_list); +@@ -253,10 +262,20 @@ meta_wayland_actor_surface_commit (MetaWaylandSurfaceRole *surface_role, + { + MetaWaylandActorSurface *actor_surface = + META_WAYLAND_ACTOR_SURFACE (surface_role); ++ MetaWaylandActorSurfacePrivate *priv = ++ meta_wayland_actor_surface_get_instance_private (actor_surface); + MetaWaylandSurface *surface = + meta_wayland_surface_role_get_surface (surface_role); + MetaWaylandSurface *toplevel_surface; + ++ if (!priv->actor) ++ { ++ wl_list_insert_list (&priv->frame_callback_list, ++ &pending->frame_callback_list); ++ wl_list_init (&pending->frame_callback_list); ++ return; ++ } ++ + meta_wayland_actor_surface_queue_frame_callbacks (actor_surface, pending); + + toplevel_surface = meta_wayland_surface_get_toplevel (surface); +@@ -307,8 +326,12 @@ meta_wayland_actor_surface_is_on_logical_monitor (MetaWaylandSurfaceRole *surfac + } + + static void +-meta_wayland_actor_surface_init (MetaWaylandActorSurface *role) ++meta_wayland_actor_surface_init (MetaWaylandActorSurface *actor_surface) + { ++ MetaWaylandActorSurfacePrivate *priv = ++ meta_wayland_actor_surface_get_instance_private (actor_surface); ++ ++ wl_list_init (&priv->frame_callback_list); + } + + static void +-- +2.31.1 + + +From 54e5cee1a8d1a94fb19b438a3c80fe72179a3c80 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Jonas=20=C3=85dahl?= +Date: Fri, 6 Aug 2021 19:09:24 +0200 +Subject: [PATCH 4/5] wayland/actor-surface: Always store away frame callbacks + on commit + +We're expected by MetaWaylandSurface to always pick the frame callbacks +out from the pending state when committing (applying) so that no frame +callbacks are unaccounted for. We failed to do this if our actor for +some reason (e.g. associated window was unmanaged) was destroyed. To +handle this situation better, store away the frame callbacks until we +some later point in time need to pass them on forward. + +https://gitlab.gnome.org/GNOME/mutter/merge_requests/893 +--- + src/compositor/meta-surface-actor-wayland.c | 29 --------- + src/wayland/meta-wayland-actor-surface.c | 65 ++++++++++++++++----- + src/wayland/meta-wayland-actor-surface.h | 3 + + src/wayland/meta-wayland-cursor-surface.c | 4 +- + src/wayland/meta-wayland-dnd-surface.c | 11 +++- + src/wayland/meta-wayland-legacy-xdg-shell.c | 8 +-- + src/wayland/meta-wayland-private.h | 2 +- + src/wayland/meta-wayland-subsurface.c | 2 - + src/wayland/meta-wayland-surface.c | 38 +++--------- + src/wayland/meta-wayland-surface.h | 9 +-- + src/wayland/meta-wayland-wl-shell.c | 3 - + src/wayland/meta-wayland-xdg-shell.c | 15 ++--- + src/wayland/meta-wayland.c | 56 +++++++++++++----- + src/wayland/meta-wayland.h | 8 ++- + src/wayland/meta-xwayland.c | 45 -------------- + 15 files changed, 127 insertions(+), 171 deletions(-) + +diff --git a/src/compositor/meta-surface-actor-wayland.c b/src/compositor/meta-surface-actor-wayland.c +index a75c4dd096..480b51c61a 100644 +--- a/src/compositor/meta-surface-actor-wayland.c ++++ b/src/compositor/meta-surface-actor-wayland.c +@@ -42,7 +42,6 @@ struct _MetaSurfaceActorWayland + MetaSurfaceActor parent; + + MetaWaylandSurface *surface; +- struct wl_list frame_callback_list; + }; + + G_DEFINE_TYPE (MetaSurfaceActorWayland, +@@ -91,13 +90,6 @@ meta_surface_actor_wayland_is_unredirected (MetaSurfaceActor *actor) + return FALSE; + } + +-void +-meta_surface_actor_wayland_add_frame_callbacks (MetaSurfaceActorWayland *self, +- struct wl_list *frame_callbacks) +-{ +- wl_list_insert_list (&self->frame_callback_list, frame_callbacks); +-} +- + static MetaWindow * + meta_surface_actor_wayland_get_window (MetaSurfaceActor *actor) + { +@@ -158,22 +150,6 @@ meta_surface_actor_wayland_get_preferred_height (ClutterActor *actor, + *natural_height_p *= scale; + } + +-static void +-meta_surface_actor_wayland_paint (ClutterActor *actor) +-{ +- MetaSurfaceActorWayland *self = META_SURFACE_ACTOR_WAYLAND (actor); +- +- if (self->surface) +- { +- MetaWaylandCompositor *compositor = self->surface->compositor; +- +- wl_list_insert_list (&compositor->frame_callbacks, &self->frame_callback_list); +- wl_list_init (&self->frame_callback_list); +- } +- +- CLUTTER_ACTOR_CLASS (meta_surface_actor_wayland_parent_class)->paint (actor); +-} +- + static void + meta_surface_actor_wayland_dispose (GObject *object) + { +@@ -190,9 +166,6 @@ meta_surface_actor_wayland_dispose (GObject *object) + self->surface = NULL; + } + +- wl_list_for_each_safe (cb, next, &self->frame_callback_list, link) +- wl_resource_destroy (cb->resource); +- + G_OBJECT_CLASS (meta_surface_actor_wayland_parent_class)->dispose (object); + } + +@@ -205,7 +178,6 @@ meta_surface_actor_wayland_class_init (MetaSurfaceActorWaylandClass *klass) + + actor_class->get_preferred_width = meta_surface_actor_wayland_get_preferred_width; + actor_class->get_preferred_height = meta_surface_actor_wayland_get_preferred_height; +- actor_class->paint = meta_surface_actor_wayland_paint; + + surface_actor_class->process_damage = meta_surface_actor_wayland_process_damage; + surface_actor_class->pre_paint = meta_surface_actor_wayland_pre_paint; +@@ -232,7 +204,6 @@ meta_surface_actor_wayland_new (MetaWaylandSurface *surface) + + g_assert (meta_is_wayland_compositor ()); + +- wl_list_init (&self->frame_callback_list); + self->surface = surface; + g_object_add_weak_pointer (G_OBJECT (self->surface), + (gpointer *) &self->surface); +diff --git a/src/wayland/meta-wayland-actor-surface.c b/src/wayland/meta-wayland-actor-surface.c +index 264565c575..037dd901ab 100644 +--- a/src/wayland/meta-wayland-actor-surface.c ++++ b/src/wayland/meta-wayland-actor-surface.c +@@ -84,16 +84,22 @@ meta_wayland_actor_surface_assigned (MetaWaylandSurfaceRole *surface_role) + meta_wayland_surface_role_get_surface (surface_role); + GList *l; + +- meta_surface_actor_wayland_add_frame_callbacks (META_SURFACE_ACTOR_WAYLAND (priv->actor), +- &surface->pending_frame_callback_list); +- wl_list_init (&surface->pending_frame_callback_list); +- + for (l = surface->subsurfaces; l; l = l->next) + { + ClutterActor *subsurface_actor = + CLUTTER_ACTOR (meta_wayland_surface_get_actor (l->data)); + clutter_actor_add_child (CLUTTER_ACTOR (priv->actor), subsurface_actor); + } ++ ++ if (wl_list_empty (&surface->unassigned.pending_frame_callback_list)) ++ return; ++ ++ wl_list_insert_list (priv->frame_callback_list.prev, ++ &surface->unassigned.pending_frame_callback_list); ++ wl_list_init (&surface->unassigned.pending_frame_callback_list); ++ ++ meta_wayland_compositor_add_frame_callback_surface (surface->compositor, ++ surface); + } + + void +@@ -102,15 +108,40 @@ meta_wayland_actor_surface_queue_frame_callbacks (MetaWaylandActorSurface *actor + { + MetaWaylandActorSurfacePrivate *priv = + meta_wayland_actor_surface_get_instance_private (actor_surface); +- MetaSurfaceActorWayland *surface_actor_wayland = +- META_SURFACE_ACTOR_WAYLAND (priv->actor); ++ MetaWaylandSurfaceRole *surface_role = ++ META_WAYLAND_SURFACE_ROLE (actor_surface); ++ MetaWaylandSurface *surface = ++ meta_wayland_surface_role_get_surface (surface_role); + +- meta_surface_actor_wayland_add_frame_callbacks (surface_actor_wayland, +- &priv->frame_callback_list); +- wl_list_init (&priv->frame_callback_list); +- meta_surface_actor_wayland_add_frame_callbacks (surface_actor_wayland, +- &pending->frame_callback_list); ++ if (!priv->actor) ++ return; ++ ++ if (wl_list_empty (&pending->frame_callback_list)) ++ return; ++ ++ wl_list_insert_list (priv->frame_callback_list.prev, ++ &pending->frame_callback_list); + wl_list_init (&pending->frame_callback_list); ++ ++ meta_wayland_compositor_add_frame_callback_surface (surface->compositor, ++ surface); ++} ++ ++void ++meta_wayland_actor_surface_emit_frame_callbacks (MetaWaylandActorSurface *actor_surface, ++ uint32_t timestamp_ms) ++{ ++ MetaWaylandActorSurfacePrivate *priv = ++ meta_wayland_actor_surface_get_instance_private (actor_surface); ++ ++ while (!wl_list_empty (&priv->frame_callback_list)) ++ { ++ MetaWaylandFrameCallback *callback = ++ wl_container_of (priv->frame_callback_list.next, callback, link); ++ ++ wl_callback_send_done (callback->resource, timestamp_ms); ++ wl_resource_destroy (callback->resource); ++ } + } + + static double +@@ -268,12 +299,14 @@ meta_wayland_actor_surface_commit (MetaWaylandSurfaceRole *surface_role, + meta_wayland_surface_role_get_surface (surface_role); + MetaWaylandSurface *toplevel_surface; + +- if (!priv->actor) ++ if (!wl_list_empty (&pending->frame_callback_list) && ++ priv->actor && ++ !meta_surface_actor_is_obscured (priv->actor)) + { +- wl_list_insert_list (&priv->frame_callback_list, +- &pending->frame_callback_list); +- wl_list_init (&pending->frame_callback_list); +- return; ++ MetaBackend *backend = meta_get_backend (); ++ ClutterActor *stage = meta_backend_get_stage (backend); ++ ++ clutter_stage_schedule_update (CLUTTER_STAGE (stage)); + } + + meta_wayland_actor_surface_queue_frame_callbacks (actor_surface, pending); +diff --git a/src/wayland/meta-wayland-actor-surface.h b/src/wayland/meta-wayland-actor-surface.h +index 444b3b1785..e79f1caff5 100644 +--- a/src/wayland/meta-wayland-actor-surface.h ++++ b/src/wayland/meta-wayland-actor-surface.h +@@ -46,4 +46,7 @@ void meta_wayland_actor_surface_reset_actor (MetaWaylandActorSurface *actor_surf + void meta_wayland_actor_surface_queue_frame_callbacks (MetaWaylandActorSurface *actor_surface, + MetaWaylandPendingState *pending); + ++void meta_wayland_actor_surface_emit_frame_callbacks (MetaWaylandActorSurface *actor_surface, ++ uint32_t timestamp_ms); ++ + #endif /* META_WAYLAND_ACTOR_SURFACE_H */ +diff --git a/src/wayland/meta-wayland-cursor-surface.c b/src/wayland/meta-wayland-cursor-surface.c +index d46b3511fa..6b791eb378 100644 +--- a/src/wayland/meta-wayland-cursor-surface.c ++++ b/src/wayland/meta-wayland-cursor-surface.c +@@ -124,8 +124,8 @@ meta_wayland_cursor_surface_assigned (MetaWaylandSurfaceRole *surface_role) + meta_wayland_cursor_surface_get_instance_private (cursor_surface); + + wl_list_insert_list (&priv->frame_callbacks, +- &surface->pending_frame_callback_list); +- wl_list_init (&surface->pending_frame_callback_list); ++ &surface->unassigned.pending_frame_callback_list); ++ wl_list_init (&surface->unassigned.pending_frame_callback_list); + } + + static void +diff --git a/src/wayland/meta-wayland-dnd-surface.c b/src/wayland/meta-wayland-dnd-surface.c +index 2aad6dcd5d..8ddeb2a7bd 100644 +--- a/src/wayland/meta-wayland-dnd-surface.c ++++ b/src/wayland/meta-wayland-dnd-surface.c +@@ -21,6 +21,8 @@ + + #include "wayland/meta-wayland-dnd-surface.h" + ++#include "wayland/meta-wayland.h" ++ + struct _MetaWaylandSurfaceRoleDND + { + MetaWaylandActorSurface parent; +@@ -36,7 +38,11 @@ dnd_surface_assigned (MetaWaylandSurfaceRole *surface_role) + MetaWaylandSurface *surface = + meta_wayland_surface_role_get_surface (surface_role); + +- meta_wayland_surface_queue_pending_frame_callbacks (surface); ++ if (wl_list_empty (&surface->unassigned.pending_frame_callback_list)) ++ return; ++ ++ meta_wayland_compositor_add_frame_callback_surface (surface->compositor, ++ surface); + } + + static void +@@ -46,7 +52,8 @@ dnd_surface_commit (MetaWaylandSurfaceRole *surface_role, + MetaWaylandSurface *surface = + meta_wayland_surface_role_get_surface (surface_role); + +- meta_wayland_surface_queue_pending_state_frame_callbacks (surface, pending); ++ meta_wayland_compositor_add_frame_callback_surface (surface->compositor, ++ surface); + } + + static void +diff --git a/src/wayland/meta-wayland-legacy-xdg-shell.c b/src/wayland/meta-wayland-legacy-xdg-shell.c +index 8230641770..b78552f31b 100644 +--- a/src/wayland/meta-wayland-legacy-xdg-shell.c ++++ b/src/wayland/meta-wayland-legacy-xdg-shell.c +@@ -659,6 +659,8 @@ meta_wayland_zxdg_toplevel_v6_commit (MetaWaylandSurfaceRole *surface_role, + META_WAYLAND_ZXDG_SURFACE_V6 (xdg_toplevel); + MetaWaylandZxdgSurfaceV6Private *xdg_surface_priv = + meta_wayland_zxdg_surface_v6_get_instance_private (xdg_surface); ++ MetaWaylandActorSurface *actor_surface = ++ META_WAYLAND_ACTOR_SURFACE (xdg_surface); + MetaWaylandSurfaceRoleClass *surface_role_class; + MetaWaylandSurface *surface = + meta_wayland_surface_role_get_surface (surface_role); +@@ -670,7 +672,7 @@ meta_wayland_zxdg_toplevel_v6_commit (MetaWaylandSurfaceRole *surface_role, + window = surface->window; + if (!window) + { +- meta_wayland_surface_cache_pending_frame_callbacks (surface, pending); ++ meta_wayland_actor_surface_queue_frame_callbacks (actor_surface, pending); + return; + } + +@@ -1220,14 +1222,10 @@ meta_wayland_zxdg_surface_v6_send_configure (MetaWaylandZxdgSurfaceV6 *xdg_surfa + static void + zxdg_surface_v6_destructor (struct wl_resource *resource) + { +- MetaWaylandSurface *surface = surface_from_xdg_surface_resource (resource); + MetaWaylandZxdgSurfaceV6 *xdg_surface = wl_resource_get_user_data (resource); + MetaWaylandZxdgSurfaceV6Private *priv = + meta_wayland_zxdg_surface_v6_get_instance_private (xdg_surface); + +- meta_wayland_compositor_destroy_frame_callbacks (surface->compositor, +- surface); +- + priv->shell_client->surfaces = g_list_remove (priv->shell_client->surfaces, + xdg_surface); + +diff --git a/src/wayland/meta-wayland-private.h b/src/wayland/meta-wayland-private.h +index 5bcb0ea4f9..215d0967f6 100644 +--- a/src/wayland/meta-wayland-private.h ++++ b/src/wayland/meta-wayland-private.h +@@ -67,7 +67,7 @@ struct _MetaWaylandCompositor + struct wl_display *wayland_display; + char *display_name; + GHashTable *outputs; +- struct wl_list frame_callbacks; ++ GList *frame_callback_surfaces; + + MetaXWaylandManager xwayland_manager; + +diff --git a/src/wayland/meta-wayland-subsurface.c b/src/wayland/meta-wayland-subsurface.c +index e0fa0a48b2..c7059b99a2 100644 +--- a/src/wayland/meta-wayland-subsurface.c ++++ b/src/wayland/meta-wayland-subsurface.c +@@ -239,8 +239,6 @@ wl_subsurface_destructor (struct wl_resource *resource) + { + MetaWaylandSurface *surface = wl_resource_get_user_data (resource); + +- meta_wayland_compositor_destroy_frame_callbacks (surface->compositor, +- surface); + if (surface->sub.parent) + { + wl_list_remove (&surface->sub.parent_destroy_listener.link); +diff --git a/src/wayland/meta-wayland-surface.c b/src/wayland/meta-wayland-surface.c +index 6ffcd6a7fb..a76ab28c24 100644 +--- a/src/wayland/meta-wayland-surface.c ++++ b/src/wayland/meta-wayland-surface.c +@@ -358,15 +358,6 @@ surface_process_damage (MetaWaylandSurface *surface, + cairo_region_destroy (transformed_region); + } + +-void +-meta_wayland_surface_queue_pending_state_frame_callbacks (MetaWaylandSurface *surface, +- MetaWaylandPendingState *pending) +-{ +- wl_list_insert_list (&surface->compositor->frame_callbacks, +- &pending->frame_callback_list); +- wl_list_init (&pending->frame_callback_list); +-} +- + void + meta_wayland_surface_destroy_window (MetaWaylandSurface *surface) + { +@@ -656,15 +647,6 @@ parent_surface_state_applied (gpointer data, + meta_wayland_subsurface_parent_state_applied (subsurface); + } + +-void +-meta_wayland_surface_cache_pending_frame_callbacks (MetaWaylandSurface *surface, +- MetaWaylandPendingState *pending) +-{ +- wl_list_insert_list (&surface->pending_frame_callback_list, +- &pending->frame_callback_list); +- wl_list_init (&pending->frame_callback_list); +-} +- + void + meta_wayland_surface_apply_pending_state (MetaWaylandSurface *surface, + MetaWaylandPendingState *pending) +@@ -810,7 +792,9 @@ meta_wayland_surface_apply_pending_state (MetaWaylandSurface *surface, + } + else + { +- meta_wayland_surface_cache_pending_frame_callbacks (surface, pending); ++ wl_list_insert_list (surface->unassigned.pending_frame_callback_list.prev, ++ &pending->frame_callback_list); ++ wl_list_init (&pending->frame_callback_list); + + if (pending->newly_attached) + { +@@ -1352,12 +1336,14 @@ wl_surface_destructor (struct wl_resource *resource) + if (surface->input_region) + cairo_region_destroy (surface->input_region); + +- meta_wayland_compositor_destroy_frame_callbacks (compositor, surface); ++ meta_wayland_compositor_remove_frame_callback_surface (compositor, surface); + + g_hash_table_foreach (surface->outputs_to_destroy_notify_id, surface_output_disconnect_signal, surface); + g_hash_table_unref (surface->outputs_to_destroy_notify_id); + +- wl_list_for_each_safe (cb, next, &surface->pending_frame_callback_list, link) ++ wl_list_for_each_safe (cb, next, ++ &surface->unassigned.pending_frame_callback_list, ++ link) + wl_resource_destroy (cb->resource); + + if (surface->resource) +@@ -1401,7 +1387,7 @@ meta_wayland_surface_create (MetaWaylandCompositor *compositor, + surface->resource = wl_resource_create (client, &wl_surface_interface, wl_resource_get_version (compositor_resource), id); + wl_resource_set_implementation (surface->resource, &meta_wayland_wl_surface_interface, surface, wl_surface_destructor); + +- wl_list_init (&surface->pending_frame_callback_list); ++ wl_list_init (&surface->unassigned.pending_frame_callback_list); + + sync_drag_dest_funcs (surface); + +@@ -1809,14 +1795,6 @@ meta_wayland_surface_role_get_surface (MetaWaylandSurfaceRole *role) + return priv->surface; + } + +-void +-meta_wayland_surface_queue_pending_frame_callbacks (MetaWaylandSurface *surface) +-{ +- wl_list_insert_list (&surface->compositor->frame_callbacks, +- &surface->pending_frame_callback_list); +- wl_list_init (&surface->pending_frame_callback_list); +-} +- + cairo_region_t * + meta_wayland_surface_calculate_input_region (MetaWaylandSurface *surface) + { +diff --git a/src/wayland/meta-wayland-surface.h b/src/wayland/meta-wayland-surface.h +index e244a3fdf7..776431fca2 100644 +--- a/src/wayland/meta-wayland-surface.h ++++ b/src/wayland/meta-wayland-surface.h +@@ -160,13 +160,9 @@ struct _MetaWaylandSurface + /* Buffer renderer state. */ + gboolean buffer_held; + +- /* List of pending frame callbacks that needs to stay queued longer than one +- * commit sequence, such as when it has not yet been assigned a role. +- */ +- struct wl_list pending_frame_callback_list; +- + /* Intermediate state for when no role has been assigned. */ + struct { ++ struct wl_list pending_frame_callback_list; + MetaWaylandBuffer *buffer; + } unassigned; + +@@ -274,9 +270,6 @@ MetaWaylandSurface *meta_wayland_surface_get_toplevel (MetaWaylandSurface *surfa + + MetaWindow * meta_wayland_surface_get_toplevel_window (MetaWaylandSurface *surface); + +-void meta_wayland_surface_cache_pending_frame_callbacks (MetaWaylandSurface *surface, +- MetaWaylandPendingState *pending); +- + void meta_wayland_surface_queue_pending_frame_callbacks (MetaWaylandSurface *surface); + + void meta_wayland_surface_queue_pending_state_frame_callbacks (MetaWaylandSurface *surface, +diff --git a/src/wayland/meta-wayland-wl-shell.c b/src/wayland/meta-wayland-wl-shell.c +index 539fb9858e..e80db17e78 100644 +--- a/src/wayland/meta-wayland-wl-shell.c ++++ b/src/wayland/meta-wayland-wl-shell.c +@@ -100,9 +100,6 @@ wl_shell_surface_destructor (struct wl_resource *resource) + surface_from_wl_shell_surface_resource (resource); + GList *l; + +- meta_wayland_compositor_destroy_frame_callbacks (surface->compositor, +- surface); +- + if (wl_shell_surface->popup) + meta_wayland_popup_dismiss (wl_shell_surface->popup); + +diff --git a/src/wayland/meta-wayland-xdg-shell.c b/src/wayland/meta-wayland-xdg-shell.c +index fa0207a03c..4a4995c425 100644 +--- a/src/wayland/meta-wayland-xdg-shell.c ++++ b/src/wayland/meta-wayland-xdg-shell.c +@@ -684,6 +684,8 @@ meta_wayland_xdg_toplevel_commit (MetaWaylandSurfaceRole *surface_role, + MetaWaylandXdgSurface *xdg_surface = META_WAYLAND_XDG_SURFACE (xdg_toplevel); + MetaWaylandXdgSurfacePrivate *xdg_surface_priv = + meta_wayland_xdg_surface_get_instance_private (xdg_surface); ++ MetaWaylandActorSurface *actor_surface = ++ META_WAYLAND_ACTOR_SURFACE (xdg_toplevel); + MetaWaylandSurfaceRoleClass *surface_role_class; + MetaWaylandSurface *surface = + meta_wayland_surface_role_get_surface (surface_role); +@@ -695,15 +697,12 @@ meta_wayland_xdg_toplevel_commit (MetaWaylandSurfaceRole *surface_role, + window = surface->window; + if (!window) + { +- meta_wayland_surface_cache_pending_frame_callbacks (surface, pending); ++ meta_wayland_actor_surface_queue_frame_callbacks (actor_surface, pending); + return; + } + + if (!surface->buffer_ref.buffer && xdg_surface_priv->first_buffer_attached) + { +- MetaWaylandActorSurface *actor_surface = +- META_WAYLAND_ACTOR_SURFACE (xdg_toplevel); +- + meta_wayland_xdg_surface_reset (xdg_surface); + meta_wayland_actor_surface_queue_frame_callbacks (actor_surface, + pending); +@@ -1037,6 +1036,8 @@ meta_wayland_xdg_popup_commit (MetaWaylandSurfaceRole *surface_role, + MetaWaylandXdgSurface *xdg_surface = META_WAYLAND_XDG_SURFACE (surface_role); + MetaWaylandXdgSurfacePrivate *xdg_surface_priv = + meta_wayland_xdg_surface_get_instance_private (xdg_surface); ++ MetaWaylandActorSurface *actor_surface = ++ META_WAYLAND_ACTOR_SURFACE (xdg_popup); + MetaWaylandSurfaceRoleClass *surface_role_class; + MetaWaylandSurface *surface = + meta_wayland_surface_role_get_surface (surface_role); +@@ -1048,7 +1049,7 @@ meta_wayland_xdg_popup_commit (MetaWaylandSurfaceRole *surface_role, + if (!surface->buffer_ref.buffer && xdg_surface_priv->first_buffer_attached) + { + meta_wayland_xdg_surface_reset (xdg_surface); +- meta_wayland_surface_cache_pending_frame_callbacks (surface, pending); ++ meta_wayland_actor_surface_queue_frame_callbacks (actor_surface, pending); + return; + } + +@@ -1313,14 +1314,10 @@ meta_wayland_xdg_surface_send_configure (MetaWaylandXdgSurface *xdg_surface) + static void + xdg_surface_destructor (struct wl_resource *resource) + { +- MetaWaylandSurface *surface = surface_from_xdg_surface_resource (resource); + MetaWaylandXdgSurface *xdg_surface = wl_resource_get_user_data (resource); + MetaWaylandXdgSurfacePrivate *priv = + meta_wayland_xdg_surface_get_instance_private (xdg_surface); + +- meta_wayland_compositor_destroy_frame_callbacks (surface->compositor, +- surface); +- + priv->shell_client->surfaces = g_list_remove (priv->shell_client->surfaces, + xdg_surface); + +diff --git a/src/wayland/meta-wayland.c b/src/wayland/meta-wayland.c +index 129da8e20d..4cb9ca650d 100644 +--- a/src/wayland/meta-wayland.c ++++ b/src/wayland/meta-wayland.c +@@ -194,15 +194,35 @@ meta_wayland_compositor_update (MetaWaylandCompositor *compositor, + void + meta_wayland_compositor_paint_finished (MetaWaylandCompositor *compositor) + { +- gint64 current_time = g_get_monotonic_time (); ++ GList *l; ++ int64_t now_us; + +- while (!wl_list_empty (&compositor->frame_callbacks)) ++ now_us = g_get_monotonic_time (); ++ ++ l = compositor->frame_callback_surfaces; ++ while (l) + { +- MetaWaylandFrameCallback *callback = +- wl_container_of (compositor->frame_callbacks.next, callback, link); ++ GList *l_cur = l; ++ MetaWaylandSurface *surface = l->data; ++ MetaSurfaceActor *actor; ++ MetaWaylandActorSurface *actor_surface; ++ ++ l = l->next; ++ ++ actor = meta_wayland_surface_get_actor (surface); ++ if (!actor) ++ continue; ++ ++ if (!clutter_actor_has_mapped_clones (CLUTTER_ACTOR (actor)) && ++ meta_surface_actor_is_obscured (actor)) ++ continue; + +- wl_callback_send_done (callback->resource, current_time / 1000); +- wl_resource_destroy (callback->resource); ++ actor_surface = META_WAYLAND_ACTOR_SURFACE (surface->role); ++ meta_wayland_actor_surface_emit_frame_callbacks (actor_surface, ++ now_us / 1000); ++ ++ compositor->frame_callback_surfaces = ++ g_list_delete_link (compositor->frame_callback_surfaces, l_cur); + } + } + +@@ -249,16 +269,22 @@ meta_wayland_compositor_update_key_state (MetaWaylandCompositor *compositor, + } + + void +-meta_wayland_compositor_destroy_frame_callbacks (MetaWaylandCompositor *compositor, +- MetaWaylandSurface *surface) ++meta_wayland_compositor_add_frame_callback_surface (MetaWaylandCompositor *compositor, ++ MetaWaylandSurface *surface) + { +- MetaWaylandFrameCallback *callback, *next; ++ if (g_list_find (compositor->frame_callback_surfaces, surface)) ++ return; + +- wl_list_for_each_safe (callback, next, &compositor->frame_callbacks, link) +- { +- if (callback->surface == surface) +- wl_resource_destroy (callback->resource); +- } ++ compositor->frame_callback_surfaces = ++ g_list_prepend (compositor->frame_callback_surfaces, surface); ++} ++ ++void ++meta_wayland_compositor_remove_frame_callback_surface (MetaWaylandCompositor *compositor, ++ MetaWaylandSurface *surface) ++{ ++ compositor->frame_callback_surfaces = ++ g_list_remove (compositor->frame_callback_surfaces, surface); + } + + static void +@@ -309,8 +335,6 @@ meta_wayland_log_func (const char *fmt, + static void + meta_wayland_compositor_init (MetaWaylandCompositor *compositor) + { +- wl_list_init (&compositor->frame_callbacks); +- + compositor->scheduled_surface_associations = g_hash_table_new (NULL, NULL); + + wl_log_set_handler_server (meta_wayland_log_func); +diff --git a/src/wayland/meta-wayland.h b/src/wayland/meta-wayland.h +index 2a0aa11400..c5e5924891 100644 +--- a/src/wayland/meta-wayland.h ++++ b/src/wayland/meta-wayland.h +@@ -64,9 +64,11 @@ void meta_wayland_compositor_set_input_focus (MetaWaylandComp + META_EXPORT_TEST + void meta_wayland_compositor_paint_finished (MetaWaylandCompositor *compositor); + +-META_EXPORT_TEST +-void meta_wayland_compositor_destroy_frame_callbacks (MetaWaylandCompositor *compositor, +- MetaWaylandSurface *surface); ++void meta_wayland_compositor_add_frame_callback_surface (MetaWaylandCompositor *compositor, ++ MetaWaylandSurface *surface); ++ ++void meta_wayland_compositor_remove_frame_callback_surface (MetaWaylandCompositor *compositor, ++ MetaWaylandSurface *surface); + + META_EXPORT_TEST + const char *meta_wayland_get_wayland_display_name (MetaWaylandCompositor *compositor); +diff --git a/src/wayland/meta-xwayland.c b/src/wayland/meta-xwayland.c +index 275aeb78cb..6e4b9a8ffd 100644 +--- a/src/wayland/meta-xwayland.c ++++ b/src/wayland/meta-xwayland.c +@@ -788,49 +788,6 @@ meta_xwayland_stop (MetaXWaylandManager *manager) + } + } + +-static void +-xwayland_surface_assigned (MetaWaylandSurfaceRole *surface_role) +-{ +- MetaWaylandSurface *surface = +- meta_wayland_surface_role_get_surface (surface_role); +- MetaWaylandSurfaceRoleClass *surface_role_class = +- META_WAYLAND_SURFACE_ROLE_CLASS (meta_wayland_surface_role_xwayland_parent_class); +- +- /* See comment in xwayland_surface_commit for why we reply even though the +- * surface may not be drawn the next frame. +- */ +- wl_list_insert_list (&surface->compositor->frame_callbacks, +- &surface->pending_frame_callback_list); +- wl_list_init (&surface->pending_frame_callback_list); +- +- surface_role_class->assigned (surface_role); +-} +- +-static void +-xwayland_surface_commit (MetaWaylandSurfaceRole *surface_role, +- MetaWaylandPendingState *pending) +-{ +- MetaWaylandSurface *surface = +- meta_wayland_surface_role_get_surface (surface_role); +- MetaWaylandSurfaceRoleClass *surface_role_class = +- META_WAYLAND_SURFACE_ROLE_CLASS (meta_wayland_surface_role_xwayland_parent_class); +- +- /* For Xwayland windows, throttling frames when the window isn't actually +- * drawn is less useful, because Xwayland still has to do the drawing sent +- * from the application - the throttling would only be of sending us damage +- * messages, so we simplify and send frame callbacks after the next paint of +- * the screen, whether the window was drawn or not. +- * +- * Currently it may take a few frames before we draw the window, for not +- * completely understood reasons, and in that case, not thottling frame +- * callbacks to drawing has the happy side effect that we avoid showing the +- * user the initial black frame from when the window is mapped empty. +- */ +- meta_wayland_surface_queue_pending_state_frame_callbacks (surface, pending); +- +- surface_role_class->commit (surface_role, pending); +-} +- + static MetaWaylandSurface * + xwayland_surface_get_toplevel (MetaWaylandSurfaceRole *surface_role) + { +@@ -848,8 +805,6 @@ meta_wayland_surface_role_xwayland_class_init (MetaWaylandSurfaceRoleXWaylandCla + MetaWaylandSurfaceRoleClass *surface_role_class = + META_WAYLAND_SURFACE_ROLE_CLASS (klass); + +- surface_role_class->assigned = xwayland_surface_assigned; +- surface_role_class->commit = xwayland_surface_commit; + surface_role_class->get_toplevel = xwayland_surface_get_toplevel; + + xwayland_surface_signals[XWAYLAND_SURFACE_WINDOW_ASSOCIATED] = +-- +2.31.1 + + +From 076ac20d34db128aea8ffe0dc3c2791918667c43 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Jonas=20=C3=85dahl?= +Date: Fri, 6 Aug 2021 19:46:06 +0200 +Subject: [PATCH 5/5] wayland: Respond to frame callbacks even if the paint was + empty + +--- + src/compositor/compositor.c | 10 +++++----- + 1 file changed, 5 insertions(+), 5 deletions(-) + +diff --git a/src/compositor/compositor.c b/src/compositor/compositor.c +index ce2c1b8a3b..8331737d1a 100644 +--- a/src/compositor/compositor.c ++++ b/src/compositor/compositor.c +@@ -467,11 +467,6 @@ after_stage_paint (ClutterStage *stage, + + for (l = compositor->windows; l; l = l->next) + meta_window_actor_post_paint (l->data); +- +-#ifdef HAVE_WAYLAND +- if (meta_is_wayland_compositor ()) +- meta_wayland_compositor_paint_finished (meta_wayland_compositor_get_default ()); +-#endif + } + + static void +@@ -1404,6 +1399,11 @@ meta_post_paint_func (gpointer data) + break; + } + ++#ifdef HAVE_WAYLAND ++ if (meta_is_wayland_compositor ()) ++ meta_wayland_compositor_paint_finished (meta_wayland_compositor_get_default ()); ++#endif ++ + return TRUE; + } + +-- +2.31.1 + diff --git a/SPECS/mutter.spec b/SPECS/mutter.spec index 82948cb..ee389e0 100644 --- a/SPECS/mutter.spec +++ b/SPECS/mutter.spec @@ -8,7 +8,7 @@ Name: mutter Version: 3.32.2 -Release: 58%{?dist} +Release: 59%{?dist} Summary: Window and compositing manager based on Clutter License: GPLv2+ @@ -186,6 +186,9 @@ Patch520: 0001-clutter-Backport-of-touch-mode.patch # Backport passing -xauth and adding local user to xhost (#1949176) Patch521: xwayland-xauth-xhost-user.patch +# Backport fixes avoiding frozen partly off-screen clients (#1989035) +Patch522: wayland-frame-callback-rework.patch + BuildRequires: chrpath BuildRequires: pango-devel BuildRequires: startup-notification-devel @@ -327,6 +330,10 @@ desktop-file-validate %{buildroot}/%{_datadir}/applications/%{name}.desktop %{_datadir}/mutter-%{mutter_api_version}/tests %changelog +* Fri Aug 06 2021 Jonas Ådahl - 3.32.2-59 +- Backport fixes avoiding frozen partly off-screen clients + Resolves: #1989035 + * Mon Jul 05 2021 Jonas Ådahl - 3.32.2-58 - Backport xauth and xhost patches Resolves: #1949176