aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--configure.ac1
-rw-r--r--src/app-menu-item.c134
-rw-r--r--src/dbus-data.h11
-rw-r--r--src/im-menu-item.c227
-rw-r--r--src/im-menu-item.h7
-rw-r--r--src/indicator-messages.c91
-rw-r--r--src/messages-service.c329
7 files changed, 569 insertions, 231 deletions
diff --git a/configure.ac b/configure.ac
index a3d937b..b7db004 100644
--- a/configure.ac
+++ b/configure.ac
@@ -34,7 +34,6 @@ PKG_CHECK_MODULES(APPLET, gtk+-2.0 >= $GTK_REQUIRED_VERSION
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)
diff --git a/src/app-menu-item.c b/src/app-menu-item.c
index feb780d..aa0b60c 100644
--- a/src/app-menu-item.c
+++ b/src/app-menu-item.c
@@ -27,6 +27,7 @@ with this program. If not, see <http://www.gnu.org/licenses/>.
#include <glib/gi18n.h>
#include <gio/gdesktopappinfo.h>
#include "app-menu-item.h"
+#include "dbus-data.h"
enum {
COUNT_CHANGED,
@@ -47,7 +48,6 @@ struct _AppMenuItemPrivate
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_init (AppMenuItem *self);
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 @@ app_menu_item_init (AppMenuItem *self)
priv->appinfo = NULL;
priv->desktop = NULL;
priv->unreadcount = 0;
- priv->count_on_label = FALSE;
-
return;
}
@@ -120,9 +116,6 @@ app_menu_item_dispose (GObject *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);
-
g_object_unref(priv->listener);
G_OBJECT_CLASS (app_menu_item_parent_class)->dispose (object);
@@ -158,75 +151,82 @@ app_menu_item_new (IndicateListener * listener, IndicateListenerServer * server)
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));
- priv->server = server;
+
/* Can not ref as not real GObject */
+ 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);
+ /* Set up listener signals */
+ g_signal_connect(G_OBJECT(listener), INDICATE_LISTENER_SIGNAL_SERVER_COUNT_CHANGED, G_CALLBACK(count_changed), self);
- indicate_listener_server_get_type(listener, server, type_cb, 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)
+static void
+update_label (AppMenuItem * self)
{
- 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);
+ 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);
+ dbusmenu_menuitem_property_set(DBUSMENU_MENUITEM(self), DBUSMENU_MENUITEM_PROP_LABEL, label);
+ g_free(label);
} else {
- indicate_listener_server_show_interest(listener, server, INDICATE_INTEREST_INDICATOR_DISPLAY);
- indicate_listener_server_show_interest(listener, server, INDICATE_INTEREST_INDICATOR_SIGNAL);
+ dbusmenu_menuitem_property_set(DBUSMENU_MENUITEM(self), DBUSMENU_MENUITEM_PROP_LABEL, app_menu_item_get_name(self));
}
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
-update_label (AppMenuItem * self)
+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->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)"), app_menu_item_get_name(self), priv->unreadcount);
- dbusmenu_menuitem_property_set(DBUSMENU_MENUITEM(self), DBUSMENU_MENUITEM_PROP_LABEL, label);
- g_free(label);
- } else {
- dbusmenu_menuitem_property_set(DBUSMENU_MENUITEM(self), DBUSMENU_MENUITEM_PROP_LABEL, app_menu_item_get_name(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 @@ activate_cb (AppMenuItem * self, gpointer data)
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)
{
diff --git a/src/dbus-data.h b/src/dbus-data.h
index db59003..9f53f94 100644
--- a/src/dbus-data.h
+++ b/src/dbus-data.h
@@ -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__ */
diff --git a/src/im-menu-item.c b/src/im-menu-item.c
index 6f58ebd..f97436e 100644
--- a/src/im-menu-item.c
+++ b/src/im-menu-item.c
@@ -25,12 +25,15 @@ with this program. If not, see <http://www.gnu.org/licenses/>.
#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 @@ struct _ImMenuItemPrivate
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 activate_cb (ImMenuItem * self,
static void indicator_modified_cb (IndicateListener * listener,
IndicateListenerServer * server,
IndicateListenerIndicator * indicator,
- gchar * type,
gchar * property,
ImMenuItem * self);
@@ -104,6 +108,13 @@ im_menu_item_class_init (ImMenuItemClass *klass)
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 @@ im_menu_item_finalize (GObject *object)
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 @@ update_time (ImMenuItem * self)
}
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 @@ time_update_cb (gpointer data)
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 @@ time_cb (IndicateListener * listener, IndicateListenerServer * server, IndicateL
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");
+ g_debug("Got Sender Information: %s", propertydata);
ImMenuItem * self = IM_MENU_ITEM(data);
- if (self == NULL) {
- g_error("Menu Item callback called without a menu item");
+
+ /* 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") && propertydata[0] == '\0') {
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);
+ 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;
}
- dbusmenu_menuitem_property_set(DBUSMENU_MENUITEM(self), DBUSMENU_MENUITEM_PROP_LABEL, propertydata);
+ 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 @@ activate_cb (ImMenuItem * self, gpointer data)
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 @@ indicator_modified_cb (IndicateListener * listener, IndicateListenerServer * ser
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 @@ im_menu_item_new (IndicateListener * listener, IndicateListenerServer * server,
priv->listener = listener;
priv->server = server;
priv->indicator = indicator;
- priv->show_time = show_time;
+ priv->count = NULL;
priv->time_update_min = 0;
+ priv->attention = FALSE;
+ priv->show = TRUE;
- dbusmenu_menuitem_property_set(DBUSMENU_MENUITEM(self), "type", DBUSMENU_CLIENT_TYPES_IMAGE);
+ 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 @@ im_menu_item_new (IndicateListener * listener, IndicateListenerServer * server,
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;
+}
diff --git a/src/im-menu-item.h b/src/im-menu-item.h
index 51414de..4279c2e 100644
--- a/src/im-menu-item.h
+++ b/src/im-menu-item.h
@@ -38,6 +38,7 @@ G_BEGIN_DECLS
#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 @@ struct _ImMenuItemClass {
DbusmenuMenuitemClass parent_class;
void (*time_changed) (glong seconds);
+ void (*attention_changed) (gboolean requestit);
};
struct _ImMenuItem {
@@ -53,8 +55,11 @@ struct _ImMenuItem {
};
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
diff --git a/src/indicator-messages.c b/src/indicator-messages.c
index c410ef7..a3f22aa 100644
--- a/src/indicator-messages.c
+++ b/src/indicator-messages.c
@@ -24,6 +24,7 @@ with this program. If not, see <http://www.gnu.org/licenses/>.
#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 GtkIconSize design_team_size;
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,91 @@ setup_icon_proxy (gpointer userdata)
return FALSE;
}
+typedef struct _indicator_item_t indicator_item_t;
+struct _indicator_item_t {
+ GtkWidget * icon;
+ GtkWidget * label;
+ GtkWidget * right;
+};
+
+/* Whenever we have a property change on a DbusmenuMenuitem
+ we need to be responsive to that. */
+static void
+indicator_prop_change_cb (DbusmenuMenuitem * mi, gchar * prop, gchar * value, indicator_item_t * mi_data)
+{
+ if (!g_strcmp0(prop, INDICATOR_MENUITEM_PROP_LABEL)) {
+ /* Set the main label */
+ gtk_label_set_text(GTK_LABEL(mi_data->label), value);
+ } else if (!g_strcmp0(prop, INDICATOR_MENUITEM_PROP_RIGHT)) {
+ /* Set the right label */
+ gtk_label_set_text(GTK_LABEL(mi_data->right), value);
+ } else if (!g_strcmp0(prop, INDICATOR_MENUITEM_PROP_ICON)) {
+ /* We don't use the value here, which is probably less efficient,
+ but it's easier to use the easy function. And since th value
+ is already cached, shouldn't be a big deal really. */
+ GdkPixbuf * pixbuf = dbusmenu_menuitem_property_get_image(mi, INDICATOR_MENUITEM_PROP_ICON);
+ if (pixbuf != NULL) {
+ gtk_image_set_from_pixbuf(GTK_IMAGE(mi_data->icon), pixbuf);
+ }
+ } else {
+ g_warning("Indicator Item property '%s' unknown", prop);
+ }
+
+ return;
+}
+
+/* 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)
+{
+ indicator_item_t * mi_data = g_new0(indicator_item_t, 1);
+
+ 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 */
+ mi_data->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(mi_data->icon), pixbuf);
+ }
+ gtk_misc_set_alignment(GTK_MISC(mi_data->icon), 0.0, 0.5);
+ gtk_box_pack_start(GTK_BOX(hbox), mi_data->icon, FALSE, FALSE, 0);
+ gtk_widget_show(mi_data->icon);
+
+ /* Label, probably a username, chat room or mailbox name */
+ mi_data->label = gtk_label_new(dbusmenu_menuitem_property_get(newitem, INDICATOR_MENUITEM_PROP_LABEL));
+ gtk_misc_set_alignment(GTK_MISC(mi_data->label), 0.0, 0.5);
+ gtk_box_pack_start(GTK_BOX(hbox), mi_data->label, TRUE, TRUE, 0);
+ gtk_widget_show(mi_data->label);
+
+ /* Usually either the time or the count on the individual
+ item. */
+ mi_data->right = gtk_label_new(dbusmenu_menuitem_property_get(newitem, INDICATOR_MENUITEM_PROP_RIGHT));
+ gtk_size_group_add_widget(indicator_right_group, mi_data->right);
+ gtk_misc_set_alignment(GTK_MISC(mi_data->right), 1.0, 0.5);
+ gtk_box_pack_start(GTK_BOX(hbox), mi_data->right, FALSE, FALSE, 0);
+ gtk_widget_show(mi_data->right);
+
+ gtk_container_add(GTK_CONTAINER(gmi), hbox);
+ gtk_widget_show(hbox);
+
+ dbusmenu_gtkclient_newitem_base(DBUSMENU_GTKCLIENT(client), newitem, gmi, parent);
+
+ g_signal_connect(G_OBJECT(newitem), DBUSMENU_MENUITEM_SIGNAL_PROPERTY_CHANGED, G_CALLBACK(indicator_prop_change_cb), mi_data);
+ g_signal_connect(G_OBJECT(newitem), "destroyed", G_CALLBACK(g_free), mi_data);
+
+ return TRUE;
+}
+
static gboolean
new_launcher_item (DbusmenuMenuitem * newitem, DbusmenuMenuitem * parent, DbusmenuClient * client)
{
@@ -207,12 +295,15 @@ get_menu (void)
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);
}
diff --git a/src/messages-service.c b/src/messages-service.c
index 754021b..f7b869e 100644
--- a/src/messages-service.c
+++ b/src/messages-service.c
@@ -49,7 +49,7 @@ static void server_count_changed (AppMenuItem * appitem, guint count, gpointer d
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 @@ typedef struct _serverList_t serverList_t;
struct _serverList_t {
IndicateListenerServer * server;
AppMenuItem * menuitem;
+ gboolean attention;
+ guint count;
GList * imList;
};
@@ -112,6 +114,7 @@ struct _imList_t {
IndicateListenerIndicator * indicator;
DbusmenuMenuitem * menuitem;
gulong timechange_cb;
+ gulong attentionchange_cb;
};
static gboolean
@@ -390,6 +393,56 @@ blacklist_dir_changed (GFileMonitor * monitor, GFile * file, GFile * other_file,
* 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 @@ server_added (IndicateListener * listener, IndicateListenerServer * server, gcha
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 @@ server_added (IndicateListener * listener, IndicateListenerServer * server, gcha
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 @@ server_name_changed (AppMenuItem * appitem, gchar * name, gpointer data)
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;
- 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;
+ 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 (!we_have_indicators) {
- g_debug("Setting image to boring");
- showing_new_icon = FALSE;
- message_service_dbus_set_attention(dbus_interface, FALSE);
+ if (count != 0 && !slt->attention) {
+ slt->attention = TRUE;
+ /* Let's tell everyone about us! */
+ message_service_dbus_set_attention(dbus_interface, TRUE);
}
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 @@ im_time_changed (ImMenuItem * imitem, glong seconds, gpointer data)
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 @@ server_removed (IndicateListener * listener, IndicateListenerServer * server, gc
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 @@ server_removed (IndicateListener * listener, IndicateListenerServer * server, gc
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 @@ resort_menu (DbusmenuMenuitem * menushell)
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 @@ subtype_cb (IndicateListener * listener, IndicateListenerServer * server, Indica
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;
- }
+ imList_t * listItem = g_new0(imList_t, 1);
+ listItem->server = server;
+ listItem->indicator = indicator;
- 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;
- }
+ /* 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);
- 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;
- }
+ /* 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);
- 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);
+ 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;
- g_debug("Placing in Shell");
- menushell_location_t msl;
- msl.found = FALSE;
- msl.position = 0;
- msl.server = server;
+ serverList = g_list_insert_sorted(serverList, sl_item, serverList_sort);
+ } else {
+ sl_item = (serverList_t *)serverentry->data;
+ }
- 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));
+ /* 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);
}
}
- 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;
+ /* 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));
}
- g_debug("Got a message");
- indicate_listener_get_property(listener, server, indicator, "subtype", subtype_cb, data);
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, gchar * type, gpointer data)
+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 @@ indicator_removed (IndicateListener * listener, IndicateListenerServer * server,
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;