aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMatthew Barnes <mbarnes@redhat.com>2013-02-21 02:59:19 +0800
committerMatthew Barnes <mbarnes@redhat.com>2013-02-21 05:35:58 +0800
commit1abd497f66baa3fe278fdb02f2a85be27d5dd86e (patch)
tree91c567284d2cef283cd698ae23072e61d48f56fc
parentbe7376c0852cb4e5c112f2dd14a79de57f8bad26 (diff)
downloadgsoc2013-evolution-1abd497f66baa3fe278fdb02f2a85be27d5dd86e.tar.gz
gsoc2013-evolution-1abd497f66baa3fe278fdb02f2a85be27d5dd86e.tar.zst
gsoc2013-evolution-1abd497f66baa3fe278fdb02f2a85be27d5dd86e.zip
EClientCache: Add a "client-notify" signal.
Rebroadcasts a GObject::notify signal emitted by a cached EClient.
-rw-r--r--e-util/e-client-cache.c102
-rw-r--r--e-util/e-client-cache.h3
2 files changed, 104 insertions, 1 deletions
diff --git a/e-util/e-client-cache.c b/e-util/e-client-cache.c
index 577ff7b759..b1d9dcfc10 100644
--- a/e-util/e-client-cache.c
+++ b/e-util/e-client-cache.c
@@ -64,11 +64,13 @@ struct _ClientData {
GQueue connecting;
gulong backend_died_handler_id;
gulong backend_error_handler_id;
+ gulong notify_handler_id;
};
struct _SignalClosure {
EClientCache *cache;
EClient *client;
+ GParamSpec *pspec;
gchar *error_message;
};
@@ -88,6 +90,7 @@ enum {
BACKEND_DIED,
BACKEND_ERROR,
CLIENT_CREATED,
+ CLIENT_NOTIFY,
LAST_SIGNAL
};
@@ -130,6 +133,7 @@ client_data_unref (ClientData *client_data)
* have already been disconnected. */
g_warn_if_fail (client_data->backend_died_handler_id == 0);
g_warn_if_fail (client_data->backend_error_handler_id == 0);
+ g_warn_if_fail (client_data->notify_handler_id == 0);
g_mutex_clear (&client_data->lock);
g_clear_object (&client_data->client);
@@ -158,6 +162,11 @@ client_data_dispose (ClientData *client_data)
client_data->backend_error_handler_id);
client_data->backend_error_handler_id = 0;
+ g_signal_handler_disconnect (
+ client_data->client,
+ client_data->notify_handler_id);
+ client_data->notify_handler_id = 0;
+
g_clear_object (&client_data->client);
}
@@ -172,6 +181,9 @@ signal_closure_free (SignalClosure *signal_closure)
g_clear_object (&signal_closure->cache);
g_clear_object (&signal_closure->client);
+ if (signal_closure->pspec != NULL)
+ g_param_spec_unref (signal_closure->pspec);
+
g_free (signal_closure->error_message);
g_slice_free (SignalClosure, signal_closure);
@@ -341,6 +353,24 @@ client_cache_emit_backend_error_idle_cb (gpointer user_data)
return FALSE;
}
+static gboolean
+client_cache_emit_client_notify_idle_cb (gpointer user_data)
+{
+ SignalClosure *signal_closure = user_data;
+ const gchar *name;
+
+ name = g_param_spec_get_name (signal_closure->pspec);
+
+ g_signal_emit (
+ signal_closure->cache,
+ signals[CLIENT_NOTIFY],
+ g_quark_from_string (name),
+ signal_closure->client,
+ signal_closure->pspec);
+
+ return FALSE;
+}
+
static void
client_cache_backend_died_cb (EClient *client,
ClientData *client_data)
@@ -402,6 +432,37 @@ client_cache_backend_error_cb (EClient *client,
}
static void
+client_cache_notify_cb (EClient *client,
+ GParamSpec *pspec,
+ ClientData *client_data)
+{
+ EClientCache *cache;
+
+ cache = g_weak_ref_get (&client_data->cache);
+
+ if (cache != NULL) {
+ GSource *idle_source;
+ SignalClosure *signal_closure;
+
+ signal_closure = g_slice_new0 (SignalClosure);
+ signal_closure->cache = g_object_ref (cache);
+ signal_closure->client = g_object_ref (client);
+ signal_closure->pspec = g_param_spec_ref (pspec);
+
+ idle_source = g_idle_source_new ();
+ g_source_set_callback (
+ idle_source,
+ client_cache_emit_client_notify_idle_cb,
+ signal_closure,
+ (GDestroyNotify) signal_closure_free);
+ g_source_attach (idle_source, cache->priv->main_context);
+ g_source_unref (idle_source);
+
+ g_object_unref (cache);
+ }
+}
+
+static void
client_cache_process_results (ClientData *client_data,
EClient *client,
const GError *error)
@@ -449,6 +510,14 @@ client_cache_process_results (ClientData *client_data,
0);
client_data->backend_error_handler_id = handler_id;
+ handler_id = g_signal_connect_data (
+ client, "notify",
+ G_CALLBACK (client_cache_notify_cb),
+ client_data_ref (client_data),
+ (GClosureNotify) client_data_unref,
+ 0);
+ client_data->notify_handler_id = handler_id;
+
g_signal_emit (
cache, signals[CLIENT_CREATED], 0, client);
@@ -684,7 +753,7 @@ e_client_cache_class_init (EClientCacheClass *class)
/**
* EClientCache::client-created:
- * @cache: the #EClientCache the received the signal
+ * @cache: the #EClientCache that received the signal
* @client: the newly-created #EClient
*
* This signal is emitted when a call to e_client_cache_get_client()
@@ -698,6 +767,37 @@ e_client_cache_class_init (EClientCacheClass *class)
NULL, NULL, NULL,
G_TYPE_NONE, 1,
E_TYPE_CLIENT);
+
+ /**
+ * EClientCache::client-notify:
+ * @cache: the #EClientCache that received the signal
+ * @client: the #EClient whose property changed
+ * @pspec: the #GParamSpec of the property that changed
+ *
+ * Rebroadcasts a #GObject::notify signal emitted by @client.
+ *
+ * This signal supports "::detail" appendices to the signal name
+ * just like the #GObject::notify signal, so you can connect to
+ * change notification signals for specific #EClient properties.
+ *
+ * As a convenience to signal handlers, this signal is always emitted
+ * from the #GMainContext that was thread-default when the @cache was
+ * created.
+ **/
+ signals[CLIENT_NOTIFY] = g_signal_new (
+ "client-notify",
+ G_TYPE_FROM_CLASS (class),
+ /* same flags as GObject::notify */
+ G_SIGNAL_RUN_FIRST |
+ G_SIGNAL_NO_RECURSE |
+ G_SIGNAL_DETAILED |
+ G_SIGNAL_NO_HOOKS |
+ G_SIGNAL_ACTION,
+ G_STRUCT_OFFSET (EClientCacheClass, client_notify),
+ NULL, NULL, NULL,
+ G_TYPE_NONE, 2,
+ E_TYPE_CLIENT,
+ G_TYPE_PARAM);
}
static void
diff --git a/e-util/e-client-cache.h b/e-util/e-client-cache.h
index d4e3799161..89a70c6f65 100644
--- a/e-util/e-client-cache.h
+++ b/e-util/e-client-cache.h
@@ -72,6 +72,9 @@ struct _EClientCacheClass {
void (*backend_error) (EClientCache *cache,
EClient *client,
EAlert *alert);
+ void (*client_notify) (EClientCache *cache,
+ EClient *client,
+ GParamSpec *pspec);
void (*client_created) (EClientCache *cache,
EClient *client);
};