← Back to team overview

ayatana-commits team mailing list archive

[Merge] lp:~ted/indicator-session/im-detect into lp:indicator-session

 

Ted Gould has proposed merging lp:~ted/indicator-session/im-detect into lp:indicator-session.

Requested reviews:
    Indicator Applet Developers (indicator-applet-developers)

This includes code for detecting when both Pidgin and Mission Control come on and off the bus.  But I learned we're shipping a new version of Mission Control that is different.  So it'll only work with the old version.  The new version is going to take a branch of its own.
-- 
https://code.launchpad.net/~ted/indicator-session/im-detect/+merge/11564
Your team ayatana-commits is subscribed to branch lp:indicator-session.
=== modified file 'src/status-provider-pidgin.c'
--- src/status-provider-pidgin.c	2009-08-17 21:52:43 +0000
+++ src/status-provider-pidgin.c	2009-09-10 18:28:43 +0000
@@ -59,12 +59,14 @@
 	/* STATUS_PROVIDER_STATUS_AWAY,    */  PG_STATUS_AWAY,
 	/* STATUS_PROVIDER_STATUS_DND      */  PG_STATUS_UNAVAILABLE,
 	/* STATUS_PROVIDER_STATUS_INVISIBLE*/  PG_STATUS_INVISIBLE,
-	/* STATUS_PROVIDER_STATUS_OFFLINE  */  PG_STATUS_OFFLINE
+	/* STATUS_PROVIDER_STATUS_OFFLINE  */  PG_STATUS_OFFLINE,
+	/* STATUS_PROVIDER_STATUS_DISCONNECTED*/ PG_STATUS_OFFLINE
 };
 
 typedef struct _StatusProviderPidginPrivate StatusProviderPidginPrivate;
 struct _StatusProviderPidginPrivate {
 	DBusGProxy * proxy;
+	DBusGProxy * dbus_proxy;
 	pg_status_t  pg_status;
 };
 
@@ -80,6 +82,8 @@
 /* Internal Funcs */
 static void set_status (StatusProvider * sp, StatusProviderStatus status);
 static StatusProviderStatus get_status (StatusProvider * sp);
+static void setup_pidgin_proxy (StatusProviderPidgin * self);
+static void dbus_namechange (DBusGProxy * proxy, const gchar * name, const gchar * prev, const gchar * new, StatusProviderPidgin * self);
 
 G_DEFINE_TYPE (StatusProviderPidgin, status_provider_pidgin, STATUS_PROVIDER_TYPE);
 
@@ -183,22 +187,85 @@
 	                                  all non-DBus stuff should be done */
 
 	GError * error = NULL;
