[gnome-shell: 1/4] Better caching for document textures and information



commit 5d067ec718ac1b5389c237b83fd0ab6219319225
Author: Colin Walters <walters verbum org>
Date:   Wed Jul 8 21:06:06 2009 -0400

    Better caching for document textures and information
    
    Move thumbnail creation into ShellTextureCache.  It's now asynchronous,
    and we cache the result.
    
    Create a DocManager class which keeps around the DocInfo objects between
    invocations.  This is also where we ensure we remove thumbnails for
    recent items not known anymore.

 js/misc/docInfo.js        |   96 ++++++++++++++------
 js/ui/docDisplay.js       |   15 +--
 src/shell-global.c        |   68 --------------
 src/shell-global.h        |    2 -
 src/shell-texture-cache.c |  225 +++++++++++++++++++++++++++++++++++++++++++--
 src/shell-texture-cache.h |   11 ++
 6 files changed, 301 insertions(+), 116 deletions(-)
---
diff --git a/js/misc/docInfo.js b/js/misc/docInfo.js
index c590dcc..3f97a19 100644
--- a/js/misc/docInfo.js
+++ b/js/misc/docInfo.js
@@ -5,6 +5,8 @@ const Gio = imports.gi.Gio;
 const Gtk = imports.gi.Gtk;
 const Shell = imports.gi.Shell;
 
+const Lang = imports.lang;
+const Signals = imports.signals;
 const Main = imports.ui.main;
 
 const THUMBNAIL_ICON_MARGIN = 2;
