Ted Gould has proposed merging 
lp:~indicator-applet-developers/indicator-applet/messages-packaging into 
lp:~ubuntu-core-dev/indicator-applet/messages-ubuntu.

Requested reviews:
    Ubuntu Sponsors for main (ubuntu-main-sponsors): sponsorship
-- 
https://code.launchpad.net/~indicator-applet-developers/indicator-applet/messages-packaging/+merge/4640
Your team Indicator Applet Developers is subscribed to branch 
lp:~indicator-applet-developers/indicator-applet/messages-packaging.
=== modified file 'configure.ac'
--- configure.ac	2009-02-16 18:53:20 +0000
+++ configure.ac	2009-03-18 19:25:23 +0000
@@ -4,7 +4,7 @@
 AC_PREREQ(2.53)
 
 AM_CONFIG_HEADER(config.h)
-AM_INIT_AUTOMAKE(indicator-messages, 0.1)
+AM_INIT_AUTOMAKE(indicator-messages, 0.1.3)
 
 AM_MAINTAINER_MODE
 

=== modified file 'debian/changelog'
--- debian/changelog	2009-02-17 10:35:44 +0000
+++ debian/changelog	2009-03-18 21:32:11 +0000
@@ -1,3 +1,18 @@
+indicator-messages (0.1.3-0ubuntu1) jaunty; urgency=low
+
+  * New upstream version.
+    * Now changes the icon based on non-IM indicators so that Evolution
+      works much better.  (LP: #342480)
+    * Now the menu items are in a predictable order, alphabetical.
+    * The Messages for a particular client (i.e. Pidgin) are grouped with
+      the client they're associated with.
+    * Adjusting the icon size to match the new one in the Human theme.
+    * Adjusting the build so that all the different libraries are not
+      built in a versioned manner.  Now it's just one .so, which is
+      what it should have been originally.
+
+ -- Ted Gould <[email protected]>  Wed, 18 Mar 2009 16:31:28 -0500
+
 indicator-messages (0.1-0ubuntu1) jaunty; urgency=low
 
   * Initial release, based on DX team's PPA packaging branch.

=== modified file 'src/Makefile.am'
--- src/Makefile.am	2009-02-06 15:26:20 +0000
+++ src/Makefile.am	2009-03-15 15:32:27 +0000
@@ -4,3 +4,4 @@
 libmessaging_la_SOURCES = indicator-messages.c im-menu-item.c im-menu-item.h app-menu-item.c app-menu-item.h
 libmessaging_la_CFLAGS = $(APPLET_CFLAGS) -Wall -Wl,-Bsymbolic-functions -Wl,-z,defs -Wl,--as-needed
 libmessaging_la_LIBADD = $(APPLET_LIBS)
+libmessaging_la_LDFLAGS = -module -avoid-version

=== modified file 'src/app-menu-item.c'
--- src/app-menu-item.c	2009-02-13 22:04:35 +0000
+++ src/app-menu-item.c	2009-03-18 19:22:08 +0000
@@ -29,6 +29,14 @@
 #include <gio/gdesktopappinfo.h>
 #include "app-menu-item.h"
 
+enum {
+	COUNT_CHANGED,
+	NAME_CHANGED,
+	LAST_SIGNAL
+};
+
+static guint signals[LAST_SIGNAL] = { 0 };
+
 typedef struct _AppMenuItemPrivate AppMenuItemPrivate;
 
 struct _AppMenuItemPrivate
@@ -38,6 +46,8 @@
 	
 	gchar * type;
 	GAppInfo * appinfo;
+	guint unreadcount;
+	gboolean count_on_label;
 
 	GtkWidget * name;
 };
@@ -52,6 +62,9 @@
 static void activate_cb (AppMenuItem * self, gpointer data);
 static void type_cb (IndicateListener * listener, IndicateListenerServer * server, gchar * value, gpointer data);
 static void desktop_cb (IndicateListener * listener, IndicateListenerServer * server, gchar * value, gpointer data);
+static void indicator_added_cb (IndicateListener * listener, IndicateListenerServer * server, IndicateListenerIndicator * indicator, gchar * type, gpointer data);
+static void indicator_removed_cb (IndicateListener * listener, IndicateListenerServer * server, IndicateListenerIndicator * indicator, gchar * type, gpointer data);
+static void update_label (AppMenuItem * self);
 
 
 
