diff --git a/0001-backends-Update-stage-views-and-stage-dimension-from.patch b/0001-backends-Update-stage-views-and-stage-dimension-from.patch new file mode 100644 index 0000000..cf2438a --- /dev/null +++ b/0001-backends-Update-stage-views-and-stage-dimension-from.patch @@ -0,0 +1,178 @@ +From cedeee4eb0c252d2450b7174b35f47ff5c27fc8e Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Jonas=20=C3=85dahl?= +Date: Wed, 12 Mar 2025 11:35:17 +0800 +Subject: [PATCH 1/2] backends: Update stage views and stage dimension from + MetaStage + +This reduces the amount of code duplication between the native and +nested backend. +--- + src/backends/meta-stage-impl-private.h | 2 ++ + src/backends/meta-stage-impl.c | 12 ++++++++++++ + src/backends/meta-stage-private.h | 2 ++ + src/backends/meta-stage.c | 16 ++++++++++++++++ + src/backends/native/meta-backend-native.c | 5 +---- + src/backends/native/meta-stage-native.c | 12 ------------ + src/backends/native/meta-stage-native.h | 2 -- + .../x11/nested/meta-backend-x11-nested.c | 11 ++--------- + 8 files changed, 35 insertions(+), 27 deletions(-) + +diff --git a/src/backends/meta-stage-impl-private.h b/src/backends/meta-stage-impl-private.h +index 766c283488..93b8bbad2f 100644 +--- a/src/backends/meta-stage-impl-private.h ++++ b/src/backends/meta-stage-impl-private.h +@@ -64,4 +64,6 @@ MetaBackend * meta_stage_impl_get_backend (MetaStageImpl *stage_impl); + void meta_stage_impl_add_onscreen_frame_info (MetaStageImpl *stage_impl, + ClutterStageView *view); + ++void meta_stage_impl_rebuild_views (MetaStageImpl *stage_impl); ++ + G_END_DECLS +diff --git a/src/backends/meta-stage-impl.c b/src/backends/meta-stage-impl.c +index 945e95ff2b..804d77f25d 100644 +--- a/src/backends/meta-stage-impl.c ++++ b/src/backends/meta-stage-impl.c +@@ -34,6 +34,7 @@ + #include + #include + ++#include "backends/meta-renderer.h" + #include "backends/meta-stage-view-private.h" + #include "clutter/clutter-mutter.h" + #include "cogl/cogl.h" +@@ -907,3 +908,14 @@ meta_stage_impl_get_backend (MetaStageImpl *stage_impl) + + return priv->backend; + } ++ ++void ++meta_stage_impl_rebuild_views (MetaStageImpl *stage_impl) ++{ ++ MetaBackend *backend = meta_stage_impl_get_backend (stage_impl); ++ MetaRenderer *renderer = meta_backend_get_renderer (backend); ++ ClutterActor *stage = meta_backend_get_stage (backend); ++ ++ meta_renderer_rebuild_views (renderer); ++ clutter_stage_clear_stage_views (CLUTTER_STAGE (stage)); ++} +diff --git a/src/backends/meta-stage-private.h b/src/backends/meta-stage-private.h +index 5546cc8ccf..e59ea35c6c 100644 +--- a/src/backends/meta-stage-private.h ++++ b/src/backends/meta-stage-private.h +@@ -68,4 +68,6 @@ META_EXPORT_TEST + void meta_stage_remove_watch (MetaStage *stage, + MetaStageWatch *watch); + ++void meta_stage_rebuild_views (MetaStage *stage); ++ + G_END_DECLS +diff --git a/src/backends/meta-stage.c b/src/backends/meta-stage.c +index 96224a03b5..32f681c8c5 100644 +--- a/src/backends/meta-stage.c ++++ b/src/backends/meta-stage.c +@@ -494,3 +494,19 @@ meta_stage_remove_watch (MetaStage *stage, + + g_assert (removed); + } ++ ++void ++meta_stage_rebuild_views (MetaStage *stage) ++{ ++ ClutterStageWindow *stage_window = ++ _clutter_stage_get_window (CLUTTER_STAGE (stage)); ++ MetaStageImpl *stage_impl = META_STAGE_IMPL (stage_window); ++ MetaMonitorManager *monitor_manager = ++ meta_backend_get_monitor_manager (stage->backend); ++ int width, height; ++ ++ meta_stage_impl_rebuild_views (stage_impl); ++ ++ meta_monitor_manager_get_screen_size (monitor_manager, &width, &height); ++ clutter_actor_set_size (CLUTTER_ACTOR (stage), width, height); ++} +diff --git a/src/backends/native/meta-backend-native.c b/src/backends/native/meta-backend-native.c +index ee02b2783a..85bfeb7810 100644 +--- a/src/backends/native/meta-backend-native.c ++++ b/src/backends/native/meta-backend-native.c +@@ -399,14 +399,11 @@ static void + meta_backend_native_update_stage (MetaBackend *backend) + { + ClutterActor *stage = meta_backend_get_stage (backend); +- ClutterStageWindow *stage_window = +- _clutter_stage_get_window (CLUTTER_STAGE (stage)); +- MetaStageNative *stage_native = META_STAGE_NATIVE (stage_window); + MetaMonitorManager *monitor_manager = + meta_backend_get_monitor_manager (backend); + int width, height; + +- meta_stage_native_rebuild_views (stage_native); ++ meta_stage_rebuild_views (META_STAGE (stage)); + + meta_monitor_manager_get_screen_size (monitor_manager, &width, &height); + clutter_actor_set_size (stage, width, height); +diff --git a/src/backends/native/meta-stage-native.c b/src/backends/native/meta-stage-native.c +index 80d869b920..34849e5b9c 100644 +--- a/src/backends/native/meta-stage-native.c ++++ b/src/backends/native/meta-stage-native.c +@@ -54,18 +54,6 @@ G_DEFINE_TYPE_WITH_CODE (MetaStageNative, meta_stage_native, + G_IMPLEMENT_INTERFACE (CLUTTER_TYPE_STAGE_WINDOW, + clutter_stage_window_iface_init)) + +-void +-meta_stage_native_rebuild_views (MetaStageNative *stage_native) +-{ +- MetaStageImpl *stage_impl = META_STAGE_IMPL (stage_native); +- MetaBackend *backend = meta_stage_impl_get_backend (stage_impl); +- MetaRenderer *renderer = meta_backend_get_renderer (backend); +- ClutterActor *stage = meta_backend_get_stage (backend); +- +- meta_renderer_rebuild_views (renderer); +- clutter_stage_clear_stage_views (CLUTTER_STAGE (stage)); +-} +- + static gboolean + meta_stage_native_can_clip_redraws (ClutterStageWindow *stage_window) + { +diff --git a/src/backends/native/meta-stage-native.h b/src/backends/native/meta-stage-native.h +index 18ce3b14bb..cf081a32ea 100644 +--- a/src/backends/native/meta-stage-native.h ++++ b/src/backends/native/meta-stage-native.h +@@ -28,5 +28,3 @@ + #define META_TYPE_STAGE_NATIVE (meta_stage_native_get_type ()) + G_DECLARE_FINAL_TYPE (MetaStageNative, meta_stage_native, + META, STAGE_NATIVE, MetaStageImpl) +- +-void meta_stage_native_rebuild_views (MetaStageNative *stage_native); +diff --git a/src/backends/x11/nested/meta-backend-x11-nested.c b/src/backends/x11/nested/meta-backend-x11-nested.c +index ec82f1d1a9..09d2a91cb6 100644 +--- a/src/backends/x11/nested/meta-backend-x11-nested.c ++++ b/src/backends/x11/nested/meta-backend-x11-nested.c +@@ -21,6 +21,7 @@ + + #include "backends/meta-input-settings-dummy.h" + #include "backends/meta-monitor-manager-dummy.h" ++#include "backends/meta-stage-private.h" + #include "backends/x11/nested/meta-backend-x11-nested.h" + #include "backends/x11/nested/meta-cursor-renderer-x11-nested.h" + #include "backends/x11/nested/meta-renderer-x11-nested.h" +@@ -107,16 +108,8 @@ static void + meta_backend_x11_nested_update_stage (MetaBackend *backend) + { + ClutterActor *stage = meta_backend_get_stage (backend); +- MetaRenderer *renderer = meta_backend_get_renderer (backend); +- MetaMonitorManager *monitor_manager = +- meta_backend_get_monitor_manager (backend); +- int width, height; + +- meta_renderer_rebuild_views (renderer); +- clutter_stage_clear_stage_views (CLUTTER_STAGE (stage)); +- +- meta_monitor_manager_get_screen_size (monitor_manager, &width, &height); +- clutter_actor_set_size (stage, width, height); ++ meta_stage_rebuild_views (META_STAGE (stage)); + } + + static void +-- +2.44.0.501.g19981daefd.dirty + diff --git a/0002-stage-Track-overlay-damage-per-view.patch b/0002-stage-Track-overlay-damage-per-view.patch new file mode 100644 index 0000000..ba3b0b3 --- /dev/null +++ b/0002-stage-Track-overlay-damage-per-view.patch @@ -0,0 +1,266 @@ +From 3e09a7f1717d8c4b0a815fd9673471a52d6328b9 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Jonas=20=C3=85dahl?= +Date: Wed, 12 Mar 2025 11:56:46 +0800 +Subject: [PATCH 2/2] stage: Track overlay damage per view + +The previously painted rectangle of an overlay is not a global state, +but depends on what view it was painted on. There was also an issue +where an overlay being updated but not changing position, e.g. due to a +0,0 pointer movement or an absolute pointer movement with the position +not changing, not properly triggering damage of the old position when it +eventually actually moved. + +Fix this by tracking damage per view, while also fixing the state +tracking to handle unchanged positions. +--- + src/backends/meta-stage.c | 163 +++++++++++++++++++++++++------------- + 1 file changed, 107 insertions(+), 56 deletions(-) + +diff --git a/src/backends/meta-stage.c b/src/backends/meta-stage.c +index 32f681c8c5..58f15bbb33 100644 +--- a/src/backends/meta-stage.c ++++ b/src/backends/meta-stage.c +@@ -38,6 +38,12 @@ struct _MetaStageWatch + gpointer user_data; + }; + ++typedef struct _MetaOverlayViewState ++{ ++ graphene_rect_t painted_rect; ++ gboolean has_painted_rect; ++} MetaOverlayViewState; ++ + struct _MetaOverlay + { + MetaStage *stage; +@@ -49,8 +55,8 @@ struct _MetaOverlay + + graphene_matrix_t transform; + graphene_rect_t current_rect; +- graphene_rect_t previous_rect; +- gboolean previous_is_valid; ++ ++ GHashTable *view_states; + }; + + struct _MetaStage +@@ -77,6 +83,7 @@ meta_overlay_new (MetaStage *stage) + overlay = g_new0 (MetaOverlay, 1); + overlay->stage = stage; + overlay->pipeline = cogl_pipeline_new (ctx); ++ overlay->view_states = g_hash_table_new_full (NULL, NULL, NULL, g_free); + + return overlay; + } +@@ -86,6 +93,7 @@ meta_overlay_free (MetaOverlay *overlay) + { + if (overlay->pipeline) + g_object_unref (overlay->pipeline); ++ g_hash_table_unref (overlay->view_states); + + g_free (overlay); + } +@@ -115,19 +123,57 @@ meta_overlay_set (MetaOverlay *overlay, + overlay->current_rect = *dst_rect; + } + ++static MetaOverlayViewState * ++get_view_state (MetaOverlay *overlay, ++ ClutterStageView *view) ++{ ++ return g_hash_table_lookup (overlay->view_states, view); ++} ++ ++static MetaOverlayViewState * ++ensure_view_state (MetaOverlay *overlay, ++ ClutterStageView *view) ++{ ++ MetaOverlayViewState *view_state; ++ ++ view_state = get_view_state (overlay, view); ++ ++ if (!view_state) ++ { ++ view_state = g_new0 (MetaOverlayViewState, 1); ++ g_hash_table_insert (overlay->view_states, view, view_state); ++ } ++ ++ return view_state; ++} ++ ++static void ++meta_overlay_invalidate_views (MetaOverlay *overlay) ++{ ++ g_hash_table_remove_all (overlay->view_states); ++} ++ + static void + meta_overlay_paint (MetaOverlay *overlay, + ClutterPaintContext *paint_context) + { ++ ClutterStageView *view; ++ MetaOverlayViewState *view_state = NULL; + CoglFramebuffer *framebuffer; + +- if (!overlay->texture) +- return; ++ view = clutter_paint_context_get_stage_view (paint_context); ++ if (view) ++ view_state = ensure_view_state (overlay, view); + +- if (!overlay->is_visible && ++ if ((!overlay->texture || ++ !overlay->is_visible) && + !(clutter_paint_context_get_paint_flags (paint_context) & + CLUTTER_PAINT_FLAG_FORCE_CURSORS)) +- return; ++ { ++ if (view_state) ++ view_state->has_painted_rect = FALSE; ++ return; ++ } + + framebuffer = clutter_paint_context_get_framebuffer (paint_context); + cogl_framebuffer_draw_rectangle (framebuffer, +@@ -139,10 +185,10 @@ meta_overlay_paint (MetaOverlay *overlay, + (overlay->current_rect.origin.y + + overlay->current_rect.size.height)); + +- if (!graphene_rect_equal (&overlay->previous_rect, &overlay->current_rect)) ++ if (view_state) + { +- overlay->previous_rect = overlay->current_rect; +- overlay->previous_is_valid = TRUE; ++ view_state->painted_rect = overlay->current_rect; ++ view_state->has_painted_rect = TRUE; + } + } + +@@ -343,67 +389,68 @@ meta_stage_new (MetaBackend *backend) + } + + static void +-queue_cursor_overlay_redraw_clutter_rect (MetaStage *stage, +- MetaOverlay *overlay, +- graphene_rect_t *rect) ++intersect_and_queue_redraw (ClutterStageView *view, ++ const MtkRectangle *clip) + { +- MtkRectangle clip = { +- .x = (int) floorf (rect->origin.x), +- .y = (int) floorf (rect->origin.y), +- .width = (int) ceilf (rect->size.width), +- .height = (int) ceilf (rect->size.height) +- }; +- GList *l; ++ MtkRectangle view_layout; ++ MtkRectangle view_clip; + +- /* Since we're flooring the coordinates, we need to enlarge the clip by the +- * difference between the actual coordinate and the floored value */ +- clip.width += (int) ceilf (rect->origin.x - clip.x) * 2; +- clip.height += (int) ceilf (rect->origin.y - clip.y) * 2; ++ clutter_stage_view_get_layout (view, &view_layout); + +- for (l = clutter_stage_peek_stage_views (CLUTTER_STAGE (stage)); +- l; +- l = l->next) ++ if (mtk_rectangle_intersect (clip, &view_layout, &view_clip)) + { +- ClutterStageView *view = l->data; +- MtkRectangle view_layout; +- MtkRectangle view_clip; +- +- if (clutter_stage_view_get_default_paint_flags (view) & +- CLUTTER_PAINT_FLAG_NO_CURSORS) +- continue; +- +- if (meta_stage_view_is_cursor_overlay_inhibited (META_STAGE_VIEW (view))) +- return; ++ clutter_stage_view_add_redraw_clip (view, &view_clip); ++ clutter_stage_view_schedule_update (view); ++ } ++} + +- clutter_stage_view_get_layout (view, &view_layout); ++static void ++cursor_rect_to_clip (const graphene_rect_t *cursor_rect, ++ MtkRectangle *clip_rect) ++{ ++ mtk_rectangle_from_graphene_rect (cursor_rect, ++ MTK_ROUNDING_STRATEGY_GROW, ++ clip_rect); + +- if (mtk_rectangle_intersect (&clip, &view_layout, &view_clip)) +- { +- clutter_stage_view_add_redraw_clip (view, &view_clip); +- clutter_stage_view_schedule_update (view); +- } +- } ++ /* Since we're flooring the coordinates, we need to enlarge the clip by the ++ * difference between the actual coordinate and the floored value */ ++ clip_rect->width += (int) ceilf (cursor_rect->origin.x - clip_rect->x) * 2; ++ clip_rect->height += (int) ceilf (cursor_rect->origin.y - clip_rect->y) * 2; + } + + static void + queue_redraw_for_cursor_overlay (MetaStage *stage, + MetaOverlay *overlay) + { +- /* Clear the location the overlay was at before, if we need to. */ +- if (overlay->previous_is_valid) +- { +- queue_cursor_overlay_redraw_clutter_rect (stage, +- overlay, +- &overlay->previous_rect); +- overlay->previous_is_valid = FALSE; +- } ++ GList *l; + +- /* Draw the overlay at the new position */ +- if (overlay->is_visible && overlay->texture) ++ for (l = clutter_stage_peek_stage_views (CLUTTER_STAGE (stage)); ++ l; ++ l = l->next) + { +- queue_cursor_overlay_redraw_clutter_rect (stage, +- overlay, +- &overlay->current_rect); ++ ClutterStageView *view = CLUTTER_STAGE_VIEW (l->data); ++ MetaOverlayViewState *view_state; ++ ++ view_state = ensure_view_state (overlay, view); ++ if (view_state->has_painted_rect) ++ { ++ MtkRectangle clip; ++ ++ cursor_rect_to_clip (&view_state->painted_rect, &clip); ++ intersect_and_queue_redraw (view, &clip); ++ } ++ ++ if (overlay->is_visible && ++ overlay->texture && ++ !(clutter_stage_view_get_default_paint_flags (view) & ++ CLUTTER_PAINT_FLAG_NO_CURSORS) && ++ !meta_stage_view_is_cursor_overlay_inhibited (META_STAGE_VIEW (view))) ++ { ++ MtkRectangle clip; ++ ++ cursor_rect_to_clip (&overlay->current_rect, &clip); ++ intersect_and_queue_redraw (view, &clip); ++ } + } + } + +@@ -509,4 +556,8 @@ meta_stage_rebuild_views (MetaStage *stage) + + meta_monitor_manager_get_screen_size (monitor_manager, &width, &height); + clutter_actor_set_size (CLUTTER_ACTOR (stage), width, height); ++ ++ g_list_foreach (stage->overlays, ++ (GFunc) meta_overlay_invalidate_views, ++ NULL); + } +-- +2.44.0.501.g19981daefd.dirty + diff --git a/mutter.spec b/mutter.spec index 4ec9f55..36ba8f7 100644 --- a/mutter.spec +++ b/mutter.spec @@ -65,6 +65,10 @@ Patch: 0003-monitor-manager-Configure-for-lease-monitors-in-Appl.patch Patch: 0001-wayland-Fix-refresh-interval-reporting-in-presentati.patch Patch: 0002-input-capture-session-Disconnect-on_keymap_changed-o.patch +# Overlay cursor damage fix: RHEL-58079, RHEL-81897 +Patch: 0001-backends-Update-stage-views-and-stage-dimension-from.patch +Patch: 0002-stage-Track-overlay-damage-per-view.patch + BuildRequires: pkgconfig(gobject-introspection-1.0) >= 1.41.0 BuildRequires: pkgconfig(sm) BuildRequires: pkgconfig(libwacom)