Updating branch refs/heads/master to 8913e999caed579d62b0021f32db6dfef65ff7f4 (commit) from f7a3eda07ec55d43f92dd2ebbe717cb5c1ddd81c (commit)
commit 8913e999caed579d62b0021f32db6dfef65ff7f4 Author: Nick Schermer <n...@xfce.org> Date: Sun Dec 16 15:30:09 2012 +0100 Add config file system to control thumbnailing plugin. Settings that allow to change the plugin priority, max file size to act on, white-listed locations or completely disable them. configure.ac | 4 +- .../cover-thumbnailer/cover-thumbnailer-provider.c | 81 ++------- plugins/cover-thumbnailer/cover-thumbnailer.c | 92 +--------- tumbler/tumbler-abstract-thumbnailer.c | 48 +++++ tumbler/tumbler-provider-factory.c | 28 +++- tumbler/tumbler-thumbnailer.c | 74 ++++++++- tumbler/tumbler-thumbnailer.h | 5 + tumbler/tumbler-util.c | 55 ++++++ tumbler/tumbler-util.h | 2 + tumblerd/Makefile.am | 5 + tumblerd/main.c | 191 ++++++++++++++++++++ tumblerd/tumbler-registry.c | 81 +++++++-- tumblerd/tumbler.rc | 95 ++++++++++ 13 files changed, 594 insertions(+), 167 deletions(-) diff --git a/configure.ac b/configure.ac index 80163e1..fea0484 100644 --- a/configure.ac +++ b/configure.ac @@ -108,13 +108,13 @@ dnl *************************************** AC_HEADER_STDC() AC_CHECK_HEADERS([fcntl.h linux/sched.h memory.h sched.h setjmp.h stdio.h \ stdlib.h string.h syscall.h sys/mman.h sys/types.h \ - sys/stat.h unistd.h sys/select.h]) + sys/stat.h unistd.h sys/select.h pwd.h]) dnl ************************************ dnl *** Check for standard functions *** dnl ************************************ AC_FUNC_MMAP() -AC_CHECK_FUNCS([sched_getparam sched_setscheduler]) +AC_CHECK_FUNCS([sched_getparam sched_setscheduler getpwnam]) dnl ****************************** dnl *** Check for i18n support *** diff --git a/plugins/cover-thumbnailer/cover-thumbnailer-provider.c b/plugins/cover-thumbnailer/cover-thumbnailer-provider.c index b29858c..d646dee 100644 --- a/plugins/cover-thumbnailer/cover-thumbnailer-provider.c +++ b/plugins/cover-thumbnailer/cover-thumbnailer-provider.c @@ -49,12 +49,6 @@ struct _CoverThumbnailerProviderClass struct _CoverThumbnailerProvider { GObject __parent__; - - /* for themoviedb metadata */ - gchar *api_key; - - /* allowed locations */ - gchar **locations; }; @@ -105,22 +99,8 @@ cover_thumbnailer_provider_thumbnailer_provider_init (TumblerThumbnailerProvider static void cover_thumbnailer_provider_init (CoverThumbnailerProvider *provider) { - GKeyFile *keyfile; - gchar *config_dir; - - config_dir = g_build_filename (g_get_user_config_dir (), "tumbler", "cover.rc", NULL); - keyfile = g_key_file_new (); - if (g_key_file_load_from_file (keyfile, config_dir, G_KEY_FILE_NONE, NULL)) - { - provider->api_key = g_key_file_get_string (keyfile, "TheMovieDB", "API-key", NULL); - provider->locations = g_key_file_get_string_list (keyfile, "General", "Locations", NULL, NULL); - } - g_key_file_free (keyfile); - g_free (config_dir); - /* curl */ - if (provider->locations != NULL) - curl_global_init (CURL_GLOBAL_ALL); + curl_global_init (CURL_GLOBAL_ALL); } @@ -128,14 +108,8 @@ cover_thumbnailer_provider_init (CoverThumbnailerProvider *provider) static void cover_thumbnailer_provider_finalize (GObject *object) { - CoverThumbnailerProvider *provider = COVER_THUMBNAILER_PROVIDER (object); - - g_free (provider->api_key); - g_strfreev (provider->locations); - /* curl */ - if (provider->locations != NULL) - curl_global_cleanup (); + curl_global_cleanup (); (*G_OBJECT_CLASS (cover_thumbnailer_provider_parent_class)->finalize) (object); } @@ -145,11 +119,10 @@ cover_thumbnailer_provider_finalize (GObject *object) static GList * cover_thumbnailer_provider_get_thumbnailers (TumblerThumbnailerProvider *provider) { - CoverThumbnailerProvider *cover = COVER_THUMBNAILER_PROVIDER (provider); - CoverThumbnailer *thumbnailer; - GList *thumbnailers = NULL; - GStrv uri_schemes; - static const gchar *mime_types[] = + CoverThumbnailer *thumbnailer; + GList *thumbnailers = NULL; + GStrv uri_schemes; + static const gchar *mime_types[] = { "video/divx", "video/jpeg", @@ -167,34 +140,20 @@ cover_thumbnailer_provider_get_thumbnailers (TumblerThumbnailerProvider *provide NULL }; - if (cover->locations != NULL) - { - /* determine the URI schemes supported by GIO */ - uri_schemes = tumbler_util_get_supported_uri_schemes (); - - /* create the pixbuf thumbnailer */ - thumbnailer = g_object_new (TYPE_COVER_THUMBNAILER, - "uri-schemes", uri_schemes, - "mime-types", mime_types, - "locations", cover->locations, - "api-key", cover->api_key, - NULL); - - /* add the thumbnailer to the list */ - thumbnailers = g_list_append (thumbnailers, thumbnailer); - - /* free URI schemes */ - g_strfreev (uri_schemes); - } - else - { - g_print ("\n"); - g_print (_("Cover thumbnailer is disabled because there are no " - "locations white-listed in the config file. See " - "%s for more information."), - "http://docs.xfce.org/xfce/thunar/tumbler"); - g_print ("\n\n"); - } + /* determine the URI schemes supported by GIO */ + uri_schemes = tumbler_util_get_supported_uri_schemes (); + + /* create the pixbuf thumbnailer */ + thumbnailer = g_object_new (TYPE_COVER_THUMBNAILER, + "uri-schemes", uri_schemes, + "mime-types", mime_types, + NULL); + + /* add the thumbnailer to the list */ + thumbnailers = g_list_append (thumbnailers, thumbnailer); + + /* free URI schemes */ + g_strfreev (uri_schemes); return thumbnailers; } diff --git a/plugins/cover-thumbnailer/cover-thumbnailer.c b/plugins/cover-thumbnailer/cover-thumbnailer.c index 14a70ff..cb3d708 100644 --- a/plugins/cover-thumbnailer/cover-thumbnailer.c +++ b/plugins/cover-thumbnailer/cover-thumbnailer.c @@ -54,10 +54,6 @@ static void cover_thumbnailer_finalize (GObject *object); -static void cover_thumbnailer_set_property (GObject *object, - guint prop_id, - const GValue *value, - GParamSpec *pspec); static void cover_thumbnailer_create (TumblerAbstractThumbnailer *thumbnailer, GCancellable *cancellable, TumblerFileInfo *info); @@ -76,9 +72,6 @@ struct _CoverThumbnailer /* themoviedb api key */ gchar *api_key; - /* whitelisted locations */ - GSList *locations; - /* precompiled */ GRegex *series_regex; GRegex *abbrev_regex; @@ -88,13 +81,6 @@ struct _CoverThumbnailer CURLM *curl_multi; }; -enum -{ - PROP_0, - PROP_LOCATIONS, - PROP_API_KEY -}; - G_DEFINE_DYNAMIC_TYPE (CoverThumbnailer, @@ -122,25 +108,6 @@ cover_thumbnailer_class_init (CoverThumbnailerClass *klass) gobject_class = G_OBJECT_CLASS (klass); gobject_class->finalize = cover_thumbnailer_finalize; - gobject_class->set_property = cover_thumbnailer_set_property; - - g_object_class_install_property (gobject_class, - PROP_LOCATIONS, - g_param_spec_boxed ("locations", - "locations", - "locations", - G_TYPE_STRV, - G_PARAM_CONSTRUCT_ONLY | - G_PARAM_WRITABLE)); - - g_object_class_install_property (gobject_class, - PROP_API_KEY, - g_param_spec_string ("api-key", - "api-key", - "api-key", - NULL, - G_PARAM_CONSTRUCT_ONLY | - G_PARAM_WRITABLE)); } @@ -155,6 +122,8 @@ cover_thumbnailer_class_finalize (CoverThumbnailerClass *klass) static void cover_thumbnailer_init (CoverThumbnailer *thumbnailer) { + GKeyFile *rc; + /* prepare the regular expressions */ thumbnailer->series_regex = g_regex_new (SERIES_PATTERN, G_REGEX_CASELESS, 0, NULL); thumbnailer->abbrev_regex = g_regex_new (ABBREV_PATTERN, G_REGEX_CASELESS, 0, NULL); @@ -162,41 +131,11 @@ cover_thumbnailer_init (CoverThumbnailer *thumbnailer) /* curl dns share */ thumbnailer->curl_multi = curl_multi_init (); -} - - - -static void -cover_thumbnailer_set_property (GObject *object, - guint prop_id, - const GValue *value, - GParamSpec *pspec) -{ - CoverThumbnailer *cover = COVER_THUMBNAILER (object); - guint i; - const gchar * const *locations; - GFile *gfile; - switch (prop_id) - { - case PROP_API_KEY: - cover->api_key = g_value_dup_string (value); - break; - - case PROP_LOCATIONS: - locations = g_value_get_boxed (value); - g_assert (locations != NULL); - for (i = 0; locations[i] != NULL; i++) - { - gfile = g_file_new_for_commandline_arg (locations[i]); - cover->locations = g_slist_prepend (cover->locations, gfile); - } - break; - - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); - break; - } + /* read the api key */ + rc = tumbler_util_get_settings (); + thumbnailer->api_key = g_key_file_get_string (rc, G_OBJECT_TYPE_NAME (thumbnailer), "APIKey", NULL); + g_key_file_free (rc); } @@ -213,9 +152,6 @@ cover_thumbnailer_finalize (GObject *object) g_free (cover->api_key); - g_slist_foreach (cover->locations, (GFunc) g_object_unref, NULL); - g_slist_free (cover->locations); - curl_multi_cleanup (cover->curl_multi); (*G_OBJECT_CLASS (cover_thumbnailer_parent_class)->finalize) (object); @@ -718,27 +654,11 @@ cover_thumbnailer_create (TumblerAbstractThumbnailer *thumbnailer, TumblerImageData data; TumblerThumbnailFlavor *flavor; GFile *gfile; - GSList *lp; /* source file */ uri = tumbler_file_info_get_uri (info); gfile = g_file_new_for_uri (uri); - /* check if file is in allowed destinations */ - for (lp = cover->locations; lp != NULL; lp = lp->next) - if (g_file_has_prefix (gfile, lp->data)) - break; - - if (lp == NULL) - { - /* location not white-listed */ - g_object_unref (gfile); - g_signal_emit_by_name (thumbnailer, "error", uri, - TUMBLER_ERROR_UNSUPPORTED, - _("Location is not whitelisted in rc file")); - return; - } - /* target data */ thumbnail = tumbler_file_info_get_thumbnail (info); flavor = tumbler_thumbnail_get_flavor (thumbnail); diff --git a/tumbler/tumbler-abstract-thumbnailer.c b/tumbler/tumbler-abstract-thumbnailer.c index ea05c0f..0bb2649 100644 --- a/tumbler/tumbler-abstract-thumbnailer.c +++ b/tumbler/tumbler-abstract-thumbnailer.c @@ -42,6 +42,9 @@ enum PROP_URI_SCHEMES, PROP_MIME_TYPES, PROP_HASH_KEYS, + PROP_PRIORITY, + PROP_MAX_FILE_SIZE, + PROP_LOCATIONS }; @@ -68,6 +71,9 @@ struct _TumblerAbstractThumbnailerPrivate gchar **hash_keys; gchar **mime_types; gchar **uri_schemes; + gint priority; + gint64 max_file_size; + GSList *locations; }; @@ -97,6 +103,9 @@ tumbler_abstract_thumbnailer_class_init (TumblerAbstractThumbnailerClass *klass) g_object_class_override_property (gobject_class, PROP_MIME_TYPES, "mime-types"); g_object_class_override_property (gobject_class, PROP_URI_SCHEMES, "uri-schemes"); g_object_class_override_property (gobject_class, PROP_HASH_KEYS, "hash-keys"); + g_object_class_override_property (gobject_class, PROP_PRIORITY, "priority"); + g_object_class_override_property (gobject_class, PROP_MAX_FILE_SIZE, "max-file-size"); + g_object_class_override_property (gobject_class, PROP_LOCATIONS, "locations"); } @@ -173,6 +182,9 @@ tumbler_abstract_thumbnailer_finalize (GObject *object) g_strfreev (thumbnailer->priv->mime_types); g_strfreev (thumbnailer->priv->uri_schemes); + g_slist_foreach (thumbnailer->priv->locations, (GFunc) g_object_unref, NULL); + g_slist_free (thumbnailer->priv->locations); + (*G_OBJECT_CLASS (tumbler_abstract_thumbnailer_parent_class)->finalize) (object); } @@ -185,18 +197,36 @@ tumbler_abstract_thumbnailer_get_property (GObject *object, GParamSpec *pspec) { TumblerAbstractThumbnailer *thumbnailer = TUMBLER_ABSTRACT_THUMBNAILER (object); + GSList *dup; switch (prop_id) { case PROP_MIME_TYPES: g_value_set_pointer (value, g_strdupv (thumbnailer->priv->mime_types)); break; + case PROP_URI_SCHEMES: g_value_set_pointer (value, g_strdupv (thumbnailer->priv->uri_schemes)); break; + case PROP_HASH_KEYS: g_value_set_pointer (value, g_strdupv (thumbnailer->priv->hash_keys)); break; + + case PROP_PRIORITY: + g_value_set_int (value, thumbnailer->priv->priority); + break; + + case PROP_MAX_FILE_SIZE: + g_value_set_int64 (value, thumbnailer->priv->max_file_size); + break; + + case PROP_LOCATIONS: + dup = g_slist_copy (thumbnailer->priv->locations); + g_slist_foreach (dup, (GFunc) g_object_ref, NULL); + g_value_set_pointer (value, dup); + break; + default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; @@ -212,18 +242,36 @@ tumbler_abstract_thumbnailer_set_property (GObject *object, GParamSpec *pspec) { TumblerAbstractThumbnailer *thumbnailer = TUMBLER_ABSTRACT_THUMBNAILER (object); + GSList *dup; switch (prop_id) { case PROP_MIME_TYPES: thumbnailer->priv->mime_types = g_strdupv (g_value_get_pointer (value)); break; + case PROP_URI_SCHEMES: thumbnailer->priv->uri_schemes = g_strdupv (g_value_get_pointer (value)); break; + case PROP_HASH_KEYS: thumbnailer->priv->hash_keys = g_strdupv (g_value_get_pointer (value)); break; + + case PROP_PRIORITY: + thumbnailer->priv->priority = g_value_get_int (value); + break; + + case PROP_MAX_FILE_SIZE: + thumbnailer->priv->max_file_size = g_value_get_int64 (value); + break; + + case PROP_LOCATIONS: + dup = g_slist_copy (g_value_get_pointer (value)); + g_slist_foreach (dup, (GFunc) g_object_ref, NULL); + thumbnailer->priv->locations = dup; + break; + default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; diff --git a/tumbler/tumbler-provider-factory.c b/tumbler/tumbler-provider-factory.c index afa47e3..5c67147 100644 --- a/tumbler/tumbler-provider-factory.c +++ b/tumbler/tumbler-provider-factory.c @@ -22,11 +22,16 @@ #include <config.h> #endif +#ifdef HAVE_STRING_H +#include <string.h> +#endif + #include <glib.h> #include <glib-object.h> #include <tumbler/tumbler-provider-factory.h> #include <tumbler/tumbler-provider-plugin.h> +#include <tumbler/tumbler-util.h> @@ -253,17 +258,34 @@ tumbler_provider_factory_get_providers (TumblerProviderFactory *factory, GList *plugins; GList *providers = NULL; guint n; + const gchar *type_name; + gchar *name; + gboolean disabled; + GKeyFile *rc; G_LOCK (factory_lock); /* load available plugins */ plugins = tumbler_provider_factory_load_plugins (factory); + /* rc file */ + rc = tumbler_util_get_settings (); + /* iterate over all provider infos */ for (n = 0; n < factory->provider_infos->len; ++n) { info = factory->provider_infos->pdata[n]; + /* check if this plugin is disabled with the assumption + * the provider only provides 1 type */ + type_name = g_type_name (info->type); + g_assert (g_str_has_suffix (type_name, "Provider")); + name = g_strndup (type_name, strlen (type_name) - 8); + disabled = g_key_file_get_boolean (rc, name, "Disabled", NULL); + g_free (name); + if (disabled) + continue; + /* check if the provider type implements the given type */ if (G_LIKELY (g_type_is_a (info->type, type))) { @@ -271,8 +293,8 @@ tumbler_provider_factory_get_providers (TumblerProviderFactory *factory, if (info->provider == NULL) info->provider = g_object_new (info->type, NULL); - /* append the provider to the list */ - providers = g_list_append (providers, g_object_ref (info->provider)); + /* add the provider to the list */ + providers = g_list_prepend (providers, g_object_ref (info->provider)); } } @@ -281,6 +303,8 @@ tumbler_provider_factory_get_providers (TumblerProviderFactory *factory, g_type_module_unuse (G_TYPE_MODULE (lp->data)); g_list_free (plugins); + g_key_file_free (rc); + G_UNLOCK (factory_lock); return providers; diff --git a/tumbler/tumbler-thumbnailer.c b/tumbler/tumbler-thumbnailer.c index 4c4d928..14e2b71 100644 --- a/tumbler/tumbler-thumbnailer.c +++ b/tumbler/tumbler-thumbnailer.c @@ -94,7 +94,28 @@ tumbler_thumbnailer_class_init (TumblerThumbnailerIface *klass) g_param_spec_pointer ("hash-keys", "hash-keys", "hash-keys", - G_PARAM_READABLE)); + G_PARAM_CONSTRUCT_ONLY | + G_PARAM_READWRITE)); + + g_object_interface_install_property (klass, + g_param_spec_int ("priority", + "priority", + "priority", + 0, G_MAXINT, 0, + G_PARAM_READWRITE)); + + g_object_interface_install_property (klass, + g_param_spec_int64 ("max-file-size", + "max-file-size", + "max-file-size", + 0, G_MAXINT64, 0, + G_PARAM_READWRITE)); + + g_object_interface_install_property (klass, + g_param_spec_pointer ("locations", + "locations", + "locations", + G_PARAM_READWRITE)); tumbler_thumbnailer_signals[SIGNAL_READY] = g_signal_new ("ready", @@ -191,6 +212,57 @@ tumbler_thumbnailer_get_uri_schemes (TumblerThumbnailer *thumbnailer) +gint +tumbler_thumbnailer_get_priority (TumblerThumbnailer *thumbnailer) +{ + gint priority; + + g_return_val_if_fail (TUMBLER_IS_THUMBNAILER (thumbnailer), 0); + + g_object_get (thumbnailer, "priority", &priority, NULL); + return priority; +} + + + +gint64 +tumbler_thumbnailer_get_max_file_size (TumblerThumbnailer *thumbnailer) +{ + gint max_file_size; + + g_return_val_if_fail (TUMBLER_IS_THUMBNAILER (thumbnailer), 0); + + g_object_get (thumbnailer, "max-file-size", &max_file_size, NULL); + return max_file_size; +} + + + +gboolean +tumbler_thumbnailer_supports_location (TumblerThumbnailer *thumbnailer, + GFile *file) +{ + GSList *locations, *lp; + gboolean supported = FALSE; + + /* we're cool if no locations are set */ + g_object_get (thumbnailer, "locations", &locations, NULL); + if (locations == NULL) + return TRUE; + + /*check if the prefix is supported */ + for (lp = locations; !supported && lp != NULL; lp = lp->next) + if (g_file_has_prefix (file, G_FILE (lp->data))) + supported = TRUE; + + g_slist_foreach (locations, (GFunc) g_object_unref, NULL); + g_slist_free (locations); + + return supported; +} + + + gboolean tumbler_thumbnailer_supports_hash_key (TumblerThumbnailer *thumbnailer, const gchar *hash_key) diff --git a/tumbler/tumbler-thumbnailer.h b/tumbler/tumbler-thumbnailer.h index 00abbbb..313e404 100644 --- a/tumbler/tumbler-thumbnailer.h +++ b/tumbler/tumbler-thumbnailer.h @@ -68,6 +68,11 @@ void tumbler_thumbnailer_create (TumblerThumbnailer gchar **tumbler_thumbnailer_get_hash_keys (TumblerThumbnailer *thumbnailer); gchar **tumbler_thumbnailer_get_mime_types (TumblerThumbnailer *thumbnailer); gchar **tumbler_thumbnailer_get_uri_schemes (TumblerThumbnailer *thumbnailer); +gint tumbler_thumbnailer_get_priority (TumblerThumbnailer *thumbnailer); +gint64 tumbler_thumbnailer_get_max_file_size (TumblerThumbnailer *thumbnailer); + +gboolean tumbler_thumbnailer_supports_location (TumblerThumbnailer *thumbnailer, + GFile *file); gboolean tumbler_thumbnailer_supports_hash_key (TumblerThumbnailer *thumbnailer, const gchar *hash_key); diff --git a/tumbler/tumbler-util.c b/tumbler/tumbler-util.c index bb36be4..9d656d5 100644 --- a/tumbler/tumbler-util.c +++ b/tumbler/tumbler-util.c @@ -75,3 +75,58 @@ tumbler_util_get_supported_uri_schemes (void) return uri_schemes; } + + +static gchar * +tumbler_util_get_settings_filename (void) +{ + gchar *path; + const gchar filename[] = "tumbler" G_DIR_SEPARATOR_S "tumbler.rc"; + const gchar * const *dirs; + guint n; + + /* check user directory */ + path = g_build_filename (g_get_user_config_dir (), filename, NULL); + if (g_file_test (path, G_FILE_TEST_IS_REGULAR)) + return path; + g_free (path); + + dirs = g_get_system_config_dirs (); + if (G_UNLIKELY (dirs == NULL)) + return FALSE; + + /* look in system config dirs */ + for (n = 0; dirs[n] != NULL; n++) + { + path = g_build_filename (dirs[n], filename, NULL); + if (g_file_test (path, G_FILE_TEST_IS_REGULAR)) + return path; + g_free (path); + } + + return NULL; +} + + + +GKeyFile * +tumbler_util_get_settings (void) +{ + GKeyFile *settings; + GError *err = NULL; + gchar *filename; + + settings = g_key_file_new (); + filename = tumbler_util_get_settings_filename (); + + if (filename != NULL + && !g_key_file_load_from_file (settings, filename, 0, &err)) + { + g_critical ("Unable to load settings from \"%s\": %s", filename, err->message); + g_error_free (err); + } + + g_free (filename); + + return settings; +} diff --git a/tumbler/tumbler-util.h b/tumbler/tumbler-util.h index eeba4d1..b68db0a 100644 --- a/tumbler/tumbler-util.h +++ b/tumbler/tumbler-util.h @@ -27,6 +27,8 @@ G_BEGIN_DECLS gchar **tumbler_util_get_supported_uri_schemes (void) G_GNUC_MALLOC; +GKeyFile *tumbler_util_get_settings (void) G_GNUC_MALLOC; + G_END_DECLS #endif /* !__TUMBLER_UTIL_H__ */ diff --git a/tumblerd/Makefile.am b/tumblerd/Makefile.am index e25a34d..6dfd249 100644 --- a/tumblerd/Makefile.am +++ b/tumblerd/Makefile.am @@ -94,11 +94,16 @@ service_DATA = $(service_in_files:.service.in=.service) sed -e "s,\@libdir\@,$(libdir),g" \ -e "s,\@TUMBLER_VERSION_API\@,$(TUMBLER_VERSION_API),g" < $< > $@ +confdir = $(sysconfdir)/xdg/tumbler +conf_DATA = \ + tumbler.rc + CLEANFILES = \ $(service_DATA) EXTRA_DIST = \ $(service_in_files) \ + tumbler.rc \ tumbler-cache-service-dbus.xml \ tumbler-manager-dbus.xml \ tumbler-service-dbus.xml diff --git a/tumblerd/main.c b/tumblerd/main.c index 046c13f..1a7face 100644 --- a/tumblerd/main.c +++ b/tumblerd/main.c @@ -22,6 +22,13 @@ #include <config.h> #endif +#ifdef HAVE_SYS_TYPES_H +#include <sys/types.h> +#endif +#ifdef HAVE_PWD_H +#include <pwd.h> +#endif + #include <stdlib.h> #include <glib.h> @@ -53,6 +60,159 @@ shutdown_tumbler (TumblerLifecycleManager *lifecycle_manager, +static inline gboolean +xfce_is_valid_tilde_prefix (const gchar *p) +{ + if (g_ascii_isspace (*p) /* thunar ~/music */ + || *p == '=' /* terminal --working-directory=~/ */ + || *p == '\'' || *p == '"') /* terminal --working-directory '~my music' */ + return TRUE; + + return FALSE; +} + + +/* from libxfce4util */ +static gchar * +xfce_expand_variables (const gchar *command, + gchar **envp) +{ + GString *buf; + const gchar *start; + gchar *variable; + const gchar *p; + const gchar *value; + gchar **ep; + guint len; +#ifdef HAVE_GETPWNAM + struct passwd *pw; + gchar *username; +#endif + + if (G_UNLIKELY (command == NULL)) + return NULL; + + buf = g_string_sized_new (strlen (command)); + + for (p = command; *p != '\0'; ++p) + { + continue_without_increase: + + if (*p == '~' + && (p == command + || xfce_is_valid_tilde_prefix (p - 1))) + { + /* walk to the end of the string or to a directory separator */ + for (start = ++p; *p != '\0' && *p != G_DIR_SEPARATOR; ++p); + + if (G_LIKELY (start == p)) + { + /* add the current user directory */ + buf = g_string_append (buf, g_get_home_dir ()); + } + else + { +#ifdef HAVE_GETPWNAM + username = g_strndup (start, p - start); + pw = getpwnam (username); + g_free (username); + + /* add the users' home directory if found, fallback to the + * not-expanded string */ + if (pw != NULL && pw->pw_dir != NULL) + buf = g_string_append (buf, pw->pw_dir); + else +#endif + buf = g_string_append_len (buf, start - 1, p - start + 1); + } + + /* we are either at the end of the string or *p is a separator, + * so continue to add it to the result buffer */ + } + else if (*p == '$') + { + /* walk to the end of a valid variable name */ + for (start = ++p; *p != '\0' && (g_ascii_isalnum (*p) || *p == '_'); ++p); + + if (start < p) + { + value = NULL; + len = p - start; + + /* lookup the variable in the environment supplied by the user */ + if (envp != NULL) + { + /* format is NAME=VALUE */ + for (ep = envp; *ep != NULL; ++ep) + if (strncmp (*ep, start, len) == 0 + && (*ep)[len] == '=') + { + value = (*ep) + len + 1; + break; + } + } + + /* fallback to the environment */ + if (value == NULL) + { + variable = g_strndup (start, len); + value = g_getenv (variable); + g_free (variable); + } + + if (G_LIKELY (value != NULL)) + { + buf = g_string_append (buf, value); + } + else + { + /* the variable name was valid, but no value was + * found, insert nothing and continue */ + } + + /* *p is at the start of the charater after the variable, + * so continue scanning without advancing the string offset + * so two variables are replaced properly */ + goto continue_without_increase; + } + else + { + /* invalid variable format, add the + * $ character and continue */ + --p; + } + } + + buf = g_string_append_c (buf, *p); + } + + return g_string_free (buf, FALSE); +} + + + +static GSList * +locations_from_strv (gchar **array) +{ + GSList *locations = NULL; + guint n; + gchar *path; + + if (array == NULL) + return NULL; + + for (n = 0; array[n] != NULL; n++) + { + path = xfce_expand_variables (array[n], NULL); + locations = g_slist_prepend (locations, g_file_new_for_commandline_arg (path)); + g_free (path); + } + + return locations; +} + + + int main (int argc, char **argv) @@ -71,6 +231,12 @@ main (int argc, GList *lp; GList *tp; gint retval = EXIT_SUCCESS; + GKeyFile *rc; + gint64 file_size; + gint priority; + const gchar *type_name; + gchar **paths; + GSList *locations; /* set the program name */ g_set_prgname (G_LOG_DOMAIN); @@ -120,6 +286,9 @@ main (int argc, providers = tumbler_provider_factory_get_providers (provider_factory, TUMBLER_TYPE_THUMBNAILER_PROVIDER); + /* settings */ + rc = tumbler_util_get_settings (); + /* iterate over all providers */ for (lp = providers; lp != NULL; lp = lp->next) { @@ -129,14 +298,36 @@ main (int argc, /* add all thumbnailers to the registry */ for (tp = thumbnailers; tp != NULL; tp = tp->next) { + /* set settings from rc file */ + type_name = G_OBJECT_TYPE_NAME (tp->data); + priority = g_key_file_get_integer (rc, type_name, "Priority", NULL); + file_size = g_key_file_get_int64 (rc, type_name, "MaxFileSize", NULL); + + paths = g_key_file_get_string_list (rc, type_name, "Locations", NULL, NULL); + locations = locations_from_strv (paths); + g_strfreev (paths); + + g_object_set (G_OBJECT (tp->data), + "priority", priority, + "max-file-size", file_size, + "locations", locations, + NULL); + + /* ready for usage */ tumbler_registry_add (registry, tp->data); + + /* cleanup */ g_object_unref (tp->data); + g_slist_foreach (locations, (GFunc) g_object_unref, NULL); + g_slist_free (locations); } /* free the thumbnailer list */ g_list_free (thumbnailers); } + g_key_file_free (rc); + /* release all providers and free the provider list */ g_list_foreach (providers, (GFunc) g_object_unref, NULL); g_list_free (providers); diff --git a/tumblerd/tumbler-registry.c b/tumblerd/tumbler-registry.c index c75ca61..61739ac 100644 --- a/tumblerd/tumbler-registry.c +++ b/tumblerd/tumbler-registry.c @@ -41,7 +41,7 @@ static void tumbler_registry_list_free (gpointer static GList *tumbler_registry_get_thumbnailers_internal (TumblerRegistry *registry); static gint tumbler_registry_compare (TumblerThumbnailer *a, TumblerThumbnailer *b); -static TumblerThumbnailer *tumbler_registry_lookup (TumblerRegistry *registry, +static GList *tumbler_registry_lookup (TumblerRegistry *registry, const gchar *hash_key); @@ -175,8 +175,8 @@ tumbler_registry_compare (TumblerThumbnailer *a, if (!TUMBLER_IS_SPECIALIZED_THUMBNAILER (a) || !TUMBLER_IS_SPECIALIZED_THUMBNAILER (b)) { - /* plugin thumbnailers are always overriden */ - insert_a_before_b = TRUE; + /* sort by priority */ + insert_a_before_b = tumbler_thumbnailer_get_priority (a) >= tumbler_thumbnailer_get_priority (b); } else if (TUMBLER_IS_SPECIALIZED_THUMBNAILER (b)) { @@ -260,32 +260,50 @@ tumbler_registry_get_thumbnailers_internal (TumblerRegistry *registry) -static TumblerThumbnailer * +static GList * tumbler_registry_lookup (TumblerRegistry *registry, const gchar *hash_key) { TumblerThumbnailer *thumbnailer = NULL; GList **list; - GList *first; + GList *available = NULL; + GList *lp; g_return_val_if_fail (TUMBLER_IS_REGISTRY (registry), NULL); g_return_val_if_fail (hash_key != NULL, NULL); thumbnailer = g_hash_table_lookup (registry->preferred_thumbnailers, hash_key); if (thumbnailer != NULL) - return g_object_ref (thumbnailer); + available = g_list_prepend (available, g_object_ref (thumbnailer)); list = g_hash_table_lookup (registry->thumbnailers, hash_key); - if (list != NULL) { - first = g_list_first (*list); + for (lp = *list; lp != NULL; lp = lp->next) + available = g_list_prepend (available, g_object_ref (lp->data)); + } + + return g_list_reverse (available); +} - if (first != NULL) - thumbnailer = g_object_ref (first->data); + + +static gint64 +tumbler_registry_get_file_size (GFile *gfile) +{ + GFileInfo *file_info; + gint64 size = 0; + + file_info = g_file_query_info (gfile, + G_FILE_ATTRIBUTE_STANDARD_SIZE, + G_FILE_QUERY_INFO_NONE, NULL, NULL); + if (file_info != NULL) + { + size = g_file_info_get_size (file_info); + g_object_unref (file_info); } - return thumbnailer; + return size; } @@ -419,6 +437,10 @@ tumbler_registry_get_thumbnailer_array (TumblerRegistry *registry, gchar *hash_key; gchar *scheme; guint n; + GList *list, *lp; + GFile *gfile; + gint64 file_size; + gint64 max_file_size; g_return_val_if_fail (TUMBLER_IS_REGISTRY (registry), NULL); g_return_val_if_fail (infos != NULL, NULL); @@ -433,17 +455,46 @@ tumbler_registry_get_thumbnailer_array (TumblerRegistry *registry, { tumbler_mutex_lock (registry->mutex); + /* reset */ + file_size = 0; + /* determine the URI scheme and generate a hash key */ - scheme = g_uri_parse_scheme (tumbler_file_info_get_uri (infos[n])); + gfile = g_file_new_for_uri (tumbler_file_info_get_uri (infos[n])); + scheme = g_file_get_uri_scheme (gfile); hash_key = g_strdup_printf ("%s-%s", scheme, tumbler_file_info_get_mime_type (infos[n])); - /* see if we can find a thumbnailer to handle this URI/MIME type pair */ - thumbnailers[n] = tumbler_registry_lookup (registry, hash_key); + /* get list of thumbnailer that can handle this URI/MIME type pair */ + list = tumbler_registry_lookup (registry, hash_key); + for (lp = list; lp != NULL; lp = lp->next) + { + /* check if the file size is a limitation */ + max_file_size = tumbler_thumbnailer_get_max_file_size (lp->data); + if (max_file_size > 0) + { + /* load the source's size on demand */ + if (file_size == 0) + file_size = tumbler_registry_get_file_size (gfile); + if (file_size > max_file_size) + continue; + } + + /* check if the location is supported */ + if (!tumbler_thumbnailer_supports_location (lp->data, gfile)) + continue; + + /* found a usable thumbnailer */ + thumbnailers[n] = g_object_ref (lp->data); + + break; + } - /* free strings */ + /* cleanup */ g_free (hash_key); g_free (scheme); + g_object_unref (gfile); + g_list_foreach (list, (GFunc) g_object_unref, NULL); + g_list_free (list); tumbler_mutex_unlock (registry->mutex); } diff --git a/tumblerd/tumbler.rc b/tumblerd/tumbler.rc new file mode 100644 index 0000000..52e73f3 --- /dev/null +++ b/tumblerd/tumbler.rc @@ -0,0 +1,95 @@ +### +# [TypeNameOfPlugin] +# Disabled: Set to true to avoid loading the plugin. By default all +# plugins are loaded. +# Priority: Priority of the plugin if more plugins support the same +# uri-scheme / mime-type combination. +# Locations: ;-separated path list the plugin will be used in. If the +# source file is not a child of one of the locations, the +# plugin won't be used and another plugin with a lower +# priority will be tried. +# Absolute paths, environement variables, ~/ and ~username/ +# are allowed. Leave empty to allow all locations. +# MaxFileSize: Maximum size of the source file the plugin will still +# try to generate a plugin for. The size is in bytes, +# 0 disabled the check. +### + +### +# Image Thumbnailers +### + +# Jpeg thumbnailer (from exif data if possible) +[JPEGThumbnailer] +Disabled=false +Priority=3 +Locations= +MaxFileSize=0 + +# Supports all type GdkPixbuf supports +[PixbufThumbnailer] +Disabled=false +Priority=2 +Locations= +MaxFileSize=0 + +# RAW image files using libopenraw +[RawThumbnailer] +Disabled=false +Priority=1 +Locations= +MaxFileSize=0 + +### +# Video Thumbnailers +### + +# Download cover from omdbapi.com or themoviedb.org if an +# API key is given. This plugin is disabled because it +# sends your (private) movie names over the internet. +[CoverThumbnailer] +Disabled=true +Priority=3 +Locations=~/movies +MaxFileSize=0 +#APIKey=your-api-key-from-themoviedb.org + +# ffmpegthumbnailer plugin +[FfmegThumbnailer] +Disabled=false +Priority=2 +Locations= +MaxFileSize=0 + +# GStreamer plugin +[GstThumbnailer] +Disabled=false +Priority=1 +Locations= +MaxFileSize=0 + +### +# Other Thumbnailers +### + +# FreeType thumbnailer +[FontThumbnailer] +Disabled=false +Priority=1 +Locations= +MaxFileSize=0 + + +# PDF/PS thumbnailer +[PopplerThumbnailer] +Disabled=false +Priority=1 +Locations= +MaxFileSize=0 + +# Open document thumbnailer (ODF) +[OdfThumbnailer] +Disabled=false +Priority=1 +Locations= +MaxFileSize=0 _______________________________________________ Xfce4-commits mailing list Xfce4-commits@xfce.org https://mail.xfce.org/mailman/listinfo/xfce4-commits