← Back to team overview

ayatana-commits team mailing list archive

[Merge] lp:~ted/indicator-messages/newapi.ubuntu into lp:indicator-messages

 

David Barth has proposed merging lp:~ted/indicator-messages/newapi.ubuntu into lp:indicator-messages.

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

Assuming the branch is in a merge'able state.

It provides:
6. Supporting new libindicate that no longer supports message types (Email, IM, etc...)
7. libindicate code is done, needs to be code reviewed

as stated in https://bugs.edge.launchpad.net/indicator-messages/+bug/423013/comments/2

Aurélien: can you have a look at this branch too please?
-- 
https://code.launchpad.net/~ted/indicator-messages/newapi.ubuntu/+merge/11317
Your team ayatana-commits is subscribed to branch lp:indicator-messages.
=== added directory '.bzr-builddeb'
=== added file '.bzr-builddeb/default.conf'
--- .bzr-builddeb/default.conf	1970-01-01 00:00:00 +0000
+++ .bzr-builddeb/default.conf	2009-03-19 11:22:21 +0000
@@ -0,0 +1,2 @@
+[BUILDDEB]
+merge = True

=== modified file 'configure.ac'
--- configure.ac	2009-09-03 19:06:22 +0000
+++ configure.ac	2009-09-04 20:37:59 +0000
@@ -34,7 +34,6 @@
                           gio-unix-2.0 >= $GIO_UNIX_REQUIRED_VERSION
                           indicator >= $INDICATOR_REQUIRED_VERSION
                           indicate >= $INDICATE_REQUIRED_VERSION
-                          indicate-gtk >= $INDICATE_REQUIRED_VERSION
                           dbusmenu-gtk >= $DBUSMENUGTK_REQUIRED_VERSION)
 AC_SUBST(APPLET_CFLAGS)
 AC_SUBST(APPLET_LIBS)

