[gnome-photos] base-item: Refactor thumbnail creation for remote items



commit 9ed0e984055387ad5c2fd465097f4d1cf4c56ca0
Author: Debarshi Ray <debarshir gnome org>
Date:   Tue Jul 2 13:20:56 2013 +0200

    base-item: Refactor thumbnail creation for remote items
    
    A new pure virtual method called "create_thumbnail" has been added. It
    is meant to be run in a thread and implementations should take care of
    creating the thumbnail image file according to the Thumbnail Managing
    Standard [1].
    
    Currently GnomeDesktopThumbnailFactory is used for creating local
    thumbnails. Thumbnailing Flickr content is yet to be implemented.
    
    [1] http://specifications.freedesktop.org/thumbnail-spec/thumbnail-spec-latest.html
    
    Fixes: https://bugzilla.gnome.org/697675

 src/photos-base-item.c   |   93 ++++++++++++++++++++++++++++++++++++----
 src/photos-base-item.h   |    1 +
 src/photos-flickr-item.c |   12 +++++
 src/photos-local-item.c  |   18 ++++++++
 src/photos-utils.c       |  105 ++++++++++++++++++---------------------------
 src/photos-utils.h       |    6 +--
 6 files changed, 159 insertions(+), 76 deletions(-)
---
diff --git a/src/photos-base-item.c b/src/photos-base-item.c
index de8d8d4..9524291 100644
--- a/src/photos-base-item.c
+++ b/src/photos-base-item.c
@@ -47,6 +47,7 @@ struct _PhotosBaseItemPrivate
   GeglNode *graph;
   GeglNode *node;
   GeglRectangle bbox;
+  GMutex mutex_create_thumbnail;
   GMutex mutex;
   PhotosCollectionIconWatcher *watcher;
   TrackerSparqlCursor *cursor;
@@ -199,6 +200,73 @@ photos_base_item_check_effects_and_update_info (PhotosBaseItem *self)
 
 
 static void
