[Xfce4-commits] [xfce/tumbler] 02/06: Load and register in tumbler a list of thumbnailers read from XDG_DATA_DIRS/thumbnailers. These "desktop" thumbnailers should have *.thumbnailer as a desktop file name and [Thumbnailer Entry] for MimeType and Exec.

noreply at xfce.org noreply at xfce.org
Sun May 28 11:20:18 CEST 2017


This is an automated email from the git hooks/post-receive script.

a   l   i       p   u   s   h   e   d       a       c   o   m   m   i   t       t   o       b   r   a   n   c   h       m   a   s   t   e   r   
   in repository xfce/tumbler.

commit b390c588b30ef388601640fc3853bce0eb3d8a05
Author: Ali Abdallah <aliovx at gmail.com>
Date:   Sat May 27 20:26:56 2017 +0200

    Load and register in tumbler a list of thumbnailers read from XDG_DATA_DIRS/thumbnailers. These "desktop" thumbnailers should have *.thumbnailer as a desktop file name and [Thumbnailer Entry] for MimeType and Exec.
---
 .../desktop-thumbnailer-provider.c                 | 166 ++++++++--
 plugins/desktop-thumbnailer/desktop-thumbnailer.c  | 335 ++++++++++++++++++++-
 2 files changed, 471 insertions(+), 30 deletions(-)

diff --git a/plugins/desktop-thumbnailer/desktop-thumbnailer-provider.c b/plugins/desktop-thumbnailer/desktop-thumbnailer-provider.c
index 8ea95c2..4a4e40f 100644
--- a/plugins/desktop-thumbnailer/desktop-thumbnailer-provider.c
+++ b/plugins/desktop-thumbnailer/desktop-thumbnailer-provider.c
@@ -24,6 +24,7 @@
 #include <glib.h>
 #include <glib-object.h>
 
+#include <glib/gi18n.h>
 
 #include <tumbler/tumbler.h>
 
@@ -93,31 +94,162 @@ desktop_thumbnailer_provider_init (DesktopThumbnailerProvider *provider)
 {
 }
 
