diff options
Diffstat (limited to 'src/messages-service.c')
-rw-r--r-- | src/messages-service.c | 329 |
1 files changed, 212 insertions, 117 deletions
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; |