@@ -22,34 +24,19 @@ DocInfo.prototype = {
     },
 
     createIcon : function(size) {
-        let icon = new Clutter.Texture();
-        let iconPixbuf;
-
-        if (this.uri.match("^file://"))
-            iconPixbuf = Shell.get_thumbnail(this.uri, this.mimeType);
-
-        if (iconPixbuf) {
-            // We calculate the width and height of the texture so as
-            // to preserve the aspect ratio of the thumbnail. Because
-            // the images generated based on thumbnails don't have an
-            // internal padding like system icons do, we create a
-            // slightly smaller texture and then create a group around
-            // it for padding purposes
-
-            let scalingFactor = (size - THUMBNAIL_ICON_MARGIN * 2) / Math.max(iconPixbuf.get_width(), iconPixbuf.get_height());
-            icon.set_width(Math.ceil(iconPixbuf.get_width() * scalingFactor));
-            icon.set_height(Math.ceil(iconPixbuf.get_height() * scalingFactor));
-            Shell.clutter_texture_set_from_pixbuf(icon, iconPixbuf);
-
-            let group = new Clutter.Group({ width: size,
-                                            height: size });
-            group.add_actor(icon);
-            icon.set_position(THUMBNAIL_ICON_MARGIN, THUMBNAIL_ICON_MARGIN);
-            return group;
-        } else {
-            Shell.clutter_texture_set_from_pixbuf(icon, this._recentInfo.get_icon(size));
-            return icon;
+        let icon = null;
+        let defaultPixbuf = this._recentInfo.get_icon(size);
+
+        if (this.uri.match("^file://")) {
+            icon = Shell.TextureCache.get_default().load_thumbnail(size, this.uri, this.mimeType,
+                                                                   defaultPixbuf);
+        }
+
+        if (!icon) {
+            icon = new Clutter.Texture({});
+            Shell.clutter_texture_set_from_pixbuf(icon, defaultPixbuf);
         }
+        return icon;
     },
 
     launch : function() {
@@ -112,3 +99,58 @@ DocInfo.prototype = {
         return this._recentInfo.get_modified();
     }
 };
+
+var docManagerInstance = null;
+
+function getDocManager(size) {
+    if (docManagerInstance == null)
+        docManagerInstance = new DocManager(size);
+    return docManagerInstance;
+}
+
+function DocManager(size) {
+    this._init(size);
+}
+
+DocManager.prototype = {
+    _init: function(iconSize) {
+        this._iconSize = iconSize;
+        this._recentManager = Gtk.RecentManager.get_default();
+        this._items = {};
+        this._recentManager.connect('changed', Lang.bind(this, function(recentManager) {
+            this._reload();
+            this.emit('changed');
+        }));
+        this._reload();
+    },
+
+    _reload: function() {
+        let docs = this._recentManager.get_items();
+        let newItems = {};
+        for (let i = 0; i < docs.length; i++) {
+            let recentInfo = docs[i];
+            let docInfo = new DocInfo(recentInfo);
+
+            // we use GtkRecentInfo URI as an item Id
+            newItems[docInfo.uri] = docInfo;
+        }
+        let deleted = {};
+        for (var uri in this._items) {
+            if (!(uri in newItems))
+                deleted[uri] = 1;
+        }
+        /* If we'd cached any thumbnail references that no longer exist,
+           dump them here */
+        let texCache = Shell.TextureCache.get_default();
+        for (var uri in deleted) {
+            texCache.unref_thumbnail(this._iconSize, uri);
+        }
+        this._items = newItems;
+    },
+
+    getItems: function() {
+        return this._items;
+    }
+}
+
+Signals.addSignalMethods(DocManager.prototype);
diff --git a/js/ui/docDisplay.js b/js/ui/docDisplay.js
index 5dd10fa..a05c036 100644
--- a/js/ui/docDisplay.js
+++ b/js/ui/docDisplay.js
@@ -77,9 +77,10 @@ DocDisplay.prototype = {
     _init : function(width) {
         GenericDisplay.GenericDisplay.prototype._init.call(this, width);
         let me = this;
-        this._recentManager = Gtk.RecentManager.get_default();
+
+        this._docManager = DocInfo.getDocManager(GenericDisplay.ITEM_DISPLAY_ICON_SIZE);
         this._docsStale = true;
-        this._recentManager.connect('changed', function(recentManager, userData) {
+        this._docManager.connect('changed', function(mgr, userData) {
             me._docsStale = true;
             // Changes in local recent files should not happen when we are in the overlay mode,
             // but redisplaying right away is cool when we use Zephyr.
@@ -96,15 +97,7 @@ DocDisplay.prototype = {
         let me = this;
         if (!this._docsStale)
             return;
-        this._allItems = {};
-        let docs = this._recentManager.get_items();
-        for (let i = 0; i < docs.length; i++) {
-            let recentInfo = docs[i];
-            let docInfo = new DocInfo.DocInfo(recentInfo);
-
-            // we use GtkRecentInfo URI as an item Id
-            this._allItems[docInfo.uri] = docInfo;
-        }
+        this._allItems = this._docManager.getItems();
         this._docsStale = false;
     },
 
diff --git a/src/shell-global.c b/src/shell-global.c
index 2c8a068..6a803b5 100644
--- a/src/shell-global.c
+++ b/src/shell-global.c
@@ -14,7 +14,6 @@
 #include <string.h>
 #include <unistd.h>
 #include <dbus/dbus-glib.h>
-#include <libgnomeui/gnome-thumbnail.h>
 #include <gio/gio.h>
 #include <math.h>
 #include <X11/extensions/Xfixes.h>
@@ -339,73 +338,6 @@ shell_clutter_texture_set_from_pixbuf (ClutterTexture *texture,
                                               0, NULL);
 }
 
-static GnomeThumbnailFactory *thumbnail_factory;
-
-/**
- * shell_get_thumbnail:
- *
- * @uri: URI of the file to thumbnail
- *
- * @mime_type: Mime-Type of the file to thumbnail
- *
- * Return value: #GdkPixbuf containing a thumbnail for file @uri
- *               if the thumbnail exists or can be generated, %NULL otherwise
- */
-GdkPixbuf *
-shell_get_thumbnail(const gchar *uri,
-                    const gchar *mime_type)
-{
-    char *existing_thumbnail;
-    GdkPixbuf *pixbuf = NULL;
-    GError *error = NULL;
-    GFile *file = NULL;
-    GFileInfo *file_info = NULL;
-    GTimeVal mtime_g;
-    time_t mtime = 0;
-
-    file = g_file_new_for_uri (uri);
-    file_info = g_file_query_info (file, G_FILE_ATTRIBUTE_TIME_MODIFIED, G_FILE_QUERY_INFO_NONE, NULL, NULL);
-    g_object_unref (file);
-    if (file_info) {
-        g_file_info_get_modification_time (file_info, &mtime_g);
-        g_object_unref (file_info);
-        mtime = (time_t) mtime_g.tv_sec;
-    }
-
-    if (thumbnail_factory == NULL)
-      thumbnail_factory = gnome_thumbnail_factory_new (GNOME_THUMBNAIL_SIZE_NORMAL);
-
-    existing_thumbnail = gnome_thumbnail_factory_lookup (thumbnail_factory, uri, mtime);
-
-    if (existing_thumbnail != NULL)
-      {
-        pixbuf = gdk_pixbuf_new_from_file(existing_thumbnail, &error);
-        if (error != NULL) 
-          {
-            g_warning("Could not generate a pixbuf from file %s: %s", existing_thumbnail, error->message);
-            g_clear_error (&error);
-          }
-      }
-    else if (gnome_thumbnail_factory_has_valid_failed_thumbnail (thumbnail_factory, uri, mtime))
-      return NULL;
-    else if (gnome_thumbnail_factory_can_thumbnail (thumbnail_factory, uri, mime_type, mtime)) 
-      {
-        pixbuf = gnome_thumbnail_factory_generate_thumbnail (thumbnail_factory, uri, mime_type);
-        if (pixbuf)
-          {
-            // we need to save the thumbnail so that we don't need to generate it again in the future
-            gnome_thumbnail_factory_save_thumbnail (thumbnail_factory, pixbuf, uri, mtime);
-          }          
-        else 
-          {
-            g_warning ("Could not generate thumbnail for %s", uri);
-            gnome_thumbnail_factory_create_failed_thumbnail (thumbnail_factory, uri, mtime);
-          }
-      }
-
-    return pixbuf;   
-}
-
 /**
  * shell_get_event_key_symbol:
  *
diff --git a/src/shell-global.h b/src/shell-global.h
index 26179c1..e7dce95 100644
--- a/src/shell-global.h
+++ b/src/shell-global.h
@@ -36,8 +36,6 @@ GType            shell_global_get_type            (void) G_GNUC_CONST;
 gboolean shell_clutter_texture_set_from_pixbuf (ClutterTexture *texture,
                                                 GdkPixbuf      *pixbuf);
 
-GdkPixbuf *shell_get_thumbnail(const gchar *uri, const gchar *mime_type);
-
 guint16 shell_get_event_key_symbol(ClutterEvent *event);
 
 guint16 shell_get_button_event_click_count(ClutterEvent *event);
diff --git a/src/shell-texture-cache.c b/src/shell-texture-cache.c
index eaf9b36..4a4c9ab 100644
--- a/src/shell-texture-cache.c
+++ b/src/shell-texture-cache.c
@@ -1,16 +1,20 @@
 #include "shell-texture-cache.h"
 #include "shell-global.h"
 #include <gtk/gtk.h>
+#include <libgnomeui/gnome-thumbnail.h>
+#include <string.h>
 
 typedef struct
 {
   GIcon *icon;
+  gchar *thumbnail_uri;
   guint size;
 } CacheKey;
 
 struct _ShellTextureCachePrivate
 {
   GHashTable *gicon_cache; /* CacheKey -> CoglTexture* */
+  GnomeThumbnailFactory *thumbnails;
 };
 
 static void shell_texture_cache_dispose (GObject *object);
@@ -25,6 +29,8 @@ cache_key_hash (gconstpointer a)
 
   if (akey->icon)
     return g_icon_hash (akey->icon) + 31*akey->size;
+  else if (akey->thumbnail_uri)
+    return g_str_hash (akey->thumbnail_uri) + 31*akey->size;
   g_assert_not_reached ();
 }
 
@@ -39,7 +45,10 @@ cache_key_equal (gconstpointer a,
     return FALSE;
   if (akey->icon && bkey->icon)
     return g_icon_equal (akey->icon, bkey->icon);
-  g_assert_not_reached ();
+  else if (akey->thumbnail_uri && bkey->thumbnail_uri)
+    return strcmp (akey->thumbnail_uri, bkey->thumbnail_uri) == 0;
+
+  return FALSE;
 }
 
 static void
@@ -48,6 +57,8 @@ cache_key_destroy (gpointer a)
   CacheKey *akey = (CacheKey*)a;
   if (akey->icon)
     g_object_unref (akey->icon);
+  if (akey->thumbnail_uri)
+    g_free (akey->thumbnail_uri);
   g_free (akey);
 }
 
@@ -66,6 +77,7 @@ shell_texture_cache_init (ShellTextureCache *self)
   self->priv = g_new0 (ShellTextureCachePrivate, 1);
   self->priv->gicon_cache = g_hash_table_new_full (cache_key_hash, cache_key_equal,
                                                    cache_key_destroy, cogl_handle_unref);
+  self->priv->thumbnails = gnome_thumbnail_factory_new (GNOME_THUMBNAIL_SIZE_NORMAL);
 }
 
 static void
@@ -77,6 +89,10 @@ shell_texture_cache_dispose (GObject *object)
     g_hash_table_destroy (self->priv->gicon_cache);
   self->priv->gicon_cache = NULL;
 
+  if (self->priv->thumbnails)
+    g_object_unref (self->priv->thumbnails);
+  self->priv->thumbnails = NULL;
+
   G_OBJECT_CLASS (shell_texture_cache_parent_class)->dispose (object);
 }
 
@@ -94,7 +110,11 @@ shell_texture_cache_new ()
 }
 
 typedef struct {
+  ShellTextureCache *cache;
   char *uri;
+  char *mimetype;
+  GdkPixbuf *fallback_pixbuf;
+  gboolean thumbnail;
   GIcon *icon;
   GtkIconInfo *icon_info;
   gint width;
@@ -102,7 +122,6 @@ typedef struct {
   gpointer user_data;
 } AsyncIconLookupData;
 
-
 static gboolean
 compute_pixbuf_scale (gint      width,
                       gint      height,
@@ -200,6 +219,10 @@ icon_lookup_data_destroy (gpointer p)
     }
   else if (data->uri)
     g_free (data->uri);
+  if (data->mimetype)
+    g_free (data->mimetype);
+  if (data->fallback_pixbuf)
+    g_object_unref (data->fallback_pixbuf);
 
   g_free (data);
 }
