diff options
Diffstat (limited to 'src/indicator-messages.c')
-rw-r--r-- | src/indicator-messages.c | 297 |
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); |