From 64d5d01360bb072ca476da85c6163f9dbef78423 Mon Sep 17 00:00:00 2001 From: Bilal Elmoussaoui Date: Fri, 15 Nov 2024 12:36:00 +0100 Subject: [PATCH] st: Merge ClutterImage with ImageContent ClutterImage as is, is very basic and doesn't really serve any purposes other than being inherited by StImageContent. As we cannot easily push ImageContent to Mutter by merging it with ClutterImage because it will bring more GdkPixbuf usages and also because Clutter doesn't really deal with theming bits. Instead, merge it with StImageContent and let GNOME Shell take over from here. Part-of: --- src/st/st-image-content.c | 241 ++++++++++++++++++++++++++++++++++++-- src/st/st-image-content.h | 20 +++- src/st/st-private.c | 5 +- src/st/st-texture-cache.c | 42 +++---- 4 files changed, 274 insertions(+), 34 deletions(-) diff --git a/src/st/st-image-content.c b/src/st/st-image-content.c index b0b4fa47e..6ca1ccc56 100644 --- a/src/st/st-image-content.c +++ b/src/st/st-image-content.c @@ -25,7 +25,9 @@ struct _StImageContent { - ClutterImage parent_instance; + GObject parent_instance; + + CoglTexture *texture; int width; int height; @@ -43,7 +45,7 @@ static void clutter_content_interface_init (ClutterContentInterface *iface); static void g_icon_interface_init (GIconIface *iface); static void g_loadable_icon_interface_init (GLoadableIconIface *iface); -G_DEFINE_FINAL_TYPE_WITH_CODE (StImageContent, st_image_content, CLUTTER_TYPE_IMAGE, +G_DEFINE_FINAL_TYPE_WITH_CODE (StImageContent, st_image_content, G_TYPE_OBJECT, G_IMPLEMENT_INTERFACE (CLUTTER_TYPE_CONTENT, clutter_content_interface_init) G_IMPLEMENT_INTERFACE (G_TYPE_ICON, @@ -114,6 +116,16 @@ st_image_content_set_property (GObject *object, } } +static void +st_image_content_finalize (GObject *gobject) +{ + StImageContent *content = ST_IMAGE_CONTENT (gobject); + + g_clear_object (&content->texture); + + G_OBJECT_CLASS (st_image_content_parent_class)->finalize (gobject); +} + static void st_image_content_class_init (StImageContentClass *klass) { @@ -123,6 +135,7 @@ st_image_content_class_init (StImageContentClass *klass) object_class->constructed = st_image_content_constructed; object_class->get_property = st_image_content_get_property; object_class->set_property = st_image_content_set_property; + object_class->finalize = st_image_content_finalize; pspec = g_param_spec_int ("preferred-width", NULL, NULL, -1, G_MAXINT, -1, @@ -141,11 +154,8 @@ st_image_content_get_preferred_size (ClutterContent *content, float *height) { StImageContent *self = ST_IMAGE_CONTENT (content); - CoglTexture *texture; - texture = clutter_image_get_texture (CLUTTER_IMAGE (content)); - - if (texture == NULL) + if (self->texture == NULL) return FALSE; g_assert_cmpint (self->width, >, -1); @@ -167,7 +177,7 @@ pixbuf_from_image (StImageContent *image) int width, height, rowstride; uint8_t *data; - texture = clutter_image_get_texture (CLUTTER_IMAGE (image)); + texture = st_image_content_get_texture (image); if (!texture || !cogl_texture_is_get_data_supported (texture)) return NULL; @@ -184,10 +194,29 @@ pixbuf_from_image (StImageContent *image) (GdkPixbufDestroyNotify)g_free, NULL); } +static void +st_image_content_paint_content (ClutterContent *content, + ClutterActor *actor, + ClutterPaintNode *root, + ClutterPaintContext *paint_context) +{ + StImageContent *image_content = ST_IMAGE_CONTENT (content); + ClutterPaintNode *node; + + if (image_content->texture == NULL) + return; + + node = clutter_actor_create_texture_paint_node (actor, image_content->texture); + clutter_paint_node_set_static_name (node, "Image Content"); + clutter_paint_node_add_child (root, node); + clutter_paint_node_unref (node); +} + static void clutter_content_interface_init (ClutterContentInterface *iface) { iface->get_preferred_size = st_image_content_get_preferred_size; + iface->paint_content = st_image_content_paint_content; } static guint @@ -318,9 +347,6 @@ g_loadable_icon_interface_init (GLoadableIconIface *iface) * * Creates a new #StImageContent, a simple content for sized images. * - * See #ClutterImage for setting the actual image to display or #StIcon for - * displaying icons. - * * Returns: (transfer full): the newly created #StImageContent content * Use g_object_unref() when done. */ @@ -350,3 +376,198 @@ st_image_content_get_is_symbolic (StImageContent *content) return content->is_symbolic; } + +static CoglTexture * +create_texture_from_data (unsigned int width, + unsigned int height, + CoglPixelFormat pixel_format, + unsigned int row_stride, + const uint8_t *data, + GError **error) +{ + ClutterBackend *backend = clutter_get_default_backend (); + CoglContext *cogl_context = clutter_backend_get_cogl_context (backend); + CoglTexture *texture_2d; + + texture_2d = cogl_texture_2d_new_from_data (cogl_context, + width, + height, + pixel_format, + row_stride, + data, + error); + + return texture_2d; +} + +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 + * @data: (array): the image data, as an array of bytes + * @pixel_format: the Cogl pixel format of the image data + * @width: the width of the image data + * @height: the height of the image data + * @row_stride: the length of each row inside @data + * @error: return location for a #GError, or %NULL + * + * Sets the image data to be displayed by @content. + * + * If the image data was successfully loaded, the @content will be invalidated. + * + * In case of error, the @error value will be set, and this function will + * return %FALSE. + * + * The image data is copied in texture memory. + * + * The image data is expected to be a linear array of RGBA or RGB pixel data; + * how to retrieve that data is left to platform specific image loaders. For + * instance, if you use the GdkPixbuf library: + * + * ```c + * StImageContent *content = + * st_image_content_new_with_preferred_size (); + * GdkPixbuf *pixbuf = gdk_pixbuf_new_from_file (filename, NULL); + * + * st_image_content_set_data (content, + * gdk_pixbuf_get_pixels (pixbuf), + * gdk_pixbuf_get_has_alpha (pixbuf) + * ? COGL_PIXEL_FORMAT_RGBA_8888 + * : COGL_PIXEL_FORMAT_RGB_888, + * gdk_pixbuf_get_width (pixbuf), + * gdk_pixbuf_get_height (pixbuf), + * gdk_pixbuf_get_rowstride (pixbuf), + * &error); + * + * g_object_unref (pixbuf); + * ``` + * + * Return value: %TRUE if the image data was successfully loaded, + * and %FALSE otherwise. + */ +gboolean +st_image_content_set_data (StImageContent *content, + const guint8 *data, + CoglPixelFormat pixel_format, + guint width, + guint height, + guint row_stride, + GError **error) +{ + 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); + + content->texture = create_texture_from_data (width, + height, + pixel_format, + row_stride, + data, + error); + + if (content->texture == NULL) + return FALSE; + + clutter_content_invalidate (CLUTTER_CONTENT (content)); + update_image_size (content); + + return TRUE; +} + +/** + * st_image_content_set_bytes: + * @content: a #StImageContent + * @data: the image data, as a #GBytes + * @pixel_format: the Cogl pixel format of the image data + * @width: the width of the image data + * @height: the height of the image data + * @row_stride: the length of each row inside @data + * @error: return location for a #GError, or %NULL + * + * Sets the image data stored inside a #GBytes to be displayed by @content. + * + * If the image data was successfully loaded, the @content will be invalidated. + * + * In case of error, the @error value will be set, and this function will + * return %FALSE. + * + * The image data contained inside the #GBytes is copied in texture memory, + * and no additional reference is acquired on the @data. + * + * Return value: %TRUE if the image data was successfully loaded, + * and %FALSE otherwise. + */ +gboolean +st_image_content_set_bytes (StImageContent *content, + GBytes *data, + CoglPixelFormat pixel_format, + guint width, + guint height, + guint row_stride, + GError **error) +{ + + 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); + + content->texture = create_texture_from_data (width, + height, + pixel_format, + row_stride, + g_bytes_get_data (data, NULL), + error); + + if (content->texture == NULL) + return FALSE; + + clutter_content_invalidate (CLUTTER_CONTENT (content)); + update_image_size (content); + + return TRUE; +} + +/** + * st_image_content_get_texture: + * @content: a #StcontentContent + * + * Retrieves a pointer to the Cogl texture used by @content. + * + * If you change the contents of the returned Cogl texture you will need + * to manually invalidate the @content with [method@Clutter.Content.invalidate] + * in order to update the actors using @content as their content. + * + * Return value: (transfer none): a pointer to the Cogl texture, or %NULL + */ +CoglTexture * +st_image_content_get_texture (StImageContent *content) +{ + g_return_val_if_fail (ST_IS_IMAGE_CONTENT (content), NULL); + + return content->texture; +} diff --git a/src/st/st-image-content.h b/src/st/st-image-content.h index 84b594e1b..4e86280b9 100644 --- a/src/st/st-image-content.h +++ b/src/st/st-image-content.h @@ -24,7 +24,25 @@ #define ST_TYPE_IMAGE_CONTENT (st_image_content_get_type ()) G_DECLARE_FINAL_TYPE (StImageContent, st_image_content, - ST, IMAGE_CONTENT, ClutterImage) + ST, IMAGE_CONTENT, GObject) ClutterContent *st_image_content_new_with_preferred_size (int width, int height); + +gboolean st_image_content_set_data (StImageContent *content, + const guint8 *data, + CoglPixelFormat pixel_format, + guint width, + guint height, + guint row_stride, + GError **error); + +gboolean st_image_content_set_bytes (StImageContent *content, + GBytes *data, + CoglPixelFormat pixel_format, + guint width, + guint height, + guint row_stride, + GError **error); + +CoglTexture * st_image_content_get_texture (StImageContent *content); \ No newline at end of file diff --git a/src/st/st-private.c b/src/st/st-private.c index b997fa1dc..133bf065e 100644 --- a/src/st/st-private.c +++ b/src/st/st-private.c @@ -23,6 +23,7 @@ #include #include "st-private.h" +#include "st-image-content.h" /** * _st_actor_get_preferred_width: @@ -528,11 +529,11 @@ _st_create_shadow_pipeline_from_actor (StShadow *shadow_spec, height = ceilf (height * resource_scale); image = clutter_actor_get_content (actor); - if (image && CLUTTER_IS_IMAGE (image)) + if (image && ST_IS_IMAGE_CONTENT (image)) { CoglTexture *texture; - texture = clutter_image_get_texture (CLUTTER_IMAGE (image)); + texture = st_image_content_get_texture (ST_IMAGE_CONTENT (image)); if (texture && cogl_texture_get_width (texture) == width && cogl_texture_get_height (texture) == height) diff --git a/src/st/st-texture-cache.c b/src/st/st-texture-cache.c index a137480ad..e526fb5b0 100644 --- a/src/st/st-texture-cache.c +++ b/src/st/st-texture-cache.c @@ -39,7 +39,7 @@ struct _StTextureCachePrivate StIconTheme *icon_theme; /* Things that were loaded with a cache policy != NONE */ - GHashTable *keyed_cache; /* char * -> ClutterImage* */ + GHashTable *keyed_cache; /* char * -> StImageContent* */ GHashTable *keyed_surface_cache; /* char * -> cairo_surface_t* */ GHashTable *used_scales; /* Set: double */ @@ -85,7 +85,7 @@ static void set_content_from_image (ClutterActor *actor, ClutterContent *image) { - g_assert (image && CLUTTER_IS_IMAGE (image)); + g_assert (image && ST_IS_IMAGE_CONTENT (image)); clutter_actor_set_content (actor, image); clutter_actor_set_opacity (actor, 255); @@ -523,14 +523,14 @@ pixbuf_to_st_content_image (GdkPixbuf *pixbuf, } image = st_image_content_new_with_preferred_size (width, height); - clutter_image_set_data (CLUTTER_IMAGE (image), - gdk_pixbuf_get_pixels (pixbuf), - gdk_pixbuf_get_has_alpha (pixbuf) ? - COGL_PIXEL_FORMAT_RGBA_8888 : COGL_PIXEL_FORMAT_RGB_888, - gdk_pixbuf_get_width (pixbuf), - gdk_pixbuf_get_height (pixbuf), - gdk_pixbuf_get_rowstride (pixbuf), - &error); + st_image_content_set_data (ST_IMAGE_CONTENT (image), + gdk_pixbuf_get_pixels (pixbuf), + gdk_pixbuf_get_has_alpha (pixbuf) ? + COGL_PIXEL_FORMAT_RGBA_8888 : COGL_PIXEL_FORMAT_RGB_888, + gdk_pixbuf_get_width (pixbuf), + gdk_pixbuf_get_height (pixbuf), + gdk_pixbuf_get_rowstride (pixbuf), + &error); if (error) { @@ -824,14 +824,14 @@ st_texture_cache_load_surface (ClutterContent **image, if (*image == NULL) *image = st_image_content_new_with_preferred_size (size, size); - clutter_image_set_data (CLUTTER_IMAGE (*image), - cairo_image_surface_get_data (surface), - cairo_image_surface_get_format (surface) == CAIRO_FORMAT_ARGB32 ? - COGL_PIXEL_FORMAT_BGRA_8888 : COGL_PIXEL_FORMAT_BGR_888, - width, - height, - cairo_image_surface_get_stride (surface), - &error); + st_image_content_set_data (ST_IMAGE_CONTENT (image), + cairo_image_surface_get_data (surface), + cairo_image_surface_get_format (surface) == CAIRO_FORMAT_ARGB32 ? + COGL_PIXEL_FORMAT_BGRA_8888 : COGL_PIXEL_FORMAT_BGR_888, + width, + height, + cairo_image_surface_get_stride (surface), + &error); if (error) g_warning ("Failed to allocate texture: %s", error->message); @@ -1519,9 +1519,9 @@ st_texture_cache_load_file_sync_to_cogl_texture (StTextureCache *cache, } /* Because the texture is loaded synchronously, we won't call - * clutter_image_set_data(), so it's safe to use the texture - * of ClutterImage here. */ - texdata = clutter_image_get_texture (CLUTTER_IMAGE (image)); + * st_image_content_set_data(), so it's safe to use the texture + * of StImageContent here. */ + texdata = st_image_content_get_texture (ST_IMAGE_CONTENT (image)); g_object_ref (texdata); ensure_monitor_for_file (cache, file);