Submitted By:            Douglas R. Reno <renodr at linuxfromscratch dot org>
Date:                    2025-03-25
Initial Package Version: 48.0
Upstream Status:         Applied (MRs 4345 and 4338)
Origin:                  Upstream
Description:             Fixes crashes and freezes that occur on systems with
                         multiple montiors. Thank you to Xi for bringing it up
                         in the Mutter ticket. These patches came from Arch,
                         but have been merged upstream (the patches were taken
                         from Arch because upstream was down at the time of the
                         update).

From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: "Jan Alexander Steffens (heftig)" <heftig@archlinux.org>
Date: Tue, 18 Mar 2025 22:58:37 +0100
Subject: [PATCH] cursor: Unify prepare_func for shape cursors

Move the root cursor prepare function into MetaCursorSpriteXcursor to
become its default prepare function. This should solve two issues:

- The root cursor prepare function was changed in f77d8e2a12a07ef6abe9
  to solve an issue with fractional scales. The tool cursor prepare
  function was missing this fix.
- The cursors created via the shape protocol had no prepare function at
  all, so were not getting scaled.

Closes: https://gitlab.gnome.org/GNOME/mutter/-/issues/3975
---
 src/backends/meta-cursor-sprite-xcursor.c | 57 ++++++++++++++++++++
 src/core/display.c                        | 63 ++---------------------
 src/wayland/meta-wayland-tablet-tool.c    | 39 --------------
 3 files changed, 60 insertions(+), 99 deletions(-)

diff --git a/src/backends/meta-cursor-sprite-xcursor.c b/src/backends/meta-cursor-sprite-xcursor.c
index a4b9cbb988ab..dc2580f65db9 100644
--- a/src/backends/meta-cursor-sprite-xcursor.c
+++ b/src/backends/meta-cursor-sprite-xcursor.c
@@ -24,6 +24,7 @@
 #include "backends/meta-cursor.h"
 #include "backends/meta-cursor-renderer.h"
 #include "backends/meta-cursor-tracker-private.h"
+#include "backends/meta-logical-monitor.h"
 #include "clutter/clutter.h"
 #include "cogl/cogl.h"
 #include "meta/prefs.h"
@@ -510,22 +511,78 @@ meta_cursor_sprite_xcursor_new (MetaCursor         cursor,
   return sprite_xcursor;
 }
 
+static void
+xcursor_prepare_at (MetaCursorSpriteXcursor *sprite_xcursor,
+                    float                    best_scale,
+                    int                      x,
+                    int                      y,
+                    void                    *user_data)
+{
+  MetaCursorSprite *cursor_sprite = META_CURSOR_SPRITE (sprite_xcursor);
+  MetaCursorTracker *cursor_tracker =
+    meta_cursor_sprite_get_cursor_tracker (cursor_sprite);
+  MetaBackend *backend =
+    meta_cursor_tracker_get_backend (cursor_tracker);
+
+  if (meta_backend_is_stage_views_scaled (backend))
+    {
+      if (best_scale != 0.0f)
+        {
+          float ceiled_scale;
+          int cursor_width, cursor_height;
+
+          ceiled_scale = ceilf (best_scale);
+          meta_cursor_sprite_xcursor_set_theme_scale (sprite_xcursor,
+                                                      (int) ceiled_scale);
+
+          meta_cursor_sprite_realize_texture (cursor_sprite);
+          meta_cursor_sprite_xcursor_get_scaled_image_size (sprite_xcursor,
+                                                            &cursor_width,
+                                                            &cursor_height);
+          meta_cursor_sprite_set_viewport_dst_size (cursor_sprite,
+                                                    cursor_width,
+                                                    cursor_height);
+        }
+    }
+  else
+    {
+      MetaMonitorManager *monitor_manager =
+        meta_backend_get_monitor_manager (backend);
+      MetaLogicalMonitor *logical_monitor;
+
+      logical_monitor =
+        meta_monitor_manager_get_logical_monitor_at (monitor_manager, x, y);
+
+      /* Reload the cursor texture if the scale has changed. */
+      if (logical_monitor)
+        {
+          meta_cursor_sprite_xcursor_set_theme_scale (sprite_xcursor,
+                                                      (int) logical_monitor->scale);
+          meta_cursor_sprite_set_texture_scale (cursor_sprite, 1.0f);
+        }
+    }
+}
+
 static void
 meta_cursor_sprite_xcursor_finalize (GObject *object)
 {
   MetaCursorSpriteXcursor *sprite_xcursor = META_CURSOR_SPRITE_XCURSOR (object);
 
   g_clear_pointer (&sprite_xcursor->xcursor_images,
                    xcursor_images_destroy);
 
   G_OBJECT_CLASS (meta_cursor_sprite_xcursor_parent_class)->finalize (object);
 }
 
 static void
 meta_cursor_sprite_xcursor_init (MetaCursorSpriteXcursor *sprite_xcursor)
 {
   sprite_xcursor->theme_scale = 1;
   sprite_xcursor->theme_dirty = TRUE;
+
+  meta_cursor_sprite_set_prepare_func (META_CURSOR_SPRITE (sprite_xcursor),
+                                       (MetaCursorPrepareFunc) xcursor_prepare_at,
+                                       NULL);
 }
 
 static void