@@ -66,6 +79,23 @@
 
 	object_class->dispose = app_menu_item_dispose;
 	object_class->finalize = app_menu_item_finalize;
+
+	signals[COUNT_CHANGED] = g_signal_new(APP_MENU_ITEM_SIGNAL_COUNT_CHANGED,
+	                                      G_TYPE_FROM_CLASS(klass),
+	                                      G_SIGNAL_RUN_LAST,
+	                                      G_STRUCT_OFFSET (AppMenuItemClass, count_changed),
+	                                      NULL, NULL,
+	                                      g_cclosure_marshal_VOID__UINT,
+	                                      G_TYPE_NONE, 1, G_TYPE_UINT);
+	signals[NAME_CHANGED] =  g_signal_new(APP_MENU_ITEM_SIGNAL_NAME_CHANGED,
+	                                      G_TYPE_FROM_CLASS(klass),
+	                                      G_SIGNAL_RUN_LAST,
+	                                      G_STRUCT_OFFSET (AppMenuItemClass, name_changed),
+	                                      NULL, NULL,
+	                                      g_cclosure_marshal_VOID__STRING,
+	                                      G_TYPE_NONE, 1, G_TYPE_STRING);
+
+	return;
 }
 
 static void
@@ -79,6 +109,8 @@
 	priv->name = NULL;
 	priv->type = NULL;
 	priv->appinfo = NULL;
+	priv->unreadcount = 0;
+	priv->count_on_label = FALSE;
 
 
 	return;
@@ -94,6 +126,14 @@
 app_menu_item_finalize (GObject *object)
 {
 	G_OBJECT_CLASS (app_menu_item_parent_class)->finalize (object);
+
+	AppMenuItem * self = APP_MENU_ITEM(object);
+	AppMenuItemPrivate * priv = APP_MENU_ITEM_GET_PRIVATE(self);
+
+	g_signal_handlers_disconnect_by_func(G_OBJECT(priv->listener), G_CALLBACK(indicator_added_cb), self);
+	g_signal_handlers_disconnect_by_func(G_OBJECT(priv->listener), G_CALLBACK(indicator_removed_cb), self);
+
+	return;
 }
 
 AppMenuItem *
@@ -106,6 +146,9 @@
 	priv->listener = listener;
 	priv->server = server;
 
+	g_signal_connect(G_OBJECT(listener), INDICATE_LISTENER_SIGNAL_INDICATOR_ADDED, G_CALLBACK(indicator_added_cb), self);
+	g_signal_connect(G_OBJECT(listener), INDICATE_LISTENER_SIGNAL_INDICATOR_REMOVED, G_CALLBACK(indicator_removed_cb), self);
+
 	priv->name = gtk_label_new(INDICATE_LISTENER_SERVER_DBUS_NAME(server));
 	gtk_misc_set_alignment(GTK_MISC(priv->name), 0.0, 0.5);
 	gtk_widget_show(GTK_WIDGET(priv->name));
@@ -132,6 +175,30 @@
 	
 	priv->type = g_strdup(value);
 
+	if (!(!g_strcmp0(priv->type, "message.instant") || !g_strcmp0(priv->type, "message.micro") || !g_strcmp0(priv->type, "message.im"))) {
+		/* For IM and Microblogging we want the individual items, not a count */
+		priv->count_on_label = TRUE;
+		update_label(self);
+	}
+
+	return;
+}
+
+static void
+update_label (AppMenuItem * self)
+{
+	AppMenuItemPrivate * priv = APP_MENU_ITEM_GET_PRIVATE(self);
+
+	if (priv->count_on_label && !priv->unreadcount < 1) {
+		/* TRANSLATORS: This is the name of the program and the number of indicators.  So it
+		                would read something like "Mail Client (5)" */
+		gchar * label = g_strdup_printf(_("%s (%d)"), g_app_info_get_name(priv->appinfo), priv->unreadcount);
+		gtk_label_set_text(GTK_LABEL(priv->name), label);
+		g_free(label);
+	} else {
+		gtk_label_set_text(GTK_LABEL(priv->name), g_app_info_get_name(priv->appinfo));
+	}
+
 	return;
 }
 
