summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJannis Pohlmann <jannis@xfce.org>2009-05-19 01:15:44 +0200
committerJannis Pohlmann <jannis@xfce.org>2009-05-19 01:15:44 +0200
commitc22081e3281b587fbeb920030705ed4ef58e960b (patch)
tree07edebfa644ed87af53f2e65ecdbccf0e0f294e4
parenta66781a82678305cee2566f72cb0ea2c34667871 (diff)
downloadtumbler-c22081e3281b587fbeb920030705ed4ef58e960b.tar.gz
Implement thumbnailer management in TumblerRegistry.
Use a (gchar *) to (GList **) hash table for managing thumbnailers in TumblerRegistry. For each so-called hash key (a combination of an URI scheme and a MIME type, e.g. "file-image/png") we store a list of registered thumbnailers. Only the first thumbnailer in this list will ever be used. The others can move forward in the list when a thumbnailer is unregistered. The order in which thumbnailers are inserted into a list is defined as follows: - thumbnailers registered dynamically over D-Bus go before anything else. The thumbnailer registered latest goes first. - specialized thumbnailers with most recent service files go first. - built-in thumbnailers are always at the end of the list in the order they were added to the registry. Connect to the new "unregister" signal of all TumblerThumbnailers to remove them when required. The signal is only emitted by TumblerSpecializedThumbnailers when their proxy is destroyed. TumblerSpecializedThumbnailer has two new properties: "foreign" and "modified". Foreign thumbnailers are those registered dynamically over D-Bus (using org.freedesktop.thumbnailer.Manager.Register()). The "modified" property represents the timestamp of when the thumbnailer's .service file was last modified. It is 0 for foreign thumbnailers.
-rw-r--r--.gitignore37
-rw-r--r--tumbler/tumbler-manager.c5
-rw-r--r--tumbler/tumbler-registry.c156
-rw-r--r--tumbler/tumbler-specialized-thumbnailer.c137
-rw-r--r--tumbler/tumbler-specialized-thumbnailer.h20
-rw-r--r--tumbler/tumbler-thumbnailer.c12
-rw-r--r--tumbler/tumbler-thumbnailer.h13
7 files changed, 334 insertions, 46 deletions
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..103637f
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,37 @@
+*.o
+*.service
+Makefile.in
+Makefile
+aclocal.m4
+autom4te.cache
+compile
+config.guess
+config.h
+config.h.in
+config.log
+config.status
+config.sub
+configure
+configure.in
+depcomp
+install-sh
+intltool-extract.in
+intltool-merge.in
+intltool-update.in
+libtool
+ltmain.sh
+missing
+mkinstalldirs
+Makefile.in.in
+POTFILES
+stamp-it
+stamp-h1
+.deps
+.libs
+stamp-*.h
+tumbler
+tumbler-manager-dbus-bindings.h
+tumbler-marshal.c
+tumbler-marshal.h
+*.swp
+commit-msg
diff --git a/tumbler/tumbler-manager.c b/tumbler/tumbler-manager.c
index 29e7c17..e8d73a4 100644
--- a/tumbler/tumbler-manager.c
+++ b/tumbler/tumbler-manager.c
@@ -319,8 +319,9 @@ tumbler_manager_register (TumblerManager *manager,
sender_name = dbus_g_method_get_sender (context);
- thumbnailer = tumbler_specialized_thumbnailer_new (manager->priv->connection,
- sender_name, uri_scheme, mime_type);
+ thumbnailer = tumbler_specialized_thumbnailer_new_foreign (manager->priv->connection,
+ sender_name, uri_scheme,
+ mime_type);
tumbler_registry_add (manager->priv->registry, thumbnailer);
diff --git a/tumbler/tumbler-registry.c b/tumbler/tumbler-registry.c
index 836b091..ff3df1b 100644
--- a/tumbler/tumbler-registry.c
+++ b/tumbler/tumbler-registry.c
@@ -25,7 +25,9 @@
#include <glib.h>
#include <glib-object.h>
+#include <tumbler/tumbler-builtin-thumbnailer.h>
#include <tumbler/tumbler-registry.h>
+#include <tumbler/tumbler-specialized-thumbnailer.h>
@@ -52,6 +54,14 @@ static void tumbler_registry_set_property (GObject *object,
guint prop_id,
const GValue *value,
GParamSpec *pspec);
+static void tumbler_registry_remove (const gchar *key,
+ GList **list,
+ TumblerThumbnailer *thumbnailer);
+static void tumbler_registry_unregister (TumblerThumbnailer *thumbnailer,
+ TumblerRegistry *registry);
+static void tumbler_registry_list_free (gpointer data);
+static gint tumbler_registry_compare (TumblerThumbnailer *a,
+ TumblerThumbnailer *b);
@@ -121,6 +131,9 @@ static void
tumbler_registry_init (TumblerRegistry *registry)
{
registry->priv = TUMBLER_REGISTRY_GET_PRIVATE (registry);
+ registry->priv->thumbnailers = g_hash_table_new_full (g_str_hash, g_str_equal,
+ g_free,
+ tumbler_registry_list_free);
}
@@ -177,6 +190,107 @@ tumbler_registry_set_property (GObject *object,
+static void
+tumbler_registry_remove (const gchar *key,
+ GList **list,
+ TumblerThumbnailer *thumbnailer)
+{
+ GList *lp;
+
+ for (lp = *list; lp != NULL; lp = lp->next)
+ {
+ if (lp->data == thumbnailer)
+ *list = g_list_delete_link (*list, lp);
+ }
+}
+
+
+
+static void
+tumbler_registry_unregister (TumblerThumbnailer *thumbnailer,
+ TumblerRegistry *registry)
+{
+ g_return_if_fail (TUMBLER_IS_THUMBNAILER (thumbnailer));
+ g_return_if_fail (TUMBLER_IS_REGISTRY (registry));
+
+ g_hash_table_foreach (registry->priv->thumbnailers, (GHFunc) tumbler_registry_remove,
+ thumbnailer);
+}
+
+
+
+static gint
+tumbler_registry_compare (TumblerThumbnailer *a,
+ TumblerThumbnailer *b)
+{
+ TumblerSpecializedThumbnailer *a_specialized;
+ TumblerSpecializedThumbnailer *b_specialized;
+ gboolean insert_a_before_b = FALSE;
+ gboolean a_foreign;
+ gboolean b_foreign;
+ guint64 a_modified;
+ guint64 b_modified;
+
+ g_return_val_if_fail (TUMBLER_IS_THUMBNAILER (a), 0);
+ g_return_val_if_fail (TUMBLER_IS_THUMBNAILER (b), 0);
+
+ if (TUMBLER_IS_BUILTIN_THUMBNAILER (b))
+ {
+ /* built-in thumbnailers are always overriden */
+ insert_a_before_b = TRUE;
+ }
+ else if (TUMBLER_IS_SPECIALIZED_THUMBNAILER (b))
+ {
+ a_specialized = TUMBLER_SPECIALIZED_THUMBNAILER (a);
+ b_specialized = TUMBLER_SPECIALIZED_THUMBNAILER (b);
+
+ a_foreign = tumbler_specialized_thumbnailer_get_foreign (a_specialized);
+ b_foreign = tumbler_specialized_thumbnailer_get_foreign (b_specialized);
+
+ if (a_foreign || b_foreign)
+ {
+ /* both thumbnailers were registered dynamically over D-Bus but
+ * whoever goes last wins */
+ insert_a_before_b = TRUE;
+ }
+ else
+ {
+ b_modified = tumbler_specialized_thumbnailer_get_modified (a_specialized);
+ a_modified = tumbler_specialized_thumbnailer_get_modified (a_specialized);
+
+ if (a_modified > b_modified)
+ {
+ /* a and b are both specialized thumbnailers but a was installed
+ * on the system last, so it wins */
+ insert_a_before_b = TRUE;
+ }
+ }
+ }
+ else
+ {
+ /* we have no other thumbnailer types at the moment */
+ g_assert_not_reached ();
+ }
+
+ return insert_a_before_b ? -1 : 1;
+}
+
+
+
+static void tumbler_registry_list_free (gpointer data)
+{
+ GList **list = data;
+
+ /* make sure to release all thumbnailers */
+ g_list_foreach (*list, (GFunc) g_object_unref, NULL);
+
+ /* free the list and the pointer to it */
+ g_list_free (*list);
+ g_free (list);
+}
+
+
+
TumblerRegistry *
tumbler_registry_new (void)
{
@@ -192,6 +306,8 @@ tumbler_registry_load (TumblerRegistry *registry,
g_return_val_if_fail (TUMBLER_IS_REGISTRY (registry), FALSE);
g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
+ /* TODO */
+
return TRUE;
}
@@ -201,8 +317,46 @@ void
tumbler_registry_add (TumblerRegistry *registry,
TumblerThumbnailer *thumbnailer)
{
+ GList **list;
+ GStrv hash_keys;
+ gint n;
+
g_return_if_fail (TUMBLER_IS_REGISTRY (registry));
g_return_if_fail (TUMBLER_IS_THUMBNAILER (thumbnailer));
- /* TODO */
+ /* determine the hash keys (all combinations of URI schemes and MIME types)
+ * for this thumbnailer */
+ hash_keys = tumbler_thumbnailer_get_hash_keys (thumbnailer);
+
+ /* iterate over all of them */
+ for (n = 0; hash_keys != NULL && hash_keys[n] != NULL; ++n)
+ {
+ /* fetch the thumbnailer list for this URI scheme/MIME type combination */
+ list = g_hash_table_lookup (registry->priv->thumbnailers, hash_keys[n]);
+
+ if (list != NULL)
+ {
+ /* we already have thumbnailers for this combination. insert the new
+ * one at the right position in the list */
+ *list = g_list_insert_sorted (*list, g_object_ref (thumbnailer),
+ (GCompareFunc) tumbler_registry_compare);
+ }
+ else
+ {
+ /* allocate a new list */
+ list = g_new0 (GList *, 1);
+
+ /* insert the thumbnailer into the list */
+ *list = g_list_prepend (*list, g_object_ref (thumbnailer));
+
+ /* insert the pointer to the list in the hash table */
+ g_hash_table_insert (registry->priv->thumbnailers, hash_keys[n], list);
+ }
+
+ /* connect to the unregister signal of the thumbnailer */
+ g_signal_connect (thumbnailer, "unregister",
+ G_CALLBACK (tumbler_registry_unregister), registry);
+ }
+
+ g_strfreev (hash_keys);
}
diff --git a/tumbler/tumbler-specialized-thumbnailer.c b/tumbler/tumbler-specialized-thumbnailer.c
index f8fa495..f18a30e 100644
--- a/tumbler/tumbler-specialized-thumbnailer.c
+++ b/tumbler/tumbler-specialized-thumbnailer.c
@@ -44,34 +44,38 @@ enum
PROP_NAME,
PROP_CONNECTION,
PROP_PROXY,
+ PROP_FOREIGN,
+ PROP_MODIFIED,
};
-static void tumbler_specialized_thumbnailer_class_init (TumblerSpecializedThumbnailerClass *klass);
-static void tumbler_specialized_thumbnailer_init (TumblerSpecializedThumbnailer *thumbnailer);
-static void tumbler_specialized_thumbnailer_iface_init (TumblerThumbnailerIface *iface);
-static void tumbler_specialized_thumbnailer_constructed (GObject *object);
-static void tumbler_specialized_thumbnailer_finalize (GObject *object);
-static void tumbler_specialized_thumbnailer_get_property (GObject *object,
- guint prop_id,
- GValue *value,
- GParamSpec *pspec);
-static void tumbler_specialized_thumbnailer_set_property (GObject *object,
- guint prop_id,
- const GValue *value,
- GParamSpec *pspec);
-static void tumbler_specialized_thumbnailer_create (TumblerThumbnailer *thumbnailer,
- const gchar *uri,
- const gchar *mime_hint);
-static void tumbler_specialized_thumbnailer_proxy_ready (DBusGProxy *proxy,
- const gchar *uri,
- TumblerSpecializedThumbnailer *thumbnailer);
-static void tumbler_specialized_thumbnailer_proxy_error (DBusGProxy *proxy,
- const gchar *uri,
- gint error_code,
- const gchar *message,
- TumblerSpecializedThumbnailer *thumbnailer);
+static void tumbler_specialized_thumbnailer_class_init (TumblerSpecializedThumbnailerClass *klass);
+static void tumbler_specialized_thumbnailer_init (TumblerSpecializedThumbnailer *thumbnailer);
+static void tumbler_specialized_thumbnailer_iface_init (TumblerThumbnailerIface *iface);
+static void tumbler_specialized_thumbnailer_constructed (GObject *object);
+static void tumbler_specialized_thumbnailer_finalize (GObject *object);
+static void tumbler_specialized_thumbnailer_get_property (GObject *object,
+ guint prop_id,
+ GValue *value,
+ GParamSpec *pspec);
+static void tumbler_specialized_thumbnailer_set_property (GObject *object,
+ guint prop_id,
+ const GValue *value,
+ GParamSpec *pspec);
+static void tumbler_specialized_thumbnailer_create (TumblerThumbnailer *thumbnailer,
+ const gchar *uri,
+ const gchar *mime_hint);
+static void tumbler_specialized_thumbnailer_proxy_ready (DBusGProxy *proxy,
+ const gchar *uri,
+ TumblerSpecializedThumbnailer *thumbnailer);
+static void tumbler_specialized_thumbnailer_proxy_error (DBusGProxy *proxy,
+ const gchar *uri,
+ gint error_code,
+ const gchar *message,
+ TumblerSpecializedThumbnailer *thumbnailer);
+static void tumbler_specialized_thumbnailer_proxy_destroyed (DBusGProxy *proxy,
+ TumblerSpecializedThumbnailer *thumbnailer);
@@ -92,6 +96,9 @@ struct _TumblerSpecializedThumbnailerPrivate
DBusGConnection *connection;
DBusGProxy *proxy;
+ gboolean foreign;
+ guint64 modified;
+
gchar *name;
GStrv uri_schemes;
@@ -178,6 +185,24 @@ tumbler_specialized_thumbnailer_class_init (TumblerSpecializedThumbnailerClass *
"proxy",
DBUS_TYPE_G_PROXY,
G_PARAM_READABLE));
+
+ g_object_class_install_property (gobject_class,
+ PROP_FOREIGN,
+ g_param_spec_boolean ("foreign",
+ "foreign",
+ "foreign",
+ FALSE,
+ G_PARAM_CONSTRUCT_ONLY |
+ G_PARAM_READWRITE));
+
+ g_object_class_install_property (gobject_class,
+ PROP_MODIFIED,
+ g_param_spec_uint64 ("modified",
+ "modified",
+ "modified",
+ 0, G_MAXUINT64, 0,
+ G_PARAM_CONSTRUCT_ONLY |
+ G_PARAM_READWRITE));
}
@@ -231,7 +256,9 @@ tumbler_specialized_thumbnailer_constructed (GObject *object)
G_CALLBACK (tumbler_specialized_thumbnailer_proxy_error),
thumbnailer, NULL);
- /* TODO make sure to handle the destroy signal of the proxy properly */
+ g_object_connect (thumbnailer->priv->proxy, "destroy",
+ G_CALLBACK (tumbler_specialized_thumbnailer_proxy_destroyed),
+ thumbnailer);
}
@@ -247,6 +274,14 @@ tumbler_specialized_thumbnailer_finalize (GObject *object)
g_strfreev (thumbnailer->priv->mime_types);
g_strfreev (thumbnailer->priv->uri_schemes);
+ dbus_g_proxy_disconnect_signal (thumbnailer->priv->proxy, "Ready",
+ G_CALLBACK (tumbler_specialized_thumbnailer_proxy_ready),
+ thumbnailer);
+
+ dbus_g_proxy_disconnect_signal (thumbnailer->priv->proxy, "Error",
+ G_CALLBACK (tumbler_specialized_thumbnailer_proxy_error),
+ thumbnailer);
+
g_object_unref (thumbnailer->priv->proxy);
dbus_g_connection_unref (thumbnailer->priv->connection);
@@ -281,6 +316,12 @@ tumbler_specialized_thumbnailer_get_property (GObject *object,
case PROP_PROXY:
g_value_set_object (value, thumbnailer->priv->proxy);
break;
+ case PROP_FOREIGN:
+ g_value_set_boolean (value, thumbnailer->priv->foreign);
+ break;
+ case PROP_MODIFIED:
+ g_value_set_uint64 (value, thumbnailer->priv->modified);
+ break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
@@ -312,6 +353,12 @@ tumbler_specialized_thumbnailer_set_property (GObject *object,
case PROP_NAME:
thumbnailer->priv->name = g_value_dup_string (value);
break;
+ case PROP_FOREIGN:
+ thumbnailer->priv->foreign = g_value_get_boolean (value);
+ break;
+ case PROP_MODIFIED:
+ thumbnailer->priv->modified = g_value_get_uint64 (value);
+ break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
@@ -361,11 +408,23 @@ tumbler_specialized_thumbnailer_proxy_error (DBusGProxy *prox
+static void
+tumbler_specialized_thumbnailer_proxy_destroyed (DBusGProxy *proxy,
+ TumblerSpecializedThumbnailer *thumbnailer)
+{
+ g_return_if_fail (DBUS_IS_G_PROXY (proxy));
+ g_return_if_fail (TUMBLER_IS_SPECIALIZED_THUMBNAILER (thumbnailer));
+
+ g_signal_emit_by_name (thumbnailer, "unregister");
+}
+
+
+
TumblerThumbnailer *
-tumbler_specialized_thumbnailer_new (DBusGConnection *connection,
- const gchar *name,
- const gchar *uri_scheme,
- const gchar *mime_type)
+tumbler_specialized_thumbnailer_new_foreign (DBusGConnection *connection,
+ const gchar *name,
+ const gchar *uri_scheme,
+ const gchar *mime_type)
{
TumblerSpecializedThumbnailer *thumbnailer;
const gchar *uri_schemes[2] = { uri_scheme, NULL };
@@ -377,9 +436,27 @@ tumbler_specialized_thumbnailer_new (DBusGConnection *connection,
g_return_val_if_fail (mime_type != NULL, NULL);
thumbnailer = g_object_new (TUMBLER_TYPE_SPECIALIZED_THUMBNAILER,
- "connection", connection, "name", name,
+ "connection", connection, "foreign", TRUE, "name", name,
"uri-schemes", uri_schemes, "mime-types", mime_types,
NULL);
return TUMBLER_THUMBNAILER (thumbnailer);
}
+
+
+
+gboolean
+tumbler_specialized_thumbnailer_get_foreign (TumblerSpecializedThumbnailer *thumbnailer)
+{
+ g_return_val_if_fail (TUMBLER_IS_SPECIALIZED_THUMBNAILER (thumbnailer), FALSE);
+ return thumbnailer->priv->foreign;
+}
+
+
+
+guint64
+tumbler_specialized_thumbnailer_get_modified (TumblerSpecializedThumbnailer *thumbnailer)
+{
+ g_return_val_if_fail (TUMBLER_IS_SPECIALIZED_THUMBNAILER (thumbnailer), 0);
+ return thumbnailer->priv->modified;
+}
diff --git a/tumbler/tumbler-specialized-thumbnailer.h b/tumbler/tumbler-specialized-thumbnailer.h
index 42c3566..3ec63b3 100644
--- a/tumbler/tumbler-specialized-thumbnailer.h
+++ b/tumbler/tumbler-specialized-thumbnailer.h
@@ -38,13 +38,19 @@ typedef struct _TumblerSpecializedThumbnailerPrivate TumblerSpecializedThumbnail
typedef struct _TumblerSpecializedThumbnailerClass TumblerSpecializedThumbnailerClass;
typedef struct _TumblerSpecializedThumbnailer TumblerSpecializedThumbnailer;
-GType tumbler_specialized_thumbnailer_get_type (void) G_GNUC_CONST;
-
-TumblerThumbnailer *tumbler_specialized_thumbnailer_new (DBusGConnection *connection,
- const gchar *name,
- const gchar *uri_scheme,
- const gchar *mime_type) G_GNUC_MALLOC G_GNUC_WARN_UNUSED_RESULT;
-gboolean tumbler_specialized_thumbnailer_connect (TumblerSpecializedThumbnailer *thumbnailer);
+GType tumbler_specialized_thumbnailer_get_type (void) G_GNUC_CONST;
+
+TumblerThumbnailer *tumbler_specialized_thumbnailer_new (DBusGConnection *connection,
+ const gchar *name,
+ const GStrv *uri_schemes,
+ const GStrv *mime_types,
+ guint64 modified) G_GNUC_MALLOC G_GNUC_WARN_UNUSED_RESULT;
+TumblerThumbnailer *tumbler_specialized_thumbnailer_new_foreign (DBusGConnection *connection,
+ const gchar *name,
+ const gchar *uri_scheme,
+ const gchar *mime_type) G_GNUC_MALLOC G_GNUC_WARN_UNUSED_RESULT;
+gboolean tumbler_specialized_thumbnailer_get_foreign (TumblerSpecializedThumbnailer *thumbnailer);
+guint64 tumbler_specialized_thumbnailer_get_modified (TumblerSpecializedThumbnailer *thumbnailer);
G_END_DECLS
diff --git a/tumbler/tumbler-thumbnailer.c b/tumbler/tumbler-thumbnailer.c
index 992fc7a..f9d4a2a 100644
--- a/tumbler/tumbler-thumbnailer.c
+++ b/tumbler/tumbler-thumbnailer.c
@@ -32,6 +32,7 @@ enum
{
SIGNAL_READY,
SIGNAL_ERROR,
+ SIGNAL_UNREGISTER,
LAST_SIGNAL,
};
@@ -116,6 +117,17 @@ tumbler_thumbnailer_class_init (TumblerThumbnailerIface *klass)
G_TYPE_STRING,
G_TYPE_INT,
G_TYPE_STRING);
+
+ tumbler_thumbnailer_signals[SIGNAL_UNREGISTER] =
+ g_signal_new ("unregister",
+ TUMBLER_TYPE_THUMBNAILER,
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (TumblerThumbnailerIface, unregister),
+ NULL,
+ NULL,
+ g_cclosure_marshal_VOID__VOID,
+ G_TYPE_NONE,
+ 0);
}
diff --git a/tumbler/tumbler-thumbnailer.h b/tumbler/tumbler-thumbnailer.h
index c5eec08..1033391 100644
--- a/tumbler/tumbler-thumbnailer.h
+++ b/tumbler/tumbler-thumbnailer.h
@@ -38,12 +38,13 @@ struct _TumblerThumbnailerIface
GTypeInterface __parent__;
/* signals */
- void (*ready) (TumblerThumbnailer *thumbnailer,
- const gchar *uri);
- void (*error) (TumblerThumbnailer *thumbnailer,
- const gchar *failed_uri,
- gint error_code,
- const gchar *message);
+ void (*ready) (TumblerThumbnailer *thumbnailer,
+ const gchar *uri);
+ void (*error) (TumblerThumbnailer *thumbnailer,
+ const gchar *failed_uri,
+ gint error_code,
+ const gchar *message);
+ void (*unregister) (TumblerThumbnailer *thumbnailer);
/* virtual methods */
void (*create) (TumblerThumbnailer *thumbnailer,