[Xfce4-commits] <tumbler:master> Add config file system to control thumbnailing plugin.
Nick Schermer
noreply at xfce.org
Thu Dec 27 11:30:12 CET 2012
Updating branch refs/heads/master
to 8913e999caed579d62b0021f32db6dfef65ff7f4 (commit)
from f7a3eda07ec55d43f92dd2ebbe717cb5c1ddd81c (commit)
commit 8913e999caed579d62b0021f32db6dfef65ff7f4
Author: Nick Schermer <nick at 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
More information about the Xfce4-commits
mailing list