+
+	/* Set up the dbus Proxy */
+	priv->dbus_proxy = dbus_g_proxy_new_for_name_owner (bus,
+	                                                    DBUS_SERVICE_DBUS,
+	                                                    DBUS_PATH_DBUS,
+	                                                    DBUS_INTERFACE_DBUS,
+	                                                    &error);
+	if (error != NULL) {
+		g_warning("Unable to connect to DBus events: %s", error->message);
+		g_error_free(error);
+		return;
+	}
+
+	/* Configure the name owner changing */
+	dbus_g_proxy_add_signal(priv->dbus_proxy, "NameOwnerChanged",
+	                        G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING,
+							G_TYPE_INVALID);
+	dbus_g_proxy_connect_signal(priv->dbus_proxy, "NameOwnerChanged",
+	                        G_CALLBACK(dbus_namechange),
+	                        self, NULL);
+
+	setup_pidgin_proxy(self);
+
+	return;
+}
+
+/* Watch to see if the Pidgin comes up on Dbus */
+static void
+dbus_namechange (DBusGProxy * proxy, const gchar * name, const gchar * prev, const gchar * new, StatusProviderPidgin * self)
+{
+	g_return_if_fail(name != NULL);
+	g_return_if_fail(new != NULL);
+
+	if (g_strcmp0(name, "im.pidgin.purple.PurpleService") == 0) {
+		setup_pidgin_proxy(self);
+	}
+	return;
+}
+
+/* Setup the Pidgin proxy so that we can talk to it
+   and get signals from it.  */
+static void
+setup_pidgin_proxy (StatusProviderPidgin * self)
+{
+	StatusProviderPidginPrivate * priv = STATUS_PROVIDER_PIDGIN_GET_PRIVATE(self);
+
+	if (priv->proxy != NULL) {
+		g_debug("Odd, we were asked to set up a Pidgin proxy when we already had one.");
+		return;
+	}
+
+	DBusGConnection * bus = dbus_g_bus_get(DBUS_BUS_SESSION, NULL);
+	g_return_if_fail(bus != NULL); /* Can't do anymore DBus stuff without this,
+	                                  all non-DBus stuff should be done */
+
+	GError * error = NULL;
+
+	/* Set up the Pidgin Proxy */
 	priv->proxy = dbus_g_proxy_new_for_name_owner (bus,
 	                                               "im.pidgin.purple.PurpleService",
 	                                               "/im/pidgin/purple/PurpleObject",
 	                                               "im.pidgin.purple.PurpleInterface",
 	                                               &error);
+	/* Report any errors */
 	if (error != NULL) {
 		g_debug("Unable to get Pidgin proxy: %s", error->message);
 		g_error_free(error);
-		return;
 	}
 
+	/* If we have a proxy, let's start using it */
 	if (priv->proxy != NULL) {
+		/* Set the proxy to NULL if it's destroyed */
 		g_object_add_weak_pointer (G_OBJECT(priv->proxy), (gpointer *)&priv->proxy);
+		/* If it's destroyed, let's clean up as well */
 		g_signal_connect(G_OBJECT(priv->proxy), "destroy",
 		                 G_CALLBACK(proxy_destroy), self);
 
+		/* Watching for the status change coming from the
+		   Pidgin side of things. */
 		g_debug("Adding Pidgin Signals");
 		dbus_g_object_register_marshaller(_status_provider_pidgin_marshal_VOID__INT_INT,
 		                            G_TYPE_NONE,
@@ -216,6 +283,8 @@
 		                            (void *)self,
 		                            NULL);
 
+		/* Get the current status to update our cached
+		   value of the status. */
 		dbus_g_proxy_begin_call(priv->proxy,
 		                        "PurpleSavedstatusGetCurrent",
 		                        savedstatus_cb,
@@ -346,11 +415,17 @@
 }
 
 /* Takes the cached Pidgin status and makes it into the generic
-   Status provider status */
+   Status provider status.  If there is no Pidgin proxy then it
+   returns the disconnected state. */
 static StatusProviderStatus
 get_status (StatusProvider * sp)
 {
-	g_return_val_if_fail(IS_STATUS_PROVIDER_PIDGIN(sp), STATUS_PROVIDER_STATUS_OFFLINE);
+	g_return_val_if_fail(IS_STATUS_PROVIDER_PIDGIN(sp), STATUS_PROVIDER_STATUS_DISCONNECTED);
 	StatusProviderPidginPrivate * priv = STATUS_PROVIDER_PIDGIN_GET_PRIVATE(sp);
+
+	if (priv->proxy == NULL) {
+		return STATUS_PROVIDER_STATUS_DISCONNECTED;
+	}
+
 	return pg_to_sp_map[priv->pg_status];
 }

=== modified file 'src/status-provider-telepathy.c'
--- src/status-provider-telepathy.c	2009-08-25 20:59:07 +0000
+++ src/status-provider-telepathy.c	2009-09-10 19:09:43 +0000
@@ -55,12 +55,14 @@
 	/* STATUS_PROVIDER_STATUS_AWAY,    */  MC_STATUS_AWAY,
 	/* STATUS_PROVIDER_STATUS_DND      */  MC_STATUS_DND,
 	/* STATUS_PROVIDER_STATUS_INVISIBLE*/  MC_STATUS_HIDDEN,
-	/* STATUS_PROVIDER_STATUS_OFFLINE  */  MC_STATUS_OFFLINE
+	/* STATUS_PROVIDER_STATUS_OFFLINE  */  MC_STATUS_OFFLINE,
+	/* STATUS_PROVIDER_STATUS_DISCONNECTED*/MC_STATUS_OFFLINE
 };
 
 typedef struct _StatusProviderTelepathyPrivate StatusProviderTelepathyPrivate;
 struct _StatusProviderTelepathyPrivate {
 	DBusGProxy * proxy;
+	DBusGProxy * dbus_proxy;
 	mc_status_t  mc_status;
 };
 
@@ -74,6 +76,8 @@
 static void status_provider_telepathy_dispose    (GObject *object);
 static void status_provider_telepathy_finalize   (GObject *object);
 /* Internal Funcs */
+static void build_telepathy_proxy (StatusProviderTelepathy * self);
+static void dbus_namechange (DBusGProxy * proxy, const gchar * name, const gchar * prev, const gchar * new, StatusProviderTelepathy * self);
 static void set_status (StatusProvider * sp, StatusProviderStatus status);
 static StatusProviderStatus get_status (StatusProvider * sp);
 static void changed_status (DBusGProxy * proxy, guint status, gchar * message, StatusProvider * sp);
@@ -107,10 +111,61 @@
 	StatusProviderTelepathyPrivate * priv = STATUS_PROVIDER_TELEPATHY_GET_PRIVATE(self);
 
 	priv->proxy = NULL;
+	priv->dbus_proxy = NULL;
 	priv->mc_status = MC_STATUS_OFFLINE;
 
 	GError * error = NULL;
 
+	/* Grabbing the session bus */
+	DBusGConnection * bus = dbus_g_bus_get(DBUS_BUS_SESSION, &error);
+	if (bus == NULL) {
+		g_warning("Unable to connect to Session Bus: %s", error == NULL ? "No message" : error->message);
+		g_error_free(error);
+		return;
+	}
+
+	/* Set up the dbus Proxy */
+	priv->dbus_proxy = dbus_g_proxy_new_for_name_owner (bus,
+	                                                    DBUS_SERVICE_DBUS,
+	                                                    DBUS_PATH_DBUS,
+	                                                    DBUS_INTERFACE_DBUS,
+	                                                    &error);
+	if (error != NULL) {
+		g_warning("Unable to connect to DBus events: %s", error->message);
+		g_error_free(error);
+		return;
+	}
+
+	/* Configure the name owner changing */
+	dbus_g_proxy_add_signal(priv->dbus_proxy, "NameOwnerChanged",
+	                        G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING,
+							G_TYPE_INVALID);
+	dbus_g_proxy_connect_signal(priv->dbus_proxy, "NameOwnerChanged",
+	                        G_CALLBACK(dbus_namechange),
+	                        self, NULL);
+
+	build_telepathy_proxy(self);
+
+	return;
+}
+
+/* Builds up the proxy to Mission Control and configures all of the
+   signals for getting info from the proxy.  Also does a call to get
+   the inital value of the status. */
+static void
+build_telepathy_proxy (StatusProviderTelepathy * self)
+{
+	g_debug("Building Telepathy Proxy");
+	StatusProviderTelepathyPrivate * priv = STATUS_PROVIDER_TELEPATHY_GET_PRIVATE(self);
+
+	if (priv->proxy != NULL) {
+		g_debug("Hmm, being asked to build a proxy we alredy have.");
+		return;
+	}
+
+	GError * error = NULL;
+
+	/* Grabbing the session bus */
 	DBusGConnection * session_bus = dbus_g_bus_get(DBUS_BUS_SESSION, &error);
 	if (session_bus == NULL) {
 		g_warning("Unable to connect to Session Bus: %s", error == NULL ? "No message" : error->message);
@@ -118,7 +173,7 @@
 		return;
 	}
 
-	priv->proxy = NULL;
+	/* Get the proxy to Mission Control */
 	priv->proxy = dbus_g_proxy_new_for_name_owner(session_bus,
 	                         "org.freedesktop.Telepathy.MissionControl",
 	                        "/org/freedesktop/Telepathy/MissionControl",
@@ -126,10 +181,13 @@
 	                         &error);
 
 	if (priv->proxy != NULL) {
+		/* If it goes, we set the proxy to NULL */
 		g_object_add_weak_pointer (G_OBJECT(priv->proxy), (gpointer *)&priv->proxy);
+		/* And we clean up other variables associated */
 		g_signal_connect(G_OBJECT(priv->proxy), "destroy",
 		                 G_CALLBACK(proxy_destroy), self);
 
+		/* Set up the signal handler for watching when status changes. */
 		dbus_g_object_register_marshaller(_status_provider_telepathy_marshal_VOID__UINT_STRING,
 		                            G_TYPE_NONE,
 		                            G_TYPE_UINT,
@@ -163,6 +221,19 @@
 	return;
 }
 
+/* Watch to see if the Mission Control comes up on Dbus */
+static void
+dbus_namechange (DBusGProxy * proxy, const gchar * name, const gchar * prev, const gchar * new, StatusProviderTelepathy * self)
+{
+	g_return_if_fail(name != NULL);
+	g_return_if_fail(new != NULL);
+
+	if (g_strcmp0(name, "org.freedesktop.Telepathy.MissionControl") == 0) {
+		build_telepathy_proxy(self);
+	}
+	return;
+}
+
 static void
 status_provider_telepathy_dispose (GObject *object)
 {
@@ -258,10 +329,11 @@
 static StatusProviderStatus
 get_status (StatusProvider * sp)
 {
+	g_return_val_if_fail(IS_STATUS_PROVIDER_TELEPATHY(sp), STATUS_PROVIDER_STATUS_DISCONNECTED);
 	StatusProviderTelepathyPrivate * priv = STATUS_PROVIDER_TELEPATHY_GET_PRIVATE(sp);
 
 	if (priv->proxy == NULL) {
-		return mc_to_sp_map[MC_STATUS_OFFLINE];
+		return STATUS_PROVIDER_STATUS_DISCONNECTED;
 	}
 
 	return mc_to_sp_map[priv->mc_status];

=== modified file 'src/status-provider.h'
--- src/status-provider.h	2009-08-25 04:43:50 +0000
+++ src/status-provider.h	2009-09-10 17:10:07 +0000
@@ -42,6 +42,7 @@
   STATUS_PROVIDER_STATUS_DND,
   STATUS_PROVIDER_STATUS_INVISIBLE,
   STATUS_PROVIDER_STATUS_OFFLINE,
+  STATUS_PROVIDER_STATUS_DISCONNECTED,
   /* Leave as last */
   STATUS_PROVIDER_STATUS_LAST
 }

=== modified file 'src/status-service.c'
--- src/status-service.c	2009-09-03 19:52:47 +0000
+++ src/status-service.c	2009-09-10 18:40:49 +0000
@@ -55,7 +55,8 @@
   /* STATUS_PROVIDER_STATUS_AWAY,      */ N_("Away"),
   /* STATUS_PROVIDER_STATUS_DND        */ N_("Busy"),
   /* STATUS_PROVIDER_STATUS_INVISIBLE  */ N_("Invisible"),
-  /* STATUS_PROVIDER_STATUS_OFFLINE,   */ N_("Offline")
+  /* STATUS_PROVIDER_STATUS_OFFLINE,   */ N_("Offline"),
+  /* STATUS_PROVIDER_STATUS_DISCONNECTED*/ N_("Offline")
 };
 
 static const gchar * status_icons[STATUS_PROVIDER_STATUS_LAST] = {
@@ -63,21 +64,25 @@
   /* STATUS_PROVIDER_STATUS_AWAY, */       "user-away",
   /* STATUS_PROVIDER_STATUS_DND, */        "user-busy",
   /* STATUS_PROVIDER_STATUS_INVISIBLE, */  "user-invisible",
-  /* STATUS_PROVIDER_STATUS_OFFLINE */     "user-offline"
+  /* STATUS_PROVIDER_STATUS_OFFLINE */     "user-offline",
+  /* STATUS_PROVIDER_STATUS_DISCONNECTED */"user-offline"
 };
 
 
 static DbusmenuMenuitem * root_menuitem = NULL;
 static DbusmenuMenuitem * status_menuitem = NULL;
+static DbusmenuMenuitem * status_menuitems[STATUS_PROVIDER_STATUS_LAST] = {0};
 static GMainLoop * mainloop = NULL;
 static StatusServiceDbus * dbus_interface = NULL;
-static StatusProviderStatus global_status = STATUS_PROVIDER_STATUS_OFFLINE;
+static StatusProviderStatus global_status = STATUS_PROVIDER_STATUS_DISCONNECTED;
 
 static void
 status_update (void) {
 	StatusProviderStatus oldglobal = global_status;
-	global_status = STATUS_PROVIDER_STATUS_OFFLINE;
+	global_status = STATUS_PROVIDER_STATUS_DISCONNECTED;
 
+	/* Ask everyone what they think the status should be, if
+	   they're more connected, up the global level */
 	int i;
 	for (i = 0; i < STATUS_PROVIDER_CNT; i++) {
 		StatusProviderStatus localstatus = status_provider_get_status(status_providers[i]);
@@ -86,11 +91,34 @@
 		}
 	}
 
+	/* If changed */
 	if (global_status != oldglobal) {
 		g_debug("Global status changed to: %s", _(status_strings[global_status]));
 
+		/* Set the status name on the menu item */
 		dbusmenu_menuitem_property_set(status_menuitem, DBUSMENU_MENUITEM_PROP_LABEL, _(status_strings[global_status]));
+		/* Configure the icon on the panel */
 		status_service_dbus_set_status(dbus_interface, status_icons[global_status]);
+
+		/* If we're now disconnected, make setting the statuses
+		   insensitive. */
+		if (global_status == STATUS_PROVIDER_STATUS_DISCONNECTED) {
+			StatusProviderStatus i;
+			for (i = STATUS_PROVIDER_STATUS_ONLINE; i < STATUS_PROVIDER_STATUS_LAST; i++) {
+				if (status_menuitems[i] == NULL) continue;
+				dbusmenu_menuitem_property_set(status_menuitems[i], DBUSMENU_MENUITEM_PROP_SENSITIVE, "false");
+			}
+		}
+
+		/* If we're now back to a state where we have an IM client
+		   connected then we need to resensitize the items. */
+		if (oldglobal == STATUS_PROVIDER_STATUS_DISCONNECTED) {
+			StatusProviderStatus i;
+			for (i = STATUS_PROVIDER_STATUS_ONLINE; i < STATUS_PROVIDER_STATUS_LAST; i++) {
+				if (status_menuitems[i] == NULL) continue;
+				dbusmenu_menuitem_property_set(status_menuitems[i], DBUSMENU_MENUITEM_PROP_SENSITIVE, "true");
+			}
+		}
 	}
 
 	return;
@@ -195,14 +223,23 @@
 
 	StatusProviderStatus i;
 	for (i = STATUS_PROVIDER_STATUS_ONLINE; i < STATUS_PROVIDER_STATUS_LAST; i++) {
-		DbusmenuMenuitem * mi = dbusmenu_menuitem_new();
-
-		dbusmenu_menuitem_property_set(mi, "type", DBUSMENU_CLIENT_TYPES_IMAGE);
-		dbusmenu_menuitem_property_set(mi, DBUSMENU_MENUITEM_PROP_LABEL, _(status_strings[i]));
-		dbusmenu_menuitem_property_set(mi, DBUSMENU_MENUITEM_PROP_ICON, status_icons[i]);
-		g_signal_connect(G_OBJECT(mi), DBUSMENU_MENUITEM_SIGNAL_ITEM_ACTIVATED, G_CALLBACK(status_menu_click), GINT_TO_POINTER(i));
-
-		dbusmenu_menuitem_child_append(status_menuitem, mi);
+		if (i == STATUS_PROVIDER_STATUS_DISCONNECTED) {
+			/* We don't want an item for the disconnected status.  Users
+			   can't set that value through the menu :) */
+			continue;
+		}
+
+		status_menuitems[i] = dbusmenu_menuitem_new();
+
+		dbusmenu_menuitem_property_set(status_menuitems[i], "type", DBUSMENU_CLIENT_TYPES_IMAGE);
+		dbusmenu_menuitem_property_set(status_menuitems[i], DBUSMENU_MENUITEM_PROP_LABEL, _(status_strings[i]));
+		dbusmenu_menuitem_property_set(status_menuitems[i], DBUSMENU_MENUITEM_PROP_ICON, status_icons[i]);
+		if (global_status == STATUS_PROVIDER_STATUS_DISCONNECTED) {
+			dbusmenu_menuitem_property_set(status_menuitems[i], DBUSMENU_MENUITEM_PROP_SENSITIVE, "false");
+		}
+		g_signal_connect(G_OBJECT(status_menuitems[i]), DBUSMENU_MENUITEM_SIGNAL_ITEM_ACTIVATED, G_CALLBACK(status_menu_click), GINT_TO_POINTER(i));
+
+		dbusmenu_menuitem_child_append(status_menuitem, status_menuitems[i]);
 
 		g_debug("Built %s", status_strings[i]);
 	}


Follow ups