st/image-content: Implement GIcon interface
On the one hand, this is a bit of a stretch: StImageContent is what we create from GIcons. But on the other hand, there's some justification: StImageContent does represent an image (and likely icon) after all, and there's some precedent with GdkPixbuf. In the end as we don't care about serialization or loading from other API, we can go with a very crude implementation that allows us to pass out a content as GIcon and use it directly when "loading" it. We will use that soon to represent X11 window icons as GIcons, which in turn will allow us to unify app icon handling. https://gitlab.gnome.org/GNOME/gnome-shell/-/merge_requests/1342
This commit is contained in:
parent
ecdf62d63e
commit
770231c2d7
@ -42,11 +42,17 @@ enum
|
|||||||
};
|
};
|
||||||
|
|
||||||
static void clutter_content_interface_init (ClutterContentInterface *iface);
|
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_TYPE_WITH_CODE (StImageContent, st_image_content, CLUTTER_TYPE_IMAGE,
|
G_DEFINE_TYPE_WITH_CODE (StImageContent, st_image_content, CLUTTER_TYPE_IMAGE,
|
||||||
G_ADD_PRIVATE (StImageContent)
|
G_ADD_PRIVATE (StImageContent)
|
||||||
G_IMPLEMENT_INTERFACE (CLUTTER_TYPE_CONTENT,
|
G_IMPLEMENT_INTERFACE (CLUTTER_TYPE_CONTENT,
|
||||||
clutter_content_interface_init))
|
clutter_content_interface_init)
|
||||||
|
G_IMPLEMENT_INTERFACE (G_TYPE_ICON,
|
||||||
|
g_icon_interface_init)
|
||||||
|
G_IMPLEMENT_INTERFACE (G_TYPE_LOADABLE_ICON,
|
||||||
|
g_loadable_icon_interface_init))
|
||||||
|
|
||||||
static void
|
static void
|
||||||
st_image_content_init (StImageContent *self)
|
st_image_content_init (StImageContent *self)
|
||||||
@ -165,12 +171,157 @@ st_image_content_get_preferred_size (ClutterContent *content,
|
|||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static GdkPixbuf*
|
||||||
|
pixbuf_from_image (StImageContent *image)
|
||||||
|
{
|
||||||
|
CoglTexture *texture;
|
||||||
|
int width, height, rowstride;
|
||||||
|
uint8_t *data;
|
||||||
|
|
||||||
|
texture = clutter_image_get_texture (CLUTTER_IMAGE (image));
|
||||||
|
if (!texture || !cogl_texture_is_get_data_supported (texture))
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
width = cogl_texture_get_width (texture);
|
||||||
|
height = cogl_texture_get_width (texture);
|
||||||
|
rowstride = 4 * width;
|
||||||
|
data = g_new (uint8_t, rowstride * height);
|
||||||
|
|
||||||
|
cogl_texture_get_data (texture, COGL_PIXEL_FORMAT_RGBA_8888, rowstride, data);
|
||||||
|
|
||||||
|
return gdk_pixbuf_new_from_data ((const guchar *)data,
|
||||||
|
GDK_COLORSPACE_RGB,
|
||||||
|
TRUE, 8, width, height, rowstride,
|
||||||
|
(GdkPixbufDestroyNotify)g_free, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
clutter_content_interface_init (ClutterContentInterface *iface)
|
clutter_content_interface_init (ClutterContentInterface *iface)
|
||||||
{
|
{
|
||||||
iface->get_preferred_size = st_image_content_get_preferred_size;
|
iface->get_preferred_size = st_image_content_get_preferred_size;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static guint
|
||||||
|
st_image_content_hash (GIcon *icon)
|
||||||
|
{
|
||||||
|
return g_direct_hash (icon);
|
||||||
|
}
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
st_image_content_equal (GIcon *icon1,
|
||||||
|
GIcon *icon2)
|
||||||
|
{
|
||||||
|
return g_direct_equal (icon1, icon2);
|
||||||
|
}
|
||||||
|
|
||||||
|
static GVariant *
|
||||||
|
st_image_content_serialize (GIcon *icon)
|
||||||
|
{
|
||||||
|
g_autoptr (GdkPixbuf) pixbuf = NULL;
|
||||||
|
|
||||||
|
pixbuf = pixbuf_from_image (ST_IMAGE_CONTENT (icon));
|
||||||
|
if (!pixbuf)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
return g_icon_serialize (G_ICON (pixbuf));
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
g_icon_interface_init (GIconIface *iface)
|
||||||
|
{
|
||||||
|
iface->hash = st_image_content_hash;
|
||||||
|
iface->equal = st_image_content_equal;
|
||||||
|
iface->serialize = st_image_content_serialize;
|
||||||
|
}
|
||||||
|
|
||||||
|
static GInputStream *
|
||||||
|
st_image_load (GLoadableIcon *icon,
|
||||||
|
int size,
|
||||||
|
char **type,
|
||||||
|
GCancellable *cancellable,
|
||||||
|
GError **error)
|
||||||
|
{
|
||||||
|
g_autoptr (GdkPixbuf) pixbuf = NULL;
|
||||||
|
|
||||||
|
pixbuf = pixbuf_from_image (ST_IMAGE_CONTENT (icon));
|
||||||
|
if (!pixbuf)
|
||||||
|
{
|
||||||
|
g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_FAILED,
|
||||||
|
"Failed to read texture");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return g_loadable_icon_load (G_LOADABLE_ICON (pixbuf),
|
||||||
|
size, type, cancellable, error);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
load_image_thread (GTask *task,
|
||||||
|
gpointer object,
|
||||||
|
gpointer task_data,
|
||||||
|
GCancellable *cancellable)
|
||||||
|
{
|
||||||
|
GInputStream *stream;
|
||||||
|
GError *error = NULL;
|
||||||
|
char *type;
|
||||||
|
|
||||||
|
stream = st_image_load (G_LOADABLE_ICON (object),
|
||||||
|
GPOINTER_TO_INT (task_data),
|
||||||
|
&type,
|
||||||
|
cancellable,
|
||||||
|
&error);
|
||||||
|
|
||||||
|
if (error)
|
||||||
|
{
|
||||||
|
g_task_return_error (task, error);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
g_task_set_task_data (task, type, g_free);
|
||||||
|
g_task_return_pointer (task, stream, g_object_unref);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
st_image_load_async (GLoadableIcon *icon,
|
||||||
|
int size,
|
||||||
|
GCancellable *cancellable,
|
||||||
|
GAsyncReadyCallback callback,
|
||||||
|
gpointer user_data)
|
||||||
|
{
|
||||||
|
g_autoptr (GTask) task = NULL;
|
||||||
|
|
||||||
|
task = g_task_new (icon, cancellable, callback, user_data);
|
||||||
|
g_task_set_task_data (task, GINT_TO_POINTER (size), NULL);
|
||||||
|
g_task_run_in_thread (task, load_image_thread);
|
||||||
|
}
|
||||||
|
|
||||||
|
static GInputStream *
|
||||||
|
st_image_load_finish (GLoadableIcon *icon,
|
||||||
|
GAsyncResult *res,
|
||||||
|
char **type,
|
||||||
|
GError **error)
|
||||||
|
{
|
||||||
|
GInputStream *stream;
|
||||||
|
|
||||||
|
stream = g_task_propagate_pointer (G_TASK (res), error);
|
||||||
|
if (!stream)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
if (type)
|
||||||
|
*type = g_strdup (g_task_get_task_data (G_TASK (res)));
|
||||||
|
|
||||||
|
return stream;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
g_loadable_icon_interface_init (GLoadableIconIface *iface)
|
||||||
|
{
|
||||||
|
iface->load = st_image_load;
|
||||||
|
iface->load_async = st_image_load_async;
|
||||||
|
iface->load_finish = st_image_load_finish;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* st_image_content_new_with_preferred_size:
|
* st_image_content_new_with_preferred_size:
|
||||||
* @width: The preferred width to be used when drawing the content
|
* @width: The preferred width to be used when drawing the content
|
||||||
|
@ -981,6 +981,18 @@ st_texture_cache_load_gicon (StTextureCache *cache,
|
|||||||
StIconStyle icon_style = ST_ICON_STYLE_REQUESTED;
|
StIconStyle icon_style = ST_ICON_STYLE_REQUESTED;
|
||||||
GtkIconLookupFlags lookup_flags;
|
GtkIconLookupFlags lookup_flags;
|
||||||
|
|
||||||
|
actor_size = size * paint_scale;
|
||||||
|
|
||||||
|
if (ST_IS_IMAGE_CONTENT (icon))
|
||||||
|
{
|
||||||
|
return g_object_new (CLUTTER_TYPE_ACTOR,
|
||||||
|
"request-mode", CLUTTER_REQUEST_CONTENT_SIZE,
|
||||||
|
"width", actor_size,
|
||||||
|
"height", actor_size,
|
||||||
|
"content", CLUTTER_CONTENT (icon),
|
||||||
|
NULL);
|
||||||
|
}
|
||||||
|
|
||||||
if (theme_node)
|
if (theme_node)
|
||||||
{
|
{
|
||||||
colors = st_theme_node_get_icon_colors (theme_node);
|
colors = st_theme_node_get_icon_colors (theme_node);
|
||||||
@ -1034,7 +1046,6 @@ st_texture_cache_load_gicon (StTextureCache *cache,
|
|||||||
g_free (gicon_string);
|
g_free (gicon_string);
|
||||||
|
|
||||||
actor = create_invisible_actor ();
|
actor = create_invisible_actor ();
|
||||||
actor_size = size * paint_scale;
|
|
||||||
clutter_actor_set_size (actor, actor_size, actor_size);
|
clutter_actor_set_size (actor, actor_size, actor_size);
|
||||||
if (ensure_request (cache, key, policy, &request, actor))
|
if (ensure_request (cache, key, policy, &request, actor))
|
||||||
{
|
{
|
||||||
|
Loading…
Reference in New Issue
Block a user