+photos_base_item_create_thumbnail_in_thread_func (GSimpleAsyncResult *simple,
+                                                  GObject *object,
+                                                  GCancellable *cancellable)
+{
+  PhotosBaseItem *self = PHOTOS_BASE_ITEM (object);
+  PhotosBaseItemPrivate *priv = self->priv;
+  GError *error;
+  gboolean op_res;
+
+  g_mutex_lock (&priv->mutex_create_thumbnail);
+
+  error = NULL;
+  op_res = PHOTOS_BASE_ITEM_GET_CLASS (self)->create_thumbnail (self, cancellable, &error);
+  if (error != NULL)
+    g_simple_async_result_take_error (simple, error);
+
+  g_simple_async_result_set_op_res_gboolean (simple, op_res);
+
+  g_mutex_unlock (&priv->mutex_create_thumbnail);
+}
+
+
+static void
+photos_base_item_create_thumbnail_async (PhotosBaseItem *self,
+                                         GCancellable *cancellable,
+                                         GAsyncReadyCallback callback,
+                                         gpointer user_data)
+{
+  GSimpleAsyncResult *simple;
+
+  simple = g_simple_async_result_new (G_OBJECT (self),
+                                      callback,
+                                      user_data,
+                                      photos_base_item_create_thumbnail_async);
+  g_simple_async_result_set_check_cancellable (simple, cancellable);
+
+  g_simple_async_result_run_in_thread (simple,
+                                       photos_base_item_create_thumbnail_in_thread_func,
+                                       G_PRIORITY_DEFAULT,
+                                       cancellable);
+  g_object_unref (simple);
+}
+
+
+static gboolean
+photos_base_item_create_thumbnail_finish (PhotosBaseItem *self, GAsyncResult *res, GError **error)
+{
+  GSimpleAsyncResult *simple = G_SIMPLE_ASYNC_RESULT (res);
+  gboolean ret_val = FALSE;
+
+  g_return_val_if_fail (g_simple_async_result_is_valid (res,
+                                                        G_OBJECT (self),
+                                                        photos_base_item_create_thumbnail_async),
+                        NULL);
+  g_return_val_if_fail (error == NULL || *error == NULL, NULL);
+
+  if (g_simple_async_result_propagate_error (simple, error))
+    goto out;
+
+  ret_val = g_simple_async_result_get_op_res_gboolean (simple);
+
+ out:
+  return ret_val;
+}
+
+
+static void
 photos_base_item_default_set_favorite (PhotosBaseItem *self, gboolean favorite)
 {
   photos_utils_set_favorite (self->priv->id, favorite);
@@ -353,17 +421,20 @@ photos_base_item_thumbnail_path_info (GObject *source_object, GAsyncResult *res,
 
 
 static void
-photos_base_item_queue_thumbnail_job (GObject *source_object, GAsyncResult *res, gpointer user_data)
+photos_base_item_create_thumbnail_cb (GObject *source_object, GAsyncResult *res, gpointer user_data)
 {
-  PhotosBaseItem *self = PHOTOS_BASE_ITEM (user_data);
+  PhotosBaseItem *self = PHOTOS_BASE_ITEM (source_object);
   PhotosBaseItemPrivate *priv = self->priv;
-  GFile *file = G_FILE (source_object);
-  gboolean thumbnailed;
+  GError *error;
+  GFile *file = G_FILE (user_data);
 
-  thumbnailed = photos_utils_queue_thumbnail_job_for_file_finish (res);
-  if (!thumbnailed)
+  error = NULL;
+  photos_base_item_create_thumbnail_finish (self, res, &error);
+  if (error != NULL)
     {
       priv->failed_thumbnailing = TRUE;
+      g_warning ("Unable to create thumbnail: %s", error->message);
+      g_error_free (error);
       goto out;
     }
 
@@ -376,6 +447,7 @@ photos_base_item_queue_thumbnail_job (GObject *source_object, GAsyncResult *res,
                            g_object_ref (self));
 
  out:
+  g_object_unref (file);
   g_object_unref (self);
 }
 
@@ -405,9 +477,10 @@ photos_base_item_file_query_info (GObject *source_object, GAsyncResult *res, gpo
   else
     {
       priv->thumbnailed = FALSE;
-      photos_utils_queue_thumbnail_job_for_file_async (file,
-                                                       photos_base_item_queue_thumbnail_job,
-                                                       g_object_ref (self));
+      photos_base_item_create_thumbnail_async (self,
+                                               NULL,
+                                               photos_base_item_create_thumbnail_cb,
+                                               g_object_ref (file));
     }
 
  out:
@@ -672,6 +745,7 @@ photos_base_item_finalize (GObject *object)
   g_free (priv->type_description);
   g_free (priv->uri);
 
+  g_mutex_clear (&priv->mutex_create_thumbnail);
   g_mutex_clear (&priv->mutex);
 
   G_OBJECT_CLASS (photos_base_item_parent_class)->finalize (object);
@@ -727,6 +801,7 @@ photos_base_item_init (PhotosBaseItem *self)
   self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self, PHOTOS_TYPE_BASE_ITEM, PhotosBaseItemPrivate);
   priv = self->priv;
 
+  g_mutex_init (&priv->mutex_create_thumbnail);
   g_mutex_init (&priv->mutex);
 }
 
diff --git a/src/photos-base-item.h b/src/photos-base-item.h
index 1cda085..216da96 100644
--- a/src/photos-base-item.h
+++ b/src/photos-base-item.h
@@ -68,6 +68,7 @@ struct _PhotosBaseItemClass
 {
   GObjectClass parent_class;
 
+  gboolean (*create_thumbnail) (PhotosBaseItem *self, GCancellable *cancellable, GError **error);
   gchar *(*download) (PhotosBaseItem *self, GCancellable *cancellable, GError **error);
   void (*set_favorite) (PhotosBaseItem *self, gboolean favorite);
   void (*update_type_description) (PhotosBaseItem *self);
diff --git a/src/photos-flickr-item.c b/src/photos-flickr-item.c
index f7ff18a..68af65b 100644
--- a/src/photos-flickr-item.c
+++ b/src/photos-flickr-item.c
@@ -37,6 +37,17 @@
 G_DEFINE_TYPE (PhotosFlickrItem, photos_flickr_item, PHOTOS_TYPE_BASE_ITEM);
 
 
+static gboolean
+photos_flickr_item_create_thumbnail (PhotosBaseItem *item, GCancellable *cancellable, GError **error)
+{
+  g_set_error (error,
+               g_quark_from_static_string ("gnome-photos-error"),
+               0,
+               "Thumbnailing Flickr items is unsupported");
+  return FALSE;
+}
+
+
 static gchar *
 photos_flickr_item_download (PhotosBaseItem *item, GCancellable *cancellable, GError **error)
 {
@@ -125,6 +136,7 @@ photos_flickr_item_class_init (PhotosFlickrItemClass *class)
   PhotosBaseItemClass *base_item_class = PHOTOS_BASE_ITEM_CLASS (class);
 
   object_class->constructed= photos_flickr_item_constructed;
+  base_item_class->create_thumbnail = photos_flickr_item_create_thumbnail;
   base_item_class->download = photos_flickr_item_download;
 }
 
diff --git a/src/photos-local-item.c b/src/photos-local-item.c
index 61e3024..79e6143 100644
--- a/src/photos-local-item.c
+++ b/src/photos-local-item.c
@@ -29,11 +29,28 @@
 #include <glib.h>
 
 #include "photos-local-item.h"
+#include "photos-utils.h"
 
 
 G_DEFINE_TYPE (PhotosLocalItem, photos_local_item, PHOTOS_TYPE_BASE_ITEM);
 
 
+static gboolean
+photos_local_item_create_thumbnail (PhotosBaseItem *item, GCancellable *cancellable, GError **error)
+{
+  GFile *file;
+  gboolean ret_val;
+  const gchar *uri;
+
+  uri = photos_base_item_get_uri (item);
+  file = g_file_new_for_uri (uri);
+  ret_val = photos_utils_create_thumbnail (file, cancellable, error);
+
+  g_object_unref (file);
+  return ret_val;
+}
+
+
 static gchar *
 photos_local_item_download (PhotosBaseItem *item, GCancellable *cancellable, GError **error)
 {
@@ -89,6 +106,7 @@ photos_local_item_class_init (PhotosLocalItemClass *class)
   PhotosBaseItemClass *base_item_class = PHOTOS_BASE_ITEM_CLASS (class);
 
   object_class->constructed= photos_local_item_constructed;
+  base_item_class->create_thumbnail = photos_local_item_create_thumbnail;
   base_item_class->download = photos_local_item_download;
 }
 
diff --git a/src/photos-utils.c b/src/photos-utils.c
index 50f55d6..1aefdb9 100644
--- a/src/photos-utils.c
+++ b/src/photos-utils.c
@@ -217,74 +217,66 @@ photos_utils_create_symbolic_icon (const gchar *name, gint base_size)
 }
 
 
-const gchar *
-photos_utils_dot_dir (void)
+gboolean
+photos_utils_create_thumbnail (GFile *file, GCancellable *cancellable, GError **error)
 {
-  const gchar *config_dir;
+  GnomeDesktopThumbnailFactory *factory = NULL;
+  GFileInfo *info = NULL;
+  const gchar *attributes = G_FILE_ATTRIBUTE_STANDARD_CONTENT_TYPE","G_FILE_ATTRIBUTE_TIME_MODIFIED;
+  gboolean ret_val = FALSE;
+  gchar *uri = NULL;
+  GdkPixbuf *pixbuf = NULL;
+  guint64 mtime;
 
-  if (dot_dir == NULL)
+  uri = g_file_get_uri (file);
+  info = g_file_query_info (file, attributes, G_FILE_QUERY_INFO_NONE, cancellable, error);
+  if (info == NULL)
+    goto out;
+
+  mtime = g_file_info_get_attribute_uint64 (info, G_FILE_ATTRIBUTE_TIME_MODIFIED);
+
+  factory = gnome_desktop_thumbnail_factory_new (GNOME_DESKTOP_THUMBNAIL_SIZE_LARGE);
+  pixbuf = gnome_desktop_thumbnail_factory_generate_thumbnail (factory, uri, g_file_info_get_content_type 
(info));
+  if (pixbuf == NULL)
     {
-      config_dir = g_get_user_config_dir ();
-      dot_dir = g_build_filename (config_dir, PACKAGE_TARNAME, NULL);
+      /* FIXME: use proper #defines and enumerated types */
+      g_set_error (error,
+                   g_quark_from_static_string ("gnome-desktop-error"),
+                   0,
+                   "GnomeDesktopThumbnailFactory failed");
+      goto out;
     }
 
-  if (g_file_test (dot_dir, G_FILE_TEST_IS_DIR))
-    goto out;
-
-  g_mkdir_with_parents (dot_dir, 0700);
+  gnome_desktop_thumbnail_factory_save_thumbnail (factory, pixbuf, uri, (time_t) mtime);
+  ret_val = TRUE;
 
  out:
-  return dot_dir;
+  g_clear_object (&pixbuf);
+  g_clear_object (&factory);
+  g_clear_object (&info);
+  g_free (uri);
+  return ret_val;
 }
 
 
-static gboolean
-photos_utils_create_thumbnail (GIOSchedulerJob *job, GCancellable *cancellable, gpointer user_data)
+const gchar *
+photos_utils_dot_dir (void)
 {
-  GSimpleAsyncResult *result = user_data;
-  GFile *file = G_FILE (g_async_result_get_source_object (G_ASYNC_RESULT (result)));
-  GnomeDesktopThumbnailFactory *factory;
-  GFileInfo *info;
-  const gchar *attributes = G_FILE_ATTRIBUTE_STANDARD_CONTENT_TYPE","G_FILE_ATTRIBUTE_TIME_MODIFIED;
-  gchar *uri;
-  GdkPixbuf *pixbuf;
-  guint64 mtime;
-
-  uri = g_file_get_uri (file);
-  info = g_file_query_info (file, attributes, G_FILE_QUERY_INFO_NONE, NULL, NULL);
+  const gchar *config_dir;
 
-  /* we don't care about reporting errors here, just fail the
-   * thumbnail.
-   */
-  if (info == NULL)
+  if (dot_dir == NULL)
     {
-      g_simple_async_result_set_op_res_gboolean (result, FALSE);
-      goto out;
+      config_dir = g_get_user_config_dir ();
+      dot_dir = g_build_filename (config_dir, PACKAGE_TARNAME, NULL);
     }
 
-  mtime = g_file_info_get_attribute_uint64 (info, G_FILE_ATTRIBUTE_TIME_MODIFIED);
-
-  factory = gnome_desktop_thumbnail_factory_new (GNOME_DESKTOP_THUMBNAIL_SIZE_LARGE);
-  pixbuf = gnome_desktop_thumbnail_factory_generate_thumbnail (factory, uri, g_file_info_get_content_type 
(info));
-
-  if (pixbuf != NULL)
-    {
-      gnome_desktop_thumbnail_factory_save_thumbnail (factory, pixbuf, uri, (time_t) mtime);
-      g_simple_async_result_set_op_res_gboolean (result, TRUE);
-    }
-  else
-    g_simple_async_result_set_op_res_gboolean (result, FALSE);
+  if (g_file_test (dot_dir, G_FILE_TEST_IS_DIR))
+    goto out;
 
-  g_object_unref (info);
-  g_object_unref (file);
-  g_object_unref (factory);
-  g_clear_object (&pixbuf);
+  g_mkdir_with_parents (dot_dir, 0700);
 
  out:
-  g_simple_async_result_complete_in_idle (result);
-  g_object_unref (result);
-
-  return FALSE;
+  return dot_dir;
 }
 
 
@@ -612,19 +604,6 @@ photos_utils_icon_from_rdf_type (const gchar *type)
 }
 
 
