aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMatthew Barnes <mbarnes@redhat.com>2013-09-15 06:57:05 +0800
committerMatthew Barnes <mbarnes@redhat.com>2013-09-15 07:19:39 +0800
commit192ac20a72567c25c653893c12bb2be0c21a2436 (patch)
tree87d0dd1c35c5b6252a67610a15d9e02727b5edd6
parent3d0ffdb864e7f1692b01e7e9a1adec37a735e704 (diff)
downloadgsoc2013-evolution-192ac20a72567c25c653893c12bb2be0c21a2436.tar
gsoc2013-evolution-192ac20a72567c25c653893c12bb2be0c21a2436.tar.gz
gsoc2013-evolution-192ac20a72567c25c653893c12bb2be0c21a2436.tar.bz2
gsoc2013-evolution-192ac20a72567c25c653893c12bb2be0c21a2436.tar.lz
gsoc2013-evolution-192ac20a72567c25c653893c12bb2be0c21a2436.tar.xz
gsoc2013-evolution-192ac20a72567c25c653893c12bb2be0c21a2436.tar.zst
gsoc2013-evolution-192ac20a72567c25c653893c12bb2be0c21a2436.zip
EClientSelector: Show an initial icon based on host name.
Have GNetworkMonitor make an initial guess at the online state of backends by evaluating the reachability of their host name. This will show an initial status icon for all displayed ESources without actually opening a connection, since some backends are expensive to start unnecssarily.
-rw-r--r--e-util/e-client-selector.c151
1 files changed, 150 insertions, 1 deletions
diff --git a/e-util/e-client-selector.c b/e-util/e-client-selector.c
index e164c80249..32a53e428d 100644
--- a/e-util/e-client-selector.c
+++ b/e-util/e-client-selector.c
@@ -32,6 +32,8 @@
(G_TYPE_INSTANCE_GET_PRIVATE \
((obj), E_TYPE_CLIENT_SELECTOR, EClientSelectorPrivate))
+typedef struct _AsyncContext AsyncContext;
+
struct _EClientSelectorPrivate {
EClientCache *client_cache;
gulong backend_died_handler_id;
@@ -39,6 +41,11 @@ struct _EClientSelectorPrivate {
gulong client_notify_online_handler_id;
};
+struct _AsyncContext {
+ EClientSelector *selector;
+ ESource *source;
+};
+
enum {
PROP_0,
PROP_CLIENT_CACHE
@@ -50,6 +57,15 @@ G_DEFINE_TYPE (
E_TYPE_SOURCE_SELECTOR)
static void
+async_context_free (AsyncContext *async_context)
+{
+ g_clear_object (&async_context->selector);
+ g_clear_object (&async_context->source);
+
+ g_slice_free (AsyncContext, async_context);
+}
+
+static void
client_selector_update_status_icon_cb (GtkTreeViewColumn *column,
GtkCellRenderer *renderer,
GtkTreeModel *model,
@@ -85,8 +101,17 @@ client_selector_update_status_icon_cb (GtkTreeViewColumn *column,
dead_backend = e_client_selector_is_backend_dead (
E_CLIENT_SELECTOR (tree_view), source);
- if (dead_backend)
+ if (dead_backend) {
icon_name = "network-error-symbolic";
+ } else {
+ gpointer data;
+
+ /* See client_selector_can_reach_cb() */
+ data = g_object_get_data (
+ G_OBJECT (source),
+ "initial-icon-name");
+ icon_name = (const gchar *) data;
+ }
g_object_unref (source);
}
@@ -141,6 +166,50 @@ client_selector_client_notify_cb (EClientCache *client_cache,
}
static void
+client_selector_can_reach_cb (GObject *source_object,
+ GAsyncResult *result,
+ gpointer user_data)
+{
+ EClient *client;
+ AsyncContext *async_context;
+ gboolean reachable;
+
+ async_context = (AsyncContext *) user_data;
+
+ /* We don't care about errors here. This is just to show some
+ * initial icon next to the ESource before creating an EClient. */
+ reachable = g_network_monitor_can_reach_finish (
+ G_NETWORK_MONITOR (source_object), result, NULL);
+
+ client = e_client_selector_ref_cached_client (
+ async_context->selector, async_context->source);
+
+ /* EClient's online state is authoritative.
+ * Defer to it if an instance already exists. */
+ if (client == NULL) {
+ const gchar *icon_name;
+
+ if (reachable)
+ icon_name = "network-idle-symbolic";
+ else
+ icon_name = "network-offline-symbolic";
+
+ /* XXX Hackish way to stash the initial icon name. */
+ g_object_set_data (
+ G_OBJECT (async_context->source),
+ "initial-icon-name", (gpointer) icon_name);
+
+ e_source_selector_update_row (
+ E_SOURCE_SELECTOR (async_context->selector),
+ async_context->source);
+ }
+
+ g_clear_object (&client);
+
+ async_context_free (async_context);
+}
+
+static void
client_selector_set_client_cache (EClientSelector *selector,
EClientCache *client_cache)
{
@@ -224,9 +293,13 @@ client_selector_constructed (GObject *object)
{
EClientSelector *selector;
EClientCache *client_cache;
+ ESourceRegistry *registry;
GtkTreeView *tree_view;
GtkTreeViewColumn *column;
GtkCellRenderer *renderer;
+ GNetworkMonitor *network_monitor;
+ const gchar *extension_name;
+ GList *list, *link;
gulong handler_id;
selector = E_CLIENT_SELECTOR (object);
@@ -270,6 +343,82 @@ client_selector_constructed (GObject *object)
selector->priv->client_notify_online_handler_id = handler_id;
g_object_unref (client_cache);
+
+ /* Have GNetworkMonitor make an initial guess at the online
+ * state of backends by evaluating the reachability of their
+ * host name. This will show an initial status icon for all
+ * displayed ESources without actually opening a connection,
+ * since some backends are expensive to start unnecessarily.
+ *
+ * XXX It occurred to me after writing this that it would be
+ * better for ESourceSelector to evaluate reachability of
+ * ESource host names, and keep it up-to-date in response
+ * to network changes. It could automatically trigger a
+ * GtkTreeModel::row-changed signal when it has a new host
+ * reachability result, and provide that result via some
+ * e_source_selector_get_host_reachable() for us to fall
+ * back on if no EClient instance is available.
+ *
+ * But the approach below is good enough for now.
+ */
+
+ network_monitor = g_network_monitor_get_default ();
+
+ registry = e_source_selector_get_registry (
+ E_SOURCE_SELECTOR (selector));
+ extension_name = e_source_selector_get_extension_name (
+ E_SOURCE_SELECTOR (selector));
+
+ list = e_source_registry_list_sources (registry, extension_name);
+
+ extension_name = E_SOURCE_EXTENSION_AUTHENTICATION;
+
+ for (link = list; link != NULL; link = g_list_next (link)) {
+ ESource *source = E_SOURCE (link->data);
+ ESource *auth_source;
+ ESourceAuthentication *auth_extension;
+ GSocketConnectable *socket_connectable;
+ const gchar *host;
+ guint16 port;
+
+ auth_source = e_source_registry_find_extension (
+ registry, source, extension_name);
+
+ if (auth_source == NULL)
+ continue;
+
+ auth_extension = e_source_get_extension (
+ auth_source, extension_name);
+
+ host = e_source_authentication_get_host (auth_extension);
+ port = e_source_authentication_get_port (auth_extension);
+
+ socket_connectable = g_network_address_new (host, port);
+
+ /* XXX GNetworkAddress will happily take a NULL host
+ * but then crash while enumerating the address,
+ * so watch out for that. */
+ if (host == NULL)
+ g_clear_object (&socket_connectable);
+
+ if (socket_connectable != NULL) {
+ AsyncContext *async_context;
+
+ async_context = g_slice_new0 (AsyncContext);
+ async_context->selector = g_object_ref (selector);
+ async_context->source = g_object_ref (source);
+
+ g_network_monitor_can_reach_async (
+ network_monitor, socket_connectable, NULL,
+ client_selector_can_reach_cb, async_context);
+
+ g_object_unref (socket_connectable);
+ }
+
+ g_object_unref (auth_source);
+ }
+
+ g_list_free_full (list, (GDestroyNotify) g_object_unref);
}
static void