[nautilus/wip/ernestask/tasks] Add thumbnail task
- From: Ernestas Kulik <ernestask src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [nautilus/wip/ernestask/tasks] Add thumbnail task
- Date: Fri, 11 Aug 2017 14:14:14 +0000 (UTC)
commit 66aee802879fe16d66f30e5ef7c96b029513eca9
Author: Ernestas Kulik <ernestask gnome org>
Date: Mon Aug 7 14:49:01 2017 +0300
Add thumbnail task
src-ng/main.c | 66 ++++++
src-ng/meson.build | 11 +-
src-ng/nautilus-file.c | 29 +++
src-ng/nautilus-file.h | 15 +-
src-ng/nautilus-marshallers.list | 1 +
src-ng/res/org.gnome.Nautilus.gresource.xml | 6 +
src-ng/res/text-x-preview.png | Bin 0 -> 923 bytes
src-ng/tasks/nautilus-thumbnail-task.c | 287 +++++++++++++++++++++++++++
src-ng/tasks/nautilus-thumbnail-task.h | 34 ++++
9 files changed, 443 insertions(+), 6 deletions(-)
---
diff --git a/src-ng/main.c b/src-ng/main.c
index df39bd4..19c3162 100644
--- a/src-ng/main.c
+++ b/src-ng/main.c
@@ -2,11 +2,13 @@
#include <stdlib.h>
#include <glib.h>
+#include <gtk/gtk.h>
#include "nautilus-directory.h"
#include "nautilus-file.h"
#include "nautilus-task-manager.h"
#include "tasks/nautilus-rename-task.h"
+#include "tasks/nautilus-thumbnail-task.h"
static void
got_info (NautilusFile *file,
@@ -145,6 +147,60 @@ _rename (const gchar *target,
g_main_loop_run (loop);
}
+static void
+on_thumbnail_finished (NautilusThumbnailTask *task,
+ GFile *location,
+ GdkPixbuf *thumbnail,
+ gpointer user_data)
+{
+ GtkWidget *image;
+
+ image = gtk_image_new_from_pixbuf (thumbnail);
+
+ gtk_widget_set_halign (image, GTK_ALIGN_CENTER);
+ gtk_widget_set_valign (image, GTK_ALIGN_CENTER);
+ gtk_widget_set_visible (image, TRUE);
+
+ gtk_container_add (GTK_CONTAINER (user_data), image);
+
+ g_object_unref (thumbnail);
+}
+
+static gboolean
+on_window_deleted (GtkWidget *widget,
+ GdkEvent *event,
+ gpointer user_data)
+{
+ gtk_main_quit ();
+
+ return GDK_EVENT_PROPAGATE;
+}
+
+static void
+display_thumbnail (const gchar *path)
+{
+ GtkWidget *window;
+ g_autoptr (GFile) location = NULL;
+ g_autoptr (NautilusTask) task = NULL;
+ g_autoptr (NautilusTaskManager) task_manager = NULL;
+
+ gtk_init (NULL, NULL);
+
+ window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
+ location = g_file_new_for_path (path);
+ task = nautilus_thumbnail_task_new (location, TRUE);
+ task_manager = nautilus_task_manager_dup_singleton ();
+
+ gtk_widget_show_all (window);
+
+ g_signal_connect_after (window, "delete-event", on_window_deleted, NULL);
+ g_signal_connect (task, "finished", on_thumbnail_finished, window);
+
+ nautilus_task_manager_queue_task (task_manager, task);
+
+ gtk_main ();
+}
+
int
main (int argc,
char **argv)
@@ -153,6 +209,7 @@ main (int argc,
gchar **files = NULL;
gboolean check = FALSE;
gchar *new_name = NULL;
+ gboolean thumbnail = FALSE;
const GOptionEntry option_entries[] =
{
{
@@ -167,6 +224,10 @@ main (int argc,
"rename", 'n', G_OPTION_FLAG_NONE, G_OPTION_ARG_STRING, &new_name,
"Rename FILE to NAME", "NAME"
},
+ {
+ "thumbnail", 't', G_OPTION_FLAG_NONE, G_OPTION_ARG_NONE, &thumbnail,
+ "Display thumbnail for FILE", NULL
+ },
{ NULL }
};
GError *error = NULL;
@@ -204,5 +265,10 @@ main (int argc,
_rename (files[0], new_name);
}
+ if (thumbnail)
+ {
+ display_thumbnail (files[0]);
+ }
+
return EXIT_SUCCESS;
}
diff --git a/src-ng/meson.build b/src-ng/meson.build
index 27399e6..493af05 100644
--- a/src-ng/meson.build
+++ b/src-ng/meson.build
@@ -1,4 +1,9 @@
-nautilus_ng_sources = ['nautilus-task.c',
+resources = gnome.compile_resources ('nautilus-ng-resources',
+ join_paths ('res', 'org.gnome.Nautilus.gresource.xml'),
+ source_dir: 'res')
+
+nautilus_ng_sources = [resources,
+ 'nautilus-task.c',
'nautilus-task.h',
'nautilus-task-private.h',
'nautilus-task-manager.c',
@@ -21,9 +26,11 @@ nautilus_ng_sources = ['nautilus-task.c',
'nautilus-signal-utilities.h',
'nautilus-file-table.c',
'nautilus-file-table.h',
+ 'tasks/nautilus-thumbnail-task.c',
+ 'tasks/nautilus-thumbnail-task.h',
'main.c']
-nautilus_ng_dependencies = [gio, glib]
+nautilus_ng_dependencies = [gio, glib, gnome_desktop, gtk]
nautilus_marshallers = gnome.genmarshal ('nautilus-marshallers',
sources: 'nautilus-marshallers.list',
diff --git a/src-ng/nautilus-file.c b/src-ng/nautilus-file.c
index 8cac9b0..9701be1 100644
--- a/src-ng/nautilus-file.c
+++ b/src-ng/nautilus-file.c
@@ -23,6 +23,7 @@
#include "nautilus-file-table.h"
#include "nautilus-task-manager.h"
#include "tasks/nautilus-attribute-task.h"
+#include "tasks/nautilus-thumbnail-task.h"
enum
{
@@ -305,6 +306,34 @@ nautilus_file_query_info (NautilusFile *file,
nautilus_task_manager_queue_task (manager, task);
}
+typedef struct
+{
+ NautilusFile *file;
+
+ NautilusFileInfoCallback callback;
+ gpointer callback_data;
+} GetThumbnailDetails;
+
+void
+nautilus_file_get_thumbnail (NautilusFile *file,
+ NautilusThumbnailCallback callback,
+ gpointer user_data)
+{
+ g_autoptr (GFile) location = NULL;
+ g_autoptr (NautilusTask) task = NULL;
+ GetThumbnailDetails *details;
+ g_autoptr (NautilusTaskManager) manager = NULL;
+
+ g_return_if_fail (NAUTILUS_IS_FILE (file));
+
+ location = nautilus_file_get_location (file);
+ task = nautilus_thumbnail_task_new (location, TRUE);
+ details = g_new0 (GetThumbnailDetails, 1);
+ manager = nautilus_task_manager_dup_singleton ();
+
+ nautilus_task_manager_queue_task (manager, task);
+}
+
NautilusFile *
nautilus_file_get_existing (GFile *location)
{
diff --git a/src-ng/nautilus-file.h b/src-ng/nautilus-file.h
index 1799143..8d26aea 100644
--- a/src-ng/nautilus-file.h
+++ b/src-ng/nautilus-file.h
@@ -21,6 +21,7 @@
#include <glib-object.h>
+#include <gdk-pixbuf/gdk-pixbuf.h>
#include <gio/gio.h>
#define NAUTILUS_TYPE_FILE (nautilus_file_get_type ())
@@ -31,6 +32,9 @@ typedef void (*NautilusFileInfoCallback) (NautilusFile *file,
GFileInfo *info,
GError *error,
gpointer user_data);
+typedef void (*NautilusThumbnailCallback) (NautilusFile *file,
+ GdkPixbuf *pixbuf,
+ gpointer user_data);
typedef enum
{
@@ -46,10 +50,13 @@ struct _NautilusFileClass
GFile *new_location);
};
-void nautilus_file_query_info (NautilusFile *file,
- GCancellable *cancellable,
- NautilusFileInfoCallback callback,
- gpointer user_data);
+void nautilus_file_query_info (NautilusFile *file,
+ GCancellable *cancellable,
+ NautilusFileInfoCallback callback,
+ gpointer user_data);
+void nautilus_file_get_thumbnail (NautilusFile *file,
+ NautilusThumbnailCallback callback,
+ gpointer user_data);
NautilusFile *nautilus_file_get_existing (GFile *location);
GFile *nautilus_file_get_location (NautilusFile *file);
diff --git a/src-ng/nautilus-marshallers.list b/src-ng/nautilus-marshallers.list
index c534700..c540ed2 100644
--- a/src-ng/nautilus-marshallers.list
+++ b/src-ng/nautilus-marshallers.list
@@ -1,2 +1,3 @@
VOID:OBJECT,OBJECT,BOXED
VOID:OBJECT,BOXED,BOXED
+VOID:OBJECT,OBJECT
diff --git a/src-ng/res/org.gnome.Nautilus.gresource.xml b/src-ng/res/org.gnome.Nautilus.gresource.xml
new file mode 100644
index 0000000..ba6aee8
--- /dev/null
+++ b/src-ng/res/org.gnome.Nautilus.gresource.xml
@@ -0,0 +1,6 @@
+<?xml version='1.0' encoding='UTF-8'?>
+<gresources>
+ <gresource prefix='/org/gnome/Nautilus'>
+ <file>text-x-preview.png</file>
+ </gresource>
+</gresources>
diff --git a/src-ng/res/text-x-preview.png b/src-ng/res/text-x-preview.png
new file mode 100644
index 0000000..0d45ff9
Binary files /dev/null and b/src-ng/res/text-x-preview.png differ
diff --git a/src-ng/tasks/nautilus-thumbnail-task.c b/src-ng/tasks/nautilus-thumbnail-task.c
new file mode 100644
index 0000000..a5aaa61
--- /dev/null
+++ b/src-ng/tasks/nautilus-thumbnail-task.c
@@ -0,0 +1,287 @@
+/* Copyright (C) 2017 Ernestas Kulik <ernestask gnome org>
+ *
+ * This file is part of Nautilus.
+ *
+ * Nautilus 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.
+ *
+ * Nautilus 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 Nautilus. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include "nautilus-thumbnail-task.h"
+
+#include "nautilus-marshallers.h"
+#include "nautilus-task-private.h"
+
+#include <gdk-pixbuf/gdk-pixbuf.h>
+
+#ifndef GNOME_DESKTOP_USE_UNSTABLE_API
+#define GNOME_DESKTOP_USE_UNSTABLE_API
+#endif
+
+#include <libgnome-desktop/gnome-desktop-thumbnail.h>
+
+struct _NautilusThumbnailTask
+{
+ NautilusTask parent_instance;
+
+ GFile *location;
+ gboolean use_external_thumbnailer;
+};
+
+G_DEFINE_TYPE (NautilusThumbnailTask, nautilus_thumbnail_task, NAUTILUS_TYPE_TASK)
+
+enum
+{
+ FINISHED,
+ LAST_SIGNAL
+};
+
+static guint signals[LAST_SIGNAL] = { 0 };
+
+static void
+finalize (GObject *object)
+{
+ NautilusThumbnailTask *self;
+
+ self = NAUTILUS_THUMBNAIL_TASK (object);
+
+ g_object_unref (self->location);
+
+ G_OBJECT_CLASS (nautilus_thumbnail_task_parent_class)->finalize (object);
+}
+
+static gpointer
+create_thumbnail_factory (gpointer data)
+{
+ (void) data;
+
+ return gnome_desktop_thumbnail_factory_new (GNOME_DESKTOP_THUMBNAIL_SIZE_LARGE);
+}
+
+static GnomeDesktopThumbnailFactory *
+get_thumbnail_factory (void)
+{
+ static GOnce once = G_ONCE_INIT;
+
+ g_once (&once, create_thumbnail_factory, NULL);
+
+ return once.retval;
+}
+
+static GdkPixbuf *
+thumbnail_gnome_desktop (GFile *location)
+{
+ GnomeDesktopThumbnailFactory *thumbnail_factory;
+ g_autofree gchar *uri = NULL;
+ g_autoptr (GFileInfo) file_info = NULL;
+ const gchar *content_type;
+ guint64 mtime;
+ GdkPixbuf *pixbuf;
+
+ thumbnail_factory = get_thumbnail_factory ();
+ uri = g_file_get_uri (location);
+ file_info = g_file_query_info (location,
+ G_FILE_ATTRIBUTE_STANDARD_CONTENT_TYPE ","
+ G_FILE_ATTRIBUTE_TIME_MODIFIED,
+ G_FILE_QUERY_INFO_NONE,
+ NULL, NULL);
+ content_type = g_file_info_get_content_type (file_info);
+ mtime = g_file_info_get_attribute_uint64 (file_info,
+ G_FILE_ATTRIBUTE_TIME_MODIFIED);
+
+ if (!gnome_desktop_thumbnail_factory_can_thumbnail (thumbnail_factory,
+ uri, content_type,
+ mtime))
+ {
+ return NULL;
+ }
+
+ pixbuf = gnome_desktop_thumbnail_factory_generate_thumbnail (thumbnail_factory,
+ uri,
+ content_type);
+
+ if (pixbuf != NULL)
+ {
+ gnome_desktop_thumbnail_factory_save_thumbnail (thumbnail_factory,
+ pixbuf, uri, mtime);
+ }
+ else
+ {
+ gnome_desktop_thumbnail_factory_create_failed_thumbnail (thumbnail_factory,
+ uri, mtime);
+ }
+
+ return pixbuf;
+}
+
+static GdkPixbuf *
+thumbnail_from_cache (GFile *location)
+{
+ g_autoptr (GFileInfo) file_info = NULL;
+ gboolean thumbnail_is_valid;
+ const char *thumbnail_path;
+
+ file_info = g_file_query_info (location,
+ G_FILE_ATTRIBUTE_THUMBNAIL_PATH ","
+ G_FILE_ATTRIBUTE_THUMBNAIL_IS_VALID,
+ G_FILE_QUERY_INFO_NONE,
+ NULL, NULL);
+
+ thumbnail_is_valid = g_file_info_get_attribute_boolean (file_info,
+ G_FILE_ATTRIBUTE_THUMBNAIL_IS_VALID);
+
+ if (!thumbnail_is_valid)
+ {
+ return NULL;
+ }
+
+ thumbnail_path = g_file_info_get_attribute_byte_string (file_info,
+ G_FILE_ATTRIBUTE_THUMBNAIL_PATH);
+
+ return gdk_pixbuf_new_from_file (thumbnail_path, NULL);
+}
+
+static gpointer
+create_gdk_pixbuf_mime_types_table (gpointer data)
+{
+ GHashTable *hash_table;
+ g_autoptr (GSList) gdk_pixbuf_formats = NULL;
+
+ (void) data;
+
+ hash_table = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
+ gdk_pixbuf_formats = gdk_pixbuf_get_formats ();
+
+ for (GSList *i = gdk_pixbuf_formats; i != NULL; i = i->next)
+ {
+ g_autofree GStrv mime_types = NULL;
+
+ mime_types = gdk_pixbuf_format_get_mime_types (i->data);
+
+ for (gsize j = 0; mime_types[j] != NULL; j++)
+ {
+ g_hash_table_insert (hash_table,
+ mime_types[j], GUINT_TO_POINTER (1));
+ }
+ }
+
+ return hash_table;
+}
+
+static GHashTable *
+get_gdk_pixbuf_mime_types (void)
+{
+ static GOnce once = G_ONCE_INIT;
+
+ g_once (&once, create_gdk_pixbuf_mime_types_table, NULL);
+
+ return once.retval;
+}
+
+static GdkPixbuf *
+thumbnail_gdk_pixbuf (GFile *location)
+{
+ GHashTable *gdk_pixbuf_mime_types;
+ g_autoptr (GFileInfo) file_info = NULL;
+ const gchar *content_type;
+
+ gdk_pixbuf_mime_types = get_gdk_pixbuf_mime_types ();
+ file_info = g_file_query_info (location,
+ G_FILE_ATTRIBUTE_STANDARD_CONTENT_TYPE ","
+ G_FILE_ATTRIBUTE_TIME_MODIFIED,
+ G_FILE_QUERY_INFO_NONE,
+ NULL, NULL);
+ content_type = g_file_info_get_content_type (file_info);
+
+ if (g_hash_table_lookup (gdk_pixbuf_mime_types, content_type) == NULL)
+ {
+ return NULL;
+ }
+
+ return NULL;
+}
+
+static void
+execute (NautilusTask *task)
+{
+ NautilusThumbnailTask *self;
+ g_autoptr (GdkPixbuf) pixbuf = NULL;
+
+ self = NAUTILUS_THUMBNAIL_TASK (task);
+
+ if (self->use_external_thumbnailer)
+ {
+ pixbuf = thumbnail_from_cache (self->location);
+
+ if (pixbuf == NULL)
+ {
+ pixbuf = thumbnail_gnome_desktop (self->location);
+ }
+ }
+ else
+ {
+ pixbuf = thumbnail_gdk_pixbuf (self->location);
+ }
+
+ if (pixbuf == NULL)
+ {
+ pixbuf = gdk_pixbuf_new_from_resource ("/org/gnome/Nautilus/text-x-preview.png",
+ NULL);
+ }
+
+ nautilus_task_emit_signal_in_main_context (task, signals[FINISHED], 0,
+ self->location, pixbuf);
+}
+
+static void
+nautilus_thumbnail_task_class_init (NautilusThumbnailTaskClass *klass)
+{
+ GObjectClass *object_class;
+ NautilusTaskClass *task_class;
+
+ object_class = G_OBJECT_CLASS (klass);
+ task_class = NAUTILUS_TASK_CLASS (klass);
+
+ object_class->finalize = finalize;
+
+ task_class->execute = execute;
+
+ signals[FINISHED] = g_signal_new ("finished",
+ G_TYPE_FROM_CLASS (klass),
+ G_SIGNAL_RUN_LAST,
+ 0, NULL, NULL,
+ nautilus_cclosure_marshal_VOID__OBJECT_OBJECT,
+ G_TYPE_NONE,
+ 2,
+ G_TYPE_FILE, GDK_TYPE_PIXBUF);
+}
+
+static void
+nautilus_thumbnail_task_init (NautilusThumbnailTask *self)
+{
+}
+
+NautilusTask *
+nautilus_thumbnail_task_new (GFile *location,
+ gboolean use_external_thumbnailer)
+{
+ NautilusThumbnailTask *instance;
+
+ g_return_val_if_fail (G_IS_FILE (location), NULL);
+
+ instance = g_object_new (NAUTILUS_TYPE_THUMBNAIL_TASK, NULL);
+
+ instance->location = g_object_ref (location);
+ instance->use_external_thumbnailer = use_external_thumbnailer;
+
+ return NAUTILUS_TASK (instance);
+}
diff --git a/src-ng/tasks/nautilus-thumbnail-task.h b/src-ng/tasks/nautilus-thumbnail-task.h
new file mode 100644
index 0000000..1c95bd0
--- /dev/null
+++ b/src-ng/tasks/nautilus-thumbnail-task.h
@@ -0,0 +1,34 @@
+/* Copyright (C) 2017 Ernestas Kulik <ernestask gnome org>
+ *
+ * This file is part of Nautilus.
+ *
+ * Nautilus 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.
+ *
+ * Nautilus 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 Nautilus. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#ifndef NAUTILUS_THUMBNAIL_TASK_H_INCLUDED
+#define NAUTILUS_THUMBNAIL_TASK_H_INCLUDED
+
+#include "nautilus-task.h"
+
+#include <gio/gio.h>
+
+#define NAUTILUS_TYPE_THUMBNAIL_TASK (nautilus_thumbnail_task_get_type ())
+
+G_DECLARE_FINAL_TYPE (NautilusThumbnailTask, nautilus_thumbnail_task,
+ NAUTILUS, THUMBNAIL_TASK, NautilusTask)
+
+NautilusTask *nautilus_thumbnail_task_new (GFile *location,
+ gboolean use_external_thumbnailer);
+
+#endif
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]