diff options
-rw-r--r-- | build-aux/flatpak/org.gnome.Nautilus.json | 15 | ||||
-rw-r--r-- | build-aux/flatpak/org.gnome.Nautilus.yml | 10 | ||||
-rw-r--r-- | build-aux/flatpak/org.gnome.NautilusMaster.yml | 10 | ||||
-rw-r--r-- | meson.build | 50 | ||||
-rw-r--r-- | src/gnome-desktop/gnome-desktop-thumbnail-script.c | 892 | ||||
-rw-r--r-- | src/gnome-desktop/gnome-desktop-thumbnail-script.h | 38 | ||||
-rw-r--r-- | src/gnome-desktop/gnome-desktop-thumbnail.c | 1303 | ||||
-rw-r--r-- | src/gnome-desktop/gnome-desktop-thumbnail.h | 102 | ||||
-rwxr-xr-x | src/gnome-desktop/gnome-desktop-update.sh | 45 | ||||
-rw-r--r-- | src/meson.build | 7 | ||||
-rw-r--r-- | src/nautilus-properties-window.c | 2 | ||||
-rw-r--r-- | src/nautilus-thumbnails.c | 2 |
12 files changed, 39 insertions, 2437 deletions
diff --git a/build-aux/flatpak/org.gnome.Nautilus.json b/build-aux/flatpak/org.gnome.Nautilus.json index 9285c4e50..ac1ee9c8d 100644 --- a/build-aux/flatpak/org.gnome.Nautilus.json +++ b/build-aux/flatpak/org.gnome.Nautilus.json @@ -121,6 +121,21 @@ ] }, { + "name": "gnome-desktop", + "buildsystem": "meson", + "build-options": [ + "config-opts": [ + "-Ddebug_tools=false", + "-Ddesktop_docs=false", + "-Dudev=disabled" + ] + ], + "sources": [ + "type": "git", + "url": "https://gitlab.gnome.org/GNOME/gnome-desktop.git" + ] + }, + { "name": "gnome-autoar", "sources": [ { diff --git a/build-aux/flatpak/org.gnome.Nautilus.yml b/build-aux/flatpak/org.gnome.Nautilus.yml index 186746412..1799e9df3 100644 --- a/build-aux/flatpak/org.gnome.Nautilus.yml +++ b/build-aux/flatpak/org.gnome.Nautilus.yml @@ -92,6 +92,16 @@ modules: - type: git url: https://gitlab.gnome.org/GNOME/tracker-miners.git tag: 2.2.1 +- name: gnome-desktop + buildsystem: meson + build-options: + config-opts: + - "-Ddebug_tools=false" + - "-Ddesktop_docs=false" + - "-Dudev=disabled" + sources: + - type: git + url: https://gitlab.gnome.org/GNOME/gnome-desktop.git - name: gnome-autoar sources: - type: git diff --git a/build-aux/flatpak/org.gnome.NautilusMaster.yml b/build-aux/flatpak/org.gnome.NautilusMaster.yml index 28c2dfb66..db0a5b2ed 100644 --- a/build-aux/flatpak/org.gnome.NautilusMaster.yml +++ b/build-aux/flatpak/org.gnome.NautilusMaster.yml @@ -89,6 +89,16 @@ modules: sources: - type: git url: https://gitlab.gnome.org/GNOME/tracker-miners.git +- name: gnome-desktop + buildsystem: meson + build-options: + config-opts: + - "-Ddebug_tools=false" + - "-Ddesktop_docs=false" + - "-Dudev=disabled" + sources: + - type: git + url: https://gitlab.gnome.org/GNOME/gnome-desktop.git - name: gnome-autoar sources: - type: git diff --git a/meson.build b/meson.build index 70e41043b..9569e22e2 100644 --- a/meson.build +++ b/meson.build @@ -73,30 +73,6 @@ add_project_arguments( language: 'c' ) -###################### -# Host system checks # -###################### - -host_system = host_machine.system() -host_cpu = host_machine.cpu() -unsupported_cpus = [ - 'alpha', - 'ia64', - 'm68k', - 'parisc', - 'parisc64', - 'sh4', - 'sparc', - 'sparc64', -] -system_supports_seccomp = host_system == 'linux' -cpu_supports_seccomp = not unsupported_cpus.contains(host_cpu) -seccomp_required = system_supports_seccomp and cpu_supports_seccomp - -########################## -# End host system checks # -########################## - ################## # Module imports # ################## @@ -137,15 +113,8 @@ gio_unix = dependency('gio-unix-2.0', version: glib_ver) glib = dependency('glib-2.0', version: glib_ver) gmodule = dependency('gmodule-no-export-2.0', version: glib_ver) gnome_autoar = dependency('gnome-autoar-0', version: '>= 0.2.1') -gsettings_desktop_schemas = dependency('gsettings-desktop-schemas') +gnome_desktop = dependency('gnome-desktop-3.0', version: '>= 3.0.0') gtk = dependency('gtk+-3.0', version: '>= 3.22.27') -if seccomp_required - message('seccomp required on this platform, make sure bubblewrap is available at runtime as well.') - seccomp = dependency('libseccomp') -else - warning('The host does not support seccomp, thumbnailer sandboxing will be disabled. Such setups are not recommended, use at your own risk!') - seccomp = dependency('', required: false) -endif selinux = [] if get_option('selinux') selinux = dependency('libselinux', version: '>= 2.0') @@ -154,8 +123,6 @@ tracker_sparql = dependency('tracker-sparql-2.0') x11 = dependency('x11') xml = dependency('libxml-2.0', version: '>= 2.7.8') -fontconfig = dependency('fontconfig', required: false) - #################### # End dependencies # #################### @@ -174,15 +141,8 @@ endif application_id = 'org.gnome.Nautilus' + profile -if fontconfig.found() - fontconfig_cache_path = fontconfig.get_pkgconfig_variable('cachedir') -else - fontconfig_cache_path = join_paths(libdir, 'fontconfig/cache') -endif - conf.set_quoted('APPLICATION_ID', application_id) conf.set_quoted('GETTEXT_PACKAGE', 'nautilus') -conf.set_quoted('INSTALL_PREFIX', prefix) conf.set_quoted('LOCALEDIR', join_paths(prefix, localedir)) conf.set_quoted('NAME_SUFFIX', name_suffix) conf.set_quoted('NAUTILUS_DATADIR', join_paths(datadir, 'nautilus')) @@ -190,14 +150,6 @@ conf.set_quoted('NAUTILUS_EXTENSIONDIR', join_paths(prefix, extensiondir)) conf.set_quoted('PACKAGE_VERSION', meson.project_version()) conf.set_quoted('PROFILE', profile) conf.set_quoted('VERSION', '@0@-@VCS_TAG@'.format(meson.project_version())) -conf.set_quoted('FONTCONFIG_CACHE_PATH', fontconfig_cache_path) - -################################################### -# gnome-desktop macros for thumbnailer sandboxing # -################################################### - -conf.set('ENABLE_SECCOMP', seccomp.found()) -conf.set('HAVE_BWRAP', seccomp.found()) conf.set('ENABLE_PACKAGEKIT', get_option('packagekit')) conf.set('ENABLE_PROFILING', get_option('profiling')) diff --git a/src/gnome-desktop/gnome-desktop-thumbnail-script.c b/src/gnome-desktop/gnome-desktop-thumbnail-script.c deleted file mode 100644 index 0aa26444a..000000000 --- a/src/gnome-desktop/gnome-desktop-thumbnail-script.c +++ /dev/null @@ -1,892 +0,0 @@ -/* - * 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> - -#ifdef ENABLE_SECCOMP -#include <errno.h> -#include <sys/socket.h> -#include <sys/ioctl.h> -#include <sys/utsname.h> -#include <seccomp.h> -#endif - -#include "gnome-desktop-thumbnail-script.h" - -typedef struct { - gboolean sandbox; - char *thumbnailer_name; - GArray *fd_array; - /* Input/output file paths outside the sandbox */ - char *infile; - char *infile_tmp; /* the host version of /tmp/gnome-desktop-file-to-thumbnail.* */ - char *outfile; - char *outdir; /* outdir is outfile's parent dir, if it needs to be deleted */ - /* I/O file paths inside the sandbox */ - char *s_infile; - char *s_outfile; -} ScriptExec; - -static char * -expand_thumbnailing_elem (const char *elem, - const int size, - const char *infile, - const char *outfile, - gboolean *got_input, - gboolean *got_output) -{ - GString *str; - const char *p, *last; - char *inuri; - - 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': - inuri = g_filename_to_uri (infile, NULL, NULL); - if (inuri) - { - g_string_append (str, inuri); - *got_input = TRUE; - g_free (inuri); - } - p++; - break; - case 'i': - g_string_append (str, infile); - *got_input = TRUE; - 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); -} - -/* From https://github.com/flatpak/flatpak/blob/master/common/flatpak-run.c */ -G_GNUC_NULL_TERMINATED -static void -add_args (GPtrArray *argv_array, ...) -{ - va_list args; - const gchar *arg; - - va_start (args, argv_array); - while ((arg = va_arg (args, const gchar *))) - g_ptr_array_add (argv_array, g_strdup (arg)); - va_end (args); -} - -static void -add_env (GPtrArray *array, - const char *envvar) -{ - if (g_getenv (envvar) != NULL) - add_args (array, - "--setenv", envvar, g_getenv (envvar), - NULL); -} - -static char * -get_extension (const char *path) -{ - g_autofree char *basename = NULL; - char *p; - - basename = g_path_get_basename (path); - p = strrchr (basename, '.'); - if (g_file_test (path, G_FILE_TEST_IS_DIR) || - !p || - p == basename) /* Leading periods on the basename are ignored. */ - return NULL; - return g_strdup (p + 1); -} - -#ifdef ENABLE_SECCOMP -static gboolean -flatpak_fail (GError **error, - const char *msg, - ...) -{ - g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_FAILED, msg); - return FALSE; -} - -/* From https://github.com/flatpak/flatpak/blob/master/common/flatpak-utils.c */ -#if !defined(__i386__) && !defined(__x86_64__) && !defined(__aarch64__) && !defined(__arm__) -static const char * -flatpak_get_kernel_arch (void) -{ - static struct utsname buf; - static char *arch = NULL; - char *m; - - if (arch != NULL) - return arch; - - if (uname (&buf)) - { - arch = "unknown"; - return arch; - } - - /* By default, just pass on machine, good enough for most arches */ - arch = buf.machine; - - /* Override for some arches */ - - m = buf.machine; - /* i?86 */ - if (strlen (m) == 4 && m[0] == 'i' && m[2] == '8' && m[3] == '6') - { - arch = "i386"; - } - else if (g_str_has_prefix (m, "arm")) - { - if (g_str_has_suffix (m, "b")) - arch = "armeb"; - else - arch = "arm"; - } - else if (strcmp (m, "mips") == 0) - { -#if G_BYTE_ORDER == G_LITTLE_ENDIAN - arch = "mipsel"; -#endif - } - else if (strcmp (m, "mips64") == 0) - { -#if G_BYTE_ORDER == G_LITTLE_ENDIAN - arch = "mips64el"; -#endif - } - - return arch; -} -#endif - -/* This maps the kernel-reported uname to a single string representing - * the cpu family, in the sense that all members of this family would - * be able to understand and link to a binary file with such cpu - * opcodes. That doesn't necessarily mean that all members of the - * family can run all opcodes, for instance for modern 32bit intel we - * report "i386", even though they support instructions that the - * original i386 cpu cannot run. Still, such an executable would - * at least try to execute a 386, whereas an arm binary would not. - */ -static const char * -flatpak_get_arch (void) -{ - /* Avoid using uname on multiarch machines, because uname reports the kernels - * arch, and that may be different from userspace. If e.g. the kernel is 64bit and - * the userspace is 32bit we want to use 32bit by default. So, we take the current build - * arch as the default. */ -#if defined(__i386__) - return "i386"; -#elif defined(__x86_64__) - return "x86_64"; -#elif defined(__aarch64__) - return "aarch64"; -#elif defined(__arm__) -#if G_BYTE_ORDER == G_LITTLE_ENDIAN - return "arm"; -#else - return "armeb"; -#endif -#else - return flatpak_get_kernel_arch (); -#endif -} - -/* From https://github.com/flatpak/flatpak/blob/master/common/flatpak-run.c */ -static const uint32_t seccomp_x86_64_extra_arches[] = { SCMP_ARCH_X86, 0, }; - -#ifdef SCMP_ARCH_AARCH64 -static const uint32_t seccomp_aarch64_extra_arches[] = { SCMP_ARCH_ARM, 0 }; -#endif - -static inline void -cleanup_seccomp (void *p) -{ - scmp_filter_ctx *pp = (scmp_filter_ctx *) p; - - if (*pp) - seccomp_release (*pp); -} - -static gboolean -setup_seccomp (GPtrArray *argv_array, - GArray *fd_array, - const char *arch, - gboolean multiarch, - gboolean devel, - GError **error) -{ - __attribute__((cleanup (cleanup_seccomp))) scmp_filter_ctx seccomp = NULL; - - /**** BEGIN NOTE ON CODE SHARING - * - * There are today a number of different Linux container - * implementations. That will likely continue for long into the - * future. But we can still try to share code, and it's important - * to do so because it affects what library and application writers - * can do, and we should support code portability between different - * container tools. - * - * This syscall blacklist is copied from linux-user-chroot, which was in turn - * clearly influenced by the Sandstorm.io blacklist. - * - * If you make any changes here, I suggest sending the changes along - * to other sandbox maintainers. Using the libseccomp list is also - * an appropriate venue: - * https://groups.google.com/forum/#!topic/libseccomp - * - * A non-exhaustive list of links to container tooling that might - * want to share this blacklist: - * - * https://github.com/sandstorm-io/sandstorm - * in src/sandstorm/supervisor.c++ - * http://cgit.freedesktop.org/xdg-app/xdg-app/ - * in common/flatpak-run.c - * https://git.gnome.org/browse/linux-user-chroot - * in src/setup-seccomp.c - * - **** END NOTE ON CODE SHARING - */ - struct - { - int scall; - struct scmp_arg_cmp *arg; - } syscall_blacklist[] = { - /* Block dmesg */ - {SCMP_SYS (syslog)}, - /* Useless old syscall */ - {SCMP_SYS (uselib)}, - /* Don't allow you to switch to bsd emulation or whatnot */ - {SCMP_SYS (personality)}, - /* Don't allow disabling accounting */ - {SCMP_SYS (acct)}, - /* 16-bit code is unnecessary in the sandbox, and modify_ldt is a - historic source of interesting information leaks. */ - {SCMP_SYS (modify_ldt)}, - /* Don't allow reading current quota use */ - {SCMP_SYS (quotactl)}, - - /* Don't allow access to the kernel keyring */ - {SCMP_SYS (add_key)}, - {SCMP_SYS (keyctl)}, - {SCMP_SYS (request_key)}, - - /* Scary VM/NUMA ops */ - {SCMP_SYS (move_pages)}, - {SCMP_SYS (mbind)}, - {SCMP_SYS (get_mempolicy)}, - {SCMP_SYS (set_mempolicy)}, - {SCMP_SYS (migrate_pages)}, - - /* Don't allow subnamespace setups: */ - {SCMP_SYS (unshare)}, - {SCMP_SYS (mount)}, - {SCMP_SYS (pivot_root)}, - {SCMP_SYS (clone), &SCMP_A0 (SCMP_CMP_MASKED_EQ, CLONE_NEWUSER, CLONE_NEWUSER)}, - - /* Don't allow faking input to the controlling tty (CVE-2017-5226) */ - {SCMP_SYS (ioctl), &SCMP_A1(SCMP_CMP_MASKED_EQ, 0xFFFFFFFFu, (int)TIOCSTI)}, - }; - - struct - { - int scall; - struct scmp_arg_cmp *arg; - } syscall_nondevel_blacklist[] = { - /* Profiling operations; we expect these to be done by tools from outside - * the sandbox. In particular perf has been the source of many CVEs. - */ - {SCMP_SYS (perf_event_open)}, - {SCMP_SYS (ptrace)} - }; - /* Blacklist all but unix, inet, inet6 and netlink */ - int socket_family_blacklist[] = { - AF_AX25, - AF_IPX, - AF_APPLETALK, - AF_NETROM, - AF_BRIDGE, - AF_ATMPVC, - AF_X25, - AF_ROSE, - AF_DECnet, - AF_NETBEUI, - AF_SECURITY, - AF_KEY, - AF_NETLINK + 1, /* Last gets CMP_GE, so order is important */ - }; - guint i; - int r; - int fd = -1; - g_autofree char *fd_str = NULL; - g_autofree char *path = NULL; - - seccomp = seccomp_init (SCMP_ACT_ALLOW); - if (!seccomp) - return flatpak_fail (error, "Initialize seccomp failed"); - - if (arch != NULL) - { - uint32_t arch_id = 0; - const uint32_t *extra_arches = NULL; - - if (strcmp (arch, "i386") == 0) - { - arch_id = SCMP_ARCH_X86; - } - else if (strcmp (arch, "x86_64") == 0) - { - arch_id = SCMP_ARCH_X86_64; - extra_arches = seccomp_x86_64_extra_arches; - } - else if (strcmp (arch, "arm") == 0) - { - arch_id = SCMP_ARCH_ARM; - } -#ifdef SCMP_ARCH_AARCH64 - else if (strcmp (arch, "aarch64") == 0) - { - arch_id = SCMP_ARCH_AARCH64; - extra_arches = seccomp_aarch64_extra_arches; - } -#endif - - /* We only really need to handle arches on multiarch systems. - * If only one arch is supported the default is fine */ - if (arch_id != 0) - { - /* This *adds* the target arch, instead of replacing the - native one. This is not ideal, because we'd like to only - allow the target arch, but we can't really disallow the - native arch at this point, because then bubblewrap - couldn't continue running. */ - r = seccomp_arch_add (seccomp, arch_id); - if (r < 0 && r != -EEXIST) - return flatpak_fail (error, "Failed to add architecture to seccomp filter"); - - if (multiarch && extra_arches != NULL) - { - for (i = 0; extra_arches[i] != 0; i++) - { - r = seccomp_arch_add (seccomp, extra_arches[i]); - if (r < 0 && r != -EEXIST) - return flatpak_fail (error, "Failed to add multiarch architecture to seccomp filter"); - } - } - } - } - - /* TODO: Should we filter the kernel keyring syscalls in some way? - * We do want them to be used by desktop apps, but they could also perhaps - * leak system stuff or secrets from other apps. - */ - - for (i = 0; i < G_N_ELEMENTS (syscall_blacklist); i++) - { - int scall = syscall_blacklist[i].scall; - if (syscall_blacklist[i].arg) - r = seccomp_rule_add (seccomp, SCMP_ACT_ERRNO (EPERM), scall, 1, *syscall_blacklist[i].arg); - else - r = seccomp_rule_add (seccomp, SCMP_ACT_ERRNO (EPERM), scall, 0); - if (r < 0 && r == -EFAULT /* unknown syscall */) - return flatpak_fail (error, "Failed to block syscall %d", scall); - } - - if (!devel) - { - for (i = 0; i < G_N_ELEMENTS (syscall_nondevel_blacklist); i++) - { - int scall = syscall_nondevel_blacklist[i].scall; - if (syscall_nondevel_blacklist[i].arg) - r = seccomp_rule_add (seccomp, SCMP_ACT_ERRNO (EPERM), scall, 1, *syscall_nondevel_blacklist[i].arg); - else - r = seccomp_rule_add (seccomp, SCMP_ACT_ERRNO (EPERM), scall, 0); - - if (r < 0 && r == -EFAULT /* unknown syscall */) - return flatpak_fail (error, "Failed to block syscall %d", scall); - } - } - - /* Socket filtering doesn't work on e.g. i386, so ignore failures here - * However, we need to user seccomp_rule_add_exact to avoid libseccomp doing - * something else: https://github.com/seccomp/libseccomp/issues/8 */ - for (i = 0; i < G_N_ELEMENTS (socket_family_blacklist); i++) - { - int family = socket_family_blacklist[i]; - if (i == G_N_ELEMENTS (socket_family_blacklist) - 1) - seccomp_rule_add_exact (seccomp, SCMP_ACT_ERRNO (EAFNOSUPPORT), SCMP_SYS (socket), 1, SCMP_A0 (SCMP_CMP_GE, family)); - else - seccomp_rule_add_exact (seccomp, SCMP_ACT_ERRNO (EAFNOSUPPORT), SCMP_SYS (socket), 1, SCMP_A0 (SCMP_CMP_EQ, family)); - } - - fd = g_file_open_tmp ("flatpak-seccomp-XXXXXX", &path, error); - if (fd == -1) - return FALSE; - - unlink (path); - - if (seccomp_export_bpf (seccomp, fd) != 0) - { - close (fd); - return flatpak_fail (error, "Failed to export bpf"); - } - - lseek (fd, 0, SEEK_SET); - - fd_str = g_strdup_printf ("%d", fd); - if (fd_array) - g_array_append_val (fd_array, fd); - - add_args (argv_array, - "--seccomp", fd_str, - NULL); - - fd = -1; /* Don't close on success */ - - return TRUE; -} -#endif - -#ifdef HAVE_BWRAP -static gboolean -path_is_usrmerged (const char *dir) -{ - /* does /dir point to /usr/dir? */ - g_autofree char *target = NULL; - GStatBuf stat_buf_src, stat_buf_target; - - if (g_stat (dir, &stat_buf_src) < 0) - return FALSE; - - target = g_strdup_printf ("/usr/%s", dir); - - if (g_stat (target, &stat_buf_target) < 0) - return FALSE; - - return (stat_buf_src.st_dev == stat_buf_target.st_dev) && - (stat_buf_src.st_ino == stat_buf_target.st_ino); -} - -static gboolean -add_bwrap (GPtrArray *array, - ScriptExec *script) -{ - const char * const usrmerged_dirs[] = { "bin", "lib64", "lib", "sbin" }; - int i; - - g_return_val_if_fail (script->outdir != NULL, FALSE); - g_return_val_if_fail (script->s_infile != NULL, FALSE); - - add_args (array, - "bwrap", - "--ro-bind", "/usr", "/usr", - "--ro-bind", "/etc/ld.so.cache", "/etc/ld.so.cache", - NULL); - - /* These directories might be symlinks into /usr/... */ - for (i = 0; i < G_N_ELEMENTS (usrmerged_dirs); i++) - { - g_autofree char *absolute_dir = g_strdup_printf ("/%s", usrmerged_dirs[i]); - - if (!g_file_test (absolute_dir, G_FILE_TEST_EXISTS)) - continue; - - if (path_is_usrmerged (absolute_dir)) - { - g_autofree char *symlink_target = g_strdup_printf ("/usr/%s", absolute_dir); - - add_args (array, - "--symlink", symlink_target, absolute_dir, - NULL); - } - else - { - add_args (array, - "--ro-bind", absolute_dir, absolute_dir, - NULL); - } - } - - /* fontconfig cache if necessary */ - if (!g_str_has_prefix (FONTCONFIG_CACHE_PATH, "/usr/")) - add_args (array, "--ro-bind-try", FONTCONFIG_CACHE_PATH, FONTCONFIG_CACHE_PATH, NULL); - - add_args (array, - "--proc", "/proc", - "--dev", "/dev", - "--chdir", "/", - "--setenv", "GIO_USE_VFS", "local", - "--unshare-all", - "--die-with-parent", - NULL); - - add_env (array, "G_MESSAGES_DEBUG"); - add_env (array, "G_MESSAGES_PREFIXED"); - - /* Add gnome-desktop's install prefix if needed */ - if (g_strcmp0 (INSTALL_PREFIX, "") != 0 && - g_strcmp0 (INSTALL_PREFIX, "/usr") != 0 && - g_strcmp0 (INSTALL_PREFIX, "/usr/") != 0) - { - add_args (array, - "--ro-bind", INSTALL_PREFIX, INSTALL_PREFIX, - NULL); - } - - g_ptr_array_add (array, g_strdup ("--bind")); - g_ptr_array_add (array, g_strdup (script->outdir)); - g_ptr_array_add (array, g_strdup ("/tmp")); - - /* We make sure to also re-use the original file's original - * extension in case it's useful for the thumbnailer to - * identify the file type */ - g_ptr_array_add (array, g_strdup ("--ro-bind")); - g_ptr_array_add (array, g_strdup (script->infile)); - g_ptr_array_add (array, g_strdup (script->s_infile)); - - return TRUE; -} -#endif /* HAVE_BWRAP */ - -static char ** -expand_thumbnailing_cmd (const char *cmd, - ScriptExec *script, - int size, - GError **error) -{ - GPtrArray *array; - g_auto(GStrv) cmd_elems = NULL; - guint i; - gboolean got_in, got_out; - - if (!g_shell_parse_argv (cmd, NULL, &cmd_elems, error)) - return NULL; - - script->thumbnailer_name = g_strdup (cmd_elems[0]); - - array = g_ptr_array_new_with_free_func (g_free); - -#ifdef HAVE_BWRAP - if (script->sandbox) - { - if (!add_bwrap (array, script)) - { - g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_FAILED, - "Bubblewrap setup failed"); - goto bail; - } - } -#endif - -#ifdef ENABLE_SECCOMP - if (script->sandbox) - { - const char *arch; - - arch = flatpak_get_arch (); - g_assert (arch); - if (!setup_seccomp (array, - script->fd_array, - arch, - FALSE, - FALSE, - error)) - { - goto bail; - } - } -#endif - - got_in = got_out = FALSE; - for (i = 0; cmd_elems[i] != NULL; i++) - { - char *expanded; - - expanded = expand_thumbnailing_elem (cmd_elems[i], - size, - script->s_infile ? script->s_infile : script->infile, - script->s_outfile ? script->s_outfile : 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 -child_setup (gpointer user_data) -{ - GArray *fd_array = user_data; - guint i; - - /* If no fd_array was specified, don't care. */ - if (fd_array == NULL) - return; - - /* Otherwise, mark not - close-on-exec all the fds in the array */ - for (i = 0; i < fd_array->len; i++) - fcntl (g_array_index (fd_array, int, i), F_SETFD, 0); -} - -static void -script_exec_free (ScriptExec *exec) -{ - if (exec == NULL) - return; - - g_free (exec->thumbnailer_name); - g_free (exec->infile); - if (exec->infile_tmp) - { - if (g_file_test (exec->infile_tmp, G_FILE_TEST_IS_DIR)) - g_rmdir (exec->infile_tmp); - else - g_unlink (exec->infile_tmp); - g_free (exec->infile_tmp); - } - if (exec->outfile) - { - g_unlink (exec->outfile); - g_free (exec->outfile); - } - if (exec->outdir) - { - if (g_rmdir (exec->outdir) < 0) - { - g_warning ("Could not remove %s, thumbnailer %s left files in directory", - exec->outdir, exec->thumbnailer_name); - } - g_free (exec->outdir); - } - g_free (exec->s_infile); - g_free (exec->s_outfile); - if (exec->fd_array) - g_array_free (exec->fd_array, TRUE); - g_free (exec); -} - -static void -clear_fd (gpointer data) -{ - int *fd_p = data; - if (fd_p != NULL && *fd_p != -1) - close (*fd_p); -} - -static ScriptExec * -script_exec_new (const char *uri, - GError **error) -{ - ScriptExec *exec; - g_autoptr(GFile) file = NULL; - - exec = g_new0 (ScriptExec, 1); -#ifdef HAVE_BWRAP - /* Bubblewrap is not used if the application is already sandboxed in - * Flatpak as all privileges to create a new namespace are dropped when - * the initial one is created. */ - if (!g_file_test ("/.flatpak-info", G_FILE_TEST_IS_REGULAR)) - exec->sandbox = TRUE; -#endif - - file = g_file_new_for_uri (uri); - - exec->infile = g_file_get_path (file); - if (!exec->infile) - { - g_set_error (error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND, - "Could not get path for URI '%s'", uri); - goto bail; - } - -#ifdef HAVE_BWRAP - if (exec->sandbox) - { - char *tmpl; - g_autofree char *ext = NULL; - g_autofree char *infile = NULL; - - exec->fd_array = g_array_new (FALSE, TRUE, sizeof (int)); - g_array_set_clear_func (exec->fd_array, clear_fd); - - tmpl = g_strdup ("/tmp/gnome-desktop-thumbnailer-XXXXXX"); - exec->outdir = g_mkdtemp (tmpl); - if (!exec->outdir) - { - g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_FAILED, - "Could not create temporary sandbox directory"); - goto bail; - } - exec->outfile = g_build_filename (exec->outdir, "gnome-desktop-thumbnailer.png", NULL); - ext = get_extension (exec->infile); - - if (ext) - infile = g_strdup_printf ("gnome-desktop-file-to-thumbnail.%s", ext); - else - infile = g_strdup_printf ("gnome-desktop-file-to-thumbnail"); - - exec->infile_tmp = g_build_filename (exec->outdir, infile, NULL); - - exec->s_infile = g_build_filename ("/tmp/", infile, NULL); - exec->s_outfile = g_build_filename ("/tmp/", "gnome-desktop-thumbnailer.png", NULL); - } - else -#endif - { - int fd; - g_autofree char *tmpname = NULL; - - fd = g_file_open_tmp (".gnome_desktop_thumbnail.XXXXXX", &tmpname, error); - if (fd == -1) - goto bail; - close (fd); - exec->outfile = g_steal_pointer (&tmpname); - } - - return exec; - -bail: - script_exec_free (exec); - return NULL; -} - -static void -print_script_debug (GStrv expanded_script) -{ - GString *out; - guint i; - - out = g_string_new (NULL); - - for (i = 0; expanded_script[i]; i++) - g_string_append_printf (out, "%s ", expanded_script[i]); - g_string_append_printf (out, "\n"); - - g_debug ("About to launch script: %s", out->str); - g_string_free (out, TRUE); -} - -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, error); - if (!exec) - goto out; - expanded_script = expand_thumbnailing_cmd (cmd, exec, size, error); - if (expanded_script == NULL) - goto out; - - print_script_debug (expanded_script); - - ret = g_spawn_sync (NULL, expanded_script, NULL, G_SPAWN_SEARCH_PATH, - child_setup, exec->fd_array, 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/src/gnome-desktop/gnome-desktop-thumbnail-script.h b/src/gnome-desktop/gnome-desktop-thumbnail-script.h deleted file mode 100644 index cbd6bbf67..000000000 --- a/src/gnome-desktop/gnome-desktop-thumbnail-script.h +++ /dev/null @@ -1,38 +0,0 @@ -/* - * 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/src/gnome-desktop/gnome-desktop-thumbnail.c b/src/gnome-desktop/gnome-desktop-thumbnail.c deleted file mode 100644 index 566fbeb84..000000000 --- a/src/gnome-desktop/gnome-desktop-thumbnail.c +++ /dev/null @@ -1,1303 +0,0 @@ -/* - * gnome-thumbnail.c: Utilities for handling thumbnails - * - * Copyright (C) 2002 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. - * - * Author: Alexander Larsson <alexl@redhat.com> - */ - -/** - * SECTION:gnome-desktop-thumbnail - * @short_description: Generates and looks up thumbnails of files and - * directories - * @stability: Unstable - * @include: libgnome-desktop/gnome-desktop-thumbnail.h - * - * #GnomeDesktopThumbnailFactory allows generation and loading of thumbnails for - * local and remote files and directories. It uses a collection of programs - * called <firstterm>thumbnailers</firstterm>, each one generating thumbnails - * for a specific set of content-types of files. For example, - * <application>totem-video-thumbnailer</application> generates thumbnails for - * video files using GStreamer; <application>evince-thumbnailer</application> - * generates thumbnails for PDFs and other document files. If no specific - * thumbnailer exists for a file, or if the thumbnailer fails, gdk-pixbuf is - * used as a fallback. - * - * To generate a thumbnail, an appropriate thumbnailer program is selected then - * executed, passing it the URI of the file to thumbnail, plus a path to write - * the thumbnail image to. If thumbnailing succeeds, the thumbnailer should have - * written the image to disk before terminating; but if thumbnailing fails, no - * image should be written, and the thumbnailer should return a non-zero exit - * status. #GnomeDesktopThumbnailFactory will then fall back to using gdk-pixbuf - * to generate a thumbnail, if possible. - * - * Thumbnailers are chosen by examining a series of - * <filename>.thumbnailer</filename> files in - * <filename><replaceable>$PREFIX</replaceable>/share/thumbnailers</filename>. - * Each is in a simple key-file format: - * <informalexample><programlisting> - * [Thumbnailer Entry] - * Exec=evince-thumbnailer -s %s %u %o - * MimeType=application/pdf;application/x-bzpdf;application/x-gzpdf; - * </programlisting></informalexample> - * - * The <filename>.thumbnailer</filename> format supports three keys: - * <variablelist> - * <varlistentry><term><code>Exec</code></term><listitem><para> - * Required. The command to execute the thumbnailer. It supports a few different - * parameters which are replaced before calling the thumbnailer: - * <replaceable>%u</replaceable> is the URI of the file being thumbnailed; - * <replaceable>%i</replaceable> is its path; <replaceable>%o</replaceable> - * is the path of the image file to be written to; - * <replaceable>%s</replaceable> is the maximum desired size of the thumbnail - * image (the maximum width or height, in pixels); and - * <replaceable>%%</replaceable> is a literal percent character. - * </para></listitem></varlistentry> - * <varlistentry><term><code>MimeType</code></term><listitem><para> - * Required. A semicolon-separated list of MIME types which the thumbnailer - * supports generating thumbnails for. - * </para></listitem></varlistentry> - * </variablelist> - * - * So in the example <filename>.thumbnailer</filename> file above, the command - * passes the requested thumbnail size, then the input file’s URI, then the - * path for the output image file to - * <application>evince-thumbnailer</application>. - * - * The code to examine and call a thumbnailer is contained in - * #GnomeDesktopThumbnailFactory, which handles looking up the right thumbnailer - * script, building and executing the command for it, and loading the resulting - * thumbnail image into a #GdkPixbuf. - * - * Thumbnail caching is also supported by #GnomeDesktopThumbnailFactory. When - * calling a thumbnailer, the path passed for the output image file is in - * <filename><envar>$XDG_CACHE_HOME</envar>/thumbnails/ - * <replaceable>$SIZE</replaceable>/</filename>. The cached image file is given - * a (probably) unique filename, generated by hashing the original file’s URI, - * so the thumbnail can be looked up in future. #GnomeDesktopThumbnailFactory - * supports two sizes of thumbnails: %GNOME_DESKTOP_THUMBNAIL_SIZE_NORMAL and - * %GNOME_DESKTOP_THUMBNAIL_SIZE_LARGE. Normal thumbnails are up to 128×128 - * pixels, whereas large thumbnails are up to 256×256 pixels. Thumbnails which - * are larger than this are scaled down before being cached, and non-square - * thumbnails are scaled so their largest dimension is at most 128 or 256 - * pixels. - * - * #GnomeDesktopThumbnailFactory also handles failed thumbnails. If a - * thumbnailer can’t generate a thumbnail for a file (e.g. because the file is - * corrupt or because the right video codecs aren’t available), it returns a - * non-zero exit status. The thumbnail factory then writes an entry to - * <filename><envar>$XDG_CACHE_HOME</envar>/thumbnails/fail/ - * gnome-thumbnail-factory/</filename> which is named after the hash of the - * input file URI (just like a successful cached thumbnail). For future queries - * for thumbnails for that file, #GnomeDesktopThumbnailFactory can immediately - * return an error after looking up the fail entry. - * - * If a file changes content, #GnomeDesktopThumbnailFactory will generate a new - * thumbnail because each cached image has associated metadata (stored as PNG - * tEXt keys) storing the full URI of the thumbnailed file (to check for hash - * collisions) and its last modification time at the point of thumbnailing. If - * the stored modification time doesn’t match the file’s current one, a new - * thumbnail is generated. - * - * Since: 2.2 - */ - -#include <config.h> - -#include <glib.h> -#include <glib/gstdio.h> -#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, - GFile *file, - GFile *other_file, - GFileMonitorEvent event_type, - GnomeDesktopThumbnailFactory *factory); - -struct _GnomeDesktopThumbnailFactoryPrivate { - GnomeDesktopThumbnailSize size; - - GMutex lock; - - GList *thumbnailers; - GHashTable *mime_types_map; - GList *monitors; - - GSettings *settings; - gboolean loaded : 1; - gboolean disabled : 1; - gchar **disabled_types; -}; - -static const char *appname = "gnome-thumbnail-factory"; - -G_DEFINE_TYPE (GnomeDesktopThumbnailFactory, - gnome_desktop_thumbnail_factory, - G_TYPE_OBJECT) -#define parent_class gnome_desktop_thumbnail_factory_parent_class - -#define GNOME_DESKTOP_THUMBNAIL_FACTORY_GET_PRIVATE(object) \ - (G_TYPE_INSTANCE_GET_PRIVATE ((object), GNOME_DESKTOP_TYPE_THUMBNAIL_FACTORY, GnomeDesktopThumbnailFactoryPrivate)) - -#define THUMBNAILER_ENTRY_GROUP "Thumbnailer Entry" -#define THUMBNAILER_EXTENSION ".thumbnailer" - -typedef struct { - volatile gint ref_count; - - gchar *path; - - gchar *command; - gchar **mime_types; -} Thumbnailer; - -static Thumbnailer * -thumbnailer_ref (Thumbnailer *thumb) -{ - g_return_val_if_fail (thumb != NULL, NULL); - g_return_val_if_fail (thumb->ref_count > 0, NULL); - - g_atomic_int_inc (&thumb->ref_count); - return thumb; -} - -static void -thumbnailer_unref (Thumbnailer *thumb) -{ - g_return_if_fail (thumb != NULL); - g_return_if_fail (thumb->ref_count > 0); - - if (g_atomic_int_dec_and_test (&thumb->ref_count)) - { - g_free (thumb->path); - g_free (thumb->command); - g_strfreev (thumb->mime_types); - - g_slice_free (Thumbnailer, thumb); - } -} - -static Thumbnailer * -thumbnailer_load (Thumbnailer *thumb) -{ - GKeyFile *key_file; - GError *error = NULL; - - key_file = g_key_file_new (); - if (!g_key_file_load_from_file (key_file, thumb->path, 0, &error)) - { - g_warning ("Failed to load thumbnailer from \"%s\": %s\n", thumb->path, error->message); - g_error_free (error); - thumbnailer_unref (thumb); - g_key_file_free (key_file); - - return NULL; - } - - if (!g_key_file_has_group (key_file, THUMBNAILER_ENTRY_GROUP)) - { - g_warning ("Invalid thumbnailer: missing group \"%s\"\n", THUMBNAILER_ENTRY_GROUP); - thumbnailer_unref (thumb); - g_key_file_free (key_file); - - return NULL; - } - - thumb->command = g_key_file_get_string (key_file, THUMBNAILER_ENTRY_GROUP, "Exec", NULL); - if (!thumb->command) - { - g_warning ("Invalid thumbnailer: missing Exec key\n"); - thumbnailer_unref (thumb); - g_key_file_free (key_file); - - return NULL; - } - - thumb->mime_types = g_key_file_get_string_list (key_file, THUMBNAILER_ENTRY_GROUP, "MimeType", NULL, NULL); - if (!thumb->mime_types) - { - g_warning ("Invalid thumbnailer: missing MimeType key\n"); - thumbnailer_unref (thumb); - g_key_file_free (key_file); - - return NULL; - } - - g_key_file_free (key_file); - - return thumb; -} - -static Thumbnailer * -thumbnailer_reload (Thumbnailer *thumb) -{ - g_return_val_if_fail (thumb != NULL, NULL); - - g_free (thumb->command); - thumb->command = NULL; - g_strfreev (thumb->mime_types); - thumb->mime_types = NULL; - - return thumbnailer_load (thumb); -} - -static Thumbnailer * -thumbnailer_new (const gchar *path) -{ - Thumbnailer *thumb; - - thumb = g_slice_new0 (Thumbnailer); - thumb->ref_count = 1; - thumb->path = g_strdup (path); - - return thumbnailer_load (thumb); -} - -static gpointer -init_thumbnailers_dirs (gpointer data) -{ - const gchar * const *data_dirs; - GPtrArray *thumbs_dirs; - guint i; - - data_dirs = g_get_system_data_dirs (); - thumbs_dirs = g_ptr_array_new (); - - g_ptr_array_add (thumbs_dirs, g_build_filename (g_get_user_data_dir (), "thumbnailers", NULL)); - for (i = 0; data_dirs[i] != NULL; i++) - g_ptr_array_add (thumbs_dirs, g_build_filename (data_dirs[i], "thumbnailers", NULL)); - g_ptr_array_add (thumbs_dirs, NULL); - - return g_ptr_array_free (thumbs_dirs, FALSE); -} - -static const gchar * const * -get_thumbnailers_dirs (void) -{ - static GOnce once_init = G_ONCE_INIT; - return g_once (&once_init, init_thumbnailers_dirs, NULL); -} - -/* These should be called with the lock held */ -static void -gnome_desktop_thumbnail_factory_register_mime_types (GnomeDesktopThumbnailFactory *factory, - Thumbnailer *thumb) -{ - GnomeDesktopThumbnailFactoryPrivate *priv = factory->priv; - gint i; - - for (i = 0; thumb->mime_types[i]; i++) - { - if (!g_hash_table_lookup (priv->mime_types_map, thumb->mime_types[i])) - g_hash_table_insert (priv->mime_types_map, - g_strdup (thumb->mime_types[i]), - thumbnailer_ref (thumb)); - } -} - -static void -gnome_desktop_thumbnail_factory_add_thumbnailer (GnomeDesktopThumbnailFactory *factory, - Thumbnailer *thumb) -{ - GnomeDesktopThumbnailFactoryPrivate *priv = factory->priv; - - gnome_desktop_thumbnail_factory_register_mime_types (factory, thumb); - priv->thumbnailers = g_list_prepend (priv->thumbnailers, thumb); -} - -static gboolean -gnome_desktop_thumbnail_factory_is_disabled (GnomeDesktopThumbnailFactory *factory, - const gchar *mime_type) -{ - GnomeDesktopThumbnailFactoryPrivate *priv = factory->priv; - guint i; - - if (priv->disabled) - return TRUE; - - if (!priv->disabled_types) - return FALSE; - - for (i = 0; priv->disabled_types[i]; i++) - { - if (g_strcmp0 (priv->disabled_types[i], mime_type) == 0) - return TRUE; - } - - return FALSE; -} - -static gboolean -remove_thumbnailer_from_mime_type_map (gchar *key, - Thumbnailer *value, - gchar *path) -{ - return (strcmp (value->path, path) == 0); -} - -static void -update_or_create_thumbnailer (GnomeDesktopThumbnailFactory *factory, - const gchar *path) -{ - GnomeDesktopThumbnailFactoryPrivate *priv = factory->priv; - GList *l; - Thumbnailer *thumb; - gboolean found = FALSE; - - g_mutex_lock (&priv->lock); - - for (l = priv->thumbnailers; l && !found; l = g_list_next (l)) - { - thumb = (Thumbnailer *)l->data; - - if (strcmp (thumb->path, path) == 0) - { - found = TRUE; - - /* First remove the mime_types associated to this thumbnailer */ - g_hash_table_foreach_remove (priv->mime_types_map, - (GHRFunc)remove_thumbnailer_from_mime_type_map, - (gpointer)path); - if (!thumbnailer_reload (thumb)) - priv->thumbnailers = g_list_delete_link (priv->thumbnailers, l); - else - gnome_desktop_thumbnail_factory_register_mime_types (factory, thumb); - } - } - - if (!found) - { - thumb = thumbnailer_new (path); - if (thumb) - gnome_desktop_thumbnail_factory_add_thumbnailer (factory, thumb); - } - - g_mutex_unlock (&priv->lock); -} - -static void -remove_thumbnailer (GnomeDesktopThumbnailFactory *factory, - const gchar *path) -{ - GnomeDesktopThumbnailFactoryPrivate *priv = factory->priv; - GList *l; - Thumbnailer *thumb; - - g_mutex_lock (&priv->lock); - - for (l = priv->thumbnailers; l; l = g_list_next (l)) - { - thumb = (Thumbnailer *)l->data; - - if (strcmp (thumb->path, path) == 0) - { - priv->thumbnailers = g_list_delete_link (priv->thumbnailers, l); - g_hash_table_foreach_remove (priv->mime_types_map, - (GHRFunc)remove_thumbnailer_from_mime_type_map, - (gpointer)path); - thumbnailer_unref (thumb); - - break; - } - } - - g_mutex_unlock (&priv->lock); -} - -static void -remove_thumbnailers_for_dir (GnomeDesktopThumbnailFactory *factory, - const gchar *thumbnailer_dir, - GFileMonitor *monitor) -{ - GnomeDesktopThumbnailFactoryPrivate *priv = factory->priv; - GList *l; - Thumbnailer *thumb; - - g_mutex_lock (&priv->lock); - - /* Remove all the thumbnailers inside this @thumbnailer_dir. */ - for (l = priv->thumbnailers; l; l = g_list_next (l)) - { - thumb = (Thumbnailer *)l->data; - - if (g_str_has_prefix (thumb->path, thumbnailer_dir) == TRUE) - { - priv->thumbnailers = g_list_delete_link (priv->thumbnailers, l); - g_hash_table_foreach_remove (priv->mime_types_map, - (GHRFunc)remove_thumbnailer_from_mime_type_map, - (gpointer)thumb->path); - thumbnailer_unref (thumb); - - break; - } - } - - /* Remove the monitor for @thumbnailer_dir. */ - priv->monitors = g_list_remove (priv->monitors, monitor); - g_signal_handlers_disconnect_by_func (monitor, thumbnailers_directory_changed, factory); - - g_mutex_unlock (&priv->lock); -} - -static void -gnome_desktop_thumbnail_factory_load_thumbnailers_for_dir (GnomeDesktopThumbnailFactory *factory, - const gchar *path) -{ - GnomeDesktopThumbnailFactoryPrivate *priv = factory->priv; - GDir *dir; - GFile *dir_file; - GFileMonitor *monitor; - const gchar *dirent; - - dir = g_dir_open (path, 0, NULL); - if (!dir) - return; - - /* Monitor dir */ - dir_file = g_file_new_for_path (path); - monitor = g_file_monitor_directory (dir_file, - G_FILE_MONITOR_NONE, - NULL, NULL); - if (monitor) - { - g_signal_connect (monitor, "changed", - G_CALLBACK (thumbnailers_directory_changed), - factory); - priv->monitors = g_list_prepend (priv->monitors, monitor); - } - g_object_unref (dir_file); - - while ((dirent = g_dir_read_name (dir))) - { - Thumbnailer *thumb; - gchar *filename; - - if (!g_str_has_suffix (dirent, THUMBNAILER_EXTENSION)) - continue; - - filename = g_build_filename (path, dirent, NULL); - thumb = thumbnailer_new (filename); - g_free (filename); - - if (thumb) - gnome_desktop_thumbnail_factory_add_thumbnailer (factory, thumb); - } - - g_dir_close (dir); -} - -static void -thumbnailers_directory_changed (GFileMonitor *monitor, - GFile *file, - GFile *other_file, - GFileMonitorEvent event_type, - GnomeDesktopThumbnailFactory *factory) -{ - gchar *path; - - switch (event_type) - { - case G_FILE_MONITOR_EVENT_CREATED: - case G_FILE_MONITOR_EVENT_CHANGED: - case G_FILE_MONITOR_EVENT_DELETED: - path = g_file_get_path (file); - if (!g_str_has_suffix (path, THUMBNAILER_EXTENSION)) - { - g_free (path); - return; - } - - if (event_type == G_FILE_MONITOR_EVENT_DELETED) - remove_thumbnailer (factory, path); - else - update_or_create_thumbnailer (factory, path); - - g_free (path); - break; - case G_FILE_MONITOR_EVENT_UNMOUNTED: - case G_FILE_MONITOR_EVENT_MOVED: - path = g_file_get_path (file); - remove_thumbnailers_for_dir (factory, path, monitor); - - if (event_type == G_FILE_MONITOR_EVENT_MOVED) - gnome_desktop_thumbnail_factory_load_thumbnailers_for_dir (factory, path); - - g_free (path); - break; - case G_FILE_MONITOR_EVENT_CHANGES_DONE_HINT: - case G_FILE_MONITOR_EVENT_ATTRIBUTE_CHANGED: - case G_FILE_MONITOR_EVENT_PRE_UNMOUNT: - case G_FILE_MONITOR_EVENT_RENAMED: - case G_FILE_MONITOR_EVENT_MOVED_IN: - case G_FILE_MONITOR_EVENT_MOVED_OUT: - default: - break; - } -} - -static void -gnome_desktop_thumbnail_factory_load_thumbnailers (GnomeDesktopThumbnailFactory *factory) -{ - GnomeDesktopThumbnailFactoryPrivate *priv = factory->priv; - const gchar * const *dirs; - guint i; - - if (priv->loaded) - return; - - dirs = get_thumbnailers_dirs (); - for (i = 0; dirs[i]; i++) - { - gnome_desktop_thumbnail_factory_load_thumbnailers_for_dir (factory, dirs[i]); - } - - priv->loaded = TRUE; -} - -static void -external_thumbnailers_disabled_all_changed_cb (GSettings *settings, - const gchar *key, - GnomeDesktopThumbnailFactory *factory) -{ - GnomeDesktopThumbnailFactoryPrivate *priv = factory->priv; - - g_mutex_lock (&priv->lock); - - priv->disabled = g_settings_get_boolean (priv->settings, "disable-all"); - if (priv->disabled) - { - g_strfreev (priv->disabled_types); - priv->disabled_types = NULL; - } - else - { - priv->disabled_types = g_settings_get_strv (priv->settings, "disable"); - gnome_desktop_thumbnail_factory_load_thumbnailers (factory); - } - - g_mutex_unlock (&priv->lock); -} - -static void -external_thumbnailers_disabled_changed_cb (GSettings *settings, - const gchar *key, - GnomeDesktopThumbnailFactory *factory) -{ - GnomeDesktopThumbnailFactoryPrivate *priv = factory->priv; - - g_mutex_lock (&priv->lock); - - if (!priv->disabled) - { - g_strfreev (priv->disabled_types); - priv->disabled_types = g_settings_get_strv (priv->settings, "disable"); - } - - g_mutex_unlock (&priv->lock); -} - -static void -gnome_desktop_thumbnail_factory_init (GnomeDesktopThumbnailFactory *factory) -{ - GnomeDesktopThumbnailFactoryPrivate *priv; - - factory->priv = GNOME_DESKTOP_THUMBNAIL_FACTORY_GET_PRIVATE (factory); - - priv = factory->priv; - - priv->size = GNOME_DESKTOP_THUMBNAIL_SIZE_NORMAL; - - priv->mime_types_map = g_hash_table_new_full (g_str_hash, - g_str_equal, - (GDestroyNotify)g_free, - (GDestroyNotify)thumbnailer_unref); - - g_mutex_init (&priv->lock); - - priv->settings = g_settings_new ("org.gnome.desktop.thumbnailers"); - priv->disabled = g_settings_get_boolean (priv->settings, "disable-all"); - if (!priv->disabled) - priv->disabled_types = g_settings_get_strv (priv->settings, "disable"); - g_signal_connect (priv->settings, "changed::disable-all", - G_CALLBACK (external_thumbnailers_disabled_all_changed_cb), - factory); - g_signal_connect (priv->settings, "changed::disable", - G_CALLBACK (external_thumbnailers_disabled_changed_cb), - factory); - - if (!priv->disabled) - gnome_desktop_thumbnail_factory_load_thumbnailers (factory); -} - -static void -gnome_desktop_thumbnail_factory_finalize (GObject *object) -{ - GnomeDesktopThumbnailFactory *factory; - GnomeDesktopThumbnailFactoryPrivate *priv; - - factory = GNOME_DESKTOP_THUMBNAIL_FACTORY (object); - - priv = factory->priv; - - if (priv->thumbnailers) - { - g_list_free_full (priv->thumbnailers, (GDestroyNotify)thumbnailer_unref); - priv->thumbnailers = NULL; - } - - g_clear_pointer (&priv->mime_types_map, g_hash_table_destroy); - - if (priv->monitors) - { - g_list_free_full (priv->monitors, (GDestroyNotify)g_object_unref); - priv->monitors = NULL; - } - - g_mutex_clear (&priv->lock); - - g_clear_pointer (&priv->disabled_types, g_strfreev); - - if (priv->settings) - { - g_signal_handlers_disconnect_by_func (priv->settings, - external_thumbnailers_disabled_all_changed_cb, - factory); - g_signal_handlers_disconnect_by_func (priv->settings, - external_thumbnailers_disabled_changed_cb, - factory); - g_clear_object (&priv->settings); - } - - if (G_OBJECT_CLASS (parent_class)->finalize) - (* G_OBJECT_CLASS (parent_class)->finalize) (object); -} - -static void -gnome_desktop_thumbnail_factory_class_init (GnomeDesktopThumbnailFactoryClass *class) -{ - GObjectClass *gobject_class; - - gobject_class = G_OBJECT_CLASS (class); - - gobject_class->finalize = gnome_desktop_thumbnail_factory_finalize; - - g_type_class_add_private (class, sizeof (GnomeDesktopThumbnailFactoryPrivate)); -} - -/** - * gnome_desktop_thumbnail_factory_new: - * @size: The thumbnail size to use - * - * Creates a new #GnomeDesktopThumbnailFactory. - * - * This function must be called on the main thread and is non-blocking. - * - * Return value: a new #GnomeDesktopThumbnailFactory - * - * Since: 2.2 - **/ -GnomeDesktopThumbnailFactory * -gnome_desktop_thumbnail_factory_new (GnomeDesktopThumbnailSize size) -{ - GnomeDesktopThumbnailFactory *factory; - - factory = g_object_new (GNOME_DESKTOP_TYPE_THUMBNAIL_FACTORY, NULL); - - factory->priv->size = size; - - return factory; -} - -static char * -thumbnail_filename (const char *uri) -{ - GChecksum *checksum; - guint8 digest[16]; - gsize digest_len = sizeof (digest); - char *file; - - checksum = g_checksum_new (G_CHECKSUM_MD5); - g_checksum_update (checksum, (const guchar *) uri, strlen (uri)); - - g_checksum_get_digest (checksum, digest, &digest_len); - g_assert (digest_len == 16); - - file = g_strconcat (g_checksum_get_string (checksum), ".png", NULL); - - g_checksum_free (checksum); - - return file; -} - -static char * -thumbnail_path (const char *uri, - GnomeDesktopThumbnailSize size) -{ - char *path, *file; - - file = thumbnail_filename (uri); - path = g_build_filename (g_get_user_cache_dir (), - "thumbnails", - size == GNOME_DESKTOP_THUMBNAIL_SIZE_LARGE ? "large" : "normal", - file, - NULL); - g_free (file); - return path; -} - -static char * -thumbnail_failed_path (const char *uri) -{ - char *path, *file; - - file = thumbnail_filename (uri); - /* XXX: appname is only used for failed thumbnails. Is this a mistake? */ - path = g_build_filename (g_get_user_cache_dir (), - "thumbnails", - "fail", - appname, - file, - NULL); - g_free (file); - return path; -} - -static char * -validate_thumbnail_path (char *path, - const char *uri, - time_t mtime, - GnomeDesktopThumbnailSize size) -{ - GdkPixbuf *pixbuf; - - pixbuf = gdk_pixbuf_new_from_file (path, NULL); - if (pixbuf == NULL || - !gnome_desktop_thumbnail_is_valid (pixbuf, uri, mtime)) { - g_free (path); - return NULL; - } - - g_clear_object (&pixbuf); - - return path; -} - -static char * -lookup_thumbnail_path (const char *uri, - time_t mtime, - GnomeDesktopThumbnailSize size) -{ - char *path = thumbnail_path (uri, size); - return validate_thumbnail_path (path, uri, mtime, size); -} - -static char * -lookup_failed_thumbnail_path (const char *uri, - time_t mtime, - GnomeDesktopThumbnailSize size) -{ - char *path = thumbnail_failed_path (uri); - return validate_thumbnail_path (path, uri, mtime, size); -} - -/** - * gnome_desktop_thumbnail_factory_lookup: - * @factory: a #GnomeDesktopThumbnailFactory - * @uri: the uri of a file - * @mtime: the mtime of the file - * - * Tries to locate an existing thumbnail for the file specified. - * - * Usage of this function is threadsafe and does blocking I/O. - * - * Return value: The absolute path of the thumbnail, or %NULL if none exist. - * - * Since: 2.2 - **/ -char * -gnome_desktop_thumbnail_factory_lookup (GnomeDesktopThumbnailFactory *factory, - const char *uri, - time_t mtime) -{ - GnomeDesktopThumbnailFactoryPrivate *priv = factory->priv; - - g_return_val_if_fail (uri != NULL, NULL); - - return lookup_thumbnail_path (uri, mtime, priv->size); -} - -/** - * gnome_desktop_thumbnail_factory_has_valid_failed_thumbnail: - * @factory: a #GnomeDesktopThumbnailFactory - * @uri: the uri of a file - * @mtime: the mtime of the file - * - * Tries to locate an failed thumbnail for the file specified. Writing - * and looking for failed thumbnails is important to avoid to try to - * thumbnail e.g. broken images several times. - * - * Usage of this function is threadsafe and does blocking I/O. - * - * Return value: TRUE if there is a failed thumbnail for the file. - * - * Since: 2.2 - **/ -gboolean -gnome_desktop_thumbnail_factory_has_valid_failed_thumbnail (GnomeDesktopThumbnailFactory *factory, - const char *uri, - time_t mtime) -{ - char *path; - - g_return_val_if_fail (uri != NULL, FALSE); - - path = lookup_failed_thumbnail_path (uri, mtime, factory->priv->size); - if (path == NULL) - return FALSE; - - g_free (path); - - return TRUE; -} - -/** - * gnome_desktop_thumbnail_factory_can_thumbnail: - * @factory: a #GnomeDesktopThumbnailFactory - * @uri: the uri of a file - * @mime_type: the mime type of the file - * @mtime: the mtime of the file - * - * Returns TRUE if this GnomeDesktopThumbnailFactory can (at least try) to thumbnail - * this file. Thumbnails or files with failed thumbnails won't be thumbnailed. - * - * Usage of this function is threadsafe and does blocking I/O. - * - * Return value: TRUE if the file can be thumbnailed. - * - * Since: 2.2 - **/ -gboolean -gnome_desktop_thumbnail_factory_can_thumbnail (GnomeDesktopThumbnailFactory *factory, - const char *uri, - const char *mime_type, - time_t mtime) -{ - gboolean have_script = FALSE; - - /* Don't thumbnail thumbnails */ - if (uri && - strncmp (uri, "file:/", 6) == 0 && - strstr (uri, "/thumbnails/") != NULL) - return FALSE; - - if (!mime_type) - return FALSE; - - g_mutex_lock (&factory->priv->lock); - if (!gnome_desktop_thumbnail_factory_is_disabled (factory, mime_type)) - { - Thumbnailer *thumb; - - thumb = g_hash_table_lookup (factory->priv->mime_types_map, mime_type); - have_script = (thumb != NULL); - } - g_mutex_unlock (&factory->priv->lock); - - if (have_script) - { - return !gnome_desktop_thumbnail_factory_has_valid_failed_thumbnail (factory, - uri, - mtime); - } - - return FALSE; -} - -static GdkPixbuf * -get_preview_thumbnail (const char *uri, - int size) -{ - GdkPixbuf *pixbuf; - GFile *file; - GFileInfo *file_info; - GInputStream *input_stream; - GObject *object; - - g_return_val_if_fail (uri != NULL, NULL); - - input_stream = NULL; - - file = g_file_new_for_uri (uri); - - /* First see if we can get an input stream via preview::icon */ - file_info = g_file_query_info (file, - G_FILE_ATTRIBUTE_PREVIEW_ICON, - G_FILE_QUERY_INFO_NONE, - NULL, /* GCancellable */ - NULL); /* return location for GError */ - g_object_unref (file); - - if (file_info == NULL) - return NULL; - - object = g_file_info_get_attribute_object (file_info, - G_FILE_ATTRIBUTE_PREVIEW_ICON); - if (object) - g_object_ref (object); - g_object_unref (file_info); - - if (!object) - return NULL; - if (!G_IS_LOADABLE_ICON (object)) { - g_object_unref (object); - return NULL; - } - - input_stream = g_loadable_icon_load (G_LOADABLE_ICON (object), - 0, /* size */ - NULL, /* return location for type */ - NULL, /* GCancellable */ - NULL); /* return location for GError */ - g_object_unref (object); - - if (!input_stream) - return NULL; - - pixbuf = gdk_pixbuf_new_from_stream_at_scale (input_stream, - size, size, - TRUE, NULL, NULL); - g_object_unref (input_stream); - - 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 - * @uri: the uri of a file - * @mime_type: the mime type of the file - * - * Tries to generate a thumbnail for the specified file. If it succeeds - * it returns a pixbuf that can be used as a thumbnail. - * - * Usage of this function is threadsafe and does blocking I/O. - * - * Return value: (transfer full): thumbnail pixbuf if thumbnailing succeeded, %NULL otherwise. - * - * Since: 2.2 - **/ -GdkPixbuf * -gnome_desktop_thumbnail_factory_generate_thumbnail (GnomeDesktopThumbnailFactory *factory, - const char *uri, - const char *mime_type) -{ - GdkPixbuf *pixbuf; - char *script; - int size; - - g_return_val_if_fail (uri != NULL, NULL); - g_return_val_if_fail (mime_type != NULL, NULL); - - /* Doesn't access any volatile fields in factory, so it's threadsafe */ - - size = 128; - if (factory->priv->size == GNOME_DESKTOP_THUMBNAIL_SIZE_LARGE) - size = 256; - - pixbuf = get_preview_thumbnail (uri, size); - if (pixbuf != NULL) - return pixbuf; - - script = NULL; - g_mutex_lock (&factory->priv->lock); - if (!gnome_desktop_thumbnail_factory_is_disabled (factory, mime_type)) - { - Thumbnailer *thumb; - - thumb = g_hash_table_lookup (factory->priv->mime_types_map, mime_type); - if (thumb) - script = g_strdup (thumb->command); - } - g_mutex_unlock (&factory->priv->lock); - - if (script) - { - GBytes *data; - GError *error = NULL; - - data = gnome_desktop_thumbnail_script_exec (script, size, uri, &error); - if (data) - { - pixbuf = pixbuf_new_from_bytes (data, &error); - if (!pixbuf) - { - g_debug ("Could not load thumbnail pixbuf: %s", error->message); - g_error_free (error); - } - g_bytes_unref (data); - } - else - { - g_debug ("Thumbnail script ('%s') failed for '%s': %s", - script, uri, error ? error->message : "no details"); - g_clear_error (&error); - } - } - else - { - g_debug ("Could not find thumbnailer for mime-type '%s'", - mime_type); - } - - g_free (script); - - return pixbuf; -} - -static gboolean -save_thumbnail (GdkPixbuf *pixbuf, - char *path, - const char *uri, - time_t mtime) -{ - char *dirname; - char *tmp_path = NULL; - int tmp_fd; - char mtime_str[21]; - gboolean ret = FALSE; - GError *error = NULL; - const char *width, *height; - - if (pixbuf == NULL) - return FALSE; - - dirname = g_path_get_dirname (path); - - if (g_mkdir_with_parents (dirname, 0700) != 0) - goto out; - - tmp_path = g_strconcat (path, ".XXXXXX", NULL); - tmp_fd = g_mkstemp (tmp_path); - - if (tmp_fd == -1) - goto out; - close (tmp_fd); - - g_snprintf (mtime_str, 21, "%" G_GINT64_FORMAT, (gint64) mtime); - width = gdk_pixbuf_get_option (pixbuf, "tEXt::Thumb::Image::Width"); - height = gdk_pixbuf_get_option (pixbuf, "tEXt::Thumb::Image::Height"); - - error = NULL; - if (width != NULL && height != NULL) - ret = gdk_pixbuf_save (pixbuf, - tmp_path, - "png", &error, - "tEXt::Thumb::Image::Width", width, - "tEXt::Thumb::Image::Height", height, - "tEXt::Thumb::URI", uri, - "tEXt::Thumb::MTime", mtime_str, - "tEXt::Software", "GNOME::ThumbnailFactory", - NULL); - else - ret = gdk_pixbuf_save (pixbuf, - tmp_path, - "png", &error, - "tEXt::Thumb::URI", uri, - "tEXt::Thumb::MTime", mtime_str, - "tEXt::Software", "GNOME::ThumbnailFactory", - NULL); - - if (!ret) - goto out; - - g_chmod (tmp_path, 0600); - g_rename (tmp_path, path); - - out: - if (error != NULL) - { - g_warning ("Failed to create thumbnail %s: %s", tmp_path, error->message); - g_error_free (error); - } - g_unlink (tmp_path); - g_free (tmp_path); - g_free (dirname); - return ret; -} - -static GdkPixbuf * -make_failed_thumbnail (void) -{ - GdkPixbuf *pixbuf; - - pixbuf = gdk_pixbuf_new (GDK_COLORSPACE_RGB, TRUE, 8, 1, 1); - gdk_pixbuf_fill (pixbuf, 0x00000000); - return pixbuf; -} - -/** - * gnome_desktop_thumbnail_factory_save_thumbnail: - * @factory: a #GnomeDesktopThumbnailFactory - * @thumbnail: the thumbnail as a pixbuf - * @uri: the uri of a file - * @original_mtime: the modification time of the original file - * - * Saves @thumbnail at the right place. If the save fails a - * failed thumbnail is written. - * - * Usage of this function is threadsafe and does blocking I/O. - * - * Since: 2.2 - **/ -void -gnome_desktop_thumbnail_factory_save_thumbnail (GnomeDesktopThumbnailFactory *factory, - GdkPixbuf *thumbnail, - const char *uri, - time_t original_mtime) -{ - char *path; - - path = thumbnail_path (uri, factory->priv->size); - if (!save_thumbnail (thumbnail, path, uri, original_mtime)) - { - thumbnail = make_failed_thumbnail (); - g_free (path); - path = thumbnail_failed_path (uri); - save_thumbnail (thumbnail, path, uri, original_mtime); - g_object_unref (thumbnail); - } - g_free (path); -} - -/** - * gnome_desktop_thumbnail_factory_create_failed_thumbnail: - * @factory: a #GnomeDesktopThumbnailFactory - * @uri: the uri of a file - * @mtime: the modification time of the file - * - * Creates a failed thumbnail for the file so that we don't try - * to re-thumbnail the file later. - * - * Usage of this function is threadsafe and does blocking I/O. - * - * Since: 2.2 - **/ -void -gnome_desktop_thumbnail_factory_create_failed_thumbnail (GnomeDesktopThumbnailFactory *factory, - const char *uri, - time_t mtime) -{ - char *path; - GdkPixbuf *pixbuf; - - path = thumbnail_failed_path (uri); - pixbuf = make_failed_thumbnail (); - save_thumbnail (pixbuf, path, uri, mtime); - g_free (path); - g_object_unref (pixbuf); -} - -/** - * gnome_desktop_thumbnail_path_for_uri: - * @uri: an uri - * @size: a thumbnail size - * - * Returns the filename that a thumbnail of size @size for @uri would have. - * This function is threadsafe and does no blocking I/O. - * - * Return value: an absolute filename - * - * Since: 2.2 - **/ -char * -gnome_desktop_thumbnail_path_for_uri (const char *uri, - GnomeDesktopThumbnailSize size) -{ - return thumbnail_path (uri, size); -} - -/** - * gnome_desktop_thumbnail_is_valid: - * @pixbuf: an loaded thumbnail #GdkPixbuf - * @uri: a uri - * @mtime: the mtime - * - * Returns whether the thumbnail has the correct uri and mtime embedded in the - * png options. This function is threadsafe and does no blocking I/O. - * - * Return value: TRUE if the thumbnail has the right @uri and @mtime - * - * Since: 2.2 - **/ -gboolean -gnome_desktop_thumbnail_is_valid (GdkPixbuf *pixbuf, - const char *uri, - time_t mtime) -{ - const char *thumb_uri, *thumb_mtime_str; - time_t thumb_mtime; - - thumb_uri = gdk_pixbuf_get_option (pixbuf, "tEXt::Thumb::URI"); - if (g_strcmp0 (uri, thumb_uri) != 0) - return FALSE; - - thumb_mtime_str = gdk_pixbuf_get_option (pixbuf, "tEXt::Thumb::MTime"); - if (!thumb_mtime_str) - return FALSE; - thumb_mtime = atol (thumb_mtime_str); - if (mtime != thumb_mtime) - return FALSE; - - return TRUE; -} diff --git a/src/gnome-desktop/gnome-desktop-thumbnail.h b/src/gnome-desktop/gnome-desktop-thumbnail.h deleted file mode 100644 index 186534ff3..000000000 --- a/src/gnome-desktop/gnome-desktop-thumbnail.h +++ /dev/null @@ -1,102 +0,0 @@ -/* - * gnome-thumbnail.h: Utilities for handling thumbnails - * - * Copyright (C) 2002 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. - * - * Author: Alexander Larsson <alexl@redhat.com> - */ - -#ifndef GNOME_DESKTOP_THUMBNAIL_H -#define GNOME_DESKTOP_THUMBNAIL_H - -#ifndef GNOME_DESKTOP_USE_UNSTABLE_API -#error GnomeDesktopThumbnail is unstable API. You must define GNOME_DESKTOP_USE_UNSTABLE_API before including gnome-desktop-thumbnail.h -#endif - -#include <glib.h> -#include <glib-object.h> -#include <time.h> -#include <gdk-pixbuf/gdk-pixbuf.h> - -G_BEGIN_DECLS - -typedef enum { - GNOME_DESKTOP_THUMBNAIL_SIZE_NORMAL, - GNOME_DESKTOP_THUMBNAIL_SIZE_LARGE -} GnomeDesktopThumbnailSize; - -#define GNOME_DESKTOP_TYPE_THUMBNAIL_FACTORY (gnome_desktop_thumbnail_factory_get_type ()) -#define GNOME_DESKTOP_THUMBNAIL_FACTORY(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GNOME_DESKTOP_TYPE_THUMBNAIL_FACTORY, GnomeDesktopThumbnailFactory)) -#define GNOME_DESKTOP_THUMBNAIL_FACTORY_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GNOME_DESKTOP_TYPE_THUMBNAIL_FACTORY, GnomeDesktopThumbnailFactoryClass)) -#define GNOME_DESKTOP_IS_THUMBNAIL_FACTORY(obj) (G_TYPE_INSTANCE_CHECK_TYPE ((obj), GNOME_DESKTOP_TYPE_THUMBNAIL_FACTORY)) -#define GNOME_DESKTOP_IS_THUMBNAIL_FACTORY_CLASS(klass) (G_TYPE_CLASS_CHECK_CLASS_TYPE ((klass), GNOME_DESKTOP_TYPE_THUMBNAIL_FACTORY)) - -typedef struct _GnomeDesktopThumbnailFactory GnomeDesktopThumbnailFactory; -typedef struct _GnomeDesktopThumbnailFactoryClass GnomeDesktopThumbnailFactoryClass; -typedef struct _GnomeDesktopThumbnailFactoryPrivate GnomeDesktopThumbnailFactoryPrivate; - -struct _GnomeDesktopThumbnailFactory { - GObject parent; - - GnomeDesktopThumbnailFactoryPrivate *priv; -}; - -struct _GnomeDesktopThumbnailFactoryClass { - GObjectClass parent; -}; - -G_DEFINE_AUTOPTR_CLEANUP_FUNC(GnomeDesktopThumbnailFactory, g_object_unref) - -GType gnome_desktop_thumbnail_factory_get_type (void); -GnomeDesktopThumbnailFactory *gnome_desktop_thumbnail_factory_new (GnomeDesktopThumbnailSize size); - -char * gnome_desktop_thumbnail_factory_lookup (GnomeDesktopThumbnailFactory *factory, - const char *uri, - time_t mtime); - -gboolean gnome_desktop_thumbnail_factory_has_valid_failed_thumbnail (GnomeDesktopThumbnailFactory *factory, - const char *uri, - time_t mtime); -gboolean gnome_desktop_thumbnail_factory_can_thumbnail (GnomeDesktopThumbnailFactory *factory, - const char *uri, - const char *mime_type, - time_t mtime); -GdkPixbuf * gnome_desktop_thumbnail_factory_generate_thumbnail (GnomeDesktopThumbnailFactory *factory, - const char *uri, - const char *mime_type); -void gnome_desktop_thumbnail_factory_save_thumbnail (GnomeDesktopThumbnailFactory *factory, - GdkPixbuf *thumbnail, - const char *uri, - time_t original_mtime); -void gnome_desktop_thumbnail_factory_create_failed_thumbnail (GnomeDesktopThumbnailFactory *factory, - const char *uri, - time_t mtime); - - -/* Thumbnailing utils: */ -gboolean gnome_desktop_thumbnail_is_valid (GdkPixbuf *pixbuf, - const char *uri, - time_t mtime); -char * gnome_desktop_thumbnail_path_for_uri (const char *uri, - GnomeDesktopThumbnailSize size); - -G_END_DECLS - -#endif /* GNOME_DESKTOP_THUMBNAIL_H */ diff --git a/src/gnome-desktop/gnome-desktop-update.sh b/src/gnome-desktop/gnome-desktop-update.sh deleted file mode 100755 index f31724ca8..000000000 --- a/src/gnome-desktop/gnome-desktop-update.sh +++ /dev/null @@ -1,45 +0,0 @@ -#!/bin/sh -# -# gnome-desktop-update.sh -# -# Fetch the latest master gnome-desktop-thumbnail source code from the -# gnome-desktop project https://gitlab.gnome.org/GNOME/gnome-desktop -# -# The Nautilus gnome-desktop thumbnail code directly tracks the gnome-desktop -# repository. There is typically no need to modify the received files. -# -# Usage: -# -# Execute the script within the nautilus/src/gnome-desktop directory. -# For example: -# -# $ cd src/gnome-desktop -# $ ./gnome-desktop-update.sh -# - -URL=https://gitlab.gnome.org/GNOME/gnome-desktop/raw/master/libgnome-desktop/ -FILES=( - "gnome-desktop-thumbnail.c" - "gnome-desktop-thumbnail.h" - "gnome-desktop-thumbnail-script.c" - "gnome-desktop-thumbnail-script.h" -) -r=0 - -for f in ${FILES[@]}; do - echo "GET: $URL$f" - if curl -sfO $URL$f; then - echo " OK: $f" - else - echo "ERR: $f download error." - r=1 - fi; -done - -if [ $r -eq 0 ]; then - echo "SUCCESS: All updates completed successfully." -else - echo "WARNING: One or more updates encountered an error." -fi; - -exit $r
\ No newline at end of file diff --git a/src/meson.build b/src/meson.build index 91c0a00c8..86d062161 100644 --- a/src/meson.build +++ b/src/meson.build @@ -53,10 +53,6 @@ libnautilus_sources = [ 'animation/ide-box-theatric.h', 'animation/ide-cairo.c', 'animation/ide-cairo.h', - 'gnome-desktop/gnome-desktop-thumbnail.c', - 'gnome-desktop/gnome-desktop-thumbnail.h', - 'gnome-desktop/gnome-desktop-thumbnail-script.c', - 'gnome-desktop/gnome-desktop-thumbnail-script.h', 'gtk/nautilusgtkplacesview.c', 'gtk/nautilusgtkplacesviewprivate.h', 'gtk/nautilusgtkplacesviewrow.c', @@ -277,10 +273,9 @@ nautilus_deps = [ gio_unix, gmodule, gnome_autoar, - gsettings_desktop_schemas, + gnome_desktop, libgd_dep, nautilus_extension, - seccomp, selinux, tracker_sparql, xml diff --git a/src/nautilus-properties-window.c b/src/nautilus-properties-window.c index 464a131ca..9d9bd1c54 100644 --- a/src/nautilus-properties-window.c +++ b/src/nautilus-properties-window.c @@ -34,7 +34,7 @@ #include <sys/stat.h> #define GNOME_DESKTOP_USE_UNSTABLE_API -#include "gnome-desktop/gnome-desktop-thumbnail.h" +#include <libgnome-desktop/gnome-desktop-thumbnail.h> #include "nautilus-enums.h" #include "nautilus-error-reporting.h" diff --git a/src/nautilus-thumbnails.c b/src/nautilus-thumbnails.c index b90dc0daa..991bfb6f6 100644 --- a/src/nautilus-thumbnails.c +++ b/src/nautilus-thumbnails.c @@ -40,7 +40,7 @@ #include <sys/wait.h> #include <unistd.h> #include <signal.h> -#include "gnome-desktop/gnome-desktop-thumbnail.h" +#include <libgnome-desktop/gnome-desktop-thumbnail.h> #define DEBUG_FLAG NAUTILUS_DEBUG_THUMBNAILS #include "nautilus-debug.h" |