summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBastien Nocera <hadess@hadess.net>2017-07-20 20:51:09 +0200
committerBastien Nocera <hadess@hadess.net>2017-07-21 13:07:00 +0200
commitc1956f35bd1a9170e433d116f36e63d58b6ff826 (patch)
tree6e0c7a46b9d3d2020a381c4342b40c2ea9742e7d
parent3b298f60287e21578b523bfb3aa75360e35f9dd1 (diff)
downloadgnome-desktop-c1956f35bd1a9170e433d116f36e63d58b6ff826.tar.gz
thumbnail: Split off running the script
Move most of the script command generation to a separate file, making the function return a GBytes from a successful thumbnailer run, so as to avoid having to clean up temporary files from the thumbnailer run. Note that it changes a few subtle things which shouldn't be a problem in practice, but, as a corner case, might have been used by applications: - Thumbnailers must output PNG images. pixbuf_new_from_bytes() could have been made more complicated to handle all images, and then we would restrict the thumbnailer output format separately, but it makes no sense to write complicated code to remove it in the next commit. - URIs which have no backing path are not supported. This will likely cause problems for thumbnailing remote shares on OSes which lack gvfsd-fuse. Support could be re-added in the future. https://bugzilla.gnome.org/show_bug.cgi?id=774497
-rw-r--r--libgnome-desktop/Makefile.am4
-rw-r--r--libgnome-desktop/gnome-desktop-thumbnail-script.c244
-rw-r--r--libgnome-desktop/gnome-desktop-thumbnail-script.h38
-rw-r--r--libgnome-desktop/gnome-desktop-thumbnail.c185
4 files changed, 321 insertions, 150 deletions
diff --git a/libgnome-desktop/Makefile.am b/libgnome-desktop/Makefile.am
index 9c4da151..a60aac8b 100644
--- a/libgnome-desktop/Makefile.am
+++ b/libgnome-desktop/Makefile.am
@@ -42,7 +42,9 @@ libgnome_desktop_3_la_SOURCES = \
gnome-datetime-source.c \
gnome-rr-private.h \
default-input-sources.h \
- meta-xrandr-shared.h
+ meta-xrandr-shared.h \
+ gnome-desktop-thumbnail-script.c\
+ gnome-desktop-thumbnail-script.h
dbus_xrandr_built_sources = meta-dbus-xrandr.c meta-dbus-xrandr.h
diff --git a/libgnome-desktop/gnome-desktop-thumbnail-script.c b/libgnome-desktop/gnome-desktop-thumbnail-script.c
new file mode 100644
index 00000000..87319bc1
--- /dev/null
+++ b/libgnome-desktop/gnome-desktop-thumbnail-script.c
@@ -0,0 +1,244 @@
+/*
+ * Copyright (C) 2002, 2017 Red Hat, Inc.
+ * Copyright (C) 2010 Carlos Garcia Campos <carlosgc@gnome.org>
+ *
+ * This file is part of the Gnome Library.
+ *
+ * The Gnome Library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * The Gnome Library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with the Gnome Library; see the file COPYING.LIB. If not,
+ * write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ * Authors: Alexander Larsson <alexl@redhat.com>
+ * Carlos Garcia Campos <carlosgc@gnome.org>
+ * Bastien Nocera <hadess@hadess.net>
+ */
+
+#include "config.h"
+
+#include <gio/gio.h>
+#include <glib/gstdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+
+#include "gnome-desktop-thumbnail-script.h"
+
+typedef struct {
+ char *infile;
+ char *outfile;
+} ScriptExec;
+
+static char *
+expand_thumbnailing_elem (const char *elem,
+ const int size,
+ const char *inuri,
+ const char *outfile,
+ gboolean *got_input,
+ gboolean *got_output)
+{
+ GString *str;
+ const char *p, *last;
+ char *localfile;
+
+ str = g_string_new (NULL);
+
+ last = elem;
+ while ((p = strchr (last, '%')) != NULL)
+ {
+ g_string_append_len (str, last, p - last);
+ p++;
+
+ switch (*p) {
+ case 'u':
+ g_string_append (str, inuri);
+ *got_input = TRUE;
+ p++;
+ break;
+ case 'i':
+ localfile = g_filename_from_uri (inuri, NULL, NULL);
+ if (localfile)
+ {
+ g_string_append (str, localfile);
+ *got_input = TRUE;
+ g_free (localfile);
+ }
+ p++;
+ break;
+ case 'o':
+ g_string_append (str, outfile);
+ *got_output = TRUE;
+ p++;
+ break;
+ case 's':
+ g_string_append_printf (str, "%d", size);
+ p++;
+ break;
+ case '%':
+ g_string_append_c (str, '%');
+ p++;
+ break;
+ case 0:
+ default:
+ break;
+ }
+ last = p;
+ }
+ g_string_append (str, last);
+
+ return g_string_free (str, FALSE);
+}
+
+static char **
+expand_thumbnailing_script (const char *cmd,
+ ScriptExec *script,
+ int size,
+ GError **error)
+{
+ GPtrArray *array;
+ g_auto(GStrv) cmd_elems = NULL;
+ guint i;
+ gboolean got_in, got_out;
+ g_autofree char *sandboxed_path = NULL;
+
+ if (!g_shell_parse_argv (cmd, NULL, &cmd_elems, error))
+ return NULL;
+
+ array = g_ptr_array_new_with_free_func (g_free);
+
+ got_in = got_out = FALSE;
+ for (i = 0; cmd_elems[i] != NULL; i++)
+ {
+ char *expanded;
+
+ expanded = expand_thumbnailing_elem (cmd_elems[i],
+ size,
+ script->infile,
+ script->outfile,
+ &got_in,
+ &got_out);
+
+ g_ptr_array_add (array, expanded);
+ }
+
+ if (!got_in)
+ {
+ g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_FAILED,
+ "Input file could not be set");
+ goto bail;
+ }
+ else if (!got_out)
+ {
+ g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_FAILED,
+ "Output file could not be set");
+ goto bail;
+ }
+
+ g_ptr_array_add (array, NULL);
+
+ return (char **) g_ptr_array_free (array, FALSE);
+
+bail:
+ g_ptr_array_free (array, TRUE);
+ return NULL;
+}
+
+static void
+script_exec_free (ScriptExec *exec)
+{
+ g_free (exec->infile);
+ if (exec->outfile)
+ {
+ g_unlink (exec->outfile);
+ g_free (exec->outfile);
+ }
+ g_free (exec);
+}
+
+static ScriptExec *
+script_exec_new (const char *uri)
+{
+ ScriptExec *exec;
+ g_autoptr(GFile) file = NULL;
+ int fd;
+ g_autofree char *tmpname = NULL;
+
+ exec = g_new0 (ScriptExec, 1);
+ file = g_file_new_for_uri (uri);
+
+ exec->infile = g_file_get_path (file);
+ if (!exec->infile)
+ goto bail;
+
+ fd = g_file_open_tmp (".gnome_desktop_thumbnail.XXXXXX", &tmpname, NULL);
+ if (fd == -1)
+ goto bail;
+ close (fd);
+ exec->outfile = g_steal_pointer (&tmpname);
+
+ return exec;
+
+bail:
+ script_exec_free (exec);
+ return NULL;
+}
+
+GBytes *
+gnome_desktop_thumbnail_script_exec (const char *cmd,
+ int size,
+ const char *uri,
+ GError **error)
+{
+ g_autofree char *error_out = NULL;
+ g_auto(GStrv) expanded_script = NULL;
+ int exit_status;
+ gboolean ret;
+ GBytes *image = NULL;
+ ScriptExec *exec;
+
+ exec = script_exec_new (uri);
+ expanded_script = expand_thumbnailing_script (cmd, exec, size, error);
+ if (expanded_script == NULL)
+ goto out;
+
+#if 0
+ guint i;
+
+ g_print ("About to launch script: ");
+ for (i = 0; expanded_script[i]; i++)
+ g_print ("%s ", expanded_script[i]);
+ g_print ("\n");
+#endif
+
+ ret = g_spawn_sync (NULL, expanded_script, NULL, G_SPAWN_SEARCH_PATH,
+ NULL, NULL, NULL, &error_out,
+ &exit_status, error);
+ if (ret && g_spawn_check_exit_status (exit_status, error))
+ {
+ char *contents;
+ gsize length;
+
+ if (g_file_get_contents (exec->outfile, &contents, &length, error))
+ image = g_bytes_new_take (contents, length);
+ }
+ else
+ {
+ g_debug ("Failed to launch script: %s", !ret ? (*error)->message : error_out);
+ }
+
+out:
+ script_exec_free (exec);
+ return image;
+}
+
diff --git a/libgnome-desktop/gnome-desktop-thumbnail-script.h b/libgnome-desktop/gnome-desktop-thumbnail-script.h
new file mode 100644
index 00000000..cbd6bbf6
--- /dev/null
+++ b/libgnome-desktop/gnome-desktop-thumbnail-script.h
@@ -0,0 +1,38 @@
+/*
+ * gnome-thumbnail.h: Utilities for handling thumbnails
+ *
+ * Copyright (C) 2002, 2017 Red Hat, Inc.
+ *
+ * This file is part of the Gnome Library.
+ *
+ * The Gnome Library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * The Gnome Library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with the Gnome Library; see the file COPYING.LIB. If not,
+ * write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ * Authors: Alexander Larsson <alexl@redhat.com>
+ * Bastien Nocera <hadess@hadess.net>
+ */
+
+#ifndef GNOME_DESKTOP_THUMBNAIL_SCRIPT_H
+#define GNOME_DESKTOP_THUMBNAIL_SCRIPT_H
+
+#include <glib.h>
+
+GBytes *
+gnome_desktop_thumbnail_script_exec (const char *cmd,
+ int size,
+ const char *uri,
+ GError **error);
+
+#endif /* GNOME_DESKTOP_THUMBNAIL_SCRIPT_H */
diff --git a/libgnome-desktop/gnome-desktop-thumbnail.c b/libgnome-desktop/gnome-desktop-thumbnail.c
index 617160d5..73751f69 100644
--- a/libgnome-desktop/gnome-desktop-thumbnail.c
+++ b/libgnome-desktop/gnome-desktop-thumbnail.c
@@ -127,9 +127,12 @@
#include <gdk-pixbuf/gdk-pixbuf.h>
#include <string.h>
#include <stdlib.h>
+#include <sys/stat.h>
+#include <fcntl.h>
#define GNOME_DESKTOP_USE_UNSTABLE_API
#include "gnome-desktop-thumbnail.h"
+#include "gnome-desktop-thumbnail-script.h"
static void
thumbnailers_directory_changed (GFileMonitor *monitor,
@@ -929,120 +932,6 @@ gnome_desktop_thumbnail_factory_can_thumbnail (GnomeDesktopThumbnailFactory *fac
return FALSE;
}
-static char *
-expand_thumbnailing_elem (const char *elem,
- const int size,
- const char *inuri,
- const char *outfile,
- gboolean *got_input,
- gboolean *got_output)
-{
- GString *str;
- const char *p, *last;
- char *localfile;
-
- str = g_string_new (NULL);
-
- last = elem;
- while ((p = strchr (last, '%')) != NULL)
- {
- g_string_append_len (str, last, p - last);
- p++;
-
- switch (*p) {
- case 'u':
- g_string_append (str, inuri);
- *got_input = TRUE;
- p++;
- break;
- case 'i':
- localfile = g_filename_from_uri (inuri, NULL, NULL);
- if (localfile)
- {
- g_string_append (str, localfile);
- *got_input = TRUE;
- g_free (localfile);
- }
- p++;
- break;
- case 'o':
- g_string_append (str, outfile);
- *got_output = TRUE;
- p++;
- break;
- case 's':
- g_string_append_printf (str, "%d", size);
- p++;
- break;
- case '%':
- g_string_append_c (str, '%');
- p++;
- break;
- case 0:
- default:
- break;
- }
- last = p;
- }
- g_string_append (str, last);
-
- return g_string_free (str, FALSE);
-}
-
-static char **
-expand_thumbnailing_script (const char *script,
- const int size,
- const char *inuri,
- const char *outfile,
- GError **error)
-{
- GPtrArray *array;
- char **script_elems;
- guint i;
- gboolean got_in, got_out;
-
- if (!g_shell_parse_argv (script, NULL, &script_elems, error))
- return NULL;
-
- array = g_ptr_array_new_with_free_func (g_free);
-
- got_in = got_out = FALSE;
- for (i = 0; script_elems[i] != NULL; i++)
- {
- char *expanded;
-
- expanded = expand_thumbnailing_elem (script_elems[i],
- size,
- inuri,
- outfile,
- &got_in,
- &got_out);
-
- g_ptr_array_add (array, expanded);
- }
-
- if (!got_in)
- {
- g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_FAILED,
- "Input file could not be set");
- goto bail;
- }
- else if (!got_out)
- {
- g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_FAILED,
- "Output file could not be set");
- goto bail;
- }
-
- g_ptr_array_add (array, NULL);
-
- return (char **) g_ptr_array_free (array, FALSE);
-
-bail:
- g_ptr_array_free (array, TRUE);
- return NULL;
-}
-
static GdkPixbuf *
get_preview_thumbnail (const char *uri,
int size)
@@ -1099,6 +988,30 @@ get_preview_thumbnail (const char *uri,
return pixbuf;
}
+static GdkPixbuf *
+pixbuf_new_from_bytes (GBytes *bytes,
+ GError **error)
+{
+ g_autoptr(GdkPixbufLoader) loader = NULL;
+
+ loader = gdk_pixbuf_loader_new_with_mime_type ("image/png", error);
+ if (!loader)
+ return NULL;
+
+ if (!gdk_pixbuf_loader_write (loader,
+ g_bytes_get_data (bytes, NULL),
+ g_bytes_get_size (bytes),
+ error))
+ {
+ return NULL;
+ }
+
+ if (!gdk_pixbuf_loader_close (loader, error))
+ return NULL;
+
+ return g_object_ref (gdk_pixbuf_loader_get_pixbuf (loader));
+}
+
/**
* gnome_desktop_thumbnail_factory_generate_thumbnail:
* @factory: a #GnomeDesktopThumbnailFactory
@@ -1122,8 +1035,6 @@ gnome_desktop_thumbnail_factory_generate_thumbnail (GnomeDesktopThumbnailFactory
GdkPixbuf *pixbuf;
char *script;
int size;
- int exit_status;
- char *tmpname;
g_return_val_if_fail (uri != NULL, NULL);
g_return_val_if_fail (mime_type != NULL, NULL);
@@ -1154,42 +1065,18 @@ gnome_desktop_thumbnail_factory_generate_thumbnail (GnomeDesktopThumbnailFactory
if (script)
{
- int fd;
-
- fd = g_file_open_tmp (".gnome_desktop_thumbnail.XXXXXX", &tmpname, NULL);
-
- if (fd != -1)
- {
- char **expanded_script;
- GError *error = NULL;
-
- close (fd);
-
- expanded_script = expand_thumbnailing_script (script, size, uri, tmpname, &error);
- if (expanded_script == NULL)
- {
- g_warning ("Failed to expand script '%s': %s", script, error->message);
- g_error_free (error);
- }
- else
- {
- gboolean ret;
+ GBytes *data;
- ret = g_spawn_sync (NULL, expanded_script, NULL, G_SPAWN_SEARCH_PATH,
- NULL, NULL, NULL, NULL, &exit_status, NULL);
- if (ret && exit_status == 0)
- pixbuf = gdk_pixbuf_new_from_file (tmpname, NULL);
-
- g_strfreev (expanded_script);
- }
-
- g_unlink (tmpname);
- g_free (tmpname);
- }
-
- g_free (script);
+ data = gnome_desktop_thumbnail_script_exec (script, size, uri, NULL);
+ if (data)
+ {
+ pixbuf = pixbuf_new_from_bytes (data, NULL);
+ g_bytes_unref (data);
+ }
}
+ g_free (script);
+
return pixbuf;
}