[gnome-photos/wip/flickr: 11/11] base-item: Refactor thumbnail creation for remote items
- From: Debarshi Ray <debarshir src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gnome-photos/wip/flickr: 11/11] base-item: Refactor thumbnail creation for remote items
- Date: Tue, 2 Jul 2013 16:21:00 +0000 (UTC)
commit 51d102af13b511f387c68719bb72da04d5e12f3f
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].
Current implementations use GnomeDesktopThumbnailFactory and Grilo
for creating thumbnails for local and Flickr items respectively.
[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 | 147 ++++++++++++++++++++++++++++++++++++++++++++++
src/photos-local-item.c | 18 ++++++
src/photos-utils.c | 105 +++++++++++++--------------------
src/photos-utils.h | 6 +-
6 files changed, 294 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..abacdfb 100644
--- a/src/photos-flickr-item.c
+++ b/src/photos-flickr-item.c
@@ -25,9 +25,12 @@
#include "config.h"
+#include <string.h>
+
#include <gdk-pixbuf/gdk-pixbuf.h>
#include <gio/gio.h>
#include <glib.h>
+#include <grilo.h>
#include <libgnome-desktop/gnome-desktop-thumbnail.h>
#include "photos-base-item.h"
@@ -37,6 +40,149 @@
G_DEFINE_TYPE (PhotosFlickrItem, photos_flickr_item, PHOTOS_TYPE_BASE_ITEM);
+typedef struct _PhotosFlickrItemSyncData PhotosFlickrItemSyncData;
+
+struct _PhotosFlickrItemSyncData
+{
+ GError **error;
+ GMainLoop *loop;
+ gboolean op_res;
+};
+
+
+static GrlOperationOptions *
+photos_flickr_item_get_grl_options (GrlSource *source)
+{
+ GrlCaps *caps;
+ GrlOperationOptions *options;
+
+ caps = grl_source_get_caps (source, GRL_OP_RESOLVE);
+ options = grl_operation_options_new (caps);
+ return options;
+}
+
+
+static void
+photos_flickr_item_source_resolve (GrlSource *source,
+ guint operation_id,
+ GrlMedia *media,
+ gpointer user_data,
+ const GError *error)
+{
+ PhotosFlickrItemSyncData *data = (PhotosFlickrItemSyncData *) user_data;
+
+ g_message ("done = %p", media);
+ if (error != NULL)
+ {
+ if (data->error != NULL)
+ *(data->error) = g_error_copy (error);
+ data->op_res = FALSE;
+ }
+ else
+ data->op_res = TRUE;
+
+ g_main_loop_quit (data->loop);
+}
+
+
+static gboolean
+photos_flickr_item_create_thumbnail (PhotosBaseItem *item, GCancellable *cancellable, GError **error)
+{
+ PhotosFlickrItemSyncData data;
+ GList *keys = NULL;
+ GMainContext *context = NULL;
+ GrlMedia *media = NULL;
+ GrlOperationOptions *options = NULL;
+ GrlRegistry *registry;
+ GrlSource *source;
+ gboolean ret_val = FALSE;
+ const gchar *const flickr_prefix = "flickr:";
+ const gchar *const resource_prefix = "gd:goa-account:";
+ const gchar *flickr_id;
+ const gchar *goa_id;
+ const gchar *identifier;
+ const gchar *resource_urn;
+ gchar *grilo_id = NULL;
+ gsize prefix_len;
+
+ data.error = error;
+ data.loop = NULL;
+
+ prefix_len = strlen (flickr_prefix);
+ identifier = photos_base_item_get_identifier (item);
+ if (strlen (identifier) <= prefix_len || !g_str_has_prefix (identifier, flickr_prefix))
+ {
+ /* FIXME: use proper #defines and enumerated types */
+ g_set_error (error,
+ g_quark_from_static_string ("gnome-photos-error"),
+ 0,
+ "Invalid nao:identifier for Flickr item %s",
+ identifier);
+ goto out;
+ }
+ flickr_id = identifier + prefix_len;
+
+ prefix_len = strlen (resource_prefix);
+ resource_urn = photos_base_item_get_resource_urn (item);
+ if (strlen (resource_urn) <= prefix_len || !g_str_has_prefix (resource_urn, resource_prefix))
+ {
+ /* FIXME: use proper #defines and enumerated types */
+ g_set_error (error,
+ g_quark_from_static_string ("gnome-photos-error"),
+ 0,
+ "Invalid nie:dataSource for Flickr item %s",
+ resource_urn);
+ goto out;
+ }
+ goa_id = resource_urn + prefix_len;
+
+ grilo_id = g_strdup_printf ("grl-flickr-%s", goa_id);
+ registry = grl_registry_get_default ();
+ source = grl_registry_lookup_source (registry, grilo_id);
+ if (source == NULL)
+ {
+ /* FIXME: use proper #defines and enumerated types */
+ g_set_error (error,
+ g_quark_from_static_string ("gnome-photos-error"),
+ 0,
+ "Failed to find a GrlSource for %s",
+ grilo_id);
+ goto out;
+ }
+
+ media = grl_media_new ();
+ grl_media_set_id (media, flickr_id);
+
+ keys = grl_metadata_key_list_new (GRL_METADATA_KEY_THUMBNAIL, GRL_METADATA_KEY_INVALID);
+ options = photos_flickr_item_get_grl_options (source);
+
+ context = g_main_context_new ();
+ g_main_context_push_thread_default (context);
+ data.loop = g_main_loop_new (context, FALSE);
+
+ grl_source_resolve (source, media, keys, options, photos_flickr_item_source_resolve, &data);
+ g_main_loop_run (data.loop);
+ g_main_context_pop_thread_default (context);
+
+ if (!data.op_res)
+ goto out;
+
+ g_message ("done");
+ ret_val = TRUE;
+
+ out:
+ g_free (grilo_id);
+ g_list_free (keys);
+ g_clear_object (&options);
+ g_clear_object (&media);
+ if (context != NULL)
+ g_main_context_unref (context);
+ if (data.loop != NULL)
+ g_main_loop_unref (data.loop);
+ return ret_val;
+}
+
+
static gchar *
photos_flickr_item_download (PhotosBaseItem *item, GCancellable *cancellable, GError **error)
{
@@ -125,6 +271,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]