=== added directory 'debian'
=== added file 'debian/changelog'
--- debian/changelog	1970-01-01 00:00:00 +0000
+++ debian/changelog	2009-09-05 16:44:38 +0000
@@ -0,0 +1,178 @@
+indicator-messages (0.2.0-0ubuntu3~ppa2~newapi2) karmic; urgency=low
+
+  * Fix for the changes in libindicate (fixes)
+
+ -- Ted Gould <ted@xxxxxxxxxx>  Sat, 05 Sep 2009 11:44:34 -0500
+
+indicator-messages (0.2.0-0ubuntu3~ppa2~newapi1) karmic; urgency=low
+
+  * Merging in changes for the new libindicate API
+
+ -- Ted Gould <ted@xxxxxxxxxx>  Sat, 05 Sep 2009 11:13:51 -0500
+
+indicator-messages (0.2.0-0ubuntu3~ppa1) karmic; urgency=low
+
+  * Bumping version after ~ubuntu-desktop merge.
+
+ -- Ted Gould <ted@xxxxxxxxxx>  Fri, 04 Sep 2009 13:56:06 -0500
+
+indicator-messages (0.2.0-0ubuntu1~ppa3) karmic; urgency=low
+
+  * Upstream usage of new Dbusmenu 0.1.1 defines.
+  * debian/control: Increasing Dbusmenu dependencies.
+
+ -- Ted Gould <ted@xxxxxxxxxx>  Fri, 04 Sep 2009 13:50:50 -0500
+
+indicator-messages (0.2.0-0ubuntu1~ppa2) karmic; urgency=low
+
+  * Upstream update to dbusmenu dependency.
+  * debian/control: Adding dependency information for libdbusmenu
+    to say >= 0.1.0 to match upstream build system.
+
+ -- Ted Gould <ted@xxxxxxxxxx>  Thu, 27 Aug 2009 14:01:03 -0500
+
+indicator-messages (0.2.0-0ubuntu2) karmic; urgency=low
+
+  * debian/control
+    - Bump build depends on dbusmenu to 0.1.0
+
+ -- Ken VanDine <ken.vandine@xxxxxxxxxxxxx>  Thu, 27 Aug 2009 21:14:46 +0200
+
+indicator-messages (0.2.0-0ubuntu1) karmic; urgency=low
+
+  [ Ted Gould ]
+  * Upstream version 0.2.0
+  * debian/control: Adding dependency information for libdbusmenu
+    to say >= 0.0.2 to match upstream build system.
+  * debian/watch: Changing to use indicator-messages project.
+
+  [ Martin Pitt ]
+  * debian/control: Update Vcs-Bzr: for new branch location.
+
+ -- Ted Gould <ted@xxxxxxxxxx>  Thu, 27 Aug 2009 20:46:27 +0200
+
+indicator-messages (0.2.0~bzr124-0ubuntu1) karmic; urgency=low
+
+  * Update to fix build issue
+
+ -- Sebastien Bacher <seb128@xxxxxxxxxx>  Fri, 07 Aug 2009 17:12:40 +0100
+
+indicator-messages (0.2.0~bzr121-0ubuntu3) karmic; urgency=low
+
+  * Fix to dereference the application menu items correctly so that
+    the signal handlers are dropped as well. (lp: #410251)
+
+ -- Ted Gould <ted@xxxxxxxxxx>  Wed, 05 Aug 2009 19:00:31 +0100
+
+indicator-messages (0.2.0~bzr121-0ubuntu2) karmic; urgency=low
+
+  * Run autogen.sh before upload
+
+ -- Jonathan Riddell <jriddell@xxxxxxxxxx>  Wed, 05 Aug 2009 00:42:39 +0100
+
+indicator-messages (0.2.0~bzr121-0ubuntu1) karmic; urgency=low
+
+  [ Ted Gould ]
+  * debian/control: Adding in a build dep on libindicate-gtk-dev
+  * Changes for the changing libindicate stuff.
+  * Merge in the dbusmenu changes from the dbusmenu branch
+  * debian/control: Adding in a build dependency on libdbusmenu-glib and
+    libdbusmenu-gtk to catch up with the merge.
+
+ -- Jonathan Riddell <jriddell@xxxxxxxxxx>  Wed, 05 Aug 2009 00:21:50 +0100
+
+indicator-messages (0.2.0~bzr120-0ubuntu1) jaunty; urgency=low
+
+  * Fix to track the timer. (LP: #365187)
+
+ -- Ted Gould <ted@xxxxxxxxxx>  Wed, 13 May 2009 09:56:20 -0500
+
+indicator-messages (0.2.0~bzr119-0ubuntu1) jaunty; urgency=low
+
+  * Upstream update
+
+ -- Ted Gould <ted@xxxxxxxxxx>  Wed, 22 Apr 2009 23:34:21 -0500
+
+indicator-messages (0.2.0~bzr116-0ubuntu3) jaunty; urgency=low
+
+  * debian/rules: Adding a rule to remove the .la/.a clutter
+
+ -- Ted Gould <ted@xxxxxxxxxx>  Wed, 22 Apr 2009 16:46:59 -0500
+
+indicator-messages (0.2.0~bzr116-0ubuntu2) jaunty; urgency=low
+
+  * debian/control: libindicator-dev to ~bzr301
+
+ -- Ted Gould <ted@xxxxxxxxxx>  Wed, 22 Apr 2009 15:58:45 -0500
+
+indicator-messages (0.2.0~bzr116-0ubuntu1) jaunty; urgency=low
+
+  * Upstream release
+    * Bug fixes
+    * Update API to new libindicator
+  * debian/control: Adding new dependency on libindicator-dev
+
+ -- Ted Gould <ted@xxxxxxxxxx>  Wed, 22 Apr 2009 15:45:21 -0500
+
+indicator-messages (0.1.6-0ubuntu1) jaunty; urgency=low
+
+  * New upstream version
+    * Patch from Cody Russell to fix LP: #359018 by correctly implementing
+      the finalize functions.
+
+ -- Ted Gould <ted@xxxxxxxxxx>  Tue, 14 Apr 2009 11:32:00 +0200
+
+indicator-messages (0.1.5-0ubuntu1) jaunty; urgency=low
+
+  * New upstream version
+    * Fixes the lifecycle of the various structures tracking the messages
+      and applications.  Fixing bugs like (LP: #355616) (LP: #352881)
+    * Fixes the visual appearance by setting the widget name to grab the
+      style settings from the main applet.  (LP: #351979)
+  * debian/control: Upgrading dependency on libindicate-dev to 0.1.5 or
+    higher as the new version requires that.
+
+ -- Ted Gould <ted@xxxxxxxxxx>  Fri, 03 Apr 2009 16:32:49 -0500
+
+indicator-messages (0.1.4-0ubuntu1) jaunty; urgency=low
+
+  * New upstream version
+    * Adding the display of indicators that are login messages coming from
+      other applications.  (LP: #345494)
+    * Making all times displayed for IM messages relative instead of
+      absolute.  (LP: #346345)
+    * Cleaning up the server removal code.  May fix (LP: #345599), I can't
+      recreate it anymore afterwards.
+
+ -- Ted Gould <ted@xxxxxxxxxx>  Mon, 30 Mar 2009 09:40:40 +0200
+
+indicator-messages (0.1.3-0ubuntu1) jaunty; urgency=low
+
+  [ Ted Gould ]
+  * 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.
+
+  [ Martin Pitt ]
+  * Add debian/watch.
+  * Add bzr-builddeb configuration.
+  * debian/copyright: Fix download location.
+
+ -- Martin Pitt <martin.pitt@xxxxxxxxxx>  Thu, 19 Mar 2009 12:23:17 +0100
+
+indicator-messages (0.1-0ubuntu1) jaunty; urgency=low
+
+  * Initial release, based on DX team's PPA packaging branch.
+    (lp:~indicator-applet-developers/indicator-applet/messages-packaging)
+  * debian/control: Add Homepage:, Vcs-Bzr:, and fix package
+    description.
+  * debian/copyright: Properly describe license.
+
+ -- Martin Pitt <martin.pitt@xxxxxxxxxx>  Tue, 17 Feb 2009 11:35:38 +0100

=== added file 'debian/control'
--- debian/control	1970-01-01 00:00:00 +0000
+++ debian/control	2009-09-04 18:54:25 +0000
@@ -0,0 +1,29 @@
+Source: indicator-messages
+Section: gnome
+Priority: optional
+Maintainer: Ubuntu Core Developers <ubuntu-devel-discuss@xxxxxxxxxxxxxxxx>
+Build-Depends: debhelper (>= 5.0),
+               cdbs (>= 0.4.41),
+               libgtk2.0-dev (>= 2.12.0),
+               libdbus-glib-1-dev,
+               gnome-doc-utils,
+               scrollkeeper,
+               intltool,
+               libindicate-dev (>= 0.2.0~bzr298),
+               libindicate-gtk-dev (>= 0.2.0~bzr298),
+               libindicator-dev (>= 0.2.0~bzr301),
+               libdbusmenu-gtk-dev (>= 0.1.1),
+               libdbusmenu-glib-dev (>= 0.1.1)
+Standards-Version: 3.8.0
+Homepage: https://launchpad.net/indicator-applet
+Vcs-Bzr: http://bazaar.launchpad.net/~ubuntu-desktop/indicator-messages/ubuntu
+
+Package: indicator-messages
+Architecture: any
+Depends: ${shlibs:Depends}, ${misc:Depends}, indicator-applet
+Description: GNOME panel indicator applet for messages
+ indicator-applet is an applet to display information from
+ various applications consistently in the GNOME panel.
+ .
+ This package provides support for messaging applications.
+

=== added file 'debian/copyright'
--- debian/copyright	1970-01-01 00:00:00 +0000
+++ debian/copyright	2009-03-19 11:22:57 +0000
@@ -0,0 +1,33 @@
+This package was debianized by Ted Gould <ted@xxxxxxxxxxxxx> on
+Wed, 11 Feb 2009 15:41:06 -0600.
+
+It was downloaded from <http://launchpad.net/indicator-applet/>
+
+Upstream Author:
+
+    Ted Gould <ted@xxxxxxxxxxxxx>
+
+Copyright:
+
+    Copyright (C) 2009 Canonical Ltd.
+
+License:
+
+  This program is free software; you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation, version 3 of the License.
+
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+
+  You should have received a copy of the GNU General Public License
+  along with this program; if not, write to the Free Software
+  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
+
+On Debian systems, the complete text of the GNU General
+Public License can be found in `/usr/share/common-licenses/GPL-3'.
+
+The Debian packaging is (C) 2009, Canonical Ltd. and
+is licensed under the GPLv3, see `/usr/share/common-licenses/GPL-3'.

=== added file 'debian/rules'
--- debian/rules	1970-01-01 00:00:00 +0000
+++ debian/rules	2009-04-22 21:46:57 +0000
@@ -0,0 +1,12 @@
+#!/usr/bin/make -f
+
+include /usr/share/cdbs/1/rules/debhelper.mk
+include /usr/share/cdbs/1/class/gnome.mk
+
+DEB_CONFIGURE_EXTRA_FLAGS += --disable-scrollkeeper
+LDFLAGS += -Wl,-z,defs -Wl,--as-needed
+
+binary-install/indicator-messages::
+	# remove .a/.la clutter
+	rm -f debian/$(cdbs_curpkg)/usr/lib/indicators/*/*.a
+	rm -f debian/$(cdbs_curpkg)/usr/lib/indicators/*/*.la

=== added file 'debian/watch'
--- debian/watch	1970-01-01 00:00:00 +0000
+++ debian/watch	2009-08-27 18:10:28 +0000
@@ -0,0 +1,2 @@
+version=3
+http://launchpad.net/indicator-messages/+download .*/indicator-messages-([0-9.]+)\.tar\.gz

=== modified file 'src/app-menu-item.c'
--- src/app-menu-item.c	2009-08-26 21:47:55 +0000
+++ src/app-menu-item.c	2009-09-05 16:43:36 +0000
@@ -27,6 +27,7 @@
 #include <glib/gi18n.h>
 #include <gio/gdesktopappinfo.h>
 #include "app-menu-item.h"
+#include "dbus-data.h"
 
 enum {
 	COUNT_CHANGED,
@@ -47,7 +48,6 @@
 	GAppInfo * appinfo;
 	gchar * desktop;
 	guint unreadcount;
-	gboolean count_on_label;
 };
 
 #define APP_MENU_ITEM_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), APP_MENU_ITEM_TYPE, AppMenuItemPrivate))
@@ -58,14 +58,12 @@
 static void app_menu_item_dispose    (GObject *object);
 static void app_menu_item_finalize   (GObject *object);
 static void activate_cb (AppMenuItem * self, gpointer data);
-static void type_cb (IndicateListener * listener, IndicateListenerServer * server, gchar * value, gpointer data);
+static void count_changed (IndicateListener * listener, IndicateListenerServer * server, guint count, gpointer data);
+static void count_cb (IndicateListener * listener, IndicateListenerServer * server, guint 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);
 
-
-
+/* GObject Boilerplate */
 G_DEFINE_TYPE (AppMenuItem, app_menu_item, DBUSMENU_TYPE_MENUITEM);
 
 static void
@@ -108,8 +106,6 @@
 	priv->appinfo = NULL;
 	priv->desktop = NULL;
 	priv->unreadcount = 0;
-	priv->count_on_label = FALSE;
-
 
 	return;
 }
@@ -120,9 +116,6 @@
 	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);
-
 	g_object_unref(priv->listener);
 
 	G_OBJECT_CLASS (app_menu_item_parent_class)->dispose (object);
@@ -158,63 +151,38 @@
 
 	AppMenuItemPrivate * priv = APP_MENU_ITEM_GET_PRIVATE(self);
 
+	/* Copy the listener so we can use it later */
 	priv->listener = listener;
 	g_object_ref(G_OBJECT(listener));
+
+	/* Can not ref as not real GObject */
 	priv->server = server;
-	/* Can not ref as not real GObject */
-
-	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);
-
-	indicate_listener_server_get_type(listener, server, type_cb, self);
+
+	/* Set up listener signals */
+	g_signal_connect(G_OBJECT(listener), INDICATE_LISTENER_SIGNAL_SERVER_COUNT_CHANGED, G_CALLBACK(count_changed), self);
+
+	/* Get the values we care about from the server */
 	indicate_listener_server_get_desktop(listener, server, desktop_cb, self);
+	indicate_listener_server_get_count(listener, server, count_cb, self);
 
 	g_signal_connect(G_OBJECT(self), DBUSMENU_MENUITEM_SIGNAL_ITEM_ACTIVATED, G_CALLBACK(activate_cb), NULL);
 
 	indicate_listener_server_show_interest(listener, server, INDICATE_INTEREST_SERVER_DISPLAY);
 	indicate_listener_server_show_interest(listener, server, INDICATE_INTEREST_SERVER_SIGNAL);
+	indicate_listener_server_show_interest(listener, server, INDICATE_INTEREST_INDICATOR_COUNT);
+	indicate_listener_server_show_interest(listener, server, INDICATE_INTEREST_INDICATOR_DISPLAY);
+	indicate_listener_server_show_interest(listener, server, INDICATE_INTEREST_INDICATOR_SIGNAL);
+	indicate_listener_set_server_max_indicators(listener, server, MAX_NUMBER_OF_INDICATORS);
 
 	return self;
 }
 
-static void 
-type_cb (IndicateListener * listener, IndicateListenerServer * server, gchar * value, gpointer data)
-{
-	AppMenuItem * self = APP_MENU_ITEM(data);
-	AppMenuItemPrivate * priv = APP_MENU_ITEM_GET_PRIVATE(self);
-
-	if (priv->type != NULL) {
-		g_free(priv->type);
-		priv->type = NULL;
-	}
-	
-	if (value == NULL) {
-		g_warning("Type value is NULL, that shouldn't really happen");
-		return;
-	}
-
-	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);
-
-		indicate_listener_server_show_interest(listener, server, INDICATE_INTEREST_INDICATOR_COUNT);
-	} else {
-		indicate_listener_server_show_interest(listener, server, INDICATE_INTEREST_INDICATOR_DISPLAY);
-		indicate_listener_server_show_interest(listener, server, INDICATE_INTEREST_INDICATOR_SIGNAL);
-	}
-
-	return;
-}
-
 static void
 update_label (AppMenuItem * self)
 {
 	AppMenuItemPrivate * priv = APP_MENU_ITEM_GET_PRIVATE(self);
 
-	if (priv->count_on_label && !priv->unreadcount < 1) {
+	if (priv->unreadcount > 0) {
 		/* 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)"), app_menu_item_get_name(self), priv->unreadcount);
@@ -227,6 +195,38 @@
 	return;
 }
 
+/* Callback to the signal that the server count
+   has changed to a new value.  This checks to see if
+   it's actually changed and if so signals everyone and
+   updates the label. */
+static void
+count_changed (IndicateListener * listener, IndicateListenerServer * server, guint count, gpointer data)
+{
+	AppMenuItem * self = APP_MENU_ITEM(data);
+	AppMenuItemPrivate * priv = APP_MENU_ITEM_GET_PRIVATE(self);
+
+	if (priv->unreadcount != count) {
+		priv->unreadcount = count;
+		update_label(self);
+		g_signal_emit(G_OBJECT(self), signals[COUNT_CHANGED], 0, priv->unreadcount, TRUE);
+	}
+
+	return;
+}
+
+/* Callback for getting the count property off
+   of the server. */
+static void 
+count_cb (IndicateListener * listener, IndicateListenerServer * server, guint value, gpointer data)
+{
+	count_changed(listener, server, value, data);
+	return;
+}
+
+/* Callback for when we ask the server for the path
+   to it's desktop file.  We then turn it into an
+   app structure and start sucking data out of it.
+   Mostly the name. */
 static void 
 desktop_cb (IndicateListener * listener, IndicateListenerServer * server, gchar * value, gpointer data)
 {
@@ -268,46 +268,6 @@
 	return;
 }
 
-static void 
-indicator_added_cb (IndicateListener * listener, IndicateListenerServer * server, IndicateListenerIndicator * indicator, gchar * type, gpointer data)
-{
-	g_return_if_fail(IS_APP_MENU_ITEM(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)
 {

=== modified file 'src/dbus-data.h'
--- src/dbus-data.h	2009-08-27 01:06:09 +0000
+++ src/dbus-data.h	2009-09-04 22:14:23 +0000
@@ -12,4 +12,15 @@
 #define LAUNCHER_MENUITEM_PROP_APP_NAME  "application-name"
 #define LAUNCHER_MENUITEM_PROP_APP_DESC  "application-description"
 
+#define APPLICATION_MENUITEM_TYPE        "application-item"
+#define APPLICATION_MENUITEM_PROP_NAME   "app-name"
+#define APPLICATION_MENUITEM_PROP_COUNT  "app-count"
+
+#define INDICATOR_MENUITEM_TYPE          "indicator-item"
+#define INDICATOR_MENUITEM_PROP_LABEL    "indicator-label"
+#define INDICATOR_MENUITEM_PROP_ICON     "indicator-icon"
+#define INDICATOR_MENUITEM_PROP_RIGHT    "right-side-text"
+
+#define MAX_NUMBER_OF_INDICATORS  7
+
 #endif /* __DBUS_DATA_H__ */

=== modified file 'src/im-menu-item.c'
--- src/im-menu-item.c	2009-09-04 14:02:34 +0000
+++ src/im-menu-item.c	2009-09-04 22:31:29 +0000
@@ -25,12 +25,15 @@
 
 #include <glib/gi18n.h>
 #include <libdbusmenu-glib/client.h>
-#include <libindicate-gtk/indicator.h>
-#include <libindicate-gtk/listener.h>
+#include <libindicate/indicator.h>
+#include <libindicate/indicator-messages.h>
+#include <libindicate/listener.h>
 #include "im-menu-item.h"
+#include "dbus-data.h"
 
 enum {
 	TIME_CHANGED,
+	ATTENTION_CHANGED,
 	LAST_SIGNAL
 };
 
@@ -45,8 +48,10 @@
 	IndicateListenerIndicator *  indicator;
 
 	glong seconds;
-	gboolean show_time;
+	gchar * count;
 	gulong indicator_changed;
+	gboolean attention;
+	gboolean show;
 
 	guint time_update_min;
 };
@@ -81,7 +86,6 @@
 static void indicator_modified_cb   (IndicateListener * listener,
                                      IndicateListenerServer * server,
                                      IndicateListenerIndicator * indicator,
-                                     gchar * type,
                                      gchar * property,
                                      ImMenuItem * self);
 
@@ -104,6 +108,13 @@
 	                                      NULL, NULL,
 	                                      g_cclosure_marshal_VOID__LONG,
 	                                      G_TYPE_NONE, 1, G_TYPE_LONG);
+	signals[ATTENTION_CHANGED] =  g_signal_new(IM_MENU_ITEM_SIGNAL_ATTENTION_CHANGED,
+	                                      G_TYPE_FROM_CLASS(klass),
+	                                      G_SIGNAL_RUN_LAST,
+	                                      G_STRUCT_OFFSET (ImMenuItemClass, attention_changed),
+	                                      NULL, NULL,
+	                                      g_cclosure_marshal_VOID__BOOLEAN,
+	                                      G_TYPE_NONE, 1, G_TYPE_BOOLEAN);
 
 	return;
 }
@@ -147,20 +158,25 @@
 	G_OBJECT_CLASS (im_menu_item_parent_class)->finalize (object);
 }
 
+/* Call back for getting icon data.  It just passes it along
+   to the indicator so that it can visualize it.  Not our problem. */
 static void
 icon_cb (IndicateListener * listener, IndicateListenerServer * server, IndicateListenerIndicator * indicator, gchar * property, gchar * propertydata, gpointer data)
 {
-	dbusmenu_menuitem_property_set(DBUSMENU_MENUITEM(data), DBUSMENU_MENUITEM_PROP_ICON_DATA, propertydata);
+	dbusmenu_menuitem_property_set(DBUSMENU_MENUITEM(data), INDICATOR_MENUITEM_PROP_ICON, propertydata);
 	return;
 }
 
+/* This function takes the time and turns it into the appropriate
+   string to put on the right side of the menu item.  Of course it
+   doesn't do that if there is a count set.  If there's a count then
+   it gets that space. */
 static void
 update_time (ImMenuItem * self)
 {
 	ImMenuItemPrivate * priv = IM_MENU_ITEM_GET_PRIVATE(self);
 
-	if (!priv->show_time) {
-		dbusmenu_menuitem_property_set(DBUSMENU_MENUITEM(self), "right-column", "");
+	if (priv->count != NULL) {
 		return;
 	}
 	
@@ -191,13 +207,15 @@
 	}
 
 	if (timestring != NULL) {
-		dbusmenu_menuitem_property_set(DBUSMENU_MENUITEM(self), "right-column", "");
+		dbusmenu_menuitem_property_set(DBUSMENU_MENUITEM(self), INDICATOR_MENUITEM_PROP_RIGHT, timestring);
 		g_free(timestring);
 	}
 
 	return;
 }
 
+/* This is a wrapper around update_time that matches the prototype
+   needed to make this a timer callback.  Silly. */
 static gboolean
 time_update_cb (gpointer data)
 {
@@ -208,6 +226,10 @@
 	return TRUE;
 }
 
+/* Yet another time function.  This one takes the time as formated as
+   we get it from libindicate and turns it into the seconds that we're
+   looking for.  It should only be called once at the init with a new
+   indicator and again when the value changes. */
 static void
 time_cb (IndicateListener * listener, IndicateListenerServer * server, IndicateListenerIndicator * indicator, gchar * property, GTimeVal * propertydata, gpointer data)
 {
@@ -238,26 +260,106 @@
 	return;
 }
 
+/* Callback from libindicate that is for getting the sender information
+   on a particular indicator. */
 static void
 sender_cb (IndicateListener * listener, IndicateListenerServer * server, IndicateListenerIndicator * indicator, gchar * property, gchar * propertydata, gpointer data)
 {
 	g_debug("Got Sender Information");
 	ImMenuItem * self = IM_MENU_ITEM(data);
-	if (self == NULL) {
-		g_error("Menu Item callback called without a menu item");
-		return;
-	}
-
-	if (property == NULL || g_strcmp0(property, "sender")) {
-		g_warning("Sender callback called without being sent the sender.  We got '%s' with value '%s'.", property, propertydata);
-		return;
-	}
-
-	dbusmenu_menuitem_property_set(DBUSMENU_MENUITEM(self), DBUSMENU_MENUITEM_PROP_LABEL, propertydata);
-
-	return;
-}
-
+
+	/* Our data should be right */
+	g_return_if_fail(self != NULL);
+	/* We should have a property name */
+	g_return_if_fail(property != NULL);
+	/* The Property should be sender or name */
+	g_return_if_fail(!g_strcmp0(property, "sender") || !g_strcmp0(property, INDICATE_INDICATOR_MESSAGES_PROP_NAME));
+
+	/* We might get the sender variable returning a
+	   null string as it doesn't exist on newer clients
+	   but we don't want to listen to that. */
+	if (!g_strcmp0(property, "sender") && property[0] == '\0') {
+		return;
+	}
+
+	dbusmenu_menuitem_property_set(DBUSMENU_MENUITEM(self), INDICATOR_MENUITEM_PROP_LABEL, propertydata);
+
+	return;
+}
+
+/* Callback saying that the count is updated, we need to either put
+   that on the menu item or just remove it if the count is gone.  If
+   that's the case we can update time. */
+static void
+count_cb (IndicateListener * listener, IndicateListenerServer * server, IndicateListenerIndicator * indicator, gchar * property, gchar * propertydata, gpointer data)
+{
+	g_debug("Got Count Information");
+	ImMenuItem * self = IM_MENU_ITEM(data);
+
+	/* Our data should be right */
+	g_return_if_fail(self != NULL);
+	/* We should have a property name */
+	g_return_if_fail(property != NULL);
+	/* The Property should be count */
+	g_return_if_fail(!g_strcmp0(property, INDICATE_INDICATOR_MESSAGES_PROP_COUNT));
+
+	ImMenuItemPrivate * priv = IM_MENU_ITEM_GET_PRIVATE(self);
+
+	if (propertydata == NULL || propertydata[0] == '\0') {
+		/* The count is either being unset or it was never
+		   set in the first place. */
+		if (priv->count != NULL) {
+			g_free(priv->count);
+			priv->count = NULL;
+			update_time(self);
+		}
+		return;
+	}
+
+	if (priv->count != NULL) {
+		g_free(priv->count);
+	}
+
+	priv->count = g_strdup_printf("(%s)", propertydata);
+	dbusmenu_menuitem_property_set(DBUSMENU_MENUITEM(self), INDICATOR_MENUITEM_PROP_RIGHT, priv->count);
+
+	return;
+}
+
+/* This is getting the attention variable that's looking at whether
+   this indicator should be calling for attention or not.  If we are,
+   we need to signal that. */
+static void
+attention_cb (IndicateListener * listener, IndicateListenerServer * server, IndicateListenerIndicator * indicator, gchar * property, gchar * propertydata, gpointer data)
+{
+	g_debug("Got Attention Information");
+	ImMenuItem * self = IM_MENU_ITEM(data);
+
+	/* Our data should be right */
+	g_return_if_fail(self != NULL);
+	/* We should have a property name */
+	g_return_if_fail(property != NULL);
+	/* The Property should be count */
+	g_return_if_fail(!g_strcmp0(property, INDICATE_INDICATOR_MESSAGES_PROP_ATTENTION));
+
+	ImMenuItemPrivate * priv = IM_MENU_ITEM_GET_PRIVATE(self);
+
+	gboolean wantit;
+	if (propertydata == NULL || propertydata[0] == '\0' || !g_strcmp0(propertydata, "false")) {
+		wantit = FALSE;
+	} else {
+		wantit = TRUE;
+	}
+
+	if (priv->attention != wantit) {
+		priv->attention = wantit;
+		g_signal_emit(G_OBJECT(self), signals[ATTENTION_CHANGED], 0, wantit, TRUE);
+	}
+
+	return;
+}
+
+/* Callback when the item gets clicked on from the Messaging Menu */
 static void
 activate_cb (ImMenuItem * self, gpointer data)
 {
@@ -266,8 +368,10 @@
 	indicate_listener_display(priv->listener, priv->server, priv->indicator);
 }
 
+/* Callback when a property gets modified.  It figures out which one
+   got modified and notifies the appropriate person. */
 void
-indicator_modified_cb (IndicateListener * listener, IndicateListenerServer * server, IndicateListenerIndicator * indicator, gchar * type, gchar * property, ImMenuItem * self)
+indicator_modified_cb (IndicateListener * listener, IndicateListenerServer * server, IndicateListenerIndicator * indicator, gchar * property, ImMenuItem * self)
 {
 	ImMenuItemPrivate * priv = IM_MENU_ITEM_GET_PRIVATE(self);
 
@@ -275,19 +379,29 @@
 	if (INDICATE_LISTENER_INDICATOR_ID(indicator) != INDICATE_LISTENER_INDICATOR_ID(priv->indicator)) return;
 	if (server != priv->server) return;
 
-	if (!g_strcmp0(property, "sender")) {
+	/* Determine which property has been changed and request the
+	   value go to the appropriate callback. */
+	if (!g_strcmp0(property, INDICATE_INDICATOR_MESSAGES_PROP_NAME)) {
+		indicate_listener_get_property(listener, server, indicator, INDICATE_INDICATOR_MESSAGES_PROP_NAME, sender_cb, self);	
+	} else if (!g_strcmp0(property, INDICATE_INDICATOR_MESSAGES_PROP_TIME)) {
+		indicate_listener_get_property_time(listener, server, indicator, INDICATE_INDICATOR_MESSAGES_PROP_TIME, time_cb, self);	
+	} else if (!g_strcmp0(property, INDICATE_INDICATOR_MESSAGES_PROP_ICON)) {
+		indicate_listener_get_property(listener, server, indicator, INDICATE_INDICATOR_MESSAGES_PROP_ICON, icon_cb, self);	
+	} else if (!g_strcmp0(property, INDICATE_INDICATOR_MESSAGES_PROP_COUNT)) {
+		indicate_listener_get_property(listener, server, indicator, INDICATE_INDICATOR_MESSAGES_PROP_COUNT, count_cb, self);	
+	} else if (!g_strcmp0(property, INDICATE_INDICATOR_MESSAGES_PROP_ATTENTION)) {
+		indicate_listener_get_property(listener, server, indicator, INDICATE_INDICATOR_MESSAGES_PROP_ATTENTION, attention_cb, self);	
+	} else if (!g_strcmp0(property, "sender")) {
+		/* This is a compatibility string with v1 and should be removed */
+		g_debug("Indicator is using 'sender' property which is a v1 string.");
 		indicate_listener_get_property(listener, server, indicator, "sender", sender_cb, self);	
-	} else if (!g_strcmp0(property, "time")) {
-		indicate_listener_get_property_time(listener, server, indicator, "time",   time_cb, self);	
-	} else if (!g_strcmp0(property, "icon")) {
-		indicate_listener_get_property(listener, server, indicator, "icon", icon_cb, self);	
 	}
 	
 	return;
 }
 
 ImMenuItem *
-im_menu_item_new (IndicateListener * listener, IndicateListenerServer * server, IndicateListenerIndicator * indicator, gboolean show_time)
+im_menu_item_new (IndicateListener * listener, IndicateListenerServer * server, IndicateListenerIndicator * indicator)
 {
 	ImMenuItem * self = g_object_new(IM_MENU_ITEM_TYPE, NULL);
 
@@ -296,14 +410,21 @@
 	priv->listener = listener;
 	priv->server = server;
 	priv->indicator = indicator;
-	priv->show_time = show_time;
+	priv->count = NULL;
 	priv->time_update_min = 0;
-
-	dbusmenu_menuitem_property_set(DBUSMENU_MENUITEM(self), "type", DBUSMENU_CLIENT_TYPES_IMAGE);
-
+	priv->attention = FALSE;
+	priv->show = TRUE;
+
+	dbusmenu_menuitem_property_set(DBUSMENU_MENUITEM(self), "type", INDICATOR_MENUITEM_TYPE);
+
+	indicate_listener_displayed(listener, server, indicator, TRUE);
+
+	indicate_listener_get_property(listener, server, indicator, INDICATE_INDICATOR_MESSAGES_PROP_NAME, sender_cb, self);	
+	indicate_listener_get_property_time(listener, server, indicator, INDICATE_INDICATOR_MESSAGES_PROP_TIME, time_cb, self);	
+	indicate_listener_get_property(listener, server, indicator, INDICATE_INDICATOR_MESSAGES_PROP_ICON, icon_cb, self);	
+	indicate_listener_get_property(listener, server, indicator, INDICATE_INDICATOR_MESSAGES_PROP_COUNT, count_cb, self);	
+	indicate_listener_get_property(listener, server, indicator, INDICATE_INDICATOR_MESSAGES_PROP_ATTENTION, attention_cb, self);	
 	indicate_listener_get_property(listener, server, indicator, "sender", sender_cb, self);	
-	indicate_listener_get_property_time(listener, server, indicator, "time",   time_cb, self);	
-	indicate_listener_get_property(listener, server, indicator, "icon",   icon_cb, self);	
 
 	g_signal_connect(G_OBJECT(self), DBUSMENU_MENUITEM_SIGNAL_ITEM_ACTIVATED, G_CALLBACK(activate_cb), NULL);
 	priv->indicator_changed = g_signal_connect(G_OBJECT(listener), INDICATE_LISTENER_SIGNAL_INDICATOR_MODIFIED, G_CALLBACK(indicator_modified_cb), self);
@@ -311,9 +432,65 @@
 	return self;
 }
 
+/* Gets the number of seconds for the creator
+   of this item. */
 glong
 im_menu_item_get_seconds (ImMenuItem * menuitem)
 {
+	g_return_val_if_fail(IS_IM_MENU_ITEM(menuitem), 0);
+
 	ImMenuItemPrivate * priv = IM_MENU_ITEM_GET_PRIVATE(menuitem);
 	return priv->seconds;
 }
+
+/* Gets whether or not this indicator item is
+   asking for attention or not. */
+gboolean
+im_menu_item_get_attention (ImMenuItem * menuitem)
+{
+	g_return_val_if_fail(IS_IM_MENU_ITEM(menuitem), FALSE);
+
+	ImMenuItemPrivate * priv = IM_MENU_ITEM_GET_PRIVATE(menuitem);
+	return priv->attention;
+}
+
+/* This takes care of items that need to be hidden, this is
+   usually because they go over the count of allowed indicators.
+   Which is more than a little bit silly.  We shouldn't do that.
+   But we need to enforce it to save users against bad apps. */
+void
+im_menu_item_show (ImMenuItem * menuitem, gboolean show)
+{
+	g_return_if_fail(IS_IM_MENU_ITEM(menuitem));
+
+	ImMenuItemPrivate * priv = IM_MENU_ITEM_GET_PRIVATE(menuitem);
+
+	if (priv->show == show) {
+		return;
+	}
+
+	priv->show = show;
+	/* Tell the app what we're doing to it.  If it's being
+	   punished it needs to know about it. */
+	indicate_listener_displayed(priv->listener, priv->server, priv->indicator, priv->show);
+	if (priv->attention) {
+		/* If we were asking for attention we can ask for it
+		   again if we're being shown, otherwise no. */
+		g_signal_emit(G_OBJECT(menuitem), signals[ATTENTION_CHANGED], 0, priv->show, TRUE);
+	}
+	dbusmenu_menuitem_property_set(DBUSMENU_MENUITEM(menuitem), DBUSMENU_MENUITEM_PROP_VISIBLE, priv->show ? "true" : "false");
+
+	return;
+}
+
+/* Check to see if this item is shown.  Accessor for the
+   internal variable. */
+gboolean
+im_menu_item_shown (ImMenuItem * menuitem)
+{
+	g_return_val_if_fail(IS_IM_MENU_ITEM(menuitem), FALSE);
+
+	ImMenuItemPrivate * priv = IM_MENU_ITEM_GET_PRIVATE(menuitem);
+
+	return priv->show;
+}

=== modified file 'src/im-menu-item.h'
--- src/im-menu-item.h	2009-05-26 14:30:37 +0000
+++ src/im-menu-item.h	2009-09-04 22:31:29 +0000
@@ -38,6 +38,7 @@
 #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"
+#define IM_MENU_ITEM_SIGNAL_ATTENTION_CHANGED  "attention-changed"
 
 typedef struct _ImMenuItem      ImMenuItem;
 typedef struct _ImMenuItemClass ImMenuItemClass;
@@ -46,6 +47,7 @@
 	DbusmenuMenuitemClass parent_class;
 
 	void (*time_changed) (glong seconds);
+	void (*attention_changed) (gboolean requestit);
 };
 
 struct _ImMenuItem {
@@ -53,8 +55,11 @@
 };
 
 GType im_menu_item_get_type (void);
-ImMenuItem * im_menu_item_new (IndicateListener * listener, IndicateListenerServer * server, IndicateListenerIndicator * indicator, gboolean show_time);
+ImMenuItem * im_menu_item_new (IndicateListener * listener, IndicateListenerServer * server, IndicateListenerIndicator * indicator);
 glong im_menu_item_get_seconds (ImMenuItem * menuitem);
+gboolean im_menu_item_get_attention (ImMenuItem * menuitem);
+void im_menu_item_show (ImMenuItem * menuitem, gboolean show);
+gboolean im_menu_item_shown (ImMenuItem * menuitem);
 
 G_END_DECLS
 

=== modified file 'src/indicator-messages.c'
--- src/indicator-messages.c	2009-08-27 14:31:43 +0000
+++ src/indicator-messages.c	2009-09-04 20:28:55 +0000
@@ -24,6 +24,7 @@
 #include <glib.h>
 #include <gtk/gtk.h>
 #include <libdbusmenu-gtk/menu.h>
+#include <libdbusmenu-gtk/menuitem.h>
 #include <dbus/dbus-glib.h>
 #include <dbus/dbus-glib-bindings.h>
 
@@ -41,6 +42,8 @@
 
 static DBusGProxy * icon_proxy = NULL;
 
+static GtkSizeGroup * indicator_right_group = NULL;
+
 static void
 attention_changed_cb (DBusGProxy * proxy, gboolean dot, gpointer userdata)
 {
@@ -137,6 +140,54 @@
 	return FALSE;
 }
 
+/* We have a small little menuitem type that handles all
+   of the fun stuff for indicators.  Mostly this is the
+   shifting over and putting the icon in with some right
+   side text that'll be determined by the service.  */
+static gboolean
+new_indicator_item (DbusmenuMenuitem * newitem, DbusmenuMenuitem * parent, DbusmenuClient * client)
+{
+	g_return_val_if_fail(DBUSMENU_IS_MENUITEM(newitem), FALSE);
+	g_return_val_if_fail(DBUSMENU_IS_GTKCLIENT(client), FALSE);
+	/* Note: not checking parent, it's reasonable for it to be NULL */
+
+	GtkMenuItem * gmi = GTK_MENU_ITEM(gtk_menu_item_new());
+
+	GtkWidget * hbox = gtk_hbox_new(FALSE, 4);
+
+	/* Icon, probably someone's face or avatar on an IM */
+	GtkWidget * icon = gtk_image_new();
+	GdkPixbuf * pixbuf = dbusmenu_menuitem_property_get_image(newitem, INDICATOR_MENUITEM_PROP_ICON);
+	if (pixbuf != NULL) {
+		gtk_image_set_from_pixbuf(GTK_IMAGE(icon), pixbuf);
+	}
+	gtk_misc_set_alignment(GTK_MISC(icon), 0.0, 0.5);
+	gtk_box_pack_start(GTK_BOX(hbox), icon, FALSE, FALSE, 0);
+	gtk_widget_show(icon);
+
+	/* Label, probably a username, chat room or mailbox name */
+	GtkWidget * label = gtk_label_new(dbusmenu_menuitem_property_get(newitem, INDICATOR_MENUITEM_PROP_LABEL));
+	gtk_misc_set_alignment(GTK_MISC(label), 0.0, 0.5);
+	gtk_box_pack_start(GTK_BOX(hbox), label, TRUE, TRUE, 0);
+	gtk_widget_show(label);
+
+	/* Usually either the time or the count on the individual
+	   item. */
+	GtkWidget * right = gtk_label_new(dbusmenu_menuitem_property_get(newitem, INDICATOR_MENUITEM_PROP_RIGHT));
+	gtk_size_group_add_widget(indicator_right_group, right);
+	gtk_misc_set_alignment(GTK_MISC(right), 1.0, 0.5);
+	gtk_box_pack_start(GTK_BOX(hbox), right, FALSE, FALSE, 0);
+	gtk_widget_show(right);
+
+	gtk_container_add(GTK_CONTAINER(gmi), hbox);
+	gtk_widget_show(hbox);
+
+	dbusmenu_gtkclient_newitem_base(DBUSMENU_GTKCLIENT(client), newitem, gmi, parent);
+	/* TODO: Handle changes */
+
+	return TRUE;
+}
+
 static gboolean
 new_launcher_item (DbusmenuMenuitem * newitem, DbusmenuMenuitem * parent, DbusmenuClient * client)
 {
@@ -207,12 +258,15 @@
 		return NULL;
 	}
 
+	indicator_right_group = gtk_size_group_new(GTK_SIZE_GROUP_HORIZONTAL);
+
 	g_idle_add(setup_icon_proxy, NULL);
 
 	DbusmenuGtkMenu * menu = dbusmenu_gtkmenu_new(INDICATOR_MESSAGES_DBUS_NAME, INDICATOR_MESSAGES_DBUS_OBJECT);
 	DbusmenuGtkClient * client = dbusmenu_gtkmenu_get_client(menu);
 
 	dbusmenu_client_add_type_handler(DBUSMENU_CLIENT(client), LAUNCHER_MENUITEM_TYPE, new_launcher_item);
+	dbusmenu_client_add_type_handler(DBUSMENU_CLIENT(client), INDICATOR_MENUITEM_TYPE, new_indicator_item);
 
 	return GTK_MENU(menu);
 }

=== modified file 'src/messages-service.c'
--- src/messages-service.c	2009-09-03 19:13:45 +0000
+++ src/messages-service.c	2009-09-05 03:06:42 +0000
@@ -49,7 +49,7 @@
 static void server_name_changed (AppMenuItem * appitem, gchar * name, gpointer data);
 static void im_time_changed (ImMenuItem * imitem, glong seconds, gpointer data);
 static void resort_menu (DbusmenuMenuitem * menushell);
-static void indicator_removed (IndicateListener * listener, IndicateListenerServer * server, IndicateListenerIndicator * indicator, gchar * type, gpointer data);
+static void indicator_removed (IndicateListener * listener, IndicateListenerServer * server, IndicateListenerIndicator * indicator, gpointer data);
 static void check_eclipses (AppMenuItem * ai);
 static void remove_eclipses (AppMenuItem * ai);
 static gboolean build_launcher (gpointer data);
@@ -71,6 +71,8 @@
 struct _serverList_t {
 	IndicateListenerServer * server;
 	AppMenuItem * menuitem;
+	gboolean attention;
+	guint count;
 	GList * imList;
 };
 
@@ -112,6 +114,7 @@
 	IndicateListenerIndicator * indicator;
 	DbusmenuMenuitem * menuitem;
 	gulong timechange_cb;
+	gulong attentionchange_cb;
 };
 
 static gboolean
