summaryrefslogtreecommitdiff
path: root/plugins/background
diff options
context:
space:
mode:
authorSunderland93 <[email protected]>2026-08-03 09:45:49 +0400
committerLuke from DC <[email protected]>2026-08-19 19:15:44 +0000
commitae5e2c5e11cf741162c34c67d87cb43ebe4abb60 (patch)
tree7b069f1220471b35154f6352a576ff8c5fb66fe4 /plugins/background
parent09e3e297fa5534d5676e7a445a4494f2a1e817c1 (diff)
downloadmate-settings-daemon-ae5e2c5e11cf741162c34c67d87cb43ebe4abb60.tar.bz2
mate-settings-daemon-ae5e2c5e11cf741162c34c67d87cb43ebe4abb60.tar.xz
Respect fade effect settings and fix redraw at resolution changes
Diffstat (limited to 'plugins/background')
-rw-r--r--plugins/background/msd-background-manager-wayland.c160
1 files changed, 119 insertions, 41 deletions
diff --git a/plugins/background/msd-background-manager-wayland.c b/plugins/background/msd-background-manager-wayland.c
index 260c49a..066e9ce 100644
--- a/plugins/background/msd-background-manager-wayland.c
+++ b/plugins/background/msd-background-manager-wayland.c
@@ -46,17 +46,18 @@ struct _MsdBackgroundManagerWayland
typedef struct
{
- GtkWidget *window;
- GdkMonitor *monitor;
- cairo_surface_t *surface;
- cairo_surface_t *fading_surface;
- cairo_surface_t *end_surface;
- guint fade_timeout_id;
- gdouble fade_start_time;
- gdouble fade_total_duration;
- gboolean fade_is_first_frame;
- int width;
- int height;
+ GtkWidget *window;
+ GdkMonitor *monitor;
+ MsdBackgroundManagerWayland *manager;
+ cairo_surface_t *surface;
+ cairo_surface_t *fading_surface;
+ cairo_surface_t *end_surface;
+ guint fade_timeout_id;
+ gdouble fade_start_time;
+ gdouble fade_total_duration;
+ gboolean fade_is_first_frame;
+ int width;
+ int height;
} MonitorWindow;
static void
@@ -194,6 +195,26 @@ on_fade_tick (MonitorWindow *mw)
}
static void
+set_surface_instantly (MonitorWindow *mw, cairo_surface_t *new_surface)
+{
+ if (mw->fade_timeout_id != 0) {
+ if (mw->fading_surface != NULL) {
+ cairo_surface_destroy (mw->fading_surface);
+ mw->fading_surface = NULL;
+ }
+ if (mw->end_surface != NULL) {
+ cairo_surface_destroy (mw->end_surface);
+ mw->end_surface = NULL;
+ }
+ g_source_remove (mw->fade_timeout_id);
+ mw->fade_timeout_id = 0;
+ }
+ free_monitor_window_surface (mw);
+ mw->surface = new_surface;
+ gtk_widget_queue_draw (mw->window);
+}
+
+static void
start_or_continue_fade (MsdBackgroundManagerWayland *manager,
MonitorWindow *mw,
cairo_surface_t *new_surface)
@@ -208,24 +229,10 @@ start_or_continue_fade (MsdBackgroundManagerWayland *manager,
animations_enabled = !animations_are_disabled (mw);
if (!fade_enabled || !animations_enabled || mw->surface == NULL) {
- /* No fade: cancel any in-flight one and swap instantly.
- * This also covers the first render after startup.
+ /* No fade: swap instantly. This also covers the first render
+ * after startup.
*/
- if (mw->fade_timeout_id != 0) {
- if (mw->fading_surface != NULL) {
- cairo_surface_destroy (mw->fading_surface);
- mw->fading_surface = NULL;
- }
- if (mw->end_surface != NULL) {
- cairo_surface_destroy (mw->end_surface);
- mw->end_surface = NULL;
- }
- g_source_remove (mw->fade_timeout_id);
- mw->fade_timeout_id = 0;
- }
- free_monitor_window_surface (mw);
- mw->surface = new_surface;
- gtk_widget_queue_draw (mw->window);
+ set_surface_instantly (mw, new_surface);
return;
}
@@ -257,28 +264,31 @@ start_or_continue_fade (MsdBackgroundManagerWayland *manager,
}
static void
-render_surface_for_monitor (MsdBackgroundManagerWayland *manager,
- MonitorWindow *mw)
+render_surface_at_size (MsdBackgroundManagerWayland *manager,
+ MonitorWindow *mw,
+ int width,
+ int height,
+ gboolean animate)
{
- GdkRectangle rect;
- GdkPixbuf *pixbuf;
+ GdkPixbuf *pixbuf;
cairo_surface_t *new_surface;
- cairo_t *cr;
+ cairo_t *cr;
- gdk_monitor_get_geometry (mw->monitor, &rect);
+ if (width <= 0 || height <= 0)
+ return;
pixbuf = gdk_pixbuf_new (GDK_COLORSPACE_RGB, TRUE, 8,
- rect.width, rect.height);
+ width, height);
if (pixbuf == NULL) {
g_warning ("msd-background-wayland: unable to create %dx%d pixbuf",
- rect.width, rect.height);
+ width, height);
return;
}
mate_bg_draw (manager->bg, pixbuf, NULL, FALSE);
new_surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32,
- rect.width, rect.height);
+ width, height);
cr = cairo_create (new_surface);
gdk_cairo_set_source_pixbuf (cr, pixbuf, 0, 0);
cairo_paint (cr);
@@ -286,7 +296,49 @@ render_surface_for_monitor (MsdBackgroundManagerWayland *manager,
g_object_unref (pixbuf);
- start_or_continue_fade (manager, mw, new_surface);
+ mw->width = width;
+ mw->height = height;
+
+ if (animate)
+ start_or_continue_fade (manager, mw, new_surface);
+ else
+ set_surface_instantly (mw, new_surface);
+}
+
+static void
+render_surface_for_monitor (MsdBackgroundManagerWayland *manager,
+ MonitorWindow *mw,
+ gboolean animate)
+{
+ GdkRectangle rect;
+
+ gdk_monitor_get_geometry (mw->monitor, &rect);
+ render_surface_at_size (manager, mw, rect.width, rect.height, animate);
+}
+
+static void
+on_window_size_allocate (GtkWidget *widget G_GNUC_UNUSED,
+ GtkAllocation *alloc,
+ MonitorWindow *mw)
+{
+ if (alloc->width <= 0 || alloc->height <= 0)
+ return;
+
+ if (mw->surface == NULL)
+ return;
+
+ /* The layer surface is anchored to the output edges, so when the
+ * output resolution or scale changes the compositor resizes the
+ * window. Re-render at the new size so the wallpaper adapts even
+ * if no monitors-changed event arrives.
+ */
+ if (alloc->width == mw->width && alloc->height == mw->height)
+ return;
+
+ g_debug ("msd-background-wayland: window resized to %dx%d, re-rendering",
+ alloc->width, alloc->height);
+ render_surface_at_size (mw->manager, mw,
+ alloc->width, alloc->height, FALSE);
}
static gboolean
@@ -323,7 +375,7 @@ redraw_all (MsdBackgroundManagerWayland *manager)
for (i = 0; i < manager->monitor_windows->len; i++) {
MonitorWindow *mw = g_ptr_array_index (manager->monitor_windows, i);
- render_surface_for_monitor (manager, mw);
+ render_surface_for_monitor (manager, mw, TRUE);
gtk_widget_queue_draw (mw->window);
}
}
@@ -395,10 +447,12 @@ create_monitor_window (MsdBackgroundManagerWayland *manager G_GNUC_UNUSED,
mw = g_new0 (MonitorWindow, 1);
mw->window = window;
mw->monitor = monitor;
+ mw->manager = manager;
mw->width = rect.width;
mw->height = rect.height;
g_signal_connect (window, "draw", G_CALLBACK (on_window_draw), mw);
+ g_signal_connect (window, "size-allocate", G_CALLBACK (on_window_size_allocate), mw);
g_signal_connect (window, "destroy", G_CALLBACK (on_window_destroy), mw);
gtk_widget_show (window);
@@ -478,8 +532,32 @@ static void
on_monitors_changed (GdkScreen *screen G_GNUC_UNUSED,
MsdBackgroundManagerWayland *manager)
{
- rebuild_monitor_windows (manager);
- redraw_all (manager);
+ guint n_monitors = gdk_display_get_n_monitors (manager->display);
+ guint i;
+
+ /* A monitor set change (added/removed) requires recreating the
+ * layer windows. A pure geometry/scale change (e.g. the compositor
+ * output is being resized) keeps the same window count, so just
+ * re-render in place at the new size - destroying and recreating
+ * windows mid-resize races with the compositor and leaves the
+ * wallpaper missing.
+ */
+ if (n_monitors != manager->monitor_windows->len) {
+ g_debug ("msd-background-wayland: monitors changed, rebuilding (%u monitors)",
+ n_monitors);
+ rebuild_monitor_windows (manager);
+ redraw_all (manager);
+ return;
+ }
+
+ g_debug ("msd-background-wayland: monitors changed, re-rendering in place (%u monitors)",
+ n_monitors);
+
+ for (i = 0; i < manager->monitor_windows->len; i++) {
+ MonitorWindow *mw = g_ptr_array_index (manager->monitor_windows, i);
+ render_surface_for_monitor (manager, mw, FALSE);
+ gtk_widget_queue_draw (mw->window);
+ }
}
static void