-void
-photos_utils_queue_thumbnail_job_for_file_async (GFile *file, GAsyncReadyCallback callback, gpointer 
user_data)
-{
-  GSimpleAsyncResult *result;
-
-  result = g_simple_async_result_new (G_OBJECT (file),
-                                      callback,
-                                      user_data,
-                                      photos_utils_queue_thumbnail_job_for_file_async);
-  g_io_scheduler_push_job (photos_utils_create_thumbnail, result, NULL, G_PRIORITY_DEFAULT, NULL);
-}
-
-
 gboolean
 photos_utils_queue_thumbnail_job_for_file_finish (GAsyncResult *res)
 {
diff --git a/src/photos-utils.h b/src/photos-utils.h
index 89b28d5..05e5d41 100644
--- a/src/photos-utils.h
+++ b/src/photos-utils.h
@@ -40,6 +40,8 @@ GdkPixbuf       *photos_utils_create_pixbuf_from_node     (GeglNode *node);
 
 GIcon           *photos_utils_create_symbolic_icon        (const gchar *name, gint base_size);
 
+gboolean         photos_utils_create_thumbnail            (GFile *file, GCancellable *cancellable, GError 
**error);
+
 const gchar     *photos_utils_dot_dir                     (void);
 
 GdkPixbuf       *photos_utils_embed_image_in_frame        (GdkPixbuf *source_image,
@@ -65,10 +67,6 @@ GList           *photos_utils_get_urns_from_paths         (GList *paths, GtkTree
 
 GIcon           *photos_utils_icon_from_rdf_type          (const gchar *type);
 
-void             photos_utils_queue_thumbnail_job_for_file_async (GFile *file,
-                                                                  GAsyncReadyCallback callback,
-                                                                  gpointer user_data);
-
 gboolean         photos_utils_queue_thumbnail_job_for_file_finish (GAsyncResult *res);
 
 void             photos_utils_set_edited_name             (const gchar *urn, const gchar *title);



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