@@ -390,6 +393,56 @@
  * More code
  */
 
+/* Goes through all the servers and sees if any of them
+   want attention.  If they do, then well we'll give it
+   to them.  If they don't, let's not bother the user
+   any, shall we? */
+static void
+check_attention (void)
+{
+	GList * pointer;
+	for (pointer = serverList; pointer != NULL; pointer = g_list_next(pointer)) {
+		serverList_t * slt = (serverList_t *)pointer->data;
+		if (slt->attention) {
+			message_service_dbus_set_attention(dbus_interface, TRUE);
+			return;
+		}
+	}
+	message_service_dbus_set_attention(dbus_interface, FALSE);
+	return;
+}
+
+/* This checks a server listing to see if it should
+   have attention.  It can get attention through it's
+   count or by having an indicator that is requestion
+   attention. */
+static void
+server_attention (serverList_t * slt)
+{
+	/* Count, easy yes and out. */
+	if (slt->count > 0) {
+		slt->attention = TRUE;
+		return;
+	}
+
+	/* Check to see if any of the indicators want attention */
+	GList * pointer;
+	for (pointer = slt->imList; pointer != NULL; pointer = g_list_next(pointer)) {
+		imList_t * ilt = (imList_t *)pointer->data;
+		if (im_menu_item_get_attention(IM_MENU_ITEM(ilt->menuitem))) {
+			slt->attention = TRUE;
+			return;
+		}
+	}
+
+	/* Nope, no one */
+	slt->attention = FALSE;
+	return;
+}
+
+/* A new server has been created on the indicate bus.
+   We need to check to see if we like it.  And build
+   structures for it if so. */
 static void 
 server_added (IndicateListener * listener, IndicateListenerServer * server, gchar * type, gpointer data)
 {
@@ -413,26 +466,34 @@
 		return;
 	}
 