@@ -144,11 +211,16 @@
 	if (priv->appinfo != NULL) {
 		g_object_unref(G_OBJECT(priv->appinfo));
 	}
+
+	if (value == NULL || value[0] == '\0') {
+		return;
+	}
 	
 	priv->appinfo = G_APP_INFO(g_desktop_app_info_new_from_filename(value));
 	g_return_if_fail(priv->appinfo != NULL);
 
-	gtk_label_set_text(GTK_LABEL(priv->name), g_app_info_get_name(priv->appinfo));
+	update_label(self);
+	g_signal_emit(G_OBJECT(self), signals[NAME_CHANGED], 0, g_app_info_get_name(priv->appinfo), TRUE);
 
 	return;
 }
@@ -162,3 +234,69 @@
 
 	return;
 }
+
+static void 
+indicator_added_cb (IndicateListener * listener, IndicateListenerServer * server, IndicateListenerIndicator * indicator, gchar * type, gpointer data)
+{
+	AppMenuItemPrivate * priv = APP_MENU_ITEM_GET_PRIVATE(data);
+
+	if (g_strcmp0(INDICATE_LISTENER_SERVER_DBUS_NAME(server), INDICATE_LISTENER_SERVER_DBUS_NAME(priv->server))) {
+		/* Not us */
+		return;
+	}
+
+	priv->unreadcount++;
+
+	update_label(APP_MENU_ITEM(data));
+	g_signal_emit(G_OBJECT(data), signals[COUNT_CHANGED], 0, priv->unreadcount, TRUE);
+
+	return;
+}
+
+static void
+indicator_removed_cb (IndicateListener * listener, IndicateListenerServer * server, IndicateListenerIndicator * indicator, gchar * type, gpointer data)
+{
+	AppMenuItemPrivate * priv = APP_MENU_ITEM_GET_PRIVATE(data);
+
+	if (g_strcmp0(INDICATE_LISTENER_SERVER_DBUS_NAME(server), INDICATE_LISTENER_SERVER_DBUS_NAME(priv->server))) {
+		/* Not us */
+		return;
+	}
+
+	/* Should never happen, but let's have some protection on that */
+	if (priv->unreadcount > 0) {
+		priv->unreadcount--;
+	}
+
+	update_label(APP_MENU_ITEM(data));
+	g_signal_emit(G_OBJECT(data), signals[COUNT_CHANGED], 0, priv->unreadcount, TRUE);
+
+	return;
+}
+
+guint
+app_menu_item_get_count (AppMenuItem * appitem)
+{
+	AppMenuItemPrivate * priv = APP_MENU_ITEM_GET_PRIVATE(appitem);
+
+	return priv->unreadcount;
+}
+
+IndicateListenerServer *
+app_menu_item_get_server (AppMenuItem * appitem) {
+	AppMenuItemPrivate * priv = APP_MENU_ITEM_GET_PRIVATE(appitem);
+
+	return priv->server;
+}
+
+const gchar *
+app_menu_item_get_name (AppMenuItem * appitem)
+{
+	AppMenuItemPrivate * priv = APP_MENU_ITEM_GET_PRIVATE(appitem);
+
+	if (priv->appinfo == NULL) {
+		return INDICATE_LISTENER_SERVER_DBUS_NAME(priv->server);
+	} else {
+		return g_app_info_get_name(priv->appinfo);
+	}
+}

=== modified file 'src/app-menu-item.h'
--- src/app-menu-item.h	2009-02-11 22:04:58 +0000
+++ src/app-menu-item.h	2009-03-15 17:19:02 +0000
@@ -36,11 +36,17 @@
 #define IS_APP_MENU_ITEM_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), APP_MENU_ITEM_TYPE))
 #define APP_MENU_ITEM_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS ((obj), APP_MENU_ITEM_TYPE, AppMenuItemClass))
 
