diff options
Diffstat (limited to 'libempathy-gtk')
-rw-r--r-- | libempathy-gtk/empathy-contact-list-store.c | 421 |
1 files changed, 192 insertions, 229 deletions
diff --git a/libempathy-gtk/empathy-contact-list-store.c b/libempathy-gtk/empathy-contact-list-store.c index dba27df53..d4946e4a7 100644 --- a/libempathy-gtk/empathy-contact-list-store.c +++ b/libempathy-gtk/empathy-contact-list-store.c @@ -33,7 +33,6 @@ #include <telepathy-glib/util.h> #include <libempathy/empathy-utils.h> -#include <libempathy/empathy-contact-list.h> #include "empathy-contact-list-store.h" #include "empathy-ui-utils.h" #include "empathy-gtk-enum-types.h" @@ -92,8 +91,12 @@ static void contact_list_store_set_property (GObject GParamSpec *pspec); static void contact_list_store_setup (EmpathyContactListStore *store); static gboolean contact_list_store_inibit_active_cb (EmpathyContactListStore *store); -static void contact_monitor_contact_added_cb (EmpathyContactMonitor *monitor, +static void contact_list_store_members_changed_cb (EmpathyContactList *list_iface, EmpathyContact *contact, + EmpathyContact *actor, + guint reason, + gchar *message, + gboolean is_member, EmpathyContactListStore *store); static void contact_list_store_groups_changed_cb (EmpathyContactList *list_iface, EmpathyContact *contact, @@ -106,6 +109,9 @@ static void contact_list_store_remove_contact (EmpathyCon EmpathyContact *contact); static void contact_list_store_contact_update (EmpathyContactListStore *store, EmpathyContact *contact); +static void contact_list_store_contact_updated_cb (EmpathyContact *contact, + GParamSpec *param, + EmpathyContactListStore *store); static void contact_list_store_contact_set_active (EmpathyContactListStore *store, EmpathyContact *contact, gboolean active, @@ -142,9 +148,6 @@ static gboolean contact_list_store_update_list_mode_foreach (GtkTreeMod GtkTreePath *path, GtkTreeIter *iter, EmpathyContactListStore *store); -static gboolean contact_list_store_iface_setup (gpointer user_data); -static void disconnect_monitor_signals (EmpathyContactMonitor *monitor, - GObject *obj); enum { PROP_0, @@ -158,6 +161,38 @@ enum { G_DEFINE_TYPE (EmpathyContactListStore, empathy_contact_list_store, GTK_TYPE_TREE_STORE); +static gboolean +contact_list_store_iface_setup (gpointer user_data) +{ + EmpathyContactListStore *store = user_data; + EmpathyContactListStorePriv *priv = GET_PRIV (store); + GList *contacts, *l; + + /* Signal connection. */ + g_signal_connect (priv->list, + "members-changed", + G_CALLBACK (contact_list_store_members_changed_cb), + store); + g_signal_connect (priv->list, + "groups-changed", + G_CALLBACK (contact_list_store_groups_changed_cb), + store); + + /* Add contacts already created. */ + contacts = empathy_contact_list_get_members (priv->list); + for (l = contacts; l; l = l->next) { + contact_list_store_members_changed_cb (priv->list, l->data, + NULL, 0, NULL, + TRUE, + store); + + g_object_unref (l->data); + } + g_list_free (contacts); + + return FALSE; +} + static void contact_list_store_set_contact_list (EmpathyContactListStore *store, @@ -251,11 +286,21 @@ static void contact_list_store_finalize (GObject *object) { EmpathyContactListStorePriv *priv = GET_PRIV (object); - EmpathyContactMonitor *monitor; + GList *contacts, *l; - monitor = empathy_contact_list_get_monitor (priv->list); - disconnect_monitor_signals (monitor, object); + contacts = empathy_contact_list_get_members (priv->list); + for (l = contacts; l; l = l->next) { + g_signal_handlers_disconnect_by_func (l->data, + G_CALLBACK (contact_list_store_contact_updated_cb), + object); + g_object_unref (l->data); + } + g_list_free (contacts); + + g_signal_handlers_disconnect_by_func (priv->list, + G_CALLBACK (contact_list_store_members_changed_cb), + object); g_signal_handlers_disconnect_by_func (priv->list, G_CALLBACK (contact_list_store_groups_changed_cb), object); @@ -479,8 +524,10 @@ empathy_contact_list_store_set_show_groups (EmpathyContactListStore *store, gtk_tree_store_clear (GTK_TREE_STORE (store)); contacts = empathy_contact_list_get_members (priv->list); for (l = contacts; l; l = l->next) { - contact_monitor_contact_added_cb (empathy_contact_list_get_monitor (priv->list), - l->data, store); + contact_list_store_members_changed_cb (priv->list, l->data, + NULL, 0, NULL, + TRUE, + store); g_object_unref (l->data); } @@ -725,6 +772,51 @@ contact_list_store_inibit_active_cb (EmpathyContactListStore *store) } static void +contact_list_store_members_changed_cb (EmpathyContactList *list_iface, + EmpathyContact *contact, + EmpathyContact *actor, + guint reason, + gchar *message, + gboolean is_member, + EmpathyContactListStore *store) +{ + EmpathyContactListStorePriv *priv; + + priv = GET_PRIV (store); + + DEBUG ("Contact %s (%d) %s", + empathy_contact_get_id (contact), + empathy_contact_get_handle (contact), + is_member ? "added" : "removed"); + + if (is_member) { + g_signal_connect (contact, "notify::presence", + G_CALLBACK (contact_list_store_contact_updated_cb), + store); + g_signal_connect (contact, "notify::presence-message", + G_CALLBACK (contact_list_store_contact_updated_cb), + store); + g_signal_connect (contact, "notify::name", + G_CALLBACK (contact_list_store_contact_updated_cb), + store); + g_signal_connect (contact, "notify::avatar", + G_CALLBACK (contact_list_store_contact_updated_cb), + store); + g_signal_connect (contact, "notify::capabilities", + G_CALLBACK (contact_list_store_contact_updated_cb), + store); + + contact_list_store_add_contact (store, contact); + } else { + g_signal_handlers_disconnect_by_func (contact, + G_CALLBACK (contact_list_store_contact_updated_cb), + store); + + contact_list_store_remove_contact (store, contact); + } +} + +static void contact_list_store_groups_changed_cb (EmpathyContactList *list_iface, EmpathyContact *contact, gchar *group, @@ -774,10 +866,11 @@ contact_list_store_add_contact (EmpathyContactListStore *store, if (!groups) { gtk_tree_store_append (GTK_TREE_STORE (store), &iter, NULL); gtk_tree_store_set (GTK_TREE_STORE (store), &iter, + EMPATHY_CONTACT_LIST_STORE_COL_NAME, empathy_contact_get_name (contact), EMPATHY_CONTACT_LIST_STORE_COL_CONTACT, contact, EMPATHY_CONTACT_LIST_STORE_COL_IS_GROUP, FALSE, EMPATHY_CONTACT_LIST_STORE_COL_IS_SEPARATOR, FALSE, - EMPATHY_CONTACT_LIST_STORE_COL_NAME, empathy_contact_get_name (contact), + EMPATHY_CONTACT_LIST_STORE_COL_CAN_VOIP, empathy_contact_can_voip (contact), -1); } @@ -790,15 +883,18 @@ contact_list_store_add_contact (EmpathyContactListStore *store, gtk_tree_store_insert_after (GTK_TREE_STORE (store), &iter, &iter_group, NULL); gtk_tree_store_set (GTK_TREE_STORE (store), &iter, + EMPATHY_CONTACT_LIST_STORE_COL_NAME, empathy_contact_get_name (contact), EMPATHY_CONTACT_LIST_STORE_COL_CONTACT, contact, EMPATHY_CONTACT_LIST_STORE_COL_IS_GROUP, FALSE, - EMPATHY_CONTACT_LIST_STORE_COL_NAME, empathy_contact_get_name (contact), + EMPATHY_CONTACT_LIST_STORE_COL_IS_SEPARATOR, FALSE, + EMPATHY_CONTACT_LIST_STORE_COL_CAN_VOIP, empathy_contact_can_voip (contact), -1); g_free (l->data); } g_list_free (groups); - contact_list_store_contact_update (store, contact); + contact_list_store_contact_update (store, contact); + } static void @@ -839,25 +935,43 @@ contact_list_store_remove_contact (EmpathyContactListStore *store, } static void -contact_monitor_presence_changed_cb (EmpathyContactMonitor *monitor, - EmpathyContact *contact, - McPresence current, - McPresence previous, - EmpathyContactListStore *store) +contact_list_store_contact_update (EmpathyContactListStore *store, + EmpathyContact *contact) { EmpathyContactListStorePriv *priv; - GList *iters, *l; - ShowActiveData *data; - gboolean in_list, should_be_in_list; - gboolean do_remove = FALSE, do_set_active = FALSE, - do_set_refresh = FALSE, set_model = FALSE; + ShowActiveData *data; + GtkTreeModel *model; + GList *iters, *l; + gboolean in_list; + gboolean should_be_in_list; + gboolean was_online = TRUE; + gboolean now_online = FALSE; + gboolean set_model = FALSE; + gboolean do_remove = FALSE; + gboolean do_set_active = FALSE; + gboolean do_set_refresh = FALSE; + gboolean show_avatar = FALSE; + GdkPixbuf *pixbuf_avatar; priv = GET_PRIV (store); + + model = GTK_TREE_MODEL (store); + iters = contact_list_store_find_contact (store, contact); + if (!iters) { + in_list = FALSE; + } else { + in_list = TRUE; + } - in_list = (iters != NULL); - should_be_in_list = (current > MC_PRESENCE_OFFLINE || - priv->show_offline); + /* Get online state now. */ + now_online = empathy_contact_is_online (contact); + + if (priv->show_offline || now_online) { + should_be_in_list = TRUE; + } else { + should_be_in_list = FALSE; + } if (!in_list && !should_be_in_list) { /* Nothing to do. */ @@ -867,7 +981,8 @@ contact_monitor_presence_changed_cb (EmpathyContactMonitor *monitor, g_list_foreach (iters, (GFunc) gtk_tree_iter_free, NULL); g_list_free (iters); return; - } else if (in_list && !should_be_in_list) { + } + else if (in_list && !should_be_in_list) { DEBUG ("Contact:'%s' in list:YES, should be:NO", empathy_contact_get_name (contact)); @@ -882,7 +997,8 @@ contact_monitor_presence_changed_cb (EmpathyContactMonitor *monitor, DEBUG ("Remove item (now)!"); contact_list_store_remove_contact (store, contact); } - } else if (!in_list && should_be_in_list) { + } + else if (!in_list && should_be_in_list) { DEBUG ("Contact:'%s' in list:NO, should be:YES", empathy_contact_get_name (contact)); @@ -897,19 +1013,57 @@ contact_monitor_presence_changed_cb (EmpathyContactMonitor *monitor, DEBUG ("Contact:'%s' in list:YES, should be:YES", empathy_contact_get_name (contact)); - do_set_active = TRUE; - do_set_refresh = TRUE; + /* Get online state before. */ + if (iters && g_list_length (iters) > 0) { + gtk_tree_model_get (model, iters->data, + EMPATHY_CONTACT_LIST_STORE_COL_IS_ONLINE, &was_online, + -1); + } + + /* Is this really an update or an online/offline. */ + if (priv->show_active) { + if (was_online != now_online) { + do_set_active = TRUE; + do_set_refresh = TRUE; + + DEBUG ("Set active (contact updated %s)", + was_online ? "online -> offline" : + "offline -> online"); + } else { + /* Was TRUE for presence updates. */ + /* do_set_active = FALSE; */ + do_set_refresh = TRUE; + + DEBUG ("Set active (contact updated)"); + } + } + set_model = TRUE; } + if (priv->show_avatars && !priv->is_compact) { + show_avatar = TRUE; + } + pixbuf_avatar = empathy_pixbuf_avatar_from_contact_scaled (contact, 32, 32); for (l = iters; l && set_model; l = l->next) { gtk_tree_store_set (GTK_TREE_STORE (store), l->data, EMPATHY_CONTACT_LIST_STORE_COL_ICON_STATUS, empathy_icon_name_for_contact (contact), - EMPATHY_CONTACT_LIST_STORE_COL_IS_ONLINE, current > MC_PRESENCE_OFFLINE, - EMPATHY_CONTACT_LIST_STORE_COL_STATUS, empathy_contact_get_status (contact), + EMPATHY_CONTACT_LIST_STORE_COL_PIXBUF_AVATAR, pixbuf_avatar, + EMPATHY_CONTACT_LIST_STORE_COL_PIXBUF_AVATAR_VISIBLE, show_avatar, + EMPATHY_CONTACT_LIST_STORE_COL_NAME, empathy_contact_get_name (contact), + EMPATHY_CONTACT_LIST_STORE_COL_STATUS, empathy_contact_get_status (contact), + EMPATHY_CONTACT_LIST_STORE_COL_STATUS_VISIBLE, !priv->is_compact, + EMPATHY_CONTACT_LIST_STORE_COL_IS_GROUP, FALSE, + EMPATHY_CONTACT_LIST_STORE_COL_IS_ONLINE, now_online, + EMPATHY_CONTACT_LIST_STORE_COL_IS_SEPARATOR, FALSE, + EMPATHY_CONTACT_LIST_STORE_COL_CAN_VOIP, empathy_contact_can_voip (contact), -1); } + if (pixbuf_avatar) { + g_object_unref (pixbuf_avatar); + } + if (priv->show_active && do_set_active) { contact_list_store_contact_set_active (store, contact, do_set_active, do_set_refresh); @@ -931,205 +1085,14 @@ contact_monitor_presence_changed_cb (EmpathyContactMonitor *monitor, } static void -contact_monitor_presence_message_changed_cb (EmpathyContactMonitor *monitor, - EmpathyContact *contact, - const char *message, - EmpathyContactListStore *store) -{ - EmpathyContactListStorePriv *priv; - GList *iters, *l; - - priv = GET_PRIV (store); - iters = contact_list_store_find_contact (store, contact); - - for (l = iters; l; l = l->next) { - gtk_tree_store_set (GTK_TREE_STORE (store), l->data, - EMPATHY_CONTACT_LIST_STORE_COL_STATUS, message, - EMPATHY_CONTACT_LIST_STORE_COL_STATUS_VISIBLE, !priv->is_compact, - -1); - } - - g_list_foreach (iters, (GFunc) gtk_tree_iter_free, NULL); - g_list_free (iters); -} - -static void -contact_monitor_capabilities_changed_cb (EmpathyContactMonitor *monitor, - EmpathyContact *contact, - EmpathyContactListStore *store) -{ - GList *iters, *l; - - iters = contact_list_store_find_contact (store, contact); - - if (!iters) { - return; - } - - for (l = iters; l; l = l->next) { - gtk_tree_store_set (GTK_TREE_STORE (store), l->data, - EMPATHY_CONTACT_LIST_STORE_COL_CAN_VOIP, empathy_contact_can_voip (contact), - -1); - } - - g_list_foreach (iters, (GFunc) gtk_tree_iter_free, NULL); - g_list_free (iters); -} - -static void -contact_monitor_avatar_changed_cb (EmpathyContactMonitor *monitor, - EmpathyContact *contact, - EmpathyContactListStore *store) +contact_list_store_contact_updated_cb (EmpathyContact *contact, + GParamSpec *param, + EmpathyContactListStore *store) { - EmpathyContactListStorePriv *priv; - GdkPixbuf *pixbuf_avatar; - GList *iters, *l; - gboolean show_avatar = FALSE; - - priv = GET_PRIV (store); + DEBUG ("Contact:'%s' updated, checking roster is in sync...", + empathy_contact_get_name (contact)); - iters = contact_list_store_find_contact (store, contact); - - if (!iters) { - return; - } - - if (priv->show_avatars && !priv->is_compact) { - show_avatar = TRUE; - } - - pixbuf_avatar = empathy_pixbuf_avatar_from_contact_scaled (contact, 32, 32); - - for (l = iters; l; l = l->next) { - gtk_tree_store_set (GTK_TREE_STORE (store), l->data, - EMPATHY_CONTACT_LIST_STORE_COL_PIXBUF_AVATAR, pixbuf_avatar, - EMPATHY_CONTACT_LIST_STORE_COL_PIXBUF_AVATAR_VISIBLE, show_avatar, - -1); - } - - if (pixbuf_avatar) { - g_object_unref (pixbuf_avatar); - } - - g_list_foreach (iters, (GFunc) gtk_tree_iter_free, NULL); - g_list_free (iters); -} - -static void -contact_monitor_name_changed_cb (EmpathyContactMonitor *monitor, - EmpathyContact *contact, - const char *name, - EmpathyContactListStore *store) -{ - GList *iters, *l; - - iters = contact_list_store_find_contact (store, contact); - - if (!iters) { - return; - } - - for (l = iters; l; l = l->next) { - gtk_tree_store_set (GTK_TREE_STORE (store), l->data, - EMPATHY_CONTACT_LIST_STORE_COL_NAME, name, - -1); - } - - g_list_foreach (iters, (GFunc) gtk_tree_iter_free, NULL); - g_list_free (iters); -} - -static void -contact_list_store_contact_update (EmpathyContactListStore *store, - EmpathyContact *contact) -{ - contact_monitor_name_changed_cb (NULL, contact, - empathy_contact_get_name (contact), - store); - contact_monitor_presence_changed_cb (NULL, contact, - empathy_contact_get_presence (contact), - MC_PRESENCE_UNSET, - store); - contact_monitor_presence_message_changed_cb (NULL, contact, - empathy_contact_get_status (contact), - store); - contact_monitor_avatar_changed_cb (NULL, contact, store); - contact_monitor_capabilities_changed_cb (NULL, contact, store); -} - -static void -contact_monitor_contact_added_cb (EmpathyContactMonitor *monitor, - EmpathyContact *contact, - EmpathyContactListStore *store) -{ - contact_list_store_add_contact (store, contact); -} - -static void -contact_monitor_contact_removed_cb (EmpathyContactMonitor *monitor, - EmpathyContact *contact, - EmpathyContactListStore *store) -{ - contact_list_store_remove_contact (store, contact); -} - - -static void -disconnect_monitor_signals (EmpathyContactMonitor *monitor, - GObject *obj) -{ - g_signal_handlers_disconnect_by_func (monitor, - contact_monitor_avatar_changed_cb, obj); - g_signal_handlers_disconnect_by_func (monitor, - contact_monitor_capabilities_changed_cb, obj); - g_signal_handlers_disconnect_by_func (monitor, - contact_monitor_contact_added_cb, obj); - g_signal_handlers_disconnect_by_func (monitor, - contact_monitor_contact_removed_cb, obj); - g_signal_handlers_disconnect_by_func (monitor, - contact_monitor_name_changed_cb, obj); - g_signal_handlers_disconnect_by_func (monitor, - contact_monitor_presence_changed_cb, obj); - g_signal_handlers_disconnect_by_func (monitor, - contact_monitor_presence_message_changed_cb, obj); -} - -static gboolean -contact_list_store_iface_setup (gpointer user_data) -{ - EmpathyContactListStore *store = user_data; - EmpathyContactListStorePriv *priv = GET_PRIV (store); - EmpathyContactMonitor *monitor; - GList *contacts, *l; - - monitor = empathy_contact_list_get_monitor (priv->list); - - /* Signal connection. */ - g_signal_connect (monitor, "contact-added", - G_CALLBACK (contact_monitor_contact_added_cb), store); - g_signal_connect (monitor, "contact-removed", - G_CALLBACK (contact_monitor_contact_removed_cb), store); - g_signal_connect (monitor, "contact-presence-changed", - G_CALLBACK (contact_monitor_presence_changed_cb), store); - g_signal_connect (monitor, "contact-presence-message-changed", - G_CALLBACK (contact_monitor_presence_message_changed_cb), store); - g_signal_connect (monitor, "contact-name-changed", - G_CALLBACK (contact_monitor_name_changed_cb), store); - g_signal_connect (monitor, "contact-capabilities-changed", - G_CALLBACK (contact_monitor_capabilities_changed_cb), store); - g_signal_connect (monitor, "contact-avatar-changed", - G_CALLBACK (contact_monitor_avatar_changed_cb), store); - - /* Add contacts already created. */ - contacts = empathy_contact_list_get_members (priv->list); - for (l = contacts; l; l = l->next) { - contact_monitor_contact_added_cb (monitor, l->data, store); - - g_object_unref (l->data); - } - g_list_free (contacts); - - return FALSE; + contact_list_store_contact_update (store, contact); } static void |