+	/* Build the Menu item */
 	AppMenuItem * menuitem = app_menu_item_new(listener, server);
-	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);
 
+	/* Build a possible server structure */
 	serverList_t * sl_item = g_new0(serverList_t, 1);
 	sl_item->server = server;
 	sl_item->menuitem = menuitem;
 	sl_item->imList = NULL;
+	sl_item->attention = FALSE;
+	sl_item->count = 0;
 
 	/* Incase we got an indicator first */
 	GList * alreadythere = g_list_find_custom(serverList, sl_item, serverList_equal);
 	if (alreadythere != NULL) {
+		/* Use the one we already had */
 		g_free(sl_item);
 		sl_item = (serverList_t *)alreadythere->data;
 		sl_item->menuitem = menuitem;
 		serverList = g_list_sort(serverList, serverList_sort);
 	} else {
+		/* Insert the new one in the list */
 		serverList = g_list_insert_sorted(serverList, sl_item, serverList_sort);
 	}
 
+	/* Connect the signals up to the menu item */
+	g_signal_connect(G_OBJECT(menuitem), APP_MENU_ITEM_SIGNAL_COUNT_CHANGED, G_CALLBACK(server_count_changed), sl_item);
+	g_signal_connect(G_OBJECT(menuitem), APP_MENU_ITEM_SIGNAL_NAME_CHANGED,  G_CALLBACK(server_name_changed),  menushell);
+
 	dbusmenu_menuitem_child_append(menushell, DBUSMENU_MENUITEM(menuitem));
 	/* Should be prepend ^ */
 