+#define APP_MENU_ITEM_SIGNAL_COUNT_CHANGED  "count-changed"
+#define APP_MENU_ITEM_SIGNAL_NAME_CHANGED   "name-changed"
+
 typedef struct _AppMenuItem      AppMenuItem;
 typedef struct _AppMenuItemClass AppMenuItemClass;
 
 struct _AppMenuItemClass {
 	GtkMenuItemClass parent_class;
+
+	void (* count_changed) (guint count);
+	void (* name_changed) (gchar * name);
 };
 
 struct _AppMenuItem {
@@ -49,6 +55,9 @@
 
 GType app_menu_item_get_type (void);
 AppMenuItem * app_menu_item_new (IndicateListener * listener, IndicateListenerServer * server);
+guint app_menu_item_get_count (AppMenuItem * appitem);
+IndicateListenerServer * app_menu_item_get_server (AppMenuItem * appitem);
+const gchar * app_menu_item_get_name (AppMenuItem * appitem);
 
 G_END_DECLS
 

=== modified file 'src/im-menu-item.c'
--- src/im-menu-item.c	2009-02-13 19:58:48 +0000
+++ src/im-menu-item.c	2009-03-18 18:21:21 +0000
@@ -27,6 +27,13 @@
 #include <gtk/gtk.h>
 #include "im-menu-item.h"
 
+enum {
+	TIME_CHANGED,
+	LAST_SIGNAL
+};
+
+static guint signals[LAST_SIGNAL] = { 0 };
+
 typedef struct _ImMenuItemPrivate ImMenuItemPrivate;
 
 struct _ImMenuItemPrivate
@@ -35,6 +42,8 @@
 	IndicateListenerServer *      server;
 	IndicateListenerIndicator *  indicator;
 
+	glong seconds;
+
 	GtkHBox * hbox;
 	GtkLabel * user;
 	GtkLabel * time;
@@ -92,6 +101,16 @@
 
 	object_class->dispose = im_menu_item_dispose;
 	object_class->finalize = im_menu_item_finalize;
+
+	signals[TIME_CHANGED] =  g_signal_new(IM_MENU_ITEM_SIGNAL_TIME_CHANGED,
+	                                      G_TYPE_FROM_CLASS(klass),
+	                                      G_SIGNAL_RUN_LAST,
+	                                      G_STRUCT_OFFSET (ImMenuItemClass, time_changed),
+	                                      NULL, NULL,
+	                                      g_cclosure_marshal_VOID__LONG,
+	                                      G_TYPE_NONE, 1, G_TYPE_LONG);
+
+	return;
 }
 
 static void
@@ -104,6 +123,8 @@
 	priv->server = NULL;
 	priv->indicator = NULL;
 
+	priv->seconds = 0;
+
 	/* build widgets first */
 	priv->icon = GTK_IMAGE(gtk_image_new());
 	priv->user = GTK_LABEL(gtk_label_new(""));
@@ -185,6 +206,8 @@
 
 	ImMenuItemPrivate * priv = IM_MENU_ITEM_GET_PRIVATE(self);
 
+	priv->seconds = propertydata->tv_sec;
+
 	time_t timet;
 	struct tm * structtm;
 
@@ -198,6 +221,8 @@
 	gtk_label_set_label(priv->time, timestring);
 	gtk_widget_show(GTK_WIDGET(priv->time));
 
+	g_signal_emit(G_OBJECT(self), signals[TIME_CHANGED], 0, priv->seconds, TRUE);
+
 	return;
 }
 
@@ -276,3 +301,10 @@
 
 	return self;
 }
+
+glong
+im_menu_item_get_seconds (ImMenuItem * menuitem)
+{
+	ImMenuItemPrivate * priv = IM_MENU_ITEM_GET_PRIVATE(menuitem);
+	return priv->seconds;
+}

=== modified file 'src/im-menu-item.h'
--- src/im-menu-item.h	2009-02-11 22:04:58 +0000
+++ src/im-menu-item.h	2009-03-18 18:21:21 +0000
@@ -36,11 +36,15 @@
 #define IS_IM_MENU_ITEM_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), IM_MENU_ITEM_TYPE))
 #define IM_MENU_ITEM_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS ((obj), IM_MENU_ITEM_TYPE, ImMenuItemClass))
 
