From 6dd1e99236abb362a7c307f993465df4d6aec6ac Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20Dre=C3=9Fler?= Date: Wed, 26 Mar 2025 16:12:19 +0100 Subject: [PATCH] st/image-content: Don't force preferred content size to texture size When ClutterImage got merged into StImageContent with commit 64d5d01360 ("st: Merge ClutterImage with ImageContent"), a small error slipped in when copying over the update_image_size() function. Within ClutterImage, update_image_size() served a simple purpose: To call clutter_content_invalidate_size() in case the texture size would change. To check that, ClutterImage was storing the existing texture size in the priv->width and priv->height fields. When merging into StImageContent, those priv->width/height fields happened to overlap with priv->width/height of StImageContent, but there they are storing the preferred size, rather than the texture size. Copying update_image_size() as-is into StImageContent meant we now set the preferred size to the texture size, subtly breaking resource-scaled StIcons (where texture size is a multiple of the preferred size). The breakage isn't very apparent because StIcons manually set the size of their internal ClutterActor child to the requested icon-size via clutter_actor_set_size() in st_texture_cache_load_gicon(), and that makes the child actor report the correct size in get_preferred_width/height(). The child actor gets allocated via clutter_actor_allocate_align_fill() from ClutterBinLayouts vfunc_allocate(), and clutter_actor_allocate_align_fill() honors both the available size from the parent and the CONTENT_SIZE request-mode on the child. So when the StIcon has a larger allocation (aka extra available size), clutter_actor_allocate_align_fill() will fill that available space with the (too large) content size. To reproduce the issue, on a resource-scaled monitor, simply create an StIcon with a fixed width and height that's larger than the icon-size. The icon will be painted too large and blurry. Fix this fallout by avoiding to touch the priv->width/height properties on StImageContent, and instead simply comparing old texture size to new texture size, we have both textures around after all! Fixes: 64d5d01360 ("st: Merge ClutterImage with ImageContent") Closes: https://gitlab.gnome.org/GNOME/gnome-shell/-/issues/8287 Part-of: --- src/st/st-image-content.c | 51 ++++++++++++++++++--------------------- 1 file changed, 24 insertions(+), 27 deletions(-) diff --git a/src/st/st-image-content.c b/src/st/st-image-content.c index 8c47af3cd..9cd0d48f1 100644 --- a/src/st/st-image-content.c +++ b/src/st/st-image-content.c @@ -425,28 +425,6 @@ st_image_content_get_is_symbolic (StImageContent *content) return content->is_symbolic; } - -static void -update_image_size (StImageContent *self) -{ - int width, height; - - if (self->texture == NULL) - return; - - width = cogl_texture_get_width (self->texture); - height = cogl_texture_get_height (self->texture); - - if (self->width == width && - self->height == height) - return; - - self->width = width; - self->height = height; - - clutter_content_invalidate_size (CLUTTER_CONTENT (self)); -} - /** * st_image_content_set_data: * @content: a #StImageContentImage @@ -502,11 +480,19 @@ st_image_content_set_data (StImageContent *content, guint row_stride, GError **error) { + int old_width = 0; + int old_height = 0; + g_return_val_if_fail (ST_IS_IMAGE_CONTENT (content), FALSE); g_return_val_if_fail (data != NULL, FALSE); if (content->texture != NULL) - g_object_unref (content->texture); + { + old_width = cogl_texture_get_width (content->texture); + old_height = cogl_texture_get_height (content->texture); + + g_object_unref (content->texture); + } content->texture = cogl_texture_2d_new_from_data (cogl_context, width, @@ -520,7 +506,9 @@ st_image_content_set_data (StImageContent *content, return FALSE; clutter_content_invalidate (CLUTTER_CONTENT (content)); - update_image_size (content); + + if (old_width != width || old_height != height) + clutter_content_invalidate_size (CLUTTER_CONTENT (content)); return TRUE; } @@ -560,12 +548,19 @@ st_image_content_set_bytes (StImageContent *content, GError **error) { + int old_width = 0; + int old_height = 0; + g_return_val_if_fail (ST_IS_IMAGE_CONTENT (content), FALSE); g_return_val_if_fail (data != NULL, FALSE); - if (content->texture != NULL) - g_object_unref (content->texture); + { + old_width = cogl_texture_get_width (content->texture); + old_height = cogl_texture_get_height (content->texture); + + g_object_unref (content->texture); + } content->texture = cogl_texture_2d_new_from_data (cogl_context, width, @@ -579,7 +574,9 @@ st_image_content_set_bytes (StImageContent *content, return FALSE; clutter_content_invalidate (CLUTTER_CONTENT (content)); - update_image_size (content); + + if (old_width != width || old_height != height) + clutter_content_invalidate_size (CLUTTER_CONTENT (content)); return TRUE; }