@@ -442,6 +503,10 @@
 	return;
 }
 
+/* The name of a server has changed, we probably
+   need to reorder the menu to keep it in alphabetical
+   order.  This happens often after we read the destkop
+   file from disk. */
 static void
 server_name_changed (AppMenuItem * appitem, gchar * name, gpointer data)
 {
@@ -451,52 +516,37 @@
 	return;
 }
 
+/* If the count on the server changes, we need to know
+   whether that should be grabbing attention or not.  If
+   it is, we need to reevaluate whether the whole thing
+   should be grabbing attention or not. */
 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;
+	serverList_t * slt = (serverList_t *)data;
+	slt->count = count;
+
+	if (count == 0 && slt->attention) {
+		/* Regen based on indicators if the count isn't going to cause it. */
+		server_attention(slt);
+		/* If we're dropping let's see if we're the last. */
+		if (!slt->attention) {
+			check_attention();
+		}
+	}
+
+	if (count != 0 && !slt->attention) {
+		slt->attention = TRUE;
+		/* Let's tell everyone about us! */
 		message_service_dbus_set_attention(dbus_interface, TRUE);
-		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;
-		message_service_dbus_set_attention(dbus_interface, FALSE);
 	}
 
 	return;
 }
 
+/* Respond to the IM entrie's time changing
+   which results in it needing to resort the list
+   and rebuild the menu to match. */
 static void
 im_time_changed (ImMenuItem * imitem, glong seconds, gpointer data)
 {
@@ -506,6 +556,26 @@
 	return;
 }
 
