[gnome-photos/wip/rishi/thumbnailer: 9/12] Add an out-of-process custom thumbnailer
- From: Debarshi Ray <debarshir src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gnome-photos/wip/rishi/thumbnailer: 9/12] Add an out-of-process custom thumbnailer
- Date: Sun, 12 Feb 2017 21:20:45 +0000 (UTC)
commit 4f941a42dc5b2f51578789e186c7fdcde4aad619
Author: Debarshi Ray <debarshir gnome org>
Date: Thu Feb 9 20:24:37 2017 +0100
Add an out-of-process custom thumbnailer
src/Makefile.am | 49 +++
src/photos-thumbnail.c | 59 ++++
src/photos-thumbnail.h | 32 ++
src/photos-thumbnailer-dbus.xml | 37 +++
src/photos-thumbnailer-main.c | 54 ++++
src/photos-thumbnailer.c | 665 +++++++++++++++++++++++++++++++++++++++
src/photos-thumbnailer.h | 35 ++
7 files changed, 931 insertions(+), 0 deletions(-)
---
diff --git a/src/Makefile.am b/src/Makefile.am
index b33cf61..ba1e4bc 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -1,5 +1,7 @@
bin_PROGRAMS = gnome-photos
+libexec_PROGRAMS = gnome-photos-thumbnailer
+
gnome_photos_built_sources = \
photos-about-data.c \
photos-about-data.h \
@@ -265,8 +267,34 @@ gnome_photos_SOURCES = \
photos-main.c \
$(NULL)
+gnome_photos_thumbnailer_built_sources = \
+ photos-thumbnailer-dbus.c \
+ photos-thumbnailer-dbus.h \
+ $(NULL)
+
+nodist_gnome_photos_thumbnailer_SOURCES = \
+ $(gnome_photos_thumbnailer_built_sources) \
+ $(NULL)
+
+gnome_photos_thumbnailer_SOURCES = \
+ photos-debug.c \
+ photos-debug.h \
+ photos-error.c \
+ photos-error.h \
+ photos-gegl.c \
+ photos-gegl.h \
+ photos-quarks.c \
+ photos-quarks.h \
+ photos-thumbnail.c \
+ photos-thumbnail.h \
+ photos-thumbnailer.c \
+ photos-thumbnailer.h \
+ photos-thumbnailer-main.c \
+ $(NULL)
+
BUILT_SOURCES = \
$(gnome_photos_built_sources) \
+ $(gnome_photos_thumbnailer_built_sources) \
$(NULL)
EXTRA_DIST = \
@@ -285,6 +313,7 @@ EXTRA_DIST = \
photos-selection-toolbar.ui \
photos-share-dialog.ui \
photos-gom-miner.xml \
+ photos-thumbnailer-dbus.xml \
photos-tracker-extract-priority.xml \
photos-tracker-resources.xml \
photos-dleyna-renderer-device.xml \
@@ -347,6 +376,18 @@ gnome_photos_LDADD = \
$(top_builddir)/libgd/libgd.la \
$(NULL)
+gnome_photos_thumbnailer_LDFLAGS = \
+ $(WARN_LDFLAGS) \
+ $(NULL)
+
+gnome_photos_thumbnailer_LDADD = \
+ $(BABL_LIBS) \
+ $(GEGL_LIBS) \
+ $(GDK_PIXBUF_LIBS) \
+ $(GIO_LIBS) \
+ $(GLIB_LIBS) \
+ $(NULL)
+
CLEANFILES = \
$(BUILT_SOURCES) \
stamp-photos-about-data.h \
@@ -493,6 +534,14 @@ photos-shell-search-provider2.h photos-shell-search-provider2.c: org.gnome.Shell
--interface-prefix org.gnome.Shell. \
$<
+photos-thumnailer-dbus.h photos-thumbnailer-dbus.c: photos-thumbnailer-dbus.xml
+ $(AM_V_GEN)gdbus-codegen \
+ --c-namespace Photos \
+ --generate-c-code photos-thumbnailer-dbus \
+ --interface-prefix org.gnome.Photos. \
+ --annotate "org.gnome.Photos.Thumbnailer" org.gtk.GDBus.C.Name ThumbnailerDBus \
+ $<
+
photos-tracker-extract-priority.h photos-tracker-extract-priority.c: photos-tracker-extract-priority.xml
$(AM_V_GEN)gdbus-codegen \
--c-namespace Tracker \
diff --git a/src/photos-thumbnail.c b/src/photos-thumbnail.c
new file mode 100644
index 0000000..0baeada
--- /dev/null
+++ b/src/photos-thumbnail.c
@@ -0,0 +1,59 @@
+/*
+ * Photos - access, organize and share your photos on GNOME
+ * Copyright © 2017 Red Hat, Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ */
+
+
+#include "config.h"
+
+#include "photos-thumbnail.h"
+
+
+enum
+{
+ THUMBNAIL_GENERATION = 0
+};
+
+
+gchar *
+photos_thumbnail_path_for_uri (const gchar *uri, gint size)
+{
+ const gchar *cache_dir;
+ gchar *filename = NULL;
+ gchar *md5 = NULL;
+ gchar *path;
+ gchar *thumbnails_subdir = NULL;
+
+ md5 = g_compute_checksum_for_string (G_CHECKSUM_MD5, uri, -1);
+ filename = g_strconcat (md5, ".png", NULL);
+
+ cache_dir = g_get_user_cache_dir ();
+ thumbnails_subdir = g_strdup_printf ("%d-%d", size, THUMBNAIL_GENERATION);
+
+ path = g_build_filename (cache_dir,
+ PACKAGE_TARNAME,
+ "thumbnails",
+ thumbnails_subdir,
+ filename,
+ NULL);
+
+ g_free (filename);
+ g_free (md5);
+ g_free (thumbnails_subdir);
+ return path;
+}
diff --git a/src/photos-thumbnail.h b/src/photos-thumbnail.h
new file mode 100644
index 0000000..eb0b4f1
--- /dev/null
+++ b/src/photos-thumbnail.h
@@ -0,0 +1,32 @@
+/*
+ * Photos - access, organize and share your photos on GNOME
+ * Copyright © 2017 Red Hat, Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ */
+
+#ifndef PHOTOS_THUMBNAIL_H
+#define PHOTOS_THUMBNAIL_H
+
+#include <glib.h>
+
+G_BEGIN_DECLS
+
+gchar *photos_thumbnail_path_for_uri (const gchar *uri, gint size);
+
+G_END_DECLS
+
+#endif /* PHOTOS_THUMBNAIL_H */
diff --git a/src/photos-thumbnailer-dbus.xml b/src/photos-thumbnailer-dbus.xml
new file mode 100644
index 0000000..452c0d2
--- /dev/null
+++ b/src/photos-thumbnailer-dbus.xml
@@ -0,0 +1,37 @@
+<!DOCTYPE node PUBLIC
+"-//freedesktop//DTD D-BUS Object Introspection 1.0//EN"
+"http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd">
+
+<!--
+ Photos - access, organize and share your photos on GNOME
+ Copyright © 2017 Red Hat, Inc.
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License
+ as published by the Free Software Foundation; either version 2
+ of the License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ 02110-1301, USA.
+-->
+
+<node name="/" xmlns:doc="http://www.freedesktop.org/dbus/1.0/doc.dtd">
+ <interface name="org.gnome.Photos.Thumbnailer">
+ <method name="GenerateThumbnail">
+ <arg name="uri" type="s" direction="in" />
+ <arg name="mime_type" type="s" direction="in" />
+ <arg name="orientation" type="s" direction="in" />
+ <arg name="original_height" type="x" direction="in" />
+ <arg name="original_width" type="x" direction="in" />
+ <arg name="pipeline_uri" type="s" direction="in" />
+ <arg name="thumbnail_size" type="i" direction="in" />
+ </method>
+ </interface>
+</node>
diff --git a/src/photos-thumbnailer-main.c b/src/photos-thumbnailer-main.c
new file mode 100644
index 0000000..1f9c517
--- /dev/null
+++ b/src/photos-thumbnailer-main.c
@@ -0,0 +1,54 @@
+/*
+ * Photos - access, organize and share your photos on GNOME
+ * Copyright © 2017 Red Hat, Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ */
+
+
+#include "config.h"
+
+#include <locale.h>
+
+#include <glib.h>
+#include <glib/gi18n.h>
+
+#include "photos-debug.h"
+#include "photos-thumbnailer.h"
+
+
+gint
+main (gint argc, gchar *argv[])
+{
+ GApplication *app;
+ gint exit_status = 0;
+
+ setlocale (LC_ALL, "");
+
+ photos_debug_init ();
+
+ bindtextdomain (GETTEXT_PACKAGE, PACKAGE_LOCALE_DIR);
+ bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8");
+ textdomain (GETTEXT_PACKAGE);
+
+ g_set_prgname (PACKAGE_TARNAME "-thumbnailer");
+
+ app = photos_thumbnailer_new ();
+ exit_status = g_application_run (app, argc, argv);
+
+ g_object_unref (app);
+ return exit_status;
+}
diff --git a/src/photos-thumbnailer.c b/src/photos-thumbnailer.c
new file mode 100644
index 0000000..3e68d75
--- /dev/null
+++ b/src/photos-thumbnailer.c
@@ -0,0 +1,665 @@
+/*
+ * Photos - access, organize and share your photos on GNOME
+ * Copyright © 2017 Red Hat, Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ */
+
+
+#include "config.h"
+
+#include <stdlib.h>
+
+#include <babl/babl.h>
+#include <gdk-pixbuf/gdk-pixbuf.h>
+#include <gegl.h>
+#include <glib/gi18n.h>
+
+#include "photos-debug.h"
+#include "photos-error.h"
+#include "photos-gegl.h"
+#include "photos-thumbnailer.h"
+#include "photos-thumbnailer-dbus.h"
+
+
+struct _PhotosThumbnailer
+{
+ GApplication parent_instance;
+ GDBusConnection *connection;
+ PhotosThumbnailerDBus *skeleton;
+ gchar *address;
+};
+
+
+G_DEFINE_TYPE (PhotosThumbnailer, photos_thumbnailer, G_TYPE_APPLICATION);
+
+
+typedef struct _PhotosThumbnailerGenerateData PhotosThumbnailerGenerateData;
+
+struct _PhotosThumbnailerGenerateData
+{
+ GFile *file;
+ GQuark orientation;
+ GdkPixbuf *pixbuf_thumbnail;
+ GeglNode *graph;
+ gint thumbnail_size;
+ gint64 original_height;
+ gint64 original_width;
+};
+
+enum
+{
+ INACTIVITY_TIMEOUT = 12000 /* ms */
+};
+
+static const GOptionEntry COMMAND_LINE_OPTIONS[] =
+{
+ { "address", 0, G_OPTION_FLAG_NONE, G_OPTION_ARG_STRING, NULL, N_("D-Bus address to use"), NULL},
+ { NULL }
+};
+
+static const gchar *THUMBNAILER_PATH = "/org/gnome/Photos/Thumbnailer";
+
+
+static PhotosThumbnailerGenerateData *
+photos_thumbnailer_generate_data_new (GFile *file,
+ GQuark orientation,
+ gint64 original_height,
+ gint64 original_width,
+ gint thumbnail_size,
+ GeglNode *graph)
+{
+ PhotosThumbnailerGenerateData *data;
+
+ data = g_slice_new0 (PhotosThumbnailerGenerateData);
+ data->file = g_object_ref (file);
+ data->orientation = orientation;
+ data->thumbnail_size = thumbnail_size;
+ data->original_height = original_height;
+ data->original_width = original_width;
+ data->graph = g_object_ref (graph);
+
+ return data;
+}
+
+
+static void
+photos_thumbnailer_generate_data_free (PhotosThumbnailerGenerateData *data)
+{
+ g_object_unref (data->file);
+ g_object_unref (data->graph);
+ g_object_unref (data->pixbuf_thumbnail);
+ g_slice_free (PhotosThumbnailerGenerateData, data);
+}
+
+
+static gboolean
+photos_thumbnailer_authorize_authenticated_peer (PhotosThumbnailer *self,
+ GIOStream *iostream,
+ GCredentials *credentials)
+{
+ GCredentials *own_credentials = NULL;
+ GError *error;
+ gboolean ret_val = FALSE;
+
+ if (credentials == NULL)
+ goto out;
+
+ own_credentials = g_credentials_new ();
+
+ error = NULL;
+ if (!g_credentials_is_same_user (credentials, own_credentials, &error))
+ {
+ g_warning ("Unable to authorize peer: %s", error->message);
+ g_error_free (error);
+ goto out;
+ }
+
+ ret_val = TRUE;
+
+ out:
+ g_clear_object (&own_credentials);
+ return ret_val;
+}
+
+
+static void
+photos_thumbnailer_generate_thumbnail_in_thread_func (GTask *task,
+ gpointer source_object,
+ gpointer task_data,
+ GCancellable *cancellable)
+{
+ const Babl *format;
+ GeglBuffer *buffer_orig = NULL;
+ GeglBuffer *buffer_zoomed = NULL;
+ GeglRectangle bbox;
+ GdkPixbuf *pixbuf = NULL;
+ PhotosThumbnailerGenerateData *data;
+ gdouble zoom;
+ gint bpp;
+ gint min_dimension;
+ guchar *buf = NULL;
+
+ data = (PhotosThumbnailerGenerateData *) g_task_get_task_data (task);
+
+ {
+ GeglNode *buffer_sink;
+ GeglNode *graph = NULL;
+ GeglNode *load;
+ gchar *path;
+
+ path = g_file_get_path (data->file);
+
+ graph = gegl_node_new ();
+ load = gegl_node_new_child (graph, "operation", "gegl:load", "path", path, NULL);
+ buffer_sink = gegl_node_new_child (graph, "operation", "gegl:buffer-sink", "buffer", &buffer_orig, NULL);
+ gegl_node_link_many (load, buffer_sink, NULL);
+ gegl_node_process (buffer_sink);
+
+ g_object_unref (graph);
+ g_free (path);
+ }
+
+ bbox = *gegl_buffer_get_extent (buffer_orig);
+ min_dimension = MIN (bbox.height, bbox.width);
+ zoom = (gdouble) data->size / (gdouble) min_dimension;
+
+ bbox.height = (gint) ((gdouble) bbox.height * zoom + 0.5);
+ bbox.width = (gint) ((gdouble) bbox.width * zoom + 0.5);
+ bbox.x = (gint) ((gdouble) bbox.x * zoom + 0.5);
+ bbox.y = (gint) ((gdouble) bbox.y * zoom + 0.5);
+
+ format = gegl_buffer_get_format (buffer_orig);
+ bpp = babl_format_get_bytes_per_pixel (format);
+ buf = g_malloc0_n (bbox.height * bbox.width, bpp);
+
+ gegl_buffer_get (buffer_orig, &bbox, zoom, format, buf, GEGL_AUTO_ROWSTRIDE, GEGL_ABYSS_NONE);
+
+ bbox.x = 0;
+ bbox.y = 0;
+ buffer_zoomed = gegl_buffer_linear_new_from_data (buf, format, &bbox, GEGL_AUTO_ROWSTRIDE, g_free, NULL);
+
+ {
+ GeglNode *buffer_source;
+ GeglNode *graph = NULL;
+ GeglNode *orientation;
+ GeglNode *save_pixbuf;
+
+ graph = gegl_node_new ();
+ buffer_source = gegl_node_new_child (graph, "operation", "gegl:buffer-source", "buffer", buffer_zoomed,
NULL);
+ orientation = photos_gegl_create_orientation_node (graph, data->orientation);
+ save_pixbuf = gegl_node_new_child (graph, "operation", "gegl:save-pixbuf", "pixbuf", &pixbuf, NULL);
+ gegl_node_link_many (buffer_source, orientation, save_pixbuf, NULL);
+ gegl_node_process (save_pixbuf);
+
+ g_object_unref (graph);
+ }
+
+ g_clear_object (&buffer_orig);
+ g_clear_object (&buffer_zoomed);
+ g_clear_object (&pixbuf);
+}
+
+
+static void
+photos_thumbnailer_generate_thumbnail_process (GObject *source_object, GAsyncResult *res, gpointer user_data)
+{
+ GTask *task = G_TASK (user_data);
+ GCancellable *cancellable;
+ GError *error;
+ GFile *file = NULL;
+ GeglProcessor *processor = GEGL_PROCESSOR (source_object);
+ PhotosThumbnailerGenerateData *data;
+ gchar *path = NULL;
+
+ self = PHOTOS_THUMBNAILER (g_task_get_source_object (task));
+ cancellable = g_task_get_cancellable (task);
+ data = g_task_get_task_data (task);
+
+ error = NULL;
+ if (!photos_gegl_processor_process_finish (processor, res, &error))
+ {
+ g_task_return_error (task, error);
+ goto out;
+ }
+
+ path = photos_thumbnail_path_for_file (data->file);
+ file = g_file_new_for_path (path);
+ g_file_replace_async (file,
+ NULL,
+ FALSE,
+ G_FILE_CREATE_REPLACE_DESTINATION,
+ G_PRIORITY_DEFAULT,
+ cancellable,
+ photos_thumbnailer_generate_thumbnail_replace,
+ g_object_ref (task));
+
+ g_task_run_in_thread (task, photos_thumbnailer_generate_thumbnail_in_thread_func);
+
+ out:
+ g_free (path);
+ g_clear_object (&file);
+ g_object_unref (task);
+}
+
+
+static void
+photos_thumbnailer_generate_thumbnail_pixbuf (GObject *source_object, GAsyncResult *res, gpointer user_data)
+{
+ GTask *task = G_TASK (user_data);
+ GCancellable *cancellable;
+ GError *error;
+ GdkPixbuf *pixbuf = NULL;
+ GdkPixbuf *pixbuf_oriented = NULL;
+ GeglNode *pipeline_node;
+ GeglNode *pixbuf_source;
+ GeglNode *save_pixbuf;
+ GeglProcessor *processor = NULL;
+ PhotosThumbnailerGenerateData *data;
+
+ self = PHOTOS_THUMBNAILER (g_task_get_source_object (task));
+ cancellable = g_task_get_cancellable (task);
+ data = g_task_get_task_data (task);
+
+ error = NULL;
+ pixbuf = photos_pixbuf_new_from_file_finish (res, &error);
+ if (error != NULL)
+ {
+ g_task_return_error (task, error);
+ goto out;
+ }
+
+ pixbuf_oriented = gdk_pixbuf_apply_embedded_orientation (pixbuf);
+
+ g_assert_null (data->pixbuf_thumbnail);
+
+ pixbuf_source = gegl_node_new_child (data->graph, "operation", "gegl:pixbuf", pixbuf_oriented, NULL);
+ pipeline_node = photos_pipeline_get_graph (data->pipeline);
+ save_pixbuf = gegl_node_new_child (data->graph,
+ "operation", "gegl:save-pixbuf",
+ "pixbuf", &data->pixbuf_thumbnail,
+ NULL);
+
+ gegl_node_link_many (pixbuf_source, pipeline_node, save_pixbuf, NULL);
+
+ processor = photos_pipeline_new_processor (data->pipeline);
+ photos_gegl_processor_process_async (processor,
+ cancellable,
+ photos_thumbnailer_generate_thumbnail_process,
+ g_object_ref (task));
+
+ out:
+ g_clear_object (&pixbuf);
+ g_clear_object (&pixbuf_oriented);
+ g_clear_object (&processor);
+ g_object_unref (task);
+}
+
+
+static void
+photos_thumbnailer_generate_thumbnail_pipeline (GObject *source_object, GAsyncResult *res, gpointer
user_data)
+{
+ GTask *task = G_TASK (user_data);
+ GError *error;
+ PhotosPipeline *pipeline = NULL;
+ PhotosThumbnailerGenerateData *data;
+ gchar *path = NULL;
+ gdouble height;
+ gdouble width;
+ gdouble x;
+ gdouble y;
+ gint load_height;
+ gint load_width;
+
+ self = PHOTOS_THUMBNAILER (g_task_get_source_object (task));
+ data = g_task_get_task_data (task);
+
+ error = NULL;
+ pipeline = photos_pipeline_new_finish (res, &error);
+ if (error != NULL)
+ {
+ g_task_return_error (task, error);
+ goto out;
+ }
+
+ g_assert_null (data->pipeline);
+ data->pipeline = g_object_ref (pipeline);
+
+ if (photos_pipeline_get (pipeline, "gegl:crop", "height", &height, "width", &width, "x", &x, "y", &y,
NULL))
+ {
+ g_assert_cmpfloat (height, >=, 0.0);
+ g_assert_cmpfloat (width >= 0.0);
+ g_assert_cmpfloat (x, >=, 0.0);
+ g_assert_cmpfloat (y, >=, 0.0);
+
+ load_height = (gint) (height / (gdouble) data->thumbnail_size * (gdouble) data->original_height + 0.5);
+ load_width = (gint) (width / (gdouble) data->thumbnail_size * (gdouble) data->original_width + 0.5);
+ }
+ else
+ {
+ load_height = data->thumbnail_size;
+ load_width = data->thumbnail_size;
+ }
+
+ path = g_file_get_path (data->file);
+ photos_pixbuf_new_from_file_at_size_async (path,
+ load_width,
+ load_height,
+ photos_thumbnailer_generate_thumbnail_pixbuf,
+ g_object_ref (task));
+
+ out:
+ g_free (path);
+ g_clear_object (&pipeline);
+ g_object_unref (task);
+}
+
+
+static void
+photos_thumbnailer_generate_thumbnail_async (PhotosThumbnailer *self,
+ const gchar *uri,
+ const gchar *mime_type,
+ const gchar *orientation,
+ gint64 original_height,
+ gint64 original_width,
+ const gchar *pipeline_uri,
+ gint thumbnail_size,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
+{
+ GFile *file = NULL;
+ GTask *task = NULL;
+ GQuark orientation_quark;
+ GeglNode *graph;
+ PhotosThumbnailerGenerateData *data;
+
+ g_return_val_if_fail (PHOTOS_IS_THUMBNAILER (self), FALSE);
+ g_return_val_if_fail (uri != NULL && uri[0] != '\0', FALSE);
+ g_return_val_if_fail (mime_type != NULL && mime_type[0] != '\0', FALSE);
+ g_return_val_if_fail (orientation != NULL && orientation[0] != '\0', FALSE);
+ g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), FALSE);
+
+ file = g_file_new_for_uri (uri);
+ orientation_quark = g_quark_from_string (orientation);
+ graph = gegl_node_new ();
+ data = photos_thumbnailer_generate_data_new (file,
+ orientation_quark,
+ original_height,
+ original_width,
+ thumbnail_size,
+ graph);
+
+ task = g_task_new (self, cancellable, callback, user_data);
+ g_task_set_source_tag (task, photos_thumbnailer_generate_thumbnail_async);
+ g_task_set_task_data (task, data, (GDestroyNotify) photos_thumbnailer_generate_data_free);
+
+ photos_pipeline_new_async (graph,
+ pipeline_uri,
+ cancellable,
+ photos_thumbnailer_generate_thumbnail_pipeline,
+ g_object_ref (task));
+
+ g_object_unref (file);
+ g_object_unref (graph);
+ g_object_unref (task);
+ return TRUE;
+}
+
+
+static gboolean
+photos_thumbnailer_generate_thumbnail_finish (PhotosThumbnailer *self, GAsyncResult *res, GError **error)
+{
+ GTask *task = G_TASK (res);
+
+ g_return_val_if_fail (g_task_is_valid (res, self), FALSE);
+ g_return_val_if_fail (g_task_get_source_tag (task) == photos_thumbnailer_generate_thumbnail_async, FALSE);
+ g_return_val_if_fail (error == NULL || *error == NULL, NULL);
+
+ return g_task_propagate_boolean (task, error);
+}
+
+
+static void
+photos_thumbnailer_handle_generate_thumbnail_generate_thumbnail (GObject *source_object,
+ GAsyncResult *res,
+ gpointer user_data)
+{
+ PhotosThumbnailer *self = PHOTOS_THUMBNAILER (source_object);
+ GDBusMethodInvocation *invocation = G_DBUS_METHOD_INVOCATION (user_data);
+ GError *error;
+
+ error = NULL;
+ if (!photos_thumbnailer_generate_thumbnail_finish (self, res, &error))
+ {
+ g_dbus_method_invocation_take_error (invocation, error);
+ goto out;
+ }
+
+ photos_thumbnailer_dbus_complete_generate_thumbnail (self->skeleton, invocation);
+
+ out:
+ photos_debug (PHOTOS_DEBUG_THUMBNAILER, "Completed GenerateThumbnail");
+ g_application_release (G_APPLICATION (self));
+ g_object_unref (invocation);
+}
+
+
+static gboolean
+photos_thumbnailer_handle_generate_thumbnail (PhotosThumbnailer *self,
+ GDBusMethodInvocation *invocation,
+ const gchar *uri,
+ const gchar *mime_type,
+ const gchar *orientation,
+ gint64 original_height,
+ gint64 original_width,
+ const gchar *pipeline_uri,
+ gint thumbnail_size)
+{
+ g_return_val_if_fail (PHOTOS_IS_THUMBNAILER (self), FALSE);
+ g_return_val_if_fail (G_IS_DBUS_INVOCATION (invocation), FALSE);
+ g_return_val_if_fail (uri != NULL && uri[0] != '\0', FALSE);
+ g_return_val_if_fail (mime_type != NULL && mime_type[0] != '\0', FALSE);
+ g_return_val_if_fail (orientation != NULL && orientation[0] != '\0', FALSE);
+ g_return_val_if_fail (pipeline_uri != NULL && pipeline_uri[0] != '\0', FALSE);
+
+ photos_debug (PHOTOS_DEBUG_THUMBNAILER, "Handling GenerateThumbnail for %s", uri);
+
+ g_application_hold (G_APPLICATION (self));
+ photos_thumbnailer_generate_thumbnail_async (self,
+ uri,
+ mime_type,
+ orientation,
+ original_height,
+ original_width,
+ pipeline_uri,
+ thumbnail_size,
+ NULL,
+
photos_thumbnailer_handle_generate_thumbnail_generate_thumbnail,
+ g_object_ref (invocation));
+
+ g_clear_object (&file);
+ g_clear_object (&task);
+ return TRUE;
+}
+
+
+static gboolean
+photos_thumbnailer_dbus_register (GApplication *application,
+ GDBusConnection *connection,
+ const gchar *object_path,
+ GError **error)
+{
+ PhotosThumbnailer *self = PHOTOS_THUMBNAILER (application);
+ GDBusAuthObserver *observer = NULL;
+ gboolean ret_val = FALSE;
+
+ if (!G_APPLICATION_CLASS (photos_thumbnailer_parent_class)->dbus_register (application,
+ connection,
+ object_path,
+ error))
+ goto out;
+
+ observer = g_dbus_auth_observer_new ();
+ g_signal_connect_swapped (observer,
+ "authorize-authenticated-peer",
+ G_CALLBACK (photos_thumbnailer_authorize_authenticated_peer),
+ self);
+
+ self->connection = g_dbus_connection_new_for_address_sync (self->address,
+ G_DBUS_CONNECTION_FLAGS_AUTHENTICATION_CLIENT,
+ observer,
+ NULL,
+ error);
+ if (self->connection == NULL)
+ goto out;
+
+ g_message ("exporting skeleton");
+ if (!g_dbus_interface_skeleton_export (G_DBUS_INTERFACE_SKELETON (self->skeleton),
+ self->connection,
+ THUMBNAILER_PATH,
+ error))
+ {
+ g_clear_object (&self->skeleton);
+ goto out;
+ }
+
+ g_message ("dbus register: %s %s", g_dbus_connection_get_unique_name (self->connection), object_path);
+
+ ret_val = TRUE;
+
+ out:
+ g_clear_object (&observer);
+ return ret_val;
+}
+
+
+static void
+photos_thumbnailer_dbus_unregister (GApplication *application,
+ GDBusConnection *connection,
+ const gchar *object_path)
+{
+ PhotosThumbnailer *self = PHOTOS_THUMBNAILER (application);
+
+ g_message ("dbus unregister: %li", g_get_monotonic_time ());
+
+ if (self->skeleton != NULL)
+ {
+ g_dbus_interface_skeleton_unexport_from_connection (G_DBUS_INTERFACE_SKELETON (self->skeleton),
+ self->connection);
+ g_clear_object (&self->skeleton);
+ }
+
+ g_message ("dbus unregister: chain up");
+ G_APPLICATION_CLASS (photos_thumbnailer_parent_class)->dbus_unregister (application, connection,
object_path);
+}
+
+
+static gint
+photos_thumbnailer_handle_local_options (GApplication *application, GVariantDict *options)
+{
+ PhotosThumbnailer *self = PHOTOS_THUMBNAILER (application);
+ gint ret_val = EXIT_FAILURE;
+
+ if (g_variant_dict_lookup (options, "address", "s", &self->address))
+ ret_val = -1;
+
+ return ret_val;
+}
+
+
+static void
+photos_thumbnailer_shutdown (GApplication *application)
+{
+ photos_debug (PHOTOS_DEBUG_THUMBNAILER, "Thumbnailer exiting");
+
+ G_APPLICATION_CLASS (photos_thumbnailer_parent_class)->shutdown (application);
+}
+
+
+static void
+photos_thumbnailer_startup (GApplication *application)
+{
+ G_APPLICATION_CLASS (photos_thumbnailer_parent_class)->startup (application);
+
+ gegl_init (NULL, NULL);
+ photos_debug (PHOTOS_DEBUG_THUMBNAILER, "Thumbnailer ready");
+}
+
+
+static void
+photos_thumbnailer_dispose (GObject *object)
+{
+ PhotosThumbnailer *self = PHOTOS_THUMBNAILER (object);
+
+ g_clear_object (&self->connection);
+ g_clear_object (&self->skeleton);
+
+ G_OBJECT_CLASS (photos_thumbnailer_parent_class)->dispose (object);
+}
+
+
+static void
+photos_thumbnailer_finalize (GObject *object)
+{
+ PhotosThumbnailer *self = PHOTOS_THUMBNAILER (object);
+
+ g_free (self->address);
+
+ if (g_application_get_is_registered (G_APPLICATION (self)))
+ gegl_exit ();
+
+ G_OBJECT_CLASS (photos_thumbnailer_parent_class)->finalize (object);
+}
+
+
+static void
+photos_thumbnailer_init (PhotosThumbnailer *self)
+{
+ self->skeleton = photos_thumbnailer_dbus_skeleton_new ();
+ g_signal_connect_swapped (self->skeleton,
+ "handle-generate-thumbnail",
+ G_CALLBACK (photos_thumbnailer_handle_generate_thumbnail),
+ self);
+
+ g_application_add_main_option_entries (G_APPLICATION (self), COMMAND_LINE_OPTIONS);
+}
+
+
+static void
+photos_thumbnailer_class_init (PhotosThumbnailerClass *class)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (class);
+ GApplicationClass *application_class = G_APPLICATION_CLASS (class);
+
+ object_class->dispose = photos_thumbnailer_dispose;
+ object_class->finalize = photos_thumbnailer_finalize;
+ application_class->dbus_register = photos_thumbnailer_dbus_register;
+ application_class->dbus_unregister = photos_thumbnailer_dbus_unregister;
+ application_class->handle_local_options = photos_thumbnailer_handle_local_options;
+ application_class->shutdown = photos_thumbnailer_shutdown;
+ application_class->startup = photos_thumbnailer_startup;
+}
+
+
+GApplication *
+photos_thumbnailer_new (void)
+{
+ return g_object_new (PHOTOS_TYPE_THUMBNAILER,
+ "flags", G_APPLICATION_IS_SERVICE | G_APPLICATION_NON_UNIQUE,
+ "inactivity-timeout", INACTIVITY_TIMEOUT,
+ NULL);
+}
diff --git a/src/photos-thumbnailer.h b/src/photos-thumbnailer.h
new file mode 100644
index 0000000..f4d287a
--- /dev/null
+++ b/src/photos-thumbnailer.h
@@ -0,0 +1,35 @@
+/*
+ * Photos - access, organize and share your photos on GNOME
+ * Copyright © 2017 Red Hat, Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ */
+
+#ifndef PHOTOS_THUMBNAILER_H
+#define PHOTOS_THUMBNAILER_H
+
+#include <gio/gio.h>
+
+G_BEGIN_DECLS
+
+#define PHOTOS_TYPE_THUMBNAILER (photos_thumbnailer_get_type ())
+G_DECLARE_FINAL_TYPE (PhotosThumbnailer, photos_thumbnailer, PHOTOS, THUMBNAILER, GApplication);
+
+GApplication *photos_thumbnailer_new (void);
+
+G_END_DECLS
+
+#endif /* PHOTOS_THUMBNAILER_H */
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]