+#define IM_MENU_ITEM_SIGNAL_TIME_CHANGED  "time-changed"
+
 typedef struct _ImMenuItem      ImMenuItem;
 typedef struct _ImMenuItemClass ImMenuItemClass;
 
 struct _ImMenuItemClass {
 	GtkMenuItemClass parent_class;
+
+	void (*time_changed) (glong seconds);
 };
 
 struct _ImMenuItem {
@@ -49,6 +53,7 @@
 
 GType im_menu_item_get_type (void);
 ImMenuItem * im_menu_item_new (IndicateListener * listener, IndicateListenerServer * server, IndicateListenerIndicator * indicator);
+glong im_menu_item_get_seconds (ImMenuItem * menuitem);
 
 G_END_DECLS
 

=== modified file 'src/indicator-messages.c'
--- src/indicator-messages.c	2009-02-16 04:25:44 +0000
+++ src/indicator-messages.c	2009-03-18 18:45:51 +0000
@@ -28,11 +28,53 @@
 #include "app-menu-item.h"
 
 static IndicateListener * listener;
-static GList * imList;
-static GHashTable * serverHash;
+static GList * serverList;
 static GtkWidget * main_image;
 static GtkWidget * main_menu;
 
+static void server_count_changed (AppMenuItem * appitem, guint count, gpointer data);
+static void server_name_changed (AppMenuItem * appitem, gchar * name, gpointer data);
+static void im_time_changed (ImMenuItem * imitem, glong seconds, gpointer data);
+static void reconsile_list_and_menu (GList * serverlist, GtkMenuShell * menushell);
+
+#define DESIGN_TEAM_SIZE  design_team_size
+static GtkIconSize design_team_size;
+
+typedef struct _serverList_t serverList_t;
+struct _serverList_t {
+	IndicateListenerServer * server;
+	AppMenuItem * menuitem;
+	GList * imList;
+};
+
+static gint
+serverList_equal (gconstpointer a, gconstpointer b)
+{
+	serverList_t * pa, * pb;
+
+	pa = (serverList_t *)a;
+	pb = (serverList_t *)b;
+
+	gchar * pas = INDICATE_LISTENER_SERVER_DBUS_NAME(pa->server);
+	gchar * pbs = INDICATE_LISTENER_SERVER_DBUS_NAME(pb->server);
+
+	return g_strcmp0(pas, pbs);
+}
+
+static gint
+serverList_sort (gconstpointer a, gconstpointer b)
+{
+	serverList_t * pa, * pb;
+
+	pa = (serverList_t *)a;
+	pb = (serverList_t *)b;
+
+	const gchar * pan = app_menu_item_get_name(pa->menuitem);
+	const gchar * pbn = app_menu_item_get_name(pb->menuitem);
+
+	return g_strcmp0(pan, pbn);
+}
+
 typedef struct _imList_t imList_t;
 struct _imList_t {
 	IndicateListenerServer * server;
@@ -59,6 +101,16 @@
 	return !((!strcmp(pas, pbs)) && (pai == pbi));
 }
 
+static gint
+imList_sort (gconstpointer a, gconstpointer b)
+{
+	imList_t * pa, * pb;
+
+	pa = (imList_t *)a;
+	pb = (imList_t *)b;
+
+	return (gint)(im_menu_item_get_seconds(IM_MENU_ITEM(pb->menuitem)) - im_menu_item_get_seconds(IM_MENU_ITEM(pa->menuitem)));
+}
 
 void 
 server_added (IndicateListener * listener, IndicateListenerServer * server, gchar * type, gpointer data)
@@ -83,14 +135,95 @@
 		return;
 	}
 
-	gchar * servername = g_strdup(INDICATE_LISTENER_SERVER_DBUS_NAME(server));
 	AppMenuItem * menuitem = app_menu_item_new(listener, server);