+/* The IM entrie's request for attention has changed
+   so we need to pass that up the stack. */
+static void
+im_attention_changed (ImMenuItem * imitem, gboolean requestit, gpointer data)
+{
+	serverList_t * sl = (serverList_t *)data;
+
+	if (requestit) {
+		sl->attention = TRUE;
+		message_service_dbus_set_attention(dbus_interface, TRUE);
+	} else {
+		server_attention(sl);
+		if (!sl->attention) {
+			check_attention();
+		}
+	}
+
+	return;
+}
+
 static void 
 server_removed (IndicateListener * listener, IndicateListenerServer * server, gchar * type, gpointer data)
 {
@@ -525,7 +595,7 @@
 
 	while (sltp->imList) {
 		imList_t * imitem = (imList_t *)sltp->imList->data;
-		indicator_removed(listener, server, imitem->indicator, "message", data);
+		indicator_removed(listener, server, imitem->indicator, data);
 	}
 
 	serverList = g_list_remove(serverList, sltp);
@@ -536,10 +606,14 @@
 		g_object_unref(G_OBJECT(sltp->menuitem));
 	}
 
+	if (sltp->attention) {
+		/* Check to see if this was the server causing the menu item to
+		   be lit up. */
+		check_attention();
+	}
+
 	g_free(sltp);
 