+static DesktopThumbnailer *
+desktop_thumbnailer_get_from_desktop_file (GFile *file,
+                                           GStrv  uri_schemes)
+{
+  DesktopThumbnailer *thumbnailer;
+  GKeyFile           *key_file;
+  GError             *error = NULL;
+  gchar              *filename;
+  gchar              *exec;
+  gchar             **mime_types;
+
+  g_return_val_if_fail (G_IS_FILE (file), NULL);
+
+  /* determine the absolute filename of the input file */
+  filename = g_file_get_path (file);
+
+  /* allocate a new key file object */
+  key_file = g_key_file_new ();
+
+  /* try to load the key file data from the input file */
+  if (!g_key_file_load_from_file (key_file, filename, G_KEY_FILE_NONE, &error))
+    {
+      g_warning (_("Failed to load the file \"%s\": %s"), filename, error->message);
+      g_clear_error (&error);
+
+      g_key_file_free (key_file);
+      g_free (filename);
+
+      return NULL;
+    }
+
+  /* determine the Exec of the desktop thumbnailer */
+  exec = g_key_file_get_string (key_file, "Thumbnailer Entry",
+								"Exec", &error);
+  if (exec == NULL)
+    {
+      g_warning (_("Malformed file \"%s\": %s"), filename, error->message);
+      g_clear_error (&error);
+
+      g_key_file_free (key_file);
+      g_free (filename);
+
+      return NULL;
+    }
+
+  /* determine the MIME types supported by this thumbnailer */
+  mime_types = g_key_file_get_string_list (key_file, "Thumbnailer Entry",
+                                           "MimeType", NULL, &error);
+  if (mime_types == NULL)
+    {
+      g_warning (_("Malformed file \"%s\": %s"), filename, error->message);
+      g_clear_error (&error);
+
+      g_free (exec);
+      g_key_file_free (key_file);
+      g_free (filename);
+
+      return NULL;
+    }
+
+  thumbnailer = g_object_new (TYPE_DESKTOP_THUMBNAILER,
+                              "uri-schemes", uri_schemes,
+                              "mime-types", mime_types,
+                              "exec", exec,
+                              NULL);
+  g_key_file_free (key_file);
+  g_strfreev(mime_types);
+
+  g_print("Registered thumbailer %s\n", exec);
+  g_free(exec);
 
+  return thumbnailer;
+}
+
+static GList *
+desktop_thumbnailer_get_thumbnailers_from_dir (GList *thumbnailers,
+                                               GFile  *directory,
+                                               GStrv   uri_schemes)
+{
+  const gchar *base_name;
+  gchar       *dirname;
+  GDir        *dir;
+
+  /* determine the absolute path to the directory */
+  dirname = g_file_get_path (directory);
+
+  /* try to open the directory for reading */
+  dir = g_dir_open (dirname, 0, NULL);
+  if (dir == NULL)
+    {
+      g_free (dirname);
+      return thumbnailers;
+    }
+
+  /* iterate over all files in the directory */
+  for (base_name = g_dir_read_name (dir);
+       base_name != NULL;
+       base_name = g_dir_read_name (dir))
+    {
+	  GFileType    type;
+	  GFile       *file;
+	  DesktopThumbnailer *thumbnailer = NULL;
+
+	  /* skip files that don't end with the .thumbnailer extension */
+      if (!g_str_has_suffix (base_name, ".thumbnailer"))
+        continue;
+
+      file = g_file_get_child (directory, base_name);
+      type = g_file_query_file_type (file, G_FILE_QUERY_INFO_NONE, NULL);
+
+      /* try to load the file if it is regular */
+      if (type == G_FILE_TYPE_REGULAR)
+	    thumbnailer = desktop_thumbnailer_get_from_desktop_file (file, uri_schemes);
+
+      g_object_unref (file);
+
+      if (thumbnailer)
+		{
+		  thumbnailers = g_list_append (thumbnailers, thumbnailer);
+		}
+	}
+  return thumbnailers;
+}
 
 static GList *
 desktop_thumbnailer_provider_get_thumbnailers (TumblerThumbnailerProvider *provider)
 {
-  /* This list is mainly from Totem. Generating a list from
-   * GStreamer isn't realistic, so we have to hardcode it. */
-  /* See https://git.gnome.org/browse/totem/tree/data/mime-type-list.txt */
-  static const char *mime_types[] = {
-	  "dummy",
-	  NULL
-  };
-
-  DesktopThumbnailer    *thumbnailer;
-  GError                *error = NULL;
-  GStrv                  uri_schemes;
+  const gchar *const *data_dirs;
+  gchar              *dirname;
+  GStrv               uri_schemes;
+  GList              *iter;
+  int                 n;
+  GList              *thumbnailers = NULL;
+  GList              *directories = NULL;
 
   uri_schemes = tumbler_util_get_supported_uri_schemes ();
 
-  thumbnailer = g_object_new (TYPE_DESKTOP_THUMBNAILER,
-                              "uri-schemes", uri_schemes,
-                              "mime-types", mime_types,
-                              NULL);
+  /* build $XDG_DATA_DIRS/thumbnailers dirnames and prepend them to the list */
+  data_dirs = g_get_system_data_dirs ();
 
-  g_strfreev (uri_schemes);
+  for (n = 0; data_dirs[n] != NULL; ++n)
+    {
+      dirname = g_build_filename (data_dirs[n], "thumbnailers", NULL);
+      directories = g_list_prepend (directories, g_file_new_for_path (dirname));
+      g_free (dirname);
+    }
+
+  /* reverse the directory list so that the directories with highest
+   * priority come first */
+  directories = g_list_reverse (directories);
 
-  return g_list_append (NULL, thumbnailer);
+  for (iter = directories; iter != NULL; iter = iter->next)
+	{
+	  thumbnailers = desktop_thumbnailer_get_thumbnailers_from_dir (thumbnailers, iter->data, uri_schemes);
+	}
+
+  g_strfreev (uri_schemes);
+  return thumbnailers;
 }