-
-	g_hash_table_insert(serverHash, servername, menuitem);
+	g_signal_connect(G_OBJECT(menuitem), APP_MENU_ITEM_SIGNAL_COUNT_CHANGED, G_CALLBACK(server_count_changed), NULL);
+	g_signal_connect(G_OBJECT(menuitem), APP_MENU_ITEM_SIGNAL_NAME_CHANGED,  G_CALLBACK(server_name_changed),  menushell);
+
+	serverList_t * sl_item = g_new(serverList_t, 1);
+	sl_item->server = server;
+	sl_item->menuitem = menuitem;
+	sl_item->imList = NULL;
+
+	/* Incase we got an indicator first */
+	GList * alreadythere = g_list_find_custom(serverList, sl_item, serverList_equal);
+	if (alreadythere != NULL) {
+		g_free(sl_item);
+		sl_item = (serverList_t *)alreadythere->data;
+		sl_item->menuitem = menuitem;
+		serverList = g_list_sort(serverList, serverList_sort);
+	} else {
+		serverList = g_list_insert_sorted(serverList, sl_item, serverList_sort);
+	}
+
 	gtk_menu_shell_prepend(menushell, GTK_WIDGET(menuitem));
-	gtk_widget_show(menuitem);
-	gtk_widget_show(main_menu);
-
+	gtk_widget_show(GTK_WIDGET(menuitem));
+	gtk_widget_show(GTK_WIDGET(main_menu));
+
+	reconsile_list_and_menu(serverList, menushell);
+
+	return;
+}
+
+static void
+server_name_changed (AppMenuItem * appitem, gchar * name, gpointer data)
+{
+	serverList = g_list_sort(serverList, serverList_sort);
+	reconsile_list_and_menu(serverList, GTK_MENU_SHELL(data));
+	return;
+}
+
+static void
+server_count_changed (AppMenuItem * appitem, guint count, gpointer data)
+{
+	static gboolean showing_new_icon = FALSE;
+
+	/* Quick check for a common case */
+	if (count != 0 && showing_new_icon) {
+		return;
+	}
+
+	/* Odd that we'd get a signal in this case, but let's
+	   take it out of the mix too */
+	if (count == 0 && !showing_new_icon) {
+		return;
+	}
+
+	if (count != 0) {
+		g_debug("Setting image to 'new'");
+		showing_new_icon = TRUE;
+		gtk_image_set_from_icon_name(GTK_IMAGE(main_image), "indicator-messages-new", DESIGN_TEAM_SIZE);
+		return;
+	}
+
+	/* Okay, now at this point the count is zero and it
+	   might result in a switching of the icon back to being
+	   the plain one.  Let's check. */
+
+	gboolean we_have_indicators = FALSE;
+	GList * appitems = serverList;
+	for (; appitems != NULL; appitems = appitems->next) {
+		AppMenuItem * appitem = ((serverList_t *)appitems->data)->menuitem;
+		if (app_menu_item_get_count(appitem) != 0) {
+			we_have_indicators = TRUE;
+			break;
+		}
+	}
+
+	if (!we_have_indicators) {
+		g_debug("Setting image to boring");
+		showing_new_icon = FALSE;
+		gtk_image_set_from_icon_name(GTK_IMAGE(main_image), "indicator-messages", DESIGN_TEAM_SIZE);
+	}
+
+	return;
+}
+
+static void
+im_time_changed (ImMenuItem * imitem, glong seconds, gpointer data)
+{
+	serverList_t * sl = (serverList_t *)data;
+	sl->imList = g_list_sort(sl->imList, imList_sort);
+	reconsile_list_and_menu(serverList, GTK_MENU_SHELL(gtk_widget_get_parent(GTK_WIDGET(imitem))));
 	return;
 }
 
