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