diff --git a/plugins/desktop-thumbnailer/desktop-thumbnailer.c b/plugins/desktop-thumbnailer/desktop-thumbnailer.c
index 7f025fe..bc8e912 100644
--- a/plugins/desktop-thumbnailer/desktop-thumbnailer.c
+++ b/plugins/desktop-thumbnailer/desktop-thumbnailer.c
@@ -1,3 +1,4 @@
+/* vi:set et ai sw=2 sts=2 ts=2: */
 /*
  * Copyright (c) 2017 Ali Abdallah <ali at xfce.org>
  *
@@ -30,7 +31,7 @@
 #include <gdk-pixbuf/gdk-pixbuf.h>
 
 #include <gio/gio.h>
-
+#include <glib/gstdio.h>
 
 #include <tumbler/tumbler.h>
 
@@ -39,8 +40,20 @@
 
 
 static void desktop_thumbnailer_create   (TumblerAbstractThumbnailer *thumbnailer,
-										  GCancellable               *cancellable,
-										  TumblerFileInfo            *info);
+                                          GCancellable               *cancellable,
+                                          TumblerFileInfo            *info);
+
+static void desktop_thumbnailer_get_property(GObject *object,
+                                             guint prop_id,
+                                             GValue *value,
+                                             GParamSpec *pspec);
+
+static void desktop_thumbnailer_set_property(GObject *object,
+                                             guint prop_id,
+                                             const GValue *value,
+                                             GParamSpec *pspec);
+
+static void desktop_thumbnailer_finalize(GObject *object);
 
 
 
@@ -52,6 +65,8 @@ struct _DesktopThumbnailerClass
 struct _DesktopThumbnailer
 {
   TumblerAbstractThumbnailer __parent__;
+
+  gchar *exec;
 };
 
 
@@ -61,6 +76,13 @@ G_DEFINE_DYNAMIC_TYPE (DesktopThumbnailer,
                        TUMBLER_TYPE_ABSTRACT_THUMBNAILER);
 
 
+enum
+{
+  PROP_0,
+  PROP_EXEC
+};
+
+
 
 void
 desktop_thumbnailer_register (TumblerProviderPlugin *plugin)
@@ -70,11 +92,69 @@ desktop_thumbnailer_register (TumblerProviderPlugin *plugin)
 
 
 
+static void desktop_thumbnailer_get_property(GObject *object,
+                                             guint prop_id,
+                                             GValue *value,
+                                             GParamSpec *pspec)
+{
+  DesktopThumbnailer *thumbnailer = DESKTOP_THUMBNAILER(object);
+
+  switch(prop_id)
+    {
+    case PROP_EXEC:
+      g_value_set_string(value, thumbnailer->exec);
+      break;
+
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
+      break;
+    }
+}
+
+
+
+static void desktop_thumbnailer_set_property(GObject *object,
+                                             guint prop_id,
+                                             const GValue *value,
+                                             GParamSpec *pspec)
+{
+  DesktopThumbnailer *thumbnailer = DESKTOP_THUMBNAILER(object);
+
+  switch(prop_id)
+    {
+    case PROP_EXEC:
+      thumbnailer->exec = g_strdup(g_value_get_string(value));
+      break;
+
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
+      break;
+    }
+}
+
+
+
 static void
 desktop_thumbnailer_class_init (DesktopThumbnailerClass *klass)
 {
   TumblerAbstractThumbnailerClass *abstractthumbnailer_class;
+  GObjectClass                    *gobject_class;
+
+  gobject_class = G_OBJECT_CLASS(klass);
 
+  gobject_class->get_property = desktop_thumbnailer_get_property;
+  gobject_class->set_property = desktop_thumbnailer_set_property;
+
+  g_object_class_install_property (gobject_class,
+                                   PROP_EXEC,
+                                   g_param_spec_string("exec",
+                                                       NULL,
+                                                       NULL,
+                                                       NULL,
+                                                       G_PARAM_CONSTRUCT_ONLY |
+                                                       G_PARAM_READWRITE));
+
+  gobject_class->finalize = desktop_thumbnailer_finalize;
   abstractthumbnailer_class = TUMBLER_ABSTRACT_THUMBNAILER_CLASS (klass);
   abstractthumbnailer_class->create = desktop_thumbnailer_create;
 }
@@ -87,6 +167,11 @@ desktop_thumbnailer_class_finalize (DesktopThumbnailerClass *klass)
 }
 
 
+static void
+desktop_thumbnailer_finalize(GObject *object)
+{
+
+}
 
 static void
 desktop_thumbnailer_init (DesktopThumbnailer *thumbnailer)
@@ -95,17 +180,225 @@ desktop_thumbnailer_init (DesktopThumbnailer *thumbnailer)
 
 
 static void
+te_string_append_quoted (GString     *string,
+                         const gchar *unquoted)
+{
+  gchar *quoted;
+
+  quoted = g_shell_quote (unquoted);
+  g_string_append (string, quoted);
+  g_free (quoted);
+}
+
+
+
+static GdkPixbuf *
+desktop_thumbnailer_get_pixbuf (GInputStream *stream,
+                                int dest_width,
+                                int dest_height,
+                                GCancellable *cancellable)
+{
+  GdkPixbuf *source;
+  gdouble    hratio;
+  gdouble    wratio;
+  gint       source_width;
+  gint       source_height;
+  GError    *error = NULL;
+
+  source = gdk_pixbuf_new_from_stream (stream, cancellable, &error);
+
+  if (!source)
+    {
+      g_clear_error (&error);
+      g_print("Failed to load pixbuf");
+      return NULL;
+    }
+
+  /* determine the source pixbuf dimensions */
+  source_width = gdk_pixbuf_get_width (source);
+  source_height = gdk_pixbuf_get_height (source);
+
+
+  /* return the same pixbuf if no scaling is required */
+  if (source_width <= dest_width && source_height <= dest_height)
+    return g_object_ref (source);
+
+  /* determine which axis needs to be scaled down more */
+  wratio = (gdouble) source_width / (gdouble) dest_width;
+  hratio = (gdouble) source_height / (gdouble) dest_height;
+
+  /* adjust the other axis */
+  if (hratio > wratio)
+    dest_width = rint (source_width / hratio);
+  else
+    dest_height = rint (source_height / wratio);
+
+  /* scale the pixbuf down to the desired size */
+  return gdk_pixbuf_scale_simple (source,
+                                  MAX (dest_width, 1), MAX (dest_height, 1),
+                                  GDK_INTERP_BILINEAR);
+
+}
+
+
+
+static gboolean
+desktop_thumbnailer_exec_parse (const gchar *exec,
+                                const gchar *file_path,
+                                const gchar *file_uri,
+                                gint         desired_size,
+                                const gchar *output_file,
+                                gint        *argc,
+                                gchar     ***argv,
+                                GError     **error)
+{
+  const gchar *p;
+  gboolean     result = FALSE;
+  GString     *command_line = g_string_new (NULL);
+
+  for (p = exec; *p != '\0'; ++p)
+    {
+      if (p[0] == '%' && p[1] != '\0')
+        {
+          switch (*++p)
+            {
+            case 'u':
+              if (G_LIKELY (file_uri != NULL))
+                te_string_append_quoted (command_line, file_uri);
+              break;
+
+            case 'i':
+              if (G_LIKELY (file_path != NULL))
+                te_string_append_quoted (command_line, file_path);
+              break;
+
+            case 's':
+              g_string_append_printf(command_line, "%d", desired_size);
+              break;
+
+            case 'o':
+              if (G_LIKELY (output_file != NULL))
+                te_string_append_quoted (command_line, output_file);
+              break;
+
+            case '%':
+              g_string_append_c (command_line, '%');
+              break;
+            }
+        }
+      else
+        {
+          g_string_append_c (command_line, *p);
+        }
+    }
+
+  result = g_shell_parse_argv (command_line->str, argc, argv, error);
+
+  g_string_free (command_line, TRUE);
+  return result;
+}
+
+
+
+static GdkPixbuf *
+desktop_thumbnailer_load_thumbnail (DesktopThumbnailer *thumbnailer,
+                                    const gchar        *uri,
+                                    const gchar        *path,
+                                    gint                width,
+                                    gint                height,
+                                    GCancellable       *cancellable)
+{
+  GFileIOStream *stream;
+  GFile     *tmpfile;
+  gchar     *exec;
+  gchar    **cmd_argv;
+  gchar     *tmpfilepath;
+  gboolean   res;
+  gint       cmd_argc;
+  gint       size;
+  gchar     *working_directory = NULL;
+  GdkPixbuf *pixbuf            = NULL;
+  GError    *error             = NULL;
+
+  g_object_get (G_OBJECT (thumbnailer), "exec", &exec, NULL);
+
+  tmpfile = g_file_new_tmp ("tumbler-XXXXXXX.png", &stream, NULL);
+
+  if ( G_LIKELY (tmpfile) )
+    {
+      tmpfilepath = g_file_get_path (tmpfile);
+
+      size = MIN (width, height);
+
+      res = desktop_thumbnailer_exec_parse (exec,
+                                            path,
+                                            uri,
+                                            size,
+                                            tmpfilepath,
+                                            &cmd_argc,
+                                            &cmd_argv,
+                                            &error);
+
+      if (G_LIKELY (res))
+        {
+          working_directory = g_path_get_dirname (path);
+
+
+          res = g_spawn_sync (working_directory,
+                              cmd_argv, NULL,
+                              G_SPAWN_SEARCH_PATH,
+                              NULL, NULL,
+                              NULL, NULL,
+                              NULL,
+                              &error);
+
+          if (G_LIKELY (res))
+            {
+              pixbuf = desktop_thumbnailer_get_pixbuf (g_io_stream_get_input_stream(G_IO_STREAM(stream)),
+                                                       width,
+                                                       height,
+                                                       cancellable);
+              g_unlink (tmpfilepath);
+            }
+
+          g_free (working_directory);
+          g_strfreev (cmd_argv);
+        }
+      else
+        {
+          g_warning (_("Malformed command line \"%s\": %s"), exec, error->message);
+          g_clear_error (&error);
+        }
+      g_free (tmpfilepath);
+      g_object_unref (tmpfile);
+      g_object_unref (stream);
+    }
+
+  g_free (exec);
+
+  return pixbuf;
+}
+
+
+
+static void
 desktop_thumbnailer_create (TumblerAbstractThumbnailer *thumbnailer,
-                        GCancellable               *cancellable,
-                        TumblerFileInfo            *info)
+                            GCancellable               *cancellable,
+                            TumblerFileInfo            *info)
 {
-  TumblerThumbnail *thumbnail;
-  const gchar      *uri;
-  GFile            *file;
-  GError           *error = NULL;
-  gchar            *path;
-  GdkPixbuf        *pixbuf = NULL;
-  TumblerImageData  data;
+
+  TumblerThumbnail           *thumbnail;
+  TumblerThumbnailFlavor     *flavor;
+  TumblerImageData            data;
+  const gchar                *uri;
+  gchar                      *path;
+  GFile                      *file;
+  gint                        height;
+  gint                        width;
+  GError                     *error  =  NULL;
+  GdkPixbuf                  *pixbuf =  NULL;
+
+  g_print("Debug \n");
 
   g_return_if_fail (IS_DESKTOP_THUMBNAILER (thumbnailer));
   g_return_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable));
