/** * st_texture_cache_load_icon_name: * @cache: The texture cache instance * @theme_node: (allow-none): a #StThemeNode * @name: Name of a themed icon * @icon_type: the type of icon to load * @size: Size of themed icon * * Load a themed icon into a texture. See the #StIconType documentation * for an explanation of how @icon_type affects the returned icon. The * colors used for symbolic icons are derived from @theme_node. * * Return Value: (transfer none): A new #ClutterTexture for the icon */ ClutterActor * st_texture_cache_load_icon_name (StTextureCache *cache, StThemeNode *theme_node, const char *name, StIconType icon_type, gint size) { ClutterActor *texture; GIcon *themed; char **names; g_return_val_if_fail (!(icon_type == ST_ICON_SYMBOLIC && theme_node == NULL), NULL); switch (icon_type) { case ST_ICON_SYMBOLIC: names = symbolic_names_for_icon (name); themed = g_themed_icon_new_from_names (names, -1); g_strfreev (names); texture = load_gicon_with_colors (cache, themed, size, st_theme_node_get_icon_colors (theme_node)); g_object_unref (themed); if (texture == NULL) { /* We don't have an equivalent of image-missing * for the symbolic icon theme, so just create a blank * actor. */ texture = (ClutterActor *) create_default_texture (); clutter_actor_set_size (texture, size, size); } return texture; break; case ST_ICON_FULLCOLOR: themed = g_themed_icon_new_with_default_fallbacks (name); texture = load_gicon_with_colors (cache, themed, size, NULL); g_object_unref (themed); if (texture == NULL) { themed = g_themed_icon_new ("image-missing"); texture = load_gicon_with_colors (cache, themed, size, NULL); g_object_unref (themed); } return texture; break; default: g_assert_not_reached (); } }
/** * st_texture_cache_load_thumbnail: * @cache: * @size: Size in pixels to use for thumbnail * @uri: Source URI * @mimetype: Source mime type * * Asynchronously load a thumbnail image of a URI into a texture. The * returned texture object will be a new instance; however, its texture data * may be shared with other objects. This implies the texture data is cached. * * The current caching policy is permanent; to uncache, you must explicitly * call st_texture_cache_unref_thumbnail(). * * Returns: (transfer none): A new #ClutterActor */ ClutterActor * st_texture_cache_load_thumbnail (StTextureCache *cache, int size, const char *uri, const char *mimetype) { ClutterTexture *texture; AsyncTextureLoadData *data; char *key; CoglHandle texdata; /* Don't attempt to load thumbnails for non-local URIs */ if (!g_str_has_prefix (uri, "file://")) { GIcon *icon = icon_for_mimetype (mimetype); return st_texture_cache_load_gicon (cache, icon, size); } texture = create_default_texture (cache); clutter_actor_set_size (CLUTTER_ACTOR (texture), size, size); key = g_strdup_printf (CACHE_PREFIX_THUMBNAIL_URI "uri=%s,size=%d", uri, size); texdata = g_hash_table_lookup (cache->priv->keyed_cache, key); if (!texdata) { data = g_new0 (AsyncTextureLoadData, 1); data->key = g_strdup (key); data->policy = ST_TEXTURE_CACHE_POLICY_FOREVER; data->uri = g_strdup (uri); data->mimetype = g_strdup (mimetype); data->thumbnail = TRUE; data->width = size; data->height = size; data->textures = g_slist_prepend (data->textures, g_object_ref (texture)); load_thumbnail_async (cache, uri, mimetype, size, NULL, on_pixbuf_loaded, data); } else { set_texture_cogl_texture (texture, texdata); } g_free (key); return CLUTTER_ACTOR (texture); }
/** * st_texture_cache_load_from_data: * @cache: The texture cache instance * @data: Image data in PNG, GIF, etc format * @len: length of @data * @size: Size in pixels to use for the resulting texture * @error: Return location for error * * Synchronously creates an image from @data. The image is scaled down * to fit the available width and height dimensions, but the image is * never scaled up beyond its actual size. The pixbuf is rotated * according to the associated orientation setting. * * Return value: (transfer none): A new #ClutterActor with the image data loaded if it was * generated succesfully, %NULL otherwise */ ClutterActor * st_texture_cache_load_from_data (StTextureCache *cache, const guchar *data, gsize len, int size, GError **error) { ClutterTexture *texture; CoglHandle texdata; GdkPixbuf *pixbuf; char *key; char *checksum; texture = create_default_texture (cache); clutter_actor_set_size (CLUTTER_ACTOR (texture), size, size); checksum = g_compute_checksum_for_data (G_CHECKSUM_SHA1, data, len); key = g_strdup_printf (CACHE_PREFIX_COMPRESSED_CHECKSUM "checksum=%s,size=%d", checksum, size); g_free (checksum); texdata = g_hash_table_lookup (cache->priv->keyed_cache, key); if (texdata == NULL) { pixbuf = impl_load_pixbuf_data (data, len, size, size, error); if (!pixbuf) { g_object_unref (texture); g_free (key); return NULL; } texdata = pixbuf_to_cogl_handle (pixbuf); g_object_unref (pixbuf); set_texture_cogl_texture (texture, texdata); g_hash_table_insert (cache->priv->keyed_cache, g_strdup (key), texdata); } g_free (key); set_texture_cogl_texture (texture, texdata); return CLUTTER_ACTOR (texture); }
/** * st_texture_cache_load_uri_async: * @cache: The texture cache instance * @uri: uri of the image file from which to create a pixbuf * @available_width: available width for the image, can be -1 if not limited * @available_height: available height for the image, can be -1 if not limited * * Asynchronously load an image. Initially, the returned texture will have a natural * size of zero. At some later point, either the image will be loaded successfully * and at that point size will be negotiated, or upon an error, no image will be set. * * Return value: (transfer none): A new #ClutterActor with no image loaded initially. */ ClutterActor * st_texture_cache_load_uri_async (StTextureCache *cache, const gchar *uri, int available_width, int available_height) { ClutterActor *texture; AsyncTextureLoadData *request; StTextureCachePolicy policy; gchar *key; int width = available_width == -1 ? -1 : available_width * cache->priv->scale; int height = available_height == -1 ? -1 : available_height * cache->priv->scale; key = g_strconcat (CACHE_PREFIX_URI, uri, NULL); policy = ST_TEXTURE_CACHE_POLICY_NONE; /* XXX */ texture = (ClutterActor *) create_default_texture (); if (ensure_request (cache, key, policy, &request, texture)) { /* If there's an outstanding request, we've just added ourselves to it */ free (key); } else { /* Else, make a new request */ request->cache = cache; /* Transfer ownership of key */ request->key = key; request->uri = g_strdup (uri); request->policy = policy; request->width = width; request->height = height; load_texture_async (cache, request); } ensure_monitor_for_uri (cache, uri); return CLUTTER_ACTOR (texture); }
static ClutterActor * load_from_pixbuf (GdkPixbuf *pixbuf) { ClutterTexture *texture; CoglTexture *texdata; int width = gdk_pixbuf_get_width (pixbuf); int height = gdk_pixbuf_get_height (pixbuf); texture = create_default_texture (); clutter_actor_set_size (CLUTTER_ACTOR (texture), width, height); texdata = pixbuf_to_cogl_texture (pixbuf); set_texture_cogl_texture (texture, texdata); cogl_object_unref (texdata); return CLUTTER_ACTOR (texture); }
/** * st_texture_cache_load_file_async: * @cache: The texture cache instance * @file: a #GFile of the image file from which to create a pixbuf * @available_width: available width for the image, can be -1 if not limited * @available_height: available height for the image, can be -1 if not limited * @scale: scale factor of the display * * Asynchronously load an image. Initially, the returned texture will have a natural * size of zero. At some later point, either the image will be loaded successfully * and at that point size will be negotiated, or upon an error, no image will be set. * * Return value: (transfer none): A new #ClutterActor with no image loaded initially. */ ClutterActor * st_texture_cache_load_file_async (StTextureCache *cache, GFile *file, int available_width, int available_height, int scale) { ClutterActor *texture; AsyncTextureLoadData *request; StTextureCachePolicy policy; gchar *key; key = g_strdup_printf (CACHE_PREFIX_FILE "%u", g_file_hash (file)); policy = ST_TEXTURE_CACHE_POLICY_NONE; /* XXX */ texture = (ClutterActor *) create_default_texture (); if (ensure_request (cache, key, policy, &request, texture)) { /* If there's an outstanding request, we've just added ourselves to it */ g_free (key); } else { /* Else, make a new request */ request->cache = cache; /* Transfer ownership of key */ request->key = key; request->file = g_object_ref (file); request->policy = policy; request->width = available_width; request->height = available_height; request->scale = scale; load_texture_async (cache, request); } ensure_monitor_for_file (cache, file); return CLUTTER_ACTOR (texture); }
/** * st_texture_cache_load_from_raw: * @cache: a #StTextureCache * @data: (array length=len): raw pixel data * @len: the length of @data * @has_alpha: whether @data includes an alpha channel * @width: width in pixels of @data * @height: width in pixels of @data * @rowstride: rowstride of @data * @size: size of icon to return * * Creates (or retrieves from cache) an icon based on raw pixel data. * * Return value: (transfer none): a new #ClutterActor displaying a * pixbuf created from @data and the other parameters. **/ ClutterActor * st_texture_cache_load_from_raw (StTextureCache *cache, const guchar *data, gsize len, gboolean has_alpha, int width, int height, int rowstride, int size, GError **error) { ClutterTexture *texture; CoglHandle texdata; char *key; char *checksum; texture = create_default_texture (); clutter_actor_set_size (CLUTTER_ACTOR (texture), size, size); /* In theory, two images of with different width and height could have the same * pixel data and thus hash the same. (Say, a 16x16 and a 8x32 blank image.) * We ignore this for now. If anybody hits this problem they should use * GChecksum directly to compute a checksum including the width and height. */ checksum = g_compute_checksum_for_data (G_CHECKSUM_SHA1, data, len); key = g_strdup_printf (CACHE_PREFIX_RAW_CHECKSUM "checksum=%s", checksum); g_free (checksum); texdata = g_hash_table_lookup (cache->priv->keyed_cache, key); if (texdata == NULL) { texdata = cogl_texture_new_from_data (width, height, COGL_TEXTURE_NONE, has_alpha ? COGL_PIXEL_FORMAT_RGBA_8888 : COGL_PIXEL_FORMAT_RGB_888, COGL_PIXEL_FORMAT_ANY, rowstride, data); g_hash_table_insert (cache->priv->keyed_cache, g_strdup (key), texdata); } g_free (key); set_texture_cogl_texture (texture, texdata); return CLUTTER_ACTOR (texture); }
/** * create_texture_and_ensure_request: * @cache: * @key: A cache key * @size: Size in pixels * @request: (out): If no request is outstanding, one will be created and returned here * @texture: (out): A new texture, also added to the request * * Check for any outstanding load for the data represented by @key. If there * is already a request pending, append it to that request to avoid loading * the data multiple times. * * Returns: %TRUE iff there is already a request pending */ static gboolean create_texture_and_ensure_request (StTextureCache *cache, const char *key, guint size, AsyncTextureLoadData **request, ClutterActor **texture) { CoglHandle texdata; AsyncTextureLoadData *pending; gboolean had_pending; *texture = (ClutterActor *) create_default_texture (cache); clutter_actor_set_size (*texture, size, size); texdata = g_hash_table_lookup (cache->priv->keyed_cache, key); if (texdata != NULL) { /* We had this cached already, just set the texture and we're done. */ set_texture_cogl_texture (CLUTTER_TEXTURE (*texture), texdata); return TRUE; } pending = g_hash_table_lookup (cache->priv->outstanding_requests, key); had_pending = pending != NULL; if (pending == NULL) { /* Not cached and no pending request, create it */ *request = g_new0 (AsyncTextureLoadData, 1); (*request)->key = g_strdup (key); g_hash_table_insert (cache->priv->outstanding_requests, g_strdup (key), *request); } else *request = pending; /* Regardless of whether there was a pending request, prepend our texture here. */ (*request)->textures = g_slist_prepend ((*request)->textures, g_object_ref (*texture)); return had_pending; }
/** * st_texture_cache_load_from_raw: * @cache: a #StTextureCache * @data: raw pixel data * @len: the length of @data * @has_alpha: whether @data includes an alpha channel * @width: width in pixels of @data * @height: width in pixels of @data * @rowstride: rowstride of @data * @size: size of icon to return * * Creates (or retrieves from cache) an icon based on raw pixel data. * * Return value: (transfer none): a new #ClutterActor displaying a * pixbuf created from @data and the other parameters. **/ ClutterActor * st_texture_cache_load_from_raw (StTextureCache *cache, const guchar *data, gsize len, gboolean has_alpha, int width, int height, int rowstride, int size, GError **error) { ClutterTexture *texture; CoglHandle texdata; char *key; char *checksum; texture = create_default_texture (cache); clutter_actor_set_size (CLUTTER_ACTOR (texture), size, size); /* In theory, two images of different size could have the same * pixel data. We ignore that theory. */ checksum = g_compute_checksum_for_data (G_CHECKSUM_SHA1, data, len); key = g_strdup_printf (CACHE_PREFIX_RAW_CHECKSUM "checksum=%s,size=%d", checksum, size); g_free (checksum); texdata = g_hash_table_lookup (cache->priv->keyed_cache, key); if (texdata == NULL) { texdata = cogl_texture_new_from_data (width, height, COGL_TEXTURE_NONE, has_alpha ? COGL_PIXEL_FORMAT_RGBA_8888 : COGL_PIXEL_FORMAT_RGB_888, COGL_PIXEL_FORMAT_ANY, rowstride, data); g_hash_table_insert (cache->priv->keyed_cache, g_strdup (key), texdata); } g_free (key); set_texture_cogl_texture (texture, texdata); return CLUTTER_ACTOR (texture); }
/** * st_texture_cache_load_from_pixbuf: * @pixbuf: A #GdkPixbuf * @size: int * * Converts a #GdkPixbuf into a #ClutterTexture. * * Return value: (transfer none): A new #ClutterActor */ ClutterActor * st_texture_cache_load_from_pixbuf (GdkPixbuf *pixbuf, int size) { ClutterTexture *texture; CoglTexture *texdata; ClutterActor *actor; texture = create_default_texture (); actor = CLUTTER_ACTOR (texture); clutter_actor_set_size (actor, size, size); texdata = pixbuf_to_cogl_texture (pixbuf); set_texture_cogl_texture (texture, texdata); cogl_object_unref (texdata); return actor; }
/** * st_texture_cache_load_uri_sync: * * @cache: The texture cache instance * @policy: Requested lifecycle of cached data * @uri: uri of the image file from which to create a pixbuf * @available_width: available width for the image, can be -1 if not limited * @available_height: available height for the image, can be -1 if not limited * @error: Return location for error * * Synchronously load an image from a uri. The image is scaled down to fit the * available width and height imensions, but the image is never scaled up beyond * its actual size. The pixbuf is rotated according to the associated orientation * setting. * * Return value: (transfer none): A new #ClutterActor with the image file loaded if it was * generated succesfully, %NULL otherwise */ ClutterActor * st_texture_cache_load_uri_sync (StTextureCache *cache, StTextureCachePolicy policy, const gchar *uri, int available_width, int available_height, GError **error) { CoglHandle texdata; ClutterTexture *texture; texdata = st_texture_cache_load_uri_sync_to_cogl_texture (cache, policy, uri, available_width, available_height, error); if (texdata == COGL_INVALID_HANDLE) return NULL; texture = create_default_texture (cache); set_texture_cogl_texture (texture, texdata); cogl_handle_unref (texdata); return CLUTTER_ACTOR (texture); }
/** * st_texture_cache_load_uri_async: * * @cache: The texture cache instance * @uri: uri of the image file from which to create a pixbuf * @available_width: available width for the image, can be -1 if not limited * @available_height: available height for the image, can be -1 if not limited * * Asynchronously load an image. Initially, the returned texture will have a natural * size of zero. At some later point, either the image will be loaded successfully * and at that point size will be negotiated, or upon an error, no image will be set. * * Return value: (transfer none): A new #ClutterActor with no image loaded initially. */ ClutterActor * st_texture_cache_load_uri_async (StTextureCache *cache, const gchar *uri, int available_width, int available_height) { ClutterTexture *texture; AsyncTextureLoadData *data; texture = create_default_texture (cache); data = g_new0 (AsyncTextureLoadData, 1); data->key = g_strconcat (CACHE_PREFIX_URI, uri, NULL); data->policy = ST_TEXTURE_CACHE_POLICY_NONE; data->uri = g_strdup (uri); data->width = available_width; data->height = available_height; data->textures = g_slist_prepend (data->textures, g_object_ref (texture)); load_uri_pixbuf_async (cache, uri, available_width, available_height, NULL, on_pixbuf_loaded, data); return CLUTTER_ACTOR (texture); }
/** * st_texture_cache_load_from_raw: * @cache: a #StTextureCache * @data: (array length=len): raw pixel data * @len: the length of @data * @has_alpha: whether @data includes an alpha channel * @width: width in pixels of @data * @height: width in pixels of @data * @rowstride: rowstride of @data * @size: size of icon to return * * Creates (or retrieves from cache) an icon based on raw pixel data. * * Return value: (transfer none): a new #ClutterActor displaying a * pixbuf created from @data and the other parameters. **/ ClutterActor * st_texture_cache_load_from_raw (StTextureCache *cache, const guchar *data, gsize len, gboolean has_alpha, int width, int height, int rowstride, int size, GError **error) { ClutterTexture *texture; CoglTexture *texdata; texture = create_default_texture (); clutter_actor_set_size (CLUTTER_ACTOR (texture), size, size); texdata = data_to_cogl_texture (data, has_alpha, width, height, rowstride); set_texture_cogl_texture (texture, texdata); return CLUTTER_ACTOR (texture); }
/** * st_texture_cache_load_gicon: * @cache: The texture cache instance * @theme_node: (nullable): The #StThemeNode to use for colors, or NULL * if the icon must not be recolored * @icon: the #GIcon to load * @size: Size of themed * @scale: Scale factor of display * * This method returns a new #ClutterActor for a given #GIcon. If the * icon isn't loaded already, the texture will be filled * asynchronously. * * Return Value: (transfer none): A new #ClutterActor for the icon, or %NULL if not found */ ClutterActor * st_texture_cache_load_gicon (StTextureCache *cache, StThemeNode *theme_node, GIcon *icon, gint size, gint scale) { AsyncTextureLoadData *request; ClutterActor *texture; char *gicon_string; char *key; GtkIconTheme *theme; GtkIconInfo *info; StTextureCachePolicy policy; StIconColors *colors = NULL; StIconStyle icon_style = ST_ICON_STYLE_REQUESTED; GtkIconLookupFlags lookup_flags; if (theme_node) { colors = st_theme_node_get_icon_colors (theme_node); icon_style = st_theme_node_get_icon_style (theme_node); } /* Do theme lookups in the main thread to avoid thread-unsafety */ theme = cache->priv->icon_theme; lookup_flags = GTK_ICON_LOOKUP_USE_BUILTIN; if (icon_style == ST_ICON_STYLE_REGULAR) lookup_flags |= GTK_ICON_LOOKUP_FORCE_REGULAR; else if (icon_style == ST_ICON_STYLE_SYMBOLIC) lookup_flags |= GTK_ICON_LOOKUP_FORCE_SYMBOLIC; if (clutter_get_default_text_direction () == CLUTTER_TEXT_DIRECTION_RTL) lookup_flags |= GTK_ICON_LOOKUP_DIR_RTL; else lookup_flags |= GTK_ICON_LOOKUP_DIR_LTR; info = gtk_icon_theme_lookup_by_gicon_for_scale (theme, icon, size, scale, lookup_flags); if (info == NULL) return NULL; gicon_string = g_icon_to_string (icon); /* A return value of NULL indicates that the icon can not be serialized, * so don't have a unique identifier for it as a cache key, and thus can't * be cached. If it is cachable, we hardcode a policy of FOREVER here for * now; we should actually blow this away on icon theme changes probably */ policy = gicon_string != NULL ? ST_TEXTURE_CACHE_POLICY_FOREVER : ST_TEXTURE_CACHE_POLICY_NONE; if (colors) { /* This raises some doubts about the practice of using string keys */ key = g_strdup_printf (CACHE_PREFIX_ICON "%s,size=%d,scale=%d,style=%d,colors=%2x%2x%2x%2x,%2x%2x%2x%2x,%2x%2x%2x%2x,%2x%2x%2x%2x", gicon_string, size, scale, icon_style, colors->foreground.red, colors->foreground.blue, colors->foreground.green, colors->foreground.alpha, colors->warning.red, colors->warning.blue, colors->warning.green, colors->warning.alpha, colors->error.red, colors->error.blue, colors->error.green, colors->error.alpha, colors->success.red, colors->success.blue, colors->success.green, colors->success.alpha); } else { key = g_strdup_printf (CACHE_PREFIX_ICON "%s,size=%d,scale=%d,style=%d", gicon_string, size, scale, icon_style); } g_free (gicon_string); texture = (ClutterActor *) create_default_texture (); clutter_actor_set_size (texture, size * scale, size * scale); if (ensure_request (cache, key, policy, &request, texture)) { /* If there's an outstanding request, we've just added ourselves to it */ g_object_unref (info); g_free (key); } else { /* Else, make a new request */ request->cache = cache; /* Transfer ownership of key */ request->key = key; request->policy = policy; request->colors = colors ? st_icon_colors_ref (colors) : NULL; request->icon_info = info; request->width = request->height = size; request->scale = scale; load_texture_async (cache, request); } return CLUTTER_ACTOR (texture); }