@@ -328,6 +351,56 @@ out:
   return rotated_pixbuf;
 }
 
+static GdkPixbuf *
+impl_load_thumbnail (ShellTextureCache *cache,
+                     const char        *uri,
+                     const char        *mime_type,
+                     guint              size,
+                     GError           **error)
+{
+  GnomeThumbnailFactory *thumbnail_factory;
+  GdkPixbuf *pixbuf = NULL;
+  GFile *file;
+  GFileInfo *file_info;
+  GTimeVal mtime_g;
+  time_t mtime = 0;
+  char *existing_thumbnail;
+
+  file = g_file_new_for_uri (uri);
+  file_info = g_file_query_info (file, G_FILE_ATTRIBUTE_TIME_MODIFIED, G_FILE_QUERY_INFO_NONE, NULL, NULL);
+  g_object_unref (file);
+  if (file_info)
+    {
+      g_file_info_get_modification_time (file_info, &mtime_g);
+      g_object_unref (file_info);
+      mtime = (time_t) mtime_g.tv_sec;
+    }
+
+  thumbnail_factory = cache->priv->thumbnails;
+
+  existing_thumbnail = gnome_thumbnail_factory_lookup (thumbnail_factory, uri, mtime);
+
+  if (existing_thumbnail != NULL)
+    pixbuf = gdk_pixbuf_new_from_file_at_size (existing_thumbnail, size, size, error);
+  else if (gnome_thumbnail_factory_has_valid_failed_thumbnail (thumbnail_factory, uri, mtime))
+    g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, "Has failed thumbnail");
+  else if (gnome_thumbnail_factory_can_thumbnail (thumbnail_factory, uri, mime_type, mtime))
+    {
+      pixbuf = gnome_thumbnail_factory_generate_thumbnail (thumbnail_factory, uri, mime_type);
+      if (pixbuf)
+        {
+          // we need to save the thumbnail so that we don't need to generate it again in the future
+          gnome_thumbnail_factory_save_thumbnail (thumbnail_factory, pixbuf, uri, mtime);
+        }
+      else
+        {
+          g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, "Failed to generate thumbnail");
+          gnome_thumbnail_factory_create_failed_thumbnail (thumbnail_factory, uri, mtime);
+        }
+     }
+   return pixbuf;
+}
+
 static void
 load_pixbuf_thread (GSimpleAsyncResult *result,
                     GObject *object,
@@ -337,9 +410,19 @@ load_pixbuf_thread (GSimpleAsyncResult *result,
   AsyncIconLookupData *data;
   GError *error = NULL;
 
-  data = g_object_get_data (G_OBJECT (result), "load_icon_pixbuf_async");
+  data = g_object_get_data (G_OBJECT (result), "load_pixbuf_async");
+  g_assert (data != NULL);
 
-  if (data->uri)
+  if (data->thumbnail)
+    {
+      pixbuf = impl_load_thumbnail (data->cache, data->uri, data->mimetype, data->width, &error);
+      if (!pixbuf && data->fallback_pixbuf)
+        {
+          g_clear_error (&error);
+          pixbuf = g_object_ref (data->fallback_pixbuf);
+        }
+    }
+  else if (data->uri)
     pixbuf = impl_load_pixbuf_file (data->uri, data->width, data->height, &error);
   else if (data->icon)
     pixbuf = impl_load_pixbuf_gicon (data->icon, data->icon_info, data->width, &error);
@@ -375,6 +458,7 @@ load_icon_pixbuf_async (ShellTextureCache    *cache,
   AsyncIconLookupData *data;
 
   data = g_new0 (AsyncIconLookupData, 1);
+  data->cache = cache;
   data->icon = g_object_ref (icon);
   data->icon_info = gtk_icon_info_copy (icon_info);
   data->width = data->height = size;
@@ -382,7 +466,7 @@ load_icon_pixbuf_async (ShellTextureCache    *cache,
 
   result = g_simple_async_result_new (G_OBJECT (cache), callback, user_data, load_icon_pixbuf_async);
 
-  g_object_set_data_full (G_OBJECT (result), "load_icon_pixbuf_async", data, icon_lookup_data_destroy);
+  g_object_set_data_full (G_OBJECT (result), "load_pixbuf_async", data, icon_lookup_data_destroy);
   g_simple_async_result_run_in_thread (result, load_pixbuf_thread, G_PRIORITY_DEFAULT, cancellable);
 
   g_object_unref (result);
@@ -401,6 +485,7 @@ load_uri_pixbuf_async (ShellTextureCache *cache,
   AsyncIconLookupData *data;
 
   data = g_new0 (AsyncIconLookupData, 1);
+  data->cache = cache;
   data->uri = g_strdup (uri);
   data->width = width;
   data->height = height;
@@ -408,7 +493,38 @@ load_uri_pixbuf_async (ShellTextureCache *cache,
 
   result = g_simple_async_result_new (G_OBJECT (cache), callback, user_data, load_uri_pixbuf_async);
 
-  g_object_set_data_full (G_OBJECT (result), "load_uri_pixbuf_async", data, icon_lookup_data_destroy);
+  g_object_set_data_full (G_OBJECT (result), "load_pixbuf_async", data, icon_lookup_data_destroy);
+  g_simple_async_result_run_in_thread (result, load_pixbuf_thread, G_PRIORITY_DEFAULT, cancellable);
+
+  g_object_unref (result);
+}
+
+static void
+load_thumbnail_async (ShellTextureCache  *cache,
+                      const char         *uri,
+                      const char         *mimetype,
+                      guint               size,
+                      GdkPixbuf          *fallback,
+                      GCancellable       *cancellable,
+                      GAsyncReadyCallback callback,
+                      gpointer            user_data)
+{
+  GSimpleAsyncResult *result;
+  AsyncIconLookupData *data;
+
+  data = g_new0 (AsyncIconLookupData, 1);
+  data->cache = cache;
+  data->uri = g_strdup (uri);
+  data->mimetype = g_strdup (mimetype);
+  data->fallback_pixbuf = g_object_ref (fallback);
+  data->thumbnail = TRUE;
+  data->width = size;
+  data->height = size;
+  data->user_data = user_data;
+
+  result = g_simple_async_result_new (G_OBJECT (cache), callback, user_data, load_thumbnail_async);
+
+  g_object_set_data_full (G_OBJECT (result), "load_pixbuf_async", data, icon_lookup_data_destroy);
   g_simple_async_result_run_in_thread (result, load_pixbuf_thread, G_PRIORITY_DEFAULT, cancellable);
 
   g_object_unref (result);
@@ -425,6 +541,8 @@ load_pixbuf_async_finish (ShellTextureCache *cache, GAsyncResult *result, GError
 
 typedef struct {
   char *uri;
+  gboolean thumbnail;
+  char *mimetype;
   GIcon *icon;
   GtkIconInfo *icon_info;
   guint width;
@@ -469,12 +587,15 @@ on_pixbuf_loaded (GObject      *source,
 
   g_object_unref (pixbuf);
 
-  if (data->icon)
+  if (data->icon || data->thumbnail)
     {
       gpointer orig_key, value;
 
       key = g_new0 (CacheKey, 1);
-      key->icon = g_object_ref (data->icon);
+      if (data->icon)
+        key->icon = g_object_ref (data->icon);
+      else
+        key->thumbnail_uri = g_strdup (data->uri);
       key->size = data->width;
 
       if (!g_hash_table_lookup_extended (cache->priv->gicon_cache, key,
@@ -495,10 +616,15 @@ out:
     }
   else if (data->uri)
     g_free (data->uri);
+
+  if (data->mimetype)
+    g_free (data->mimetype);
+
   /* Alternatively we could weakref and just do nothing if the texture
      is destroyed */
   g_object_unref (data->texture);
 
+  g_clear_error (&error);
   g_free (data);
 }
 
@@ -522,6 +648,7 @@ shell_texture_cache_load_gicon (ShellTextureCache *cache,
   texture = CLUTTER_TEXTURE (clutter_texture_new ());
   clutter_actor_set_size (CLUTTER_ACTOR (texture), size, size);
 
+  memset (&key, 0, sizeof(key));
   key.icon = icon;
   key.size = size;
   texdata = g_hash_table_lookup (cache->priv->gicon_cache, &key);
@@ -630,6 +757,88 @@ shell_texture_cache_load_uri_sync (ShellTextureCache *cache,
   return CLUTTER_ACTOR (texture);
 }
 
+/**
+ * shell_texture_cache_load_thumbnail:
+ * @cache:
+ * @size: Size in pixels to use for thumbnail
+ * @uri: Source URI
+ * @mimetype: Source mime type
+ * @fallback: (allow-none): If no thumbnail is cached, use this pixbuf
+ *
+ * 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 shell_texture_cache_unref_thumbnail().
+ *
+ * A fallback pixbuf may be provided in the case where thumbnailing is
+ * not applicable, or fails.
+ *
+ * Returns: (transfer none): A new #ClutterActor
+ */
+ClutterActor *
+shell_texture_cache_load_thumbnail (ShellTextureCache *cache,
+                                    int                size,
+                                    const char        *uri,
+                                    const char        *mimetype,
+                                    GdkPixbuf         *fallback)
+{
+  ClutterTexture *texture;
+  AsyncTextureLoadData *data;
+  CacheKey key;
+  CoglHandle texdata;
+
+  texture = CLUTTER_TEXTURE (clutter_texture_new ());
+  clutter_actor_set_size (CLUTTER_ACTOR (texture), size, size);
+
+  memset (&key, 0, sizeof(key));
+  key.size = size;
+  key.thumbnail_uri = (char*)uri;
+
+  texdata = g_hash_table_lookup (cache->priv->gicon_cache, &key);
+  if (!texdata)
+    {
+      data = g_new0 (AsyncTextureLoadData, 1);
+      data->uri = g_strdup (uri);
+      data->mimetype = g_strdup (mimetype);
+      data->thumbnail = TRUE;
+      data->width = size;
+      data->height = size;
+      data->texture = g_object_ref (texture);
+      load_thumbnail_async (cache, uri, mimetype, size, fallback, NULL, on_pixbuf_loaded, data);
+    }
+  else
+    {
+      clutter_texture_set_cogl_texture (texture, texdata);
+    }
+
+  return CLUTTER_ACTOR (texture);
+}
+
+/**
+ * shell_texture_cache_unref_thumbnail:
+ * @cache:
+ * @size: Size in pixels
+ * @uri: Source URI
+ *
+ * Removes the reference the shell_texture_cache_load_thumbnail() function
+ * created for a thumbnail.
+ */
+void
+shell_texture_cache_unref_thumbnail (ShellTextureCache *cache,
+                                     int                size,
+                                     const char        *uri)
+{
+  CacheKey key;
+
+  memset (&key, 0, sizeof(key));
+  key.size = size;
+  key.thumbnail_uri = (char*)uri;
+
+  g_hash_table_remove (cache->priv->gicon_cache, &key);
+}
+
 static ShellTextureCache *instance = NULL;
 
 /**
diff --git a/src/shell-texture-cache.h b/src/shell-texture-cache.h
index 68dd7d6..ec80963 100644
--- a/src/shell-texture-cache.h
+++ b/src/shell-texture-cache.h
@@ -2,6 +2,7 @@
 #define __SHELL_TEXTURE_CACHE_H__
 
 #include <gio/gio.h>
+#include <gdk-pixbuf/gdk-pixbuf.h>
 #include <clutter/clutter.h>
 
 #define SHELL_TYPE_TEXTURE_CACHE                 (shell_texture_cache_get_type ())
@@ -37,6 +38,16 @@ ClutterActor *shell_texture_cache_load_gicon (ShellTextureCache *cache,
                                               GIcon             *icon,
                                               gint               size);
 
+ClutterActor *shell_texture_cache_load_thumbnail (ShellTextureCache *cache,
+                                                  int                size,
+                                                  const char        *uri,
+                                                  const char        *mimetype,
+                                                  GdkPixbuf         *fallback);
+
+void          shell_texture_cache_unref_thumbnail (ShellTextureCache *cache,
+                                                   int                size,
+                                                   const char        *uri);
+
 ClutterActor *shell_texture_cache_load_uri_async (ShellTextureCache *cache,
                                                   const gchar       *filename,
                                                   int                available_width,



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]