@@ -116,13 +409,23 @@ desktop_thumbnailer_create (TumblerAbstractThumbnailer *thumbnailer,
     return;
 
   uri = tumbler_file_info_get_uri (info);
-  file = g_file_new_for_uri (uri);
 
+  file = g_file_new_for_uri (uri);
+  path = g_file_get_path (file);
 
   thumbnail = tumbler_file_info_get_thumbnail (info);
+  g_assert (thumbnail != NULL);
+
+  flavor = tumbler_thumbnail_get_flavor (thumbnail);
+  g_assert (flavor != NULL);
+
+  tumbler_thumbnail_flavor_get_size (flavor, &width, &height);
+
+  pixbuf = desktop_thumbnailer_load_thumbnail (DESKTOP_THUMBNAILER(thumbnailer), uri, path, width, height, cancellable);
 
   if (pixbuf != NULL)
     {
+      g_print("Yay pixbuff != NULL\n");
       data.data = gdk_pixbuf_get_pixels (pixbuf);
       data.has_alpha = gdk_pixbuf_get_has_alpha (pixbuf);
       data.bits_per_sample = gdk_pixbuf_get_bits_per_sample (pixbuf);
@@ -137,6 +440,8 @@ desktop_thumbnailer_create (TumblerAbstractThumbnailer *thumbnailer,
 
       g_object_unref (pixbuf);
     }
+  else
+    g_print(":(\n");
 
   if (error != NULL)
     {
@@ -148,5 +453,9 @@ desktop_thumbnailer_create (TumblerAbstractThumbnailer *thumbnailer,
       g_signal_emit_by_name (thumbnailer, "ready", uri);
     }
 
+  g_free (path);
+
   g_object_unref (thumbnail);
+  g_object_unref (flavor);
+  g_object_unref (file);
 }

-- 
To stop receiving notification emails like this one, please contact
the administrator of this repository.


More information about the Xfce4-commits mailing list