diff --git a/src/core/display.c b/src/core/display.c
index ae66a0cfcb8e..2bdf5be44c2c 100644
--- a/src/core/display.c
+++ b/src/core/display.c
@@ -1681,76 +1681,19 @@ meta_display_notify_window_created (MetaDisplay  *display,
   g_signal_emit (display, display_signals[WINDOW_CREATED], 0, window);
 }
 
-static void
-root_cursor_prepare_at (MetaCursorSpriteXcursor *sprite_xcursor,
-                        float                    best_scale,
-                        int                      x,
-                        int                      y,
-                        MetaDisplay             *display)
-{
-  MetaCursorSprite *cursor_sprite = META_CURSOR_SPRITE (sprite_xcursor);
-  MetaBackend *backend = backend_from_display (display);
-
-  if (meta_backend_is_stage_views_scaled (backend))
-    {
-      if (best_scale != 0.0f)
-        {
-          float ceiled_scale;
-          int cursor_width, cursor_height;
-
-          ceiled_scale = ceilf (best_scale);
-          meta_cursor_sprite_xcursor_set_theme_scale (sprite_xcursor,
-                                                      (int) ceiled_scale);
-
-          meta_cursor_sprite_realize_texture (cursor_sprite);
-          meta_cursor_sprite_xcursor_get_scaled_image_size (sprite_xcursor,
-                                                            &cursor_width,
-                                                            &cursor_height);
-          meta_cursor_sprite_set_viewport_dst_size (cursor_sprite,
-                                                    cursor_width,
-                                                    cursor_height);
-        }
-    }
-  else
-    {
-      MetaMonitorManager *monitor_manager =
-        meta_backend_get_monitor_manager (backend);
-      MetaLogicalMonitor *logical_monitor;
-
-      logical_monitor =
-        meta_monitor_manager_get_logical_monitor_at (monitor_manager, x, y);
-
-      /* Reload the cursor texture if the scale has changed. */
-      if (logical_monitor)
-        {
-          meta_cursor_sprite_xcursor_set_theme_scale (sprite_xcursor,
-                                                      (int) logical_monitor->scale);
-          meta_cursor_sprite_set_texture_scale (cursor_sprite, 1.0f);
-        }
-    }
-}
-
-static void
-manage_root_cursor_sprite_scale (MetaDisplay             *display,
-                                 MetaCursorSpriteXcursor *sprite_xcursor)
-{
-  meta_cursor_sprite_set_prepare_func (META_CURSOR_SPRITE (sprite_xcursor),
-                                       (MetaCursorPrepareFunc) root_cursor_prepare_at,
-                                       display);
-}
-
 void
 meta_display_reload_cursor (MetaDisplay *display)
 {
   MetaCursor cursor = display->current_cursor;
   MetaCursorSpriteXcursor *sprite_xcursor;
   MetaBackend *backend = backend_from_display (display);
   MetaCursorTracker *cursor_tracker = meta_backend_get_cursor_tracker (backend);
 
   sprite_xcursor = meta_cursor_sprite_xcursor_new (cursor, cursor_tracker);
 
-  if (meta_is_wayland_compositor ())
-    manage_root_cursor_sprite_scale (display, sprite_xcursor);
+  if (!meta_is_wayland_compositor ())
+    meta_cursor_sprite_set_prepare_func (META_CURSOR_SPRITE (sprite_xcursor),
+                                         NULL, NULL);
 
   meta_cursor_tracker_set_root_cursor (cursor_tracker,
                                        META_CURSOR_SPRITE (sprite_xcursor));
diff --git a/src/wayland/meta-wayland-tablet-tool.c b/src/wayland/meta-wayland-tablet-tool.c
index 86523918ba34..8306babf0cf3 100644
--- a/src/wayland/meta-wayland-tablet-tool.c
+++ b/src/wayland/meta-wayland-tablet-tool.c
@@ -32,7 +32,6 @@
 #include "wayland/meta-wayland-tablet.h"
 #include "wayland/meta-wayland-tablet-seat.h"
 #include "backends/meta-input-settings-private.h"
-#include "backends/meta-logical-monitor.h"
 
 #include "tablet-unstable-v2-server-protocol.h"
 
@@ -425,87 +424,49 @@ tablet_tool_handle_cursor_surface_destroy (struct wl_listener *listener,
   meta_wayland_tablet_tool_set_cursor_surface (tool, NULL);
 }
 
-static void
-tool_cursor_prepare_at (MetaCursorSpriteXcursor *sprite_xcursor,
-                        float                    best_scale,
-                        int                      x,
-                        int                      y,
-                        MetaWaylandTabletTool   *tool)
-{
-  MetaBackend *backend = backend_from_tool (tool);
-  MetaMonitorManager *monitor_manager =
-    meta_backend_get_monitor_manager (backend);
-  MetaLogicalMonitor *logical_monitor;
-
-  logical_monitor =
-    meta_monitor_manager_get_logical_monitor_at (monitor_manager, x, y);
-
-  /* Reload the cursor texture if the scale has changed. */
-  if (logical_monitor)
-    {
-      MetaCursorSprite *cursor_sprite = META_CURSOR_SPRITE (sprite_xcursor);
-      float ceiled_scale;
-
-      ceiled_scale = ceilf (logical_monitor->scale);
-      meta_cursor_sprite_xcursor_set_theme_scale (sprite_xcursor,
-                                                  (int) ceiled_scale);
-
-      if (meta_backend_is_stage_views_scaled (backend))
-        meta_cursor_sprite_set_texture_scale (cursor_sprite,
-                                              1.0f / ceiled_scale);
-      else
-        meta_cursor_sprite_set_texture_scale (cursor_sprite, 1.0f);
-    }
-}
-
 MetaWaylandTabletTool *
 meta_wayland_tablet_tool_new (MetaWaylandTabletSeat  *seat,
                               ClutterInputDeviceTool *device_tool)
 {
   MetaWaylandCompositor *compositor =
     meta_wayland_seat_get_compositor (seat->seat);
   MetaContext *context = meta_wayland_compositor_get_context (compositor);
   MetaBackend *backend = meta_context_get_backend (context);
   MetaCursorTracker *cursor_tracker = meta_backend_get_cursor_tracker (backend);
   MetaWaylandTabletTool *tool;
 
   tool = g_new0 (MetaWaylandTabletTool, 1);
   tool->seat = seat;
   tool->device_tool = device_tool;
   wl_list_init (&tool->resource_list);
   wl_list_init (&tool->focus_resource_list);
 
   tool->focus_surface_destroy_listener.notify = tablet_tool_handle_focus_surface_destroy;
   tool->cursor_surface_destroy_listener.notify = tablet_tool_handle_cursor_surface_destroy;
 
   tool->default_sprite = meta_cursor_sprite_xcursor_new (META_CURSOR_DEFAULT,
                                                          cursor_tracker);
-  meta_cursor_sprite_set_prepare_func (META_CURSOR_SPRITE (tool->default_sprite),
-                                       (MetaCursorPrepareFunc) tool_cursor_prepare_at,
-                                       tool);
 
   return tool;
 }
 
 void
 meta_wayland_tablet_tool_free (MetaWaylandTabletTool *tool)
 {
   struct wl_resource *resource, *next;
 
   meta_wayland_tablet_tool_set_current_surface (tool, NULL);
   meta_wayland_tablet_tool_set_focus (tool, NULL, NULL);
   meta_wayland_tablet_tool_set_cursor_surface (tool, NULL);
   g_clear_object (&tool->cursor_renderer);
 
   wl_resource_for_each_safe (resource, next, &tool->resource_list)
     {
       zwp_tablet_tool_v2_send_removed (resource);
       wl_list_remove (wl_resource_get_link (resource));
       wl_list_init (wl_resource_get_link (resource));
     }
 
-  meta_cursor_sprite_set_prepare_func (META_CURSOR_SPRITE (tool->default_sprite),
-                                       NULL, NULL);
   g_object_unref (tool->default_sprite);
 
   g_free (tool);

From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Michel=20D=C3=A4nzer?= <mdaenzer@redhat.com>
Date: Mon, 17 Mar 2025 11:00:11 +0100
Subject: [PATCH] kms/impl-device: Always catch pending KMS update in
 _schedule_process

Not only if the deadline timer is enabled. With the next commit, it'll
be semi-expected to happen even if the deadline timer is disabled.

Still leave the warning though, as a reminder that we'd rather prevent
this outside of the KMS thread.
---
 src/backends/native/meta-kms-impl-device.c | 19 +++++++++----------
 1 file changed, 9 insertions(+), 10 deletions(-)

diff --git a/src/backends/native/meta-kms-impl-device.c b/src/backends/native/meta-kms-impl-device.c
index 0135f22033fe..25cb1cbd5e1a 100644
--- a/src/backends/native/meta-kms-impl-device.c
+++ b/src/backends/native/meta-kms-impl-device.c
@@ -2081,25 +2081,24 @@ meta_kms_impl_device_schedule_process (MetaKmsImplDevice *impl_device,
 
       if (ensure_deadline_timer_armed (impl_device, crtc_frame))
         return;
-
-      if (crtc_frame->pending_update)
-        {
-          meta_kms_impl_device_do_process_update (impl_device, crtc_frame,
-                                                  crtc_frame->crtc,
-                                                  crtc_frame->pending_update,
-                                                  META_KMS_UPDATE_FLAG_NONE);
-        }
     }
-
-  if (crtc_frame->pending_update)
+  else if (crtc_frame->pending_update)
     {
       MetaKmsImplDevicePrivate *priv =
         meta_kms_impl_device_get_instance_private (impl_device);
 
       g_warning_once ("crtc_frame->pending_update=%p, deadline_timer_state=%d",
                       crtc_frame->pending_update, priv->deadline_timer_state);
     }
 
+  if (crtc_frame->pending_update)
+    {
+      meta_kms_impl_device_do_process_update (impl_device, crtc_frame,
+                                              crtc_frame->crtc,
+                                              crtc_frame->pending_update,
+                                              META_KMS_UPDATE_FLAG_NONE);
+    }
+
   meta_kms_device_set_needs_flush (meta_kms_crtc_get_device (crtc), crtc);
 }
 

From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Michel=20D=C3=A4nzer?= <mdaenzer@redhat.com>
Date: Mon, 17 Mar 2025 10:50:13 +0100
Subject: [PATCH] Revert "onscreen/native: Account for all posted frames"

This reverts commit 9fc5fdc953f96cd91ad54fce6c50964e7ce57815.

It caused freezes for some users.

Closes: https://gitlab.gnome.org/GNOME/mutter/-/issues/3974
---
 src/backends/native/meta-onscreen-native.c | 2 --
 1 file changed, 2 deletions(-)

diff --git a/src/backends/native/meta-onscreen-native.c b/src/backends/native/meta-onscreen-native.c
index bb7a2c4bd570..a8d7d7aa2681 100644
--- a/src/backends/native/meta-onscreen-native.c
+++ b/src/backends/native/meta-onscreen-native.c
@@ -1672,7 +1672,6 @@ maybe_post_next_frame (CoglOnscreen *onscreen)
     {
       kms_update = meta_frame_native_steal_kms_update (frame_native);
       post_nonprimary_plane_update (onscreen_native, frame, kms_update);
-      onscreen_native->posted_frame = clutter_frame_ref (frame);
       return;
     }
 
@@ -2127,7 +2126,6 @@ meta_onscreen_native_finish_frame (CoglOnscreen *onscreen,
     }
 
   post_nonprimary_plane_update (onscreen_native, frame, kms_update);
-  onscreen_native->posted_frame = clutter_frame_ref (frame);
 
   clutter_frame_set_result (frame, CLUTTER_FRAME_RESULT_PENDING_PRESENTED);
 }