@@ -98,23 +231,88 @@
 server_removed (IndicateListener * listener, IndicateListenerServer * server, gchar * type, gpointer data)
 {
 	g_debug("Removing server: %s", INDICATE_LISTENER_SERVER_DBUS_NAME(server));
-	gpointer lookup = g_hash_table_lookup(serverHash, INDICATE_LISTENER_SERVER_DBUS_NAME(server));
+	serverList_t slt;
+	slt.server = server;
+	GList * lookup = g_list_find_custom(serverList, &slt, serverList_equal);
 
 	if (lookup == NULL) {
 		g_debug("\tUnable to find server: %s", INDICATE_LISTENER_SERVER_DBUS_NAME(server));
 		return;
 	}
 
-	g_hash_table_remove(serverHash, INDICATE_LISTENER_SERVER_DBUS_NAME(server));
-
-	AppMenuItem * menuitem = APP_MENU_ITEM(lookup);
-	g_return_if_fail(menuitem != NULL);
-
-	gtk_widget_hide(GTK_WIDGET(menuitem));
-	gtk_container_remove(GTK_CONTAINER(data), GTK_WIDGET(menuitem));
-
-	if (g_list_length(g_hash_table_get_keys(serverHash)) == 0 && g_list_length(imList) == 0) {
+	serverList_t * sltp = (serverList_t *)lookup->data;
+	serverList = g_list_remove(serverList, sltp);
+
+	if (sltp->menuitem != NULL) {
+		gtk_widget_hide(GTK_WIDGET(sltp->menuitem));
+		gtk_container_remove(GTK_CONTAINER(data), GTK_WIDGET(sltp->menuitem));
+	}
+
+	g_free(sltp);
+
+	if (g_list_length(serverList) == 0) {
 		gtk_widget_hide(main_menu);
+	} else {
+		/* Simulate a server saying zero to recalculate icon */
+		server_count_changed(NULL, 0, NULL);
+	}
+
+	return;
+}
+
+typedef struct _menushell_location menushell_location_t;
+struct _menushell_location {
+	const IndicateListenerServer * server;
+	gint position;
+	gboolean found;
+};
+
+static void
+menushell_foreach_cb (GtkWidget * data_mi, gpointer data_ms) {
+	menushell_location_t * msl = (menushell_location_t *)data_ms;
+
+	if (msl->found) return;
+
+	msl->position++;
+
+	if (!IS_APP_MENU_ITEM(data_mi)) {
+		return;
+	}
+
+	AppMenuItem * appmenu = APP_MENU_ITEM(data_mi);
+	if (!g_strcmp0(INDICATE_LISTENER_SERVER_DBUS_NAME(msl->server), INDICATE_LISTENER_SERVER_DBUS_NAME(app_menu_item_get_server(appmenu)))) {
+		msl->found = TRUE;
+	}
+
+	return;
+}
+
+static void
+reconsile_list_and_menu (GList * serverlist, GtkMenuShell * menushell)
+{
+	guint position = 0;
+	GList * serverentry;
+
+	g_debug("Reordering Menu:");
+
+	for (serverentry = serverList; serverentry != NULL; serverentry = serverentry->next) {
+		serverList_t * si = (serverList_t *)serverentry->data;
+		if (si->menuitem != NULL) {
+			g_debug("\tMoving app %s to position %d", INDICATE_LISTENER_SERVER_DBUS_NAME(si->server), position);
+			gtk_menu_reorder_child(GTK_MENU(menushell), GTK_WIDGET(si->menuitem), position);
+			position++;
+		}
+
+		GList * imentry;
+		for (imentry = si->imList; imentry != NULL; imentry = imentry->next) {
+			imList_t * imi = (imList_t *)imentry->data;
+
+			if (imi->menuitem != NULL) {
+				g_debug("\tMoving indicator on %s id %d to position %d", INDICATE_LISTENER_SERVER_DBUS_NAME(imi->server), INDICATE_LISTENER_INDICATOR_ID(imi->indicator), position);
+				gtk_menu_reorder_child(GTK_MENU(menushell), imi->menuitem, position);
+				position++;
+			}
+		}
 	}
 
 	return;
@@ -154,18 +352,42 @@
 		g_object_ref(G_OBJECT(menuitem));
 		listItem->menuitem = GTK_WIDGET(menuitem);
 
-		g_debug("Adding to IM Hash");
-		imList = g_list_append(imList, listItem);
+		g_debug("Finding the server entry");
+		serverList_t sl_item_local;
+		serverList_t * sl_item = NULL;
+		sl_item_local.server = server;
+		GList * serverentry = g_list_find_custom(serverList, &sl_item_local, serverList_equal);
+
+		if (serverentry == NULL) {
+			/* This sucks, we got an indicator before the server.  I guess
+			   that's the joy of being asynchronous */
+			serverList_t * sl_item = g_new(serverList_t, 1);
+			sl_item->server = server;
+			sl_item->menuitem = NULL;
+			sl_item->imList = NULL;
+
+			serverList = g_list_insert_sorted(serverList, sl_item, serverList_sort);
+		} else {
+			sl_item = (serverList_t *)serverentry->data;
+		}
+
+		g_debug("Adding to IM List");
+		sl_item->imList = g_list_insert_sorted(sl_item->imList, listItem, imList_sort);
+		g_signal_connect(G_OBJECT(menuitem), IM_MENU_ITEM_SIGNAL_TIME_CHANGED, G_CALLBACK(im_time_changed), sl_item);
 
 		g_debug("Placing in Shell");
-		gtk_menu_shell_prepend(menushell, GTK_WIDGET(menuitem));
-	}
+		menushell_location_t msl;
+		msl.found = FALSE;
+		msl.position = 0;
+		msl.server = server;
 
-	if (g_list_length(imList) != 0) {
-		g_debug("Setting image to 'new'");
-		gtk_image_set_from_icon_name(main_image, "indicator-messages-new", GTK_ICON_SIZE_MENU);
-	} else {
-		g_debug("Hmm, still no entries");
+		gtk_container_foreach(GTK_CONTAINER(menushell), menushell_foreach_cb, &msl);
+		if (msl.found) {
+			gtk_menu_shell_insert(menushell, GTK_WIDGET(menuitem), msl.position);
+		} else {
+			g_warning("Unable to find server menu item");
+			gtk_menu_shell_append(menushell, GTK_WIDGET(menuitem));
+		}
 	}
 
 	return;
@@ -199,12 +421,21 @@
 
 	gboolean removed = FALSE;
 
+	serverList_t sl_item_local;
+	serverList_t * sl_item = NULL;
+	sl_item_local.server = server;
+	GList * serverentry = g_list_find_custom(serverList, &sl_item_local, serverList_equal);
+	if (serverentry == NULL) {
+		return;
+	}
+	sl_item = (serverList_t *)serverentry->data;
+
 	/* Look in the IM Hash Table */
 	imList_t listData;
 	listData.server = server;
 	listData.indicator = indicator;
 
-	GList * listItem = g_list_find_custom(imList, &listData, imList_equal);
+	GList * listItem = g_list_find_custom(sl_item->imList, &listData, imList_equal);
 	GtkWidget * menuitem = NULL;
 	if (listItem != NULL) {
 		menuitem = ((imList_t *)listItem->data)->menuitem;
@@ -212,7 +443,7 @@
 
 	if (!removed && menuitem != NULL) {
 		g_object_ref(menuitem);
-		imList = g_list_remove(imList, listItem->data);
+		sl_item->imList = g_list_remove(sl_item->imList, listItem->data);
 
 		gtk_widget_hide(menuitem);
 		gtk_container_remove(GTK_CONTAINER(data), menuitem);
@@ -225,28 +456,20 @@
 		g_warning("We were asked to remove %s %d but we didn't.", (gchar*)server, (guint)indicator);
 	}
 
-	if (g_list_length(imList) == 0) {
-		gtk_image_set_from_icon_name(main_image, "indicator-messages", GTK_ICON_SIZE_MENU);
-		if (g_list_length(g_hash_table_get_keys(serverHash)) == 0) {
-			gtk_widget_hide(main_menu);
-		}
-	}
-
 	return;
 }
 
 GtkWidget *
 get_menu_item (void)
 {
+	design_team_size = gtk_icon_size_register("design-team-size", 22, 22);
+
 	listener = indicate_listener_new();
-	imList = NULL;
-
-	serverHash = g_hash_table_new_full(g_str_hash, g_str_equal,
-	                                   g_free, NULL);
+	serverList = NULL;
 
 	main_menu = gtk_menu_item_new();
 
-	main_image = gtk_image_new_from_icon_name("indicator-messages", GTK_ICON_SIZE_MENU);
+	main_image = gtk_image_new_from_icon_name("indicator-messages", DESIGN_TEAM_SIZE);
 	gtk_widget_show(main_image);
 	gtk_container_add(GTK_CONTAINER(main_menu), main_image);
 

_______________________________________________
Mailing list: https://launchpad.net/~dx-team
Post to     : [email protected]
Unsubscribe : https://launchpad.net/~dx-team
More help   : https://help.launchpad.net/ListHelp

Reply via email to