-	/* Simulate a server saying zero to recalculate icon */
-	server_count_changed(NULL, 0, NULL);
 	check_hidden();
 
 	return;
@@ -646,8 +720,11 @@
 	return;
 }
 
+/* Responding to a new indicator showing up on the bus.  We
+   need to create a menuitem for it and start populating the
+   internal structures to track it. */
 static void
-subtype_cb (IndicateListener * listener, IndicateListenerServer * server, IndicateListenerIndicator * indicator, gchar * property, gchar * propertydata, gpointer data)
+indicator_added (IndicateListener * listener, IndicateListenerServer * server, IndicateListenerIndicator * indicator, gpointer data)
 {
 	DbusmenuMenuitem * menushell = DBUSMENU_MENUITEM(data);
 	if (menushell == NULL) {
@@ -655,105 +732,93 @@
 		return;
 	}
 
-	if (property == NULL || g_strcmp0(property, "subtype")) {
-		/* We should only ever get subtypes, but just in case */
-		g_warning("Subtype callback got a property '%s'", property);
-		return;
-	}
-
-	if (propertydata == NULL || propertydata[0] == '\0') {
-		/* It's possible that this message didn't have a subtype.  That's
-		 * okay, but we don't want to display those */
-		g_debug("No subtype");
-		return;
-	}
-
-	g_debug("Message subtype: %s", propertydata);
-
-	if (!g_strcmp0(propertydata, "im") || !g_strcmp0(propertydata, "login")) {
-		imList_t * listItem = g_new0(imList_t, 1);
-		listItem->server = server;
-		listItem->indicator = indicator;
-
-		g_debug("Building IM Item");
-		ImMenuItem * menuitem = im_menu_item_new(listener, server, indicator, !g_strcmp0(propertydata, "im"));
-		g_object_ref(G_OBJECT(menuitem));
-		listItem->menuitem = DBUSMENU_MENUITEM(menuitem);
-
-		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_new0(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);
-		listItem->timechange_cb = g_signal_connect(G_OBJECT(menuitem), IM_MENU_ITEM_SIGNAL_TIME_CHANGED, G_CALLBACK(im_time_changed), sl_item);
-
-		g_debug("Placing in Shell");
-		menushell_location_t msl;
-		msl.found = FALSE;
-		msl.position = 0;
-		msl.server = server;
-
-		dbusmenu_menuitem_foreach(DBUSMENU_MENUITEM(menushell), menushell_foreach_cb, &msl);
-		if (msl.found) {
-			dbusmenu_menuitem_child_add_position(menushell, DBUSMENU_MENUITEM(menuitem), msl.position);
-		} else {
-			g_warning("Unable to find server menu item");
-			dbusmenu_menuitem_child_append(menushell, DBUSMENU_MENUITEM(menuitem));
-		}
-	}
-
-	return;
-}
-
-static void
-indicator_added (IndicateListener * listener, IndicateListenerServer * server, IndicateListenerIndicator * indicator, gchar * type, gpointer data)
-{
-	if (type == NULL || g_strcmp0(type, "message")) {
-		/* We only care about message type indicators
-		   all of the others can go to the bit bucket */
-		g_debug("Ignoreing indicator of type '%s'", type);
-		return;
-	}
-	g_debug("Got a message");
-
-	indicate_listener_get_property(listener, server, indicator, "subtype", subtype_cb, data);	
-	return;
-}
-
-static void
-indicator_removed (IndicateListener * listener, IndicateListenerServer * server, IndicateListenerIndicator * indicator, gchar * type, gpointer data)
+	imList_t * listItem = g_new0(imList_t, 1);
+	listItem->server = server;
+	listItem->indicator = indicator;
+
+	/* Building the IM Menu Item which is a subclass
+	   of DBus Menuitem */
+	ImMenuItem * menuitem = im_menu_item_new(listener, server, indicator);
+	g_object_ref(G_OBJECT(menuitem));
+	listItem->menuitem = DBUSMENU_MENUITEM(menuitem);
+
+	/* Looking for a server entry to attach this indicator
+	   to.  If we can't find one then we have to build one
+	   and attach the indicator to it. */
+	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_new0(serverList_t, 1);
+		sl_item->server = server;
+		sl_item->menuitem = NULL;
+		sl_item->imList = NULL;
+		sl_item->attention = FALSE;
+		sl_item->count = 0;
+
+		serverList = g_list_insert_sorted(serverList, sl_item, serverList_sort);
+	} else {
+		sl_item = (serverList_t *)serverentry->data;
+	}
+
+	/* Added a this entry into the IM list */
+	sl_item->imList = g_list_insert_sorted(sl_item->imList, listItem, imList_sort);
+	listItem->timechange_cb = g_signal_connect(G_OBJECT(menuitem), IM_MENU_ITEM_SIGNAL_TIME_CHANGED, G_CALLBACK(im_time_changed), sl_item);
+	listItem->attentionchange_cb = g_signal_connect(G_OBJECT(menuitem), IM_MENU_ITEM_SIGNAL_ATTENTION_CHANGED, G_CALLBACK(im_attention_changed), sl_item);
+
+	/* Check the length of the list.  If we've got more inidactors
+	   than we allow.  Well.  Someone's gotta pay.  Sorry.  I didn't
+	   want to do this, but you did it to yourself. */
+	if (g_list_length(sl_item->imList) > MAX_NUMBER_OF_INDICATORS) {
+		GList * indicatoritem;
+		gint count;
+		for (indicatoritem = sl_item->imList, count = 0; indicatoritem != NULL; indicatoritem = g_list_next(indicatoritem), count++) {
+			imList_t * im = (imList_t *)indicatoritem->data;
+			im_menu_item_show(IM_MENU_ITEM(im->menuitem), count < MAX_NUMBER_OF_INDICATORS);
+		}
+	}
+
+	/* Placing the item into the shell.  Look to see if
+	   we can find our server and slip in there.  Otherwise
+	   we'll just append. */
+	menushell_location_t msl;
+	msl.found = FALSE;
+	msl.position = 0;
+	msl.server = server;
+
+	dbusmenu_menuitem_foreach(DBUSMENU_MENUITEM(menushell), menushell_foreach_cb, &msl);
+	if (msl.found) {
+		dbusmenu_menuitem_child_add_position(menushell, DBUSMENU_MENUITEM(menuitem), msl.position);
+	} else {
+		g_warning("Unable to find server menu item");
+		dbusmenu_menuitem_child_append(menushell, DBUSMENU_MENUITEM(menuitem));
+	}
+
+	return;
+}
+
+/* Process and indicator getting removed from the system.  We
+   first need to ensure that it's one of ours and figure out
+   where we put it.  When we find all that out we can go through
+   the process of removing the effect it had on the system. */
+static void
+indicator_removed (IndicateListener * listener, IndicateListenerServer * server, IndicateListenerIndicator * indicator, gpointer data)
 {
 	g_debug("Removing %s %d", INDICATE_LISTENER_SERVER_DBUS_NAME(server), INDICATE_LISTENER_INDICATOR_ID(indicator));
-	if (type == NULL || g_strcmp0(type, "message")) {
-		/* We only care about message type indicators
-		   all of the others can go to the bit bucket */
-		g_debug("Ignoreing indicator of type '%s'", type);
-		return;
-	}
 
 	gboolean removed = FALSE;
 
+	/* Find the server that was related to this item */
 	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) {
+		/* We didn't care about that server */
 		return;
 	}
 	sl_item = (serverList_t *)serverentry->data;
