1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
3 * Copyright (C) 2005-2007 Imendio AB
4 * Copyright (C) 2007-2008 Collabora Ltd.
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License as
8 * published by the Free Software Foundation; either version 2 of the
9 * License, or (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * General Public License for more details.
16 * You should have received a copy of the GNU General Public
17 * License along with this program; if not, write to the
18 * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
19 * Boston, MA 02110-1301 USA
21 * Authors: Mikael Hallendal <micke@imendio.com>
22 * Martyn Russell <martyn@imendio.com>
23 * Xavier Claessens <xclaesse@gmail.com>
33 #include <telepathy-glib/util.h>
35 #include <libempathy/empathy-utils.h>
36 #include <libempathy/empathy-enum-types.h>
37 #include <libempathy/empathy-contact-manager.h>
39 #include "empathy-contact-list-store.h"
40 #include "empathy-ui-utils.h"
41 #include "empathy-gtk-enum-types.h"
43 #define DEBUG_FLAG EMPATHY_DEBUG_CONTACT
44 #include <libempathy/empathy-debug.h>
46 /* Active users are those which have recently changed state
47 * (e.g. online, offline or from normal to a busy state).
50 /* Time in seconds user is shown as active */
51 #define ACTIVE_USER_SHOW_TIME 7
53 /* Time in seconds after connecting which we wait before active users are enabled */
54 #define ACTIVE_USER_WAIT_TO_ENABLE_TIME 5
56 #define GET_PRIV(obj) EMPATHY_GET_PRIV (obj, EmpathyContactListStore)
58 EmpathyContactList
*list
;
59 gboolean show_offline
;
60 gboolean show_avatars
;
63 gboolean show_protocols
;
65 EmpathyContactListStoreSort sort_criterium
;
68 gboolean dispose_has_run
;
69 GHashTable
*status_icons
;
70 } EmpathyContactListStorePriv
;
79 EmpathyContact
*contact
;
85 EmpathyContactListStore
*store
;
86 EmpathyContact
*contact
;
90 static void contact_list_store_dispose (GObject
*object
);
91 static void contact_list_store_get_property (GObject
*object
,
95 static void contact_list_store_set_property (GObject
*object
,
99 static void contact_list_store_setup (EmpathyContactListStore
*store
);
100 static gboolean
contact_list_store_inibit_active_cb (EmpathyContactListStore
*store
);
101 static void contact_list_store_members_changed_cb (EmpathyContactList
*list_iface
,
102 EmpathyContact
*contact
,
103 EmpathyContact
*actor
,
107 EmpathyContactListStore
*store
);
108 static void contact_list_store_member_renamed_cb (EmpathyContactList
*list_iface
,
109 EmpathyContact
*old_contact
,
110 EmpathyContact
*new_contact
,
113 EmpathyContactListStore
*store
);
114 static void contact_list_store_groups_changed_cb (EmpathyContactList
*list_iface
,
115 EmpathyContact
*contact
,
118 EmpathyContactListStore
*store
);
119 static void contact_list_store_add_contact (EmpathyContactListStore
*store
,
120 EmpathyContact
*contact
);
121 static void contact_list_store_remove_contact (EmpathyContactListStore
*store
,
122 EmpathyContact
*contact
);
123 static void contact_list_store_contact_update (EmpathyContactListStore
*store
,
124 EmpathyContact
*contact
);
125 static void contact_list_store_contact_updated_cb (EmpathyContact
*contact
,
127 EmpathyContactListStore
*store
);
128 static void contact_list_store_contact_set_active (EmpathyContactListStore
*store
,
129 EmpathyContact
*contact
,
131 gboolean set_changed
);
132 static ShowActiveData
* contact_list_store_contact_active_new (EmpathyContactListStore
*store
,
133 EmpathyContact
*contact
,
135 static void contact_list_store_contact_active_free (ShowActiveData
*data
);
136 static gboolean
contact_list_store_contact_active_cb (ShowActiveData
*data
);
137 static gboolean
contact_list_store_get_group_foreach (GtkTreeModel
*model
,
141 static void contact_list_store_get_group (EmpathyContactListStore
*store
,
143 GtkTreeIter
*iter_group_to_set
,
144 GtkTreeIter
*iter_separator_to_set
,
146 static gint
contact_list_store_state_sort_func (GtkTreeModel
*model
,
150 static gint
contact_list_store_name_sort_func (GtkTreeModel
*model
,
154 static gboolean
contact_list_store_find_contact_foreach (GtkTreeModel
*model
,
158 static GList
* contact_list_store_find_contact (EmpathyContactListStore
*store
,
159 EmpathyContact
*contact
);
160 static gboolean
contact_list_store_update_list_mode_foreach (GtkTreeModel
*model
,
163 EmpathyContactListStore
*store
);
176 G_DEFINE_TYPE (EmpathyContactListStore
, empathy_contact_list_store
, GTK_TYPE_TREE_STORE
);
179 contact_list_store_iface_setup (gpointer user_data
)
181 EmpathyContactListStore
*store
= user_data
;
182 EmpathyContactListStorePriv
*priv
= GET_PRIV (store
);
185 /* Signal connection. */
186 g_signal_connect (priv
->list
,
188 G_CALLBACK (contact_list_store_member_renamed_cb
),
190 g_signal_connect (priv
->list
,
192 G_CALLBACK (contact_list_store_members_changed_cb
),
194 g_signal_connect (priv
->list
,
196 G_CALLBACK (contact_list_store_groups_changed_cb
),
199 /* Add contacts already created. */
200 contacts
= empathy_contact_list_get_members (priv
->list
);
201 for (l
= contacts
; l
; l
= l
->next
) {
202 contact_list_store_members_changed_cb (priv
->list
, l
->data
,
207 g_object_unref (l
->data
);
209 g_list_free (contacts
);
211 priv
->setup_idle_id
= 0;
217 contact_list_store_set_contact_list (EmpathyContactListStore
*store
,
218 EmpathyContactList
*list_iface
)
220 EmpathyContactListStorePriv
*priv
= GET_PRIV (store
);
222 priv
->list
= g_object_ref (list_iface
);
224 /* Let a chance to have all properties set before populating */
225 priv
->setup_idle_id
= g_idle_add (contact_list_store_iface_setup
, store
);
229 empathy_contact_list_store_class_init (EmpathyContactListStoreClass
*klass
)
231 GObjectClass
*object_class
= G_OBJECT_CLASS (klass
);
233 object_class
->dispose
= contact_list_store_dispose
;
234 object_class
->get_property
= contact_list_store_get_property
;
235 object_class
->set_property
= contact_list_store_set_property
;
237 g_object_class_install_property (object_class
,
239 g_param_spec_object ("contact-list",
240 "The contact list iface",
241 "The contact list iface",
242 EMPATHY_TYPE_CONTACT_LIST
,
243 G_PARAM_CONSTRUCT_ONLY
|
245 g_object_class_install_property (object_class
,
247 g_param_spec_boolean ("show-offline",
249 "Whether contact list should display "
253 g_object_class_install_property (object_class
,
255 g_param_spec_boolean ("show-avatars",
257 "Whether contact list should display "
258 "avatars for contacts",
261 g_object_class_install_property (object_class
,
263 g_param_spec_boolean ("show-protocols",
265 "Whether contact list should display "
266 "protocols for contacts",
269 g_object_class_install_property (object_class
,
271 g_param_spec_boolean ("show-groups",
273 "Whether contact list should display "
277 g_object_class_install_property (object_class
,
279 g_param_spec_boolean ("is-compact",
281 "Whether the contact list is in compact mode or not",
285 g_object_class_install_property (object_class
,
287 g_param_spec_enum ("sort-criterium",
289 "The sort criterium to use for sorting the contact list",
290 EMPATHY_TYPE_CONTACT_LIST_STORE_SORT
,
291 EMPATHY_CONTACT_LIST_STORE_SORT_NAME
,
294 g_type_class_add_private (object_class
, sizeof (EmpathyContactListStorePriv
));
298 empathy_contact_list_store_init (EmpathyContactListStore
*store
)
300 EmpathyContactListStorePriv
*priv
= G_TYPE_INSTANCE_GET_PRIVATE (store
,
301 EMPATHY_TYPE_CONTACT_LIST_STORE
, EmpathyContactListStorePriv
);
304 priv
->show_avatars
= TRUE
;
305 priv
->show_groups
= TRUE
;
306 priv
->show_protocols
= FALSE
;
307 priv
->inhibit_active
= g_timeout_add_seconds (ACTIVE_USER_WAIT_TO_ENABLE_TIME
,
308 (GSourceFunc
) contact_list_store_inibit_active_cb
,
310 priv
->status_icons
= g_hash_table_new_full (g_str_hash
, g_str_equal
, g_free
, g_object_unref
);
311 contact_list_store_setup (store
);
315 contact_list_store_dispose (GObject
*object
)
317 EmpathyContactListStorePriv
*priv
= GET_PRIV (object
);
320 if (priv
->dispose_has_run
)
322 priv
->dispose_has_run
= TRUE
;
324 contacts
= empathy_contact_list_get_members (priv
->list
);
325 for (l
= contacts
; l
; l
= l
->next
) {
326 g_signal_handlers_disconnect_by_func (l
->data
,
327 G_CALLBACK (contact_list_store_contact_updated_cb
),
330 g_object_unref (l
->data
);
332 g_list_free (contacts
);
334 g_signal_handlers_disconnect_by_func (priv
->list
,
335 G_CALLBACK (contact_list_store_member_renamed_cb
),
337 g_signal_handlers_disconnect_by_func (priv
->list
,
338 G_CALLBACK (contact_list_store_members_changed_cb
),
340 g_signal_handlers_disconnect_by_func (priv
->list
,
341 G_CALLBACK (contact_list_store_groups_changed_cb
),
343 g_object_unref (priv
->list
);
345 if (priv
->inhibit_active
) {
346 g_source_remove (priv
->inhibit_active
);
349 if (priv
->setup_idle_id
!= 0) {
350 g_source_remove (priv
->setup_idle_id
);
353 g_hash_table_destroy (priv
->status_icons
);
354 G_OBJECT_CLASS (empathy_contact_list_store_parent_class
)->dispose (object
);
358 contact_list_store_get_property (GObject
*object
,
363 EmpathyContactListStorePriv
*priv
;
365 priv
= GET_PRIV (object
);
368 case PROP_CONTACT_LIST
:
369 g_value_set_object (value
, priv
->list
);
371 case PROP_SHOW_OFFLINE
:
372 g_value_set_boolean (value
, priv
->show_offline
);
374 case PROP_SHOW_AVATARS
:
375 g_value_set_boolean (value
, priv
->show_avatars
);
377 case PROP_SHOW_PROTOCOLS
:
378 g_value_set_boolean (value
, priv
->show_protocols
);
380 case PROP_SHOW_GROUPS
:
381 g_value_set_boolean (value
, priv
->show_groups
);
383 case PROP_IS_COMPACT
:
384 g_value_set_boolean (value
, priv
->is_compact
);
386 case PROP_SORT_CRITERIUM
:
387 g_value_set_enum (value
, priv
->sort_criterium
);
390 G_OBJECT_WARN_INVALID_PROPERTY_ID (object
, param_id
, pspec
);
396 contact_list_store_set_property (GObject
*object
,
401 EmpathyContactListStorePriv
*priv
;
403 priv
= GET_PRIV (object
);
406 case PROP_CONTACT_LIST
:
407 contact_list_store_set_contact_list (EMPATHY_CONTACT_LIST_STORE (object
),
408 g_value_get_object (value
));
410 case PROP_SHOW_OFFLINE
:
411 empathy_contact_list_store_set_show_offline (EMPATHY_CONTACT_LIST_STORE (object
),
412 g_value_get_boolean (value
));
414 case PROP_SHOW_AVATARS
:
415 empathy_contact_list_store_set_show_avatars (EMPATHY_CONTACT_LIST_STORE (object
),
416 g_value_get_boolean (value
));
418 case PROP_SHOW_PROTOCOLS
:
419 empathy_contact_list_store_set_show_protocols (EMPATHY_CONTACT_LIST_STORE (object
),
420 g_value_get_boolean (value
));
422 case PROP_SHOW_GROUPS
:
423 empathy_contact_list_store_set_show_groups (EMPATHY_CONTACT_LIST_STORE (object
),
424 g_value_get_boolean (value
));
426 case PROP_IS_COMPACT
:
427 empathy_contact_list_store_set_is_compact (EMPATHY_CONTACT_LIST_STORE (object
),
428 g_value_get_boolean (value
));
430 case PROP_SORT_CRITERIUM
:
431 empathy_contact_list_store_set_sort_criterium (EMPATHY_CONTACT_LIST_STORE (object
),
432 g_value_get_enum (value
));
435 G_OBJECT_WARN_INVALID_PROPERTY_ID (object
, param_id
, pspec
);
440 EmpathyContactListStore
*
441 empathy_contact_list_store_new (EmpathyContactList
*list_iface
)
443 g_return_val_if_fail (EMPATHY_IS_CONTACT_LIST (list_iface
), NULL
);
445 return g_object_new (EMPATHY_TYPE_CONTACT_LIST_STORE
,
446 "contact-list", list_iface
,
451 empathy_contact_list_store_get_list_iface (EmpathyContactListStore
*store
)
453 EmpathyContactListStorePriv
*priv
;
455 g_return_val_if_fail (EMPATHY_IS_CONTACT_LIST_STORE (store
), FALSE
);
457 priv
= GET_PRIV (store
);
463 empathy_contact_list_store_get_show_offline (EmpathyContactListStore
*store
)
465 EmpathyContactListStorePriv
*priv
;
467 g_return_val_if_fail (EMPATHY_IS_CONTACT_LIST_STORE (store
), FALSE
);
469 priv
= GET_PRIV (store
);
471 return priv
->show_offline
;
475 empathy_contact_list_store_set_show_offline (EmpathyContactListStore
*store
,
476 gboolean show_offline
)
478 EmpathyContactListStorePriv
*priv
;
480 gboolean show_active
;
482 g_return_if_fail (EMPATHY_IS_CONTACT_LIST_STORE (store
));
484 priv
= GET_PRIV (store
);
486 priv
->show_offline
= show_offline
;
487 show_active
= priv
->show_active
;
489 /* Disable temporarily. */
490 priv
->show_active
= FALSE
;
492 contacts
= empathy_contact_list_get_members (priv
->list
);
493 for (l
= contacts
; l
; l
= l
->next
) {
494 contact_list_store_contact_update (store
, l
->data
);
496 g_object_unref (l
->data
);
498 g_list_free (contacts
);
500 /* Restore to original setting. */
501 priv
->show_active
= show_active
;
503 g_object_notify (G_OBJECT (store
), "show-offline");
507 empathy_contact_list_store_get_show_avatars (EmpathyContactListStore
*store
)
509 EmpathyContactListStorePriv
*priv
;
511 g_return_val_if_fail (EMPATHY_IS_CONTACT_LIST_STORE (store
), TRUE
);
513 priv
= GET_PRIV (store
);
515 return priv
->show_avatars
;
519 empathy_contact_list_store_set_show_avatars (EmpathyContactListStore
*store
,
520 gboolean show_avatars
)
522 EmpathyContactListStorePriv
*priv
;
525 g_return_if_fail (EMPATHY_IS_CONTACT_LIST_STORE (store
));
527 priv
= GET_PRIV (store
);
529 priv
->show_avatars
= show_avatars
;
531 model
= GTK_TREE_MODEL (store
);
533 gtk_tree_model_foreach (model
,
534 (GtkTreeModelForeachFunc
)
535 contact_list_store_update_list_mode_foreach
,
538 g_object_notify (G_OBJECT (store
), "show-avatars");
543 empathy_contact_list_store_get_show_protocols (EmpathyContactListStore
*store
)
545 EmpathyContactListStorePriv
*priv
;
547 g_return_val_if_fail (EMPATHY_IS_CONTACT_LIST_STORE (store
), TRUE
);
549 priv
= GET_PRIV (store
);
551 return priv
->show_protocols
;
555 empathy_contact_list_store_set_show_protocols (EmpathyContactListStore
*store
,
556 gboolean show_protocols
)
558 EmpathyContactListStorePriv
*priv
;
561 g_return_if_fail (EMPATHY_IS_CONTACT_LIST_STORE (store
));
563 priv
= GET_PRIV (store
);
565 priv
->show_protocols
= show_protocols
;
567 model
= GTK_TREE_MODEL (store
);
569 gtk_tree_model_foreach (model
,
570 (GtkTreeModelForeachFunc
)
571 contact_list_store_update_list_mode_foreach
,
574 g_object_notify (G_OBJECT (store
), "show-protocols");
578 empathy_contact_list_store_get_show_groups (EmpathyContactListStore
*store
)
580 EmpathyContactListStorePriv
*priv
;
582 g_return_val_if_fail (EMPATHY_IS_CONTACT_LIST_STORE (store
), TRUE
);
584 priv
= GET_PRIV (store
);
586 return priv
->show_groups
;
590 empathy_contact_list_store_set_show_groups (EmpathyContactListStore
*store
,
591 gboolean show_groups
)
593 EmpathyContactListStorePriv
*priv
;
596 g_return_if_fail (EMPATHY_IS_CONTACT_LIST_STORE (store
));
598 priv
= GET_PRIV (store
);
600 if (priv
->show_groups
== show_groups
) {
604 priv
->show_groups
= show_groups
;
606 /* Remove all contacts and add them back, not optimized but that's the
608 gtk_tree_store_clear (GTK_TREE_STORE (store
));
609 contacts
= empathy_contact_list_get_members (priv
->list
);
610 for (l
= contacts
; l
; l
= l
->next
) {
611 contact_list_store_members_changed_cb (priv
->list
, l
->data
,
616 g_object_unref (l
->data
);
618 g_list_free (contacts
);
620 g_object_notify (G_OBJECT (store
), "show-groups");
624 empathy_contact_list_store_get_is_compact (EmpathyContactListStore
*store
)
626 EmpathyContactListStorePriv
*priv
;
628 g_return_val_if_fail (EMPATHY_IS_CONTACT_LIST_STORE (store
), TRUE
);
630 priv
= GET_PRIV (store
);
632 return priv
->is_compact
;
636 empathy_contact_list_store_set_is_compact (EmpathyContactListStore
*store
,
639 EmpathyContactListStorePriv
*priv
;
642 g_return_if_fail (EMPATHY_IS_CONTACT_LIST_STORE (store
));
644 priv
= GET_PRIV (store
);
646 priv
->is_compact
= is_compact
;
648 model
= GTK_TREE_MODEL (store
);
650 gtk_tree_model_foreach (model
,
651 (GtkTreeModelForeachFunc
)
652 contact_list_store_update_list_mode_foreach
,
655 g_object_notify (G_OBJECT (store
), "is-compact");
658 EmpathyContactListStoreSort
659 empathy_contact_list_store_get_sort_criterium (EmpathyContactListStore
*store
)
661 EmpathyContactListStorePriv
*priv
;
663 g_return_val_if_fail (EMPATHY_IS_CONTACT_LIST_STORE (store
), 0);
665 priv
= GET_PRIV (store
);
667 return priv
->sort_criterium
;
671 empathy_contact_list_store_set_sort_criterium (EmpathyContactListStore
*store
,
672 EmpathyContactListStoreSort sort_criterium
)
674 EmpathyContactListStorePriv
*priv
;
676 g_return_if_fail (EMPATHY_IS_CONTACT_LIST_STORE (store
));
678 priv
= GET_PRIV (store
);
680 priv
->sort_criterium
= sort_criterium
;
682 switch (sort_criterium
) {
683 case EMPATHY_CONTACT_LIST_STORE_SORT_STATE
:
684 gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (store
),
685 EMPATHY_CONTACT_LIST_STORE_COL_STATUS
,
689 case EMPATHY_CONTACT_LIST_STORE_SORT_NAME
:
690 gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (store
),
691 EMPATHY_CONTACT_LIST_STORE_COL_NAME
,
696 g_object_notify (G_OBJECT (store
), "sort-criterium");
700 empathy_contact_list_store_row_separator_func (GtkTreeModel
*model
,
704 gboolean is_separator
= FALSE
;
706 g_return_val_if_fail (GTK_IS_TREE_MODEL (model
), FALSE
);
708 gtk_tree_model_get (model
, iter
,
709 EMPATHY_CONTACT_LIST_STORE_COL_IS_SEPARATOR
, &is_separator
,
716 empathy_contact_list_store_get_parent_group (GtkTreeModel
*model
,
718 gboolean
*path_is_group
)
720 GtkTreeIter parent_iter
, iter
;
724 g_return_val_if_fail (GTK_IS_TREE_MODEL (model
), NULL
);
727 *path_is_group
= FALSE
;
730 if (!gtk_tree_model_get_iter (model
, &iter
, path
)) {
734 gtk_tree_model_get (model
, &iter
,
735 EMPATHY_CONTACT_LIST_STORE_COL_IS_GROUP
, &is_group
,
736 EMPATHY_CONTACT_LIST_STORE_COL_NAME
, &name
,
743 if (!gtk_tree_model_iter_parent (model
, &parent_iter
, &iter
)) {
749 gtk_tree_model_get (model
, &iter
,
750 EMPATHY_CONTACT_LIST_STORE_COL_IS_GROUP
, &is_group
,
751 EMPATHY_CONTACT_LIST_STORE_COL_NAME
, &name
,
760 *path_is_group
= TRUE
;
767 empathy_contact_list_store_search_equal_func (GtkTreeModel
*model
,
771 gpointer search_data
)
773 gchar
*name
, *name_folded
;
777 g_return_val_if_fail (GTK_IS_TREE_MODEL (model
), FALSE
);
783 gtk_tree_model_get (model
, iter
,
784 EMPATHY_CONTACT_LIST_STORE_COL_NAME
, &name
,
791 name_folded
= g_utf8_casefold (name
, -1);
792 key_folded
= g_utf8_casefold (key
, -1);
794 if (name_folded
&& key_folded
&&
795 strstr (name_folded
, key_folded
)) {
802 g_free (name_folded
);
809 contact_list_store_setup (EmpathyContactListStore
*store
)
811 EmpathyContactListStorePriv
*priv
;
813 GDK_TYPE_PIXBUF
, /* Status pixbuf */
814 GDK_TYPE_PIXBUF
, /* Avatar pixbuf */
815 G_TYPE_BOOLEAN
, /* Avatar pixbuf visible */
816 G_TYPE_STRING
, /* Name */
817 G_TYPE_STRING
, /* Status string */
818 G_TYPE_BOOLEAN
, /* Show status */
819 EMPATHY_TYPE_CONTACT
, /* Contact type */
820 G_TYPE_BOOLEAN
, /* Is group */
821 G_TYPE_BOOLEAN
, /* Is active */
822 G_TYPE_BOOLEAN
, /* Is online */
823 G_TYPE_BOOLEAN
, /* Is separator */
824 G_TYPE_BOOLEAN
, /* Can make audio calls */
825 G_TYPE_BOOLEAN
, /* Can make video calls */
826 EMPATHY_TYPE_CONTACT_LIST_FLAGS
, /* Flags */
829 priv
= GET_PRIV (store
);
831 gtk_tree_store_set_column_types (GTK_TREE_STORE (store
),
832 EMPATHY_CONTACT_LIST_STORE_COL_COUNT
,
836 gtk_tree_sortable_set_sort_func (GTK_TREE_SORTABLE (store
),
837 EMPATHY_CONTACT_LIST_STORE_COL_NAME
,
838 contact_list_store_name_sort_func
,
840 gtk_tree_sortable_set_sort_func (GTK_TREE_SORTABLE (store
),
841 EMPATHY_CONTACT_LIST_STORE_COL_STATUS
,
842 contact_list_store_state_sort_func
,
845 priv
->sort_criterium
= EMPATHY_CONTACT_LIST_STORE_SORT_NAME
;
846 empathy_contact_list_store_set_sort_criterium (store
, priv
->sort_criterium
);
850 contact_list_store_inibit_active_cb (EmpathyContactListStore
*store
)
852 EmpathyContactListStorePriv
*priv
;
854 priv
= GET_PRIV (store
);
856 priv
->show_active
= TRUE
;
857 priv
->inhibit_active
= 0;
863 contact_list_store_add_contact_and_connect (EmpathyContactListStore
*store
, EmpathyContact
*contact
)
865 g_signal_connect (contact
, "notify::presence",
866 G_CALLBACK (contact_list_store_contact_updated_cb
),
868 g_signal_connect (contact
, "notify::presence-message",
869 G_CALLBACK (contact_list_store_contact_updated_cb
),
871 g_signal_connect (contact
, "notify::name",
872 G_CALLBACK (contact_list_store_contact_updated_cb
),
874 g_signal_connect (contact
, "notify::avatar",
875 G_CALLBACK (contact_list_store_contact_updated_cb
),
877 g_signal_connect (contact
, "notify::capabilities",
878 G_CALLBACK (contact_list_store_contact_updated_cb
),
881 contact_list_store_add_contact (store
, contact
);
885 contact_list_store_remove_contact_and_disconnect (EmpathyContactListStore
*store
, EmpathyContact
*contact
)
887 g_signal_handlers_disconnect_by_func (contact
,
888 G_CALLBACK (contact_list_store_contact_updated_cb
),
891 contact_list_store_remove_contact (store
, contact
);
895 contact_list_store_members_changed_cb (EmpathyContactList
*list_iface
,
896 EmpathyContact
*contact
,
897 EmpathyContact
*actor
,
901 EmpathyContactListStore
*store
)
903 EmpathyContactListStorePriv
*priv
;
905 priv
= GET_PRIV (store
);
907 DEBUG ("Contact %s (%d) %s",
908 empathy_contact_get_id (contact
),
909 empathy_contact_get_handle (contact
),
910 is_member
? "added" : "removed");
913 contact_list_store_add_contact_and_connect (store
, contact
);
915 contact_list_store_remove_contact_and_disconnect (store
, contact
);
920 contact_list_store_member_renamed_cb (EmpathyContactList
*list_iface
,
921 EmpathyContact
*old_contact
,
922 EmpathyContact
*new_contact
,
925 EmpathyContactListStore
*store
)
927 EmpathyContactListStorePriv
*priv
;
929 priv
= GET_PRIV (store
);
931 DEBUG ("Contact %s (%d) renamed to %s (%d)",
932 empathy_contact_get_id (old_contact
),
933 empathy_contact_get_handle (old_contact
),
934 empathy_contact_get_id (new_contact
),
935 empathy_contact_get_handle (new_contact
));
937 /* add the new contact */
938 contact_list_store_add_contact_and_connect (store
, new_contact
);
940 /* remove old contact */
941 contact_list_store_remove_contact_and_disconnect (store
, old_contact
);
945 contact_list_store_groups_changed_cb (EmpathyContactList
*list_iface
,
946 EmpathyContact
*contact
,
949 EmpathyContactListStore
*store
)
951 EmpathyContactListStorePriv
*priv
;
952 gboolean show_active
;
954 priv
= GET_PRIV (store
);
956 DEBUG ("Updating groups for contact %s (%d)",
957 empathy_contact_get_id (contact
),
958 empathy_contact_get_handle (contact
));
960 /* We do this to make sure the groups are correct, if not, we
961 * would have to check the groups already set up for each
962 * contact and then see what has been updated.
964 show_active
= priv
->show_active
;
965 priv
->show_active
= FALSE
;
966 contact_list_store_remove_contact (store
, contact
);
967 contact_list_store_add_contact (store
, contact
);
968 priv
->show_active
= show_active
;
972 contact_list_store_add_contact (EmpathyContactListStore
*store
,
973 EmpathyContact
*contact
)
975 EmpathyContactListStorePriv
*priv
;
977 GList
*groups
= NULL
, *l
;
978 TpConnection
*connection
;
979 EmpathyContactListFlags flags
= 0;
981 priv
= GET_PRIV (store
);
983 if (EMP_STR_EMPTY (empathy_contact_get_name (contact
)) ||
984 (!priv
->show_offline
&& !empathy_contact_is_online (contact
))) {
988 if (priv
->show_groups
) {
989 groups
= empathy_contact_list_get_groups (priv
->list
, contact
);
992 connection
= empathy_contact_get_connection (contact
);
993 if (EMPATHY_IS_CONTACT_MANAGER (priv
->list
)) {
994 flags
= empathy_contact_manager_get_flags_for_connection (
995 EMPATHY_CONTACT_MANAGER (priv
->list
), connection
);
997 /* If no groups just add it at the top level. */
999 GtkTreeModel
*model
= GTK_TREE_MODEL (store
);
1001 if (gtk_tree_model_get_iter_first (model
, &iter
)) do {
1004 gtk_tree_model_get (model
, &iter
,
1005 EMPATHY_CONTACT_LIST_STORE_COL_CONTACT
, &c
,
1014 } while (gtk_tree_model_iter_next (model
, &iter
));
1016 gtk_tree_store_append (GTK_TREE_STORE (store
), &iter
, NULL
);
1017 gtk_tree_store_set (GTK_TREE_STORE (store
), &iter
,
1018 EMPATHY_CONTACT_LIST_STORE_COL_NAME
, empathy_contact_get_name (contact
),
1019 EMPATHY_CONTACT_LIST_STORE_COL_CONTACT
, contact
,
1020 EMPATHY_CONTACT_LIST_STORE_COL_IS_GROUP
, FALSE
,
1021 EMPATHY_CONTACT_LIST_STORE_COL_IS_SEPARATOR
, FALSE
,
1022 EMPATHY_CONTACT_LIST_STORE_COL_CAN_AUDIO_CALL
,
1023 empathy_contact_get_capabilities (contact
) &
1024 EMPATHY_CAPABILITIES_AUDIO
,
1025 EMPATHY_CONTACT_LIST_STORE_COL_CAN_VIDEO_CALL
,
1026 empathy_contact_get_capabilities (contact
) &
1027 EMPATHY_CAPABILITIES_VIDEO
,
1028 EMPATHY_CONTACT_LIST_STORE_COL_FLAGS
, flags
,
1032 /* Else add to each group. */
1033 for (l
= groups
; l
; l
= l
->next
) {
1034 GtkTreeIter iter_group
;
1036 contact_list_store_get_group (store
, l
->data
, &iter_group
, NULL
, NULL
);
1038 gtk_tree_store_insert_after (GTK_TREE_STORE (store
), &iter
,
1040 gtk_tree_store_set (GTK_TREE_STORE (store
), &iter
,
1041 EMPATHY_CONTACT_LIST_STORE_COL_NAME
, empathy_contact_get_name (contact
),
1042 EMPATHY_CONTACT_LIST_STORE_COL_CONTACT
, contact
,
1043 EMPATHY_CONTACT_LIST_STORE_COL_IS_GROUP
, FALSE
,
1044 EMPATHY_CONTACT_LIST_STORE_COL_IS_SEPARATOR
, FALSE
,
1045 EMPATHY_CONTACT_LIST_STORE_COL_CAN_AUDIO_CALL
,
1046 empathy_contact_get_capabilities (contact
) &
1047 EMPATHY_CAPABILITIES_AUDIO
,
1048 EMPATHY_CONTACT_LIST_STORE_COL_CAN_VIDEO_CALL
,
1049 empathy_contact_get_capabilities (contact
) &
1050 EMPATHY_CAPABILITIES_VIDEO
,
1051 EMPATHY_CONTACT_LIST_STORE_COL_FLAGS
, flags
,
1055 g_list_free (groups
);
1057 contact_list_store_contact_update (store
, contact
);
1062 contact_list_store_remove_contact (EmpathyContactListStore
*store
,
1063 EmpathyContact
*contact
)
1065 EmpathyContactListStorePriv
*priv
;
1066 GtkTreeModel
*model
;
1069 priv
= GET_PRIV (store
);
1071 iters
= contact_list_store_find_contact (store
, contact
);
1076 /* Clean up model */
1077 model
= GTK_TREE_MODEL (store
);
1079 for (l
= iters
; l
; l
= l
->next
) {
1082 /* NOTE: it is only <= 2 here because we have
1083 * separators after the group name, otherwise it
1086 if (gtk_tree_model_iter_parent (model
, &parent
, l
->data
) &&
1087 gtk_tree_model_iter_n_children (model
, &parent
) <= 2) {
1088 gtk_tree_store_remove (GTK_TREE_STORE (store
), &parent
);
1090 gtk_tree_store_remove (GTK_TREE_STORE (store
), l
->data
);
1094 g_list_foreach (iters
, (GFunc
) gtk_tree_iter_free
, NULL
);
1095 g_list_free (iters
);
1099 contact_list_store_contact_update (EmpathyContactListStore
*store
,
1100 EmpathyContact
*contact
)
1102 EmpathyContactListStorePriv
*priv
;
1103 ShowActiveData
*data
;
1104 GtkTreeModel
*model
;
1107 gboolean should_be_in_list
;
1108 gboolean was_online
= TRUE
;
1109 gboolean now_online
= FALSE
;
1110 gboolean set_model
= FALSE
;
1111 gboolean do_remove
= FALSE
;
1112 gboolean do_set_active
= FALSE
;
1113 gboolean do_set_refresh
= FALSE
;
1114 gboolean show_avatar
= FALSE
;
1115 gboolean show_protocol
= FALSE
;
1116 GdkPixbuf
*pixbuf_avatar
;
1117 GdkPixbuf
*pixbuf_status
;
1119 priv
= GET_PRIV (store
);
1121 model
= GTK_TREE_MODEL (store
);
1123 iters
= contact_list_store_find_contact (store
, contact
);
1130 /* Get online state now. */
1131 now_online
= empathy_contact_is_online (contact
);
1133 if (priv
->show_offline
|| now_online
) {
1134 should_be_in_list
= TRUE
;
1136 should_be_in_list
= FALSE
;
1139 if (!in_list
&& !should_be_in_list
) {
1140 /* Nothing to do. */
1141 DEBUG ("Contact:'%s' in list:NO, should be:NO",
1142 empathy_contact_get_name (contact
));
1144 g_list_foreach (iters
, (GFunc
) gtk_tree_iter_free
, NULL
);
1145 g_list_free (iters
);
1148 else if (in_list
&& !should_be_in_list
) {
1149 DEBUG ("Contact:'%s' in list:YES, should be:NO",
1150 empathy_contact_get_name (contact
));
1152 if (priv
->show_active
) {
1154 do_set_active
= TRUE
;
1155 do_set_refresh
= TRUE
;
1158 DEBUG ("Remove item (after timeout)");
1160 DEBUG ("Remove item (now)!");
1161 contact_list_store_remove_contact (store
, contact
);
1164 else if (!in_list
&& should_be_in_list
) {
1165 DEBUG ("Contact:'%s' in list:NO, should be:YES",
1166 empathy_contact_get_name (contact
));
1168 contact_list_store_add_contact (store
, contact
);
1170 if (priv
->show_active
) {
1171 do_set_active
= TRUE
;
1173 DEBUG ("Set active (contact added)");
1176 DEBUG ("Contact:'%s' in list:YES, should be:YES",
1177 empathy_contact_get_name (contact
));
1179 /* Get online state before. */
1180 if (iters
&& g_list_length (iters
) > 0) {
1181 gtk_tree_model_get (model
, iters
->data
,
1182 EMPATHY_CONTACT_LIST_STORE_COL_IS_ONLINE
, &was_online
,
1186 /* Is this really an update or an online/offline. */
1187 if (priv
->show_active
) {
1188 if (was_online
!= now_online
) {
1189 do_set_active
= TRUE
;
1190 do_set_refresh
= TRUE
;
1192 DEBUG ("Set active (contact updated %s)",
1193 was_online
? "online -> offline" :
1194 "offline -> online");
1196 /* Was TRUE for presence updates. */
1197 /* do_set_active = FALSE; */
1198 do_set_refresh
= TRUE
;
1200 DEBUG ("Set active (contact updated)");
1207 if (priv
->show_avatars
&& !priv
->is_compact
) {
1210 if (priv
->show_protocols
&& !priv
->is_compact
) {
1211 show_protocol
= TRUE
;
1213 pixbuf_avatar
= empathy_pixbuf_avatar_from_contact_scaled (contact
, 32, 32);
1214 pixbuf_status
= contact_list_store_get_contact_status_icon (store
, contact
);
1215 for (l
= iters
; l
&& set_model
; l
= l
->next
) {
1216 gtk_tree_store_set (GTK_TREE_STORE (store
), l
->data
,
1217 EMPATHY_CONTACT_LIST_STORE_COL_ICON_STATUS
, pixbuf_status
,
1218 EMPATHY_CONTACT_LIST_STORE_COL_PIXBUF_AVATAR
, pixbuf_avatar
,
1219 EMPATHY_CONTACT_LIST_STORE_COL_PIXBUF_AVATAR_VISIBLE
, show_avatar
,
1220 EMPATHY_CONTACT_LIST_STORE_COL_NAME
, empathy_contact_get_name (contact
),
1221 EMPATHY_CONTACT_LIST_STORE_COL_STATUS
, empathy_contact_get_status (contact
),
1222 EMPATHY_CONTACT_LIST_STORE_COL_STATUS_VISIBLE
, !priv
->is_compact
,
1223 EMPATHY_CONTACT_LIST_STORE_COL_IS_GROUP
, FALSE
,
1224 EMPATHY_CONTACT_LIST_STORE_COL_IS_ONLINE
, now_online
,
1225 EMPATHY_CONTACT_LIST_STORE_COL_IS_SEPARATOR
, FALSE
,
1226 EMPATHY_CONTACT_LIST_STORE_COL_CAN_AUDIO_CALL
,
1227 empathy_contact_get_capabilities (contact
) &
1228 EMPATHY_CAPABILITIES_AUDIO
,
1229 EMPATHY_CONTACT_LIST_STORE_COL_CAN_VIDEO_CALL
,
1230 empathy_contact_get_capabilities (contact
) &
1231 EMPATHY_CAPABILITIES_VIDEO
,
1235 if (pixbuf_avatar
) {
1236 g_object_unref (pixbuf_avatar
);
1239 if (priv
->show_active
&& do_set_active
) {
1240 contact_list_store_contact_set_active (store
, contact
, do_set_active
, do_set_refresh
);
1242 if (do_set_active
) {
1243 data
= contact_list_store_contact_active_new (store
, contact
, do_remove
);
1244 g_timeout_add_seconds (ACTIVE_USER_SHOW_TIME
,
1245 (GSourceFunc
) contact_list_store_contact_active_cb
,
1250 /* FIXME: when someone goes online then offline quickly, the
1251 * first timeout sets the user to be inactive and the second
1252 * timeout removes the user from the contact list, really we
1253 * should remove the first timeout.
1255 g_list_foreach (iters
, (GFunc
) gtk_tree_iter_free
, NULL
);
1256 g_list_free (iters
);
1260 contact_list_store_contact_updated_cb (EmpathyContact
*contact
,
1262 EmpathyContactListStore
*store
)
1264 DEBUG ("Contact:'%s' updated, checking roster is in sync...",
1265 empathy_contact_get_name (contact
));
1267 contact_list_store_contact_update (store
, contact
);
1271 contact_list_store_contact_set_active (EmpathyContactListStore
*store
,
1272 EmpathyContact
*contact
,
1274 gboolean set_changed
)
1276 EmpathyContactListStorePriv
*priv
;
1277 GtkTreeModel
*model
;
1280 priv
= GET_PRIV (store
);
1281 model
= GTK_TREE_MODEL (store
);
1283 iters
= contact_list_store_find_contact (store
, contact
);
1284 for (l
= iters
; l
; l
= l
->next
) {
1287 gtk_tree_store_set (GTK_TREE_STORE (store
), l
->data
,
1288 EMPATHY_CONTACT_LIST_STORE_COL_IS_ACTIVE
, active
,
1291 DEBUG ("Set item %s", active
? "active" : "inactive");
1294 path
= gtk_tree_model_get_path (model
, l
->data
);
1295 gtk_tree_model_row_changed (model
, path
, l
->data
);
1296 gtk_tree_path_free (path
);
1300 g_list_foreach (iters
, (GFunc
) gtk_tree_iter_free
, NULL
);
1301 g_list_free (iters
);
1305 static ShowActiveData
*
1306 contact_list_store_contact_active_new (EmpathyContactListStore
*store
,
1307 EmpathyContact
*contact
,
1310 ShowActiveData
*data
;
1312 DEBUG ("Contact:'%s' now active, and %s be removed",
1313 empathy_contact_get_name (contact
),
1314 remove_
? "WILL" : "WILL NOT");
1316 data
= g_slice_new0 (ShowActiveData
);
1318 data
->store
= g_object_ref (store
);
1319 data
->contact
= g_object_ref (contact
);
1320 data
->remove
= remove_
;
1326 contact_list_store_contact_active_free (ShowActiveData
*data
)
1328 g_object_unref (data
->contact
);
1329 g_object_unref (data
->store
);
1331 g_slice_free (ShowActiveData
, data
);
1335 contact_list_store_contact_active_cb (ShowActiveData
*data
)
1337 EmpathyContactListStorePriv
*priv
;
1339 priv
= GET_PRIV (data
->store
);
1342 !priv
->show_offline
&&
1343 !empathy_contact_is_online (data
->contact
)) {
1344 DEBUG ("Contact:'%s' active timeout, removing item",
1345 empathy_contact_get_name (data
->contact
));
1346 contact_list_store_remove_contact (data
->store
, data
->contact
);
1349 DEBUG ("Contact:'%s' no longer active",
1350 empathy_contact_get_name (data
->contact
));
1352 contact_list_store_contact_set_active (data
->store
,
1357 contact_list_store_contact_active_free (data
);
1363 contact_list_store_get_group_foreach (GtkTreeModel
*model
,
1371 /* Groups are only at the top level. */
1372 if (gtk_tree_path_get_depth (path
) != 1) {
1376 gtk_tree_model_get (model
, iter
,
1377 EMPATHY_CONTACT_LIST_STORE_COL_NAME
, &str
,
1378 EMPATHY_CONTACT_LIST_STORE_COL_IS_GROUP
, &is_group
,
1381 if (is_group
&& !tp_strdiff (str
, fg
->name
)) {
1392 contact_list_store_get_group (EmpathyContactListStore
*store
,
1394 GtkTreeIter
*iter_group_to_set
,
1395 GtkTreeIter
*iter_separator_to_set
,
1398 EmpathyContactListStorePriv
*priv
;
1399 GtkTreeModel
*model
;
1400 GtkTreeIter iter_group
;
1401 GtkTreeIter iter_separator
;
1404 priv
= GET_PRIV (store
);
1406 memset (&fg
, 0, sizeof (fg
));
1410 model
= GTK_TREE_MODEL (store
);
1411 gtk_tree_model_foreach (model
,
1412 (GtkTreeModelForeachFunc
) contact_list_store_get_group_foreach
,
1420 gtk_tree_store_append (GTK_TREE_STORE (store
), &iter_group
, NULL
);
1421 gtk_tree_store_set (GTK_TREE_STORE (store
), &iter_group
,
1422 EMPATHY_CONTACT_LIST_STORE_COL_ICON_STATUS
, NULL
,
1423 EMPATHY_CONTACT_LIST_STORE_COL_NAME
, name
,
1424 EMPATHY_CONTACT_LIST_STORE_COL_IS_GROUP
, TRUE
,
1425 EMPATHY_CONTACT_LIST_STORE_COL_IS_ACTIVE
, FALSE
,
1426 EMPATHY_CONTACT_LIST_STORE_COL_IS_SEPARATOR
, FALSE
,
1429 if (iter_group_to_set
) {
1430 *iter_group_to_set
= iter_group
;
1433 gtk_tree_store_append (GTK_TREE_STORE (store
),
1436 gtk_tree_store_set (GTK_TREE_STORE (store
), &iter_separator
,
1437 EMPATHY_CONTACT_LIST_STORE_COL_IS_SEPARATOR
, TRUE
,
1440 if (iter_separator_to_set
) {
1441 *iter_separator_to_set
= iter_separator
;
1448 if (iter_group_to_set
) {
1449 *iter_group_to_set
= fg
.iter
;
1452 iter_separator
= fg
.iter
;
1454 if (gtk_tree_model_iter_next (model
, &iter_separator
)) {
1455 gboolean is_separator
;
1457 gtk_tree_model_get (model
, &iter_separator
,
1458 EMPATHY_CONTACT_LIST_STORE_COL_IS_SEPARATOR
, &is_separator
,
1461 if (is_separator
&& iter_separator_to_set
) {
1462 *iter_separator_to_set
= iter_separator
;
1469 contact_list_store_state_sort_func (GtkTreeModel
*model
,
1470 GtkTreeIter
*iter_a
,
1471 GtkTreeIter
*iter_b
,
1475 gchar
*name_a
, *name_b
;
1476 gboolean is_separator_a
, is_separator_b
;
1477 EmpathyContact
*contact_a
, *contact_b
;
1479 gtk_tree_model_get (model
, iter_a
,
1480 EMPATHY_CONTACT_LIST_STORE_COL_NAME
, &name_a
,
1481 EMPATHY_CONTACT_LIST_STORE_COL_CONTACT
, &contact_a
,
1482 EMPATHY_CONTACT_LIST_STORE_COL_IS_SEPARATOR
, &is_separator_a
,
1484 gtk_tree_model_get (model
, iter_b
,
1485 EMPATHY_CONTACT_LIST_STORE_COL_NAME
, &name_b
,
1486 EMPATHY_CONTACT_LIST_STORE_COL_CONTACT
, &contact_b
,
1487 EMPATHY_CONTACT_LIST_STORE_COL_IS_SEPARATOR
, &is_separator_b
,
1490 /* Separator or group? */
1491 if (is_separator_a
|| is_separator_b
) {
1492 if (is_separator_a
) {
1494 } else if (is_separator_b
) {
1497 } else if (!contact_a
&& contact_b
) {
1499 } else if (contact_a
&& !contact_b
) {
1501 } else if (!contact_a
&& !contact_b
) {
1503 ret_val
= g_utf8_collate (name_a
, name_b
);
1510 /* If we managed to get this far, we can start looking at
1513 ret_val
= -tp_connection_presence_type_cmp_availability (
1514 empathy_contact_get_presence (EMPATHY_CONTACT (contact_a
)),
1515 empathy_contact_get_presence (EMPATHY_CONTACT (contact_b
)));
1518 /* Fallback: compare by name */
1519 ret_val
= g_utf8_collate (name_a
, name_b
);
1527 g_object_unref (contact_a
);
1531 g_object_unref (contact_b
);
1538 contact_list_store_name_sort_func (GtkTreeModel
*model
,
1539 GtkTreeIter
*iter_a
,
1540 GtkTreeIter
*iter_b
,
1543 gchar
*name_a
, *name_b
;
1544 EmpathyContact
*contact_a
, *contact_b
;
1545 gboolean is_separator_a
, is_separator_b
;
1548 gtk_tree_model_get (model
, iter_a
,
1549 EMPATHY_CONTACT_LIST_STORE_COL_NAME
, &name_a
,
1550 EMPATHY_CONTACT_LIST_STORE_COL_CONTACT
, &contact_a
,
1551 EMPATHY_CONTACT_LIST_STORE_COL_IS_SEPARATOR
, &is_separator_a
,
1553 gtk_tree_model_get (model
, iter_b
,
1554 EMPATHY_CONTACT_LIST_STORE_COL_NAME
, &name_b
,
1555 EMPATHY_CONTACT_LIST_STORE_COL_CONTACT
, &contact_b
,
1556 EMPATHY_CONTACT_LIST_STORE_COL_IS_SEPARATOR
, &is_separator_b
,
1559 /* If contact is NULL it means it's a group. */
1561 if (is_separator_a
|| is_separator_b
) {
1562 if (is_separator_a
) {
1564 } else if (is_separator_b
) {
1567 } else if (!contact_a
&& contact_b
) {
1569 } else if (contact_a
&& !contact_b
) {
1572 ret_val
= g_utf8_collate (name_a
, name_b
);
1579 g_object_unref (contact_a
);
1583 g_object_unref (contact_b
);
1590 contact_list_store_find_contact_foreach (GtkTreeModel
*model
,
1595 EmpathyContact
*contact
;
1597 gtk_tree_model_get (model
, iter
,
1598 EMPATHY_CONTACT_LIST_STORE_COL_CONTACT
, &contact
,
1601 if (contact
== fc
->contact
) {
1603 fc
->iters
= g_list_append (fc
->iters
, gtk_tree_iter_copy (iter
));
1607 g_object_unref (contact
);
1614 contact_list_store_find_contact (EmpathyContactListStore
*store
,
1615 EmpathyContact
*contact
)
1617 EmpathyContactListStorePriv
*priv
;
1618 GtkTreeModel
*model
;
1622 priv
= GET_PRIV (store
);
1624 memset (&fc
, 0, sizeof (fc
));
1626 fc
.contact
= contact
;
1628 model
= GTK_TREE_MODEL (store
);
1629 gtk_tree_model_foreach (model
,
1630 (GtkTreeModelForeachFunc
) contact_list_store_find_contact_foreach
,
1641 contact_list_store_update_list_mode_foreach (GtkTreeModel
*model
,
1644 EmpathyContactListStore
*store
)
1646 EmpathyContactListStorePriv
*priv
;
1647 gboolean show_avatar
= FALSE
;
1648 gboolean show_protocol
= FALSE
;
1649 EmpathyContact
*contact
;
1650 GdkPixbuf
*pixbuf_status
;
1652 priv
= GET_PRIV (store
);
1654 if (priv
->show_avatars
&& !priv
->is_compact
) {
1657 if (priv
->show_protocols
&& !priv
->is_compact
) {
1658 show_protocol
= TRUE
;
1661 gtk_tree_model_get (model
, iter
,
1662 EMPATHY_CONTACT_LIST_STORE_COL_CONTACT
, &contact
,
1665 if (contact
== NULL
){
1668 /* get icon from hash_table */
1669 pixbuf_status
= contact_list_store_get_contact_status_icon (store
, contact
);
1671 gtk_tree_store_set (GTK_TREE_STORE (store
), iter
,
1672 EMPATHY_CONTACT_LIST_STORE_COL_ICON_STATUS
, pixbuf_status
,
1673 EMPATHY_CONTACT_LIST_STORE_COL_PIXBUF_AVATAR_VISIBLE
, show_avatar
,
1674 EMPATHY_CONTACT_LIST_STORE_COL_STATUS_VISIBLE
, !priv
->is_compact
,
1681 contact_list_store_get_contact_status_icon_with_icon_name (
1682 EmpathyContactListStore
*store
,
1683 EmpathyContact
*contact
,
1684 const gchar
*status_icon_name
)
1686 GdkPixbuf
*pixbuf_status
= NULL
;
1687 EmpathyContactListStorePriv
*priv
;
1688 const gchar
*protocol_name
= NULL
;
1689 gchar
*icon_name
= NULL
;
1690 gboolean show_protocol
= FALSE
;
1692 priv
= GET_PRIV (store
);
1694 if (priv
->show_protocols
&& !priv
->is_compact
) {
1695 show_protocol
= TRUE
;
1697 if (show_protocol
) {
1698 protocol_name
= empathy_protocol_name_for_contact (contact
);
1699 icon_name
= g_strdup_printf ("%s-%s", status_icon_name
, protocol_name
);
1701 icon_name
= g_strdup_printf ("%s", status_icon_name
);
1703 pixbuf_status
= g_hash_table_lookup (priv
->status_icons
, icon_name
);
1704 if (pixbuf_status
== NULL
) {
1705 pixbuf_status
= empathy_pixbuf_contact_status_icon_with_icon_name (contact
,
1708 if (pixbuf_status
!= NULL
) {
1709 g_hash_table_insert (priv
->status_icons
,
1710 g_strdup (icon_name
),
1712 DEBUG( "Created status icon %s\n", icon_name
);
1715 DEBUG( "retrieved from cache status icon %s\n", icon_name
);
1718 return pixbuf_status
;
1722 contact_list_store_get_contact_status_icon (EmpathyContactListStore
*store
,
1723 EmpathyContact
*contact
)
1725 GdkPixbuf
*pixbuf_status
= NULL
;
1726 const gchar
*status_icon_name
= NULL
;
1728 status_icon_name
= empathy_icon_name_for_contact (contact
);
1729 pixbuf_status
= contact_list_store_get_contact_status_icon_with_icon_name (
1734 return pixbuf_status
;