@@ -771,11 +836,41 @@
 		menuitem = ilt->menuitem;
 	}
 
+	/* If we found a menu item and an imList_t item then
+	   we can go ahead and remove it.  Otherwise we can 
+	   skip this and exit. */
 	if (!removed && menuitem != NULL) {
 		sl_item->imList = g_list_remove(sl_item->imList, ilt);
 		g_signal_handler_disconnect(menuitem, ilt->timechange_cb);
+		g_signal_handler_disconnect(menuitem, ilt->attentionchange_cb);
 		g_free(ilt);
 
+		if (im_menu_item_get_attention(IM_MENU_ITEM(menuitem)) && im_menu_item_shown(IM_MENU_ITEM(menuitem))) {
+			/* If the removed indicator menu item was asking for
+			   attention we need to see if this server should still
+			   be asking for attention. */
+			server_attention(sl_item);
+			/* If the server is no longer asking for attention then
+			   we need to check if the whole system should be. */
+			if (!sl_item->attention) {
+				check_attention();
+			}
+		}
+
+		if (im_menu_item_shown(IM_MENU_ITEM(menuitem)) && g_list_length(sl_item->imList) >= MAX_NUMBER_OF_INDICATORS) {
+			/* In this case we need to show a different indicator
+			   becasue a shown one has left.  But we're going to be
+			   easy and set all the values. */
+			GList * indicatoritem;
+			gint count;
+			for (indicatoritem = sl_item->imList, count = 0; indicatoritem != NULL; indicatoritem = g_list_next(indicatoritem), count++) {
+				imList_t * im = (imList_t *)indicatoritem->data;
+				im_menu_item_show(IM_MENU_ITEM(im->menuitem), count < MAX_NUMBER_OF_INDICATORS);
+			}
+		}
+
+		/* Hide the item immediately, and then remove it
+		   which might take a little longer. */
 		dbusmenu_menuitem_property_set(menuitem, DBUSMENU_MENUITEM_PROP_VISIBLE, "false");
 		dbusmenu_menuitem_child_delete(DBUSMENU_MENUITEM(data), menuitem);
 		removed = TRUE;


Follow ups