2 * Copyright (C) 2002-2007 Imendio AB
3 * Copyright (C) 2007-2010 Collabora Ltd.
5 * This program is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU General Public License as
7 * published by the Free Software Foundation; either version 2 of the
8 * License, or (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * General Public License for more details.
15 * You should have received a copy of the GNU General Public
16 * License along with this program; if not, write to the
17 * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
18 * Boston, MA 02110-1301 USA
20 * Authors: Xavier Claessens <xclaesse@gmail.com>
21 * Danielle Madeley <danielle.madeley@collabora.co.uk>
25 #include "empathy-roster-window.h"
28 #include <glib/gi18n.h>
29 #include <tp-account-widgets/tpaw-builder.h>
31 #include "empathy-about-dialog.h"
32 #include "empathy-accounts-dialog.h"
33 #include "empathy-call-observer.h"
34 #include "empathy-chat-manager.h"
35 #include "empathy-chatroom-manager.h"
36 #include "empathy-chatrooms-window.h"
37 #include "empathy-client-factory.h"
38 #include "empathy-contact-blocking-dialog.h"
39 #include "empathy-contact-search-dialog.h"
40 #include "empathy-event-manager.h"
41 #include "empathy-ft-manager.h"
42 #include "empathy-geometry.h"
43 #include "empathy-gsettings.h"
44 #include "empathy-gsettings.h"
45 #include "empathy-gtk-enum-types.h"
46 #include "empathy-individual-dialogs.h"
47 #include "empathy-log-window.h"
48 #include "empathy-new-call-dialog.h"
49 #include "empathy-new-chatroom-dialog.h"
50 #include "empathy-new-message-dialog.h"
51 #include "empathy-preferences.h"
52 #include "empathy-presence-chooser.h"
53 #include "empathy-presence-manager.h"
54 #include "empathy-request-util.h"
55 #include "empathy-roster-model-manager.h"
56 #include "empathy-roster-view.h"
57 #include "empathy-status-presets.h"
58 #include "empathy-ui-utils.h"
59 #include "empathy-utils.h"
61 #define DEBUG_FLAG EMPATHY_DEBUG_OTHER
62 #include "empathy-debug.h"
64 /* Flashing delay for icons (milliseconds). */
65 #define FLASH_TIMEOUT 500
67 /* Minimum width of roster window if something goes wrong. */
70 /* Accels (menu shortcuts) can be configured and saved */
71 #define ACCELS_FILENAME "accels.txt"
73 /* Name in the geometry file */
74 #define GEOMETRY_NAME "roster-window"
78 PAGE_CONTACT_LIST
= 0,
88 G_DEFINE_TYPE (EmpathyRosterWindow
, empathy_roster_window
, GTK_TYPE_APPLICATION_WINDOW
)
90 struct _EmpathyRosterWindowPriv
{
91 EmpathyRosterView
*view
;
92 TpAccountManager
*account_manager
;
93 EmpathyChatroomManager
*chatroom_manager
;
94 EmpathyEventManager
*event_manager
;
95 EmpathySoundManager
*sound_mgr
;
96 EmpathyCallObserver
*call_observer
;
97 EmpathyIndividualManager
*individual_manager
;
98 guint flash_timeout_id
;
101 GSettings
*gsettings_ui
;
103 GtkWidget
*preferences
;
104 GtkWidget
*main_vbox
;
106 GtkWidget
*presence_toolbar
;
107 GtkWidget
*presence_chooser
;
108 GtkWidget
*errors_vbox
;
109 GtkWidget
*auth_vbox
;
110 GtkWidget
*search_bar
;
112 GtkWidget
*no_entry_label
;
113 GtkWidget
*button_account_settings
;
114 GtkWidget
*button_online
;
115 GtkWidget
*button_show_offline
;
116 GtkWidget
*button_add_contact
;
117 GtkWidget
*spinner_loading
;
118 GtkWidget
*tooltip_widget
;
121 GMenu
*rooms_section
;
123 GtkWidget
*balance_vbox
;
125 guint size_timeout_id
;
127 /* reffed TpAccount* => visible GtkInfoBar* */
130 /* EmpathyEvent* => visible GtkInfoBar* */
133 /* stores a mapping from TpAccount to Handler ID to prevent
134 * to listen more than once to the status-changed signal */
135 GHashTable
*status_changed_handlers
;
137 /* Actions that are enabled when there are connected accounts */
138 GList
*actions_connected
;
140 gboolean shell_running
;
144 roster_window_remove_auth (EmpathyRosterWindow
*self
,
147 GtkWidget
*error_widget
;
149 error_widget
= g_hash_table_lookup (self
->priv
->auths
, event
);
150 if (error_widget
!= NULL
)
152 gtk_widget_destroy (error_widget
);
153 g_hash_table_remove (self
->priv
->auths
, event
);
158 roster_window_auth_add_clicked_cb (GtkButton
*button
,
159 EmpathyRosterWindow
*self
)
163 event
= g_object_get_data (G_OBJECT (button
), "event");
165 empathy_event_approve (event
);
167 roster_window_remove_auth (self
, event
);
171 roster_window_auth_close_clicked_cb (GtkButton
*button
,
172 EmpathyRosterWindow
*self
)
176 event
= g_object_get_data (G_OBJECT (button
), "event");
178 empathy_event_decline (event
);
179 roster_window_remove_auth (self
, event
);
183 roster_window_auth_display (EmpathyRosterWindow
*self
,
186 TpAccount
*account
= event
->account
;
188 GtkWidget
*content_area
;
191 GtkWidget
*add_button
;
192 GtkWidget
*close_button
;
193 GtkWidget
*action_area
;
194 GtkWidget
*action_grid
;
195 const gchar
*icon_name
;
198 if (g_hash_table_lookup (self
->priv
->auths
, event
) != NULL
)
201 info_bar
= gtk_info_bar_new ();
202 gtk_info_bar_set_message_type (GTK_INFO_BAR (info_bar
), GTK_MESSAGE_QUESTION
);
204 gtk_widget_set_no_show_all (info_bar
, TRUE
);
205 gtk_box_pack_start (GTK_BOX (self
->priv
->auth_vbox
), info_bar
, FALSE
, TRUE
, 0);
206 gtk_widget_show (info_bar
);
208 icon_name
= tp_account_get_icon_name (account
);
209 image
= gtk_image_new_from_icon_name (icon_name
, GTK_ICON_SIZE_SMALL_TOOLBAR
);
210 gtk_widget_show (image
);
212 str
= g_markup_printf_escaped ("<b>%s</b>\n%s",
213 tp_account_get_display_name (account
),
214 _("Password required"));
216 label
= gtk_label_new (str
);
217 gtk_label_set_use_markup (GTK_LABEL (label
), TRUE
);
218 gtk_label_set_ellipsize (GTK_LABEL (label
), PANGO_ELLIPSIZE_END
);
219 gtk_misc_set_alignment (GTK_MISC (label
), 0, 0.5);
220 gtk_widget_show (label
);
224 content_area
= gtk_info_bar_get_content_area (GTK_INFO_BAR (info_bar
));
225 gtk_box_pack_start (GTK_BOX (content_area
), image
, FALSE
, FALSE
, 0);
226 gtk_box_pack_start (GTK_BOX (content_area
), label
, TRUE
, TRUE
, 0);
228 image
= gtk_image_new_from_stock (GTK_STOCK_ADD
, GTK_ICON_SIZE_BUTTON
);
229 add_button
= gtk_button_new ();
230 gtk_button_set_image (GTK_BUTTON (add_button
), image
);
231 gtk_widget_set_tooltip_text (add_button
, _("Provide Password"));
232 gtk_widget_show (add_button
);
234 image
= gtk_image_new_from_stock (GTK_STOCK_CLOSE
, GTK_ICON_SIZE_BUTTON
);
235 close_button
= gtk_button_new ();
236 gtk_button_set_image (GTK_BUTTON (close_button
), image
);
237 gtk_widget_set_tooltip_text (close_button
, _("Disconnect"));
238 gtk_widget_show (close_button
);
240 action_grid
= gtk_grid_new ();
241 gtk_grid_set_column_spacing (GTK_GRID (action_grid
), 6);
242 gtk_widget_show (action_grid
);
244 action_area
= gtk_info_bar_get_action_area (GTK_INFO_BAR (info_bar
));
245 gtk_box_pack_start (GTK_BOX (action_area
), action_grid
, FALSE
, FALSE
, 0);
247 gtk_grid_attach (GTK_GRID (action_grid
), add_button
, 0, 0, 1, 1);
248 gtk_grid_attach (GTK_GRID (action_grid
), close_button
, 1, 0, 1, 1);
250 g_object_set_data_full (G_OBJECT (info_bar
),
251 "event", event
, NULL
);
252 g_object_set_data_full (G_OBJECT (add_button
),
253 "event", event
, NULL
);
254 g_object_set_data_full (G_OBJECT (close_button
),
255 "event", event
, NULL
);
257 g_signal_connect (add_button
, "clicked",
258 G_CALLBACK (roster_window_auth_add_clicked_cb
), self
);
259 g_signal_connect (close_button
, "clicked",
260 G_CALLBACK (roster_window_auth_close_clicked_cb
), self
);
262 gtk_widget_show (self
->priv
->auth_vbox
);
264 g_hash_table_insert (self
->priv
->auths
, event
, info_bar
);
267 static FolksIndividual
*
268 ensure_individual_for_event (EmpathyEvent
*event
)
272 contact
= empathy_contact_get_tp_contact (event
->contact
);
276 return empathy_ensure_individual_from_tp_contact (contact
);
280 roster_window_event_added_cb (EmpathyEventManager
*manager
,
282 EmpathyRosterWindow
*self
)
286 FolksIndividual
*individual
;
288 individual
= ensure_individual_for_event (event
);
289 if (individual
== NULL
)
292 event
->roster_view_id
= empathy_roster_view_add_event (self
->priv
->view
,
293 individual
, event
->icon_name
, event
);
295 g_object_unref (individual
);
297 else if (event
->type
== EMPATHY_EVENT_TYPE_AUTH
)
299 roster_window_auth_display (self
, event
);
304 roster_window_event_removed_cb (EmpathyEventManager
*manager
,
306 EmpathyRosterWindow
*self
)
308 if (event
->type
== EMPATHY_EVENT_TYPE_AUTH
)
310 roster_window_remove_auth (self
, event
);
314 empathy_roster_view_remove_event (self
->priv
->view
, event
->roster_view_id
);
318 roster_window_load_events_idle_cb (gpointer user_data
)
320 EmpathyRosterWindow
*self
= user_data
;
323 l
= empathy_event_manager_get_events (self
->priv
->event_manager
);
326 roster_window_event_added_cb (self
->priv
->event_manager
, l
->data
,
335 hide_search_bar (EmpathyRosterWindow
*roster_window
)
337 if (TPAW_IS_LIVE_SEARCH (roster_window
->priv
->search_bar
) &&
338 gtk_widget_is_visible (roster_window
->priv
->search_bar
))
339 gtk_widget_hide (roster_window
->priv
->search_bar
);
343 individual_activated_cb (EmpathyRosterView
*self
,
344 FolksIndividual
*individual
,
347 EmpathyContact
*contact
;
349 contact
= empathy_contact_dup_best_for_action (individual
,
350 EMPATHY_ACTION_CHAT
);
355 DEBUG ("Starting a chat");
357 empathy_chat_with_contact (contact
, gtk_get_current_event_time ());
359 g_object_unref (contact
);
361 /* Hide the search-bar upon hitting "Enter" on an individual */
362 hide_search_bar (EMPATHY_ROSTER_WINDOW (user_data
));
366 event_activated_cb (EmpathyRosterView
*self
,
367 FolksIndividual
*individual
,
371 empathy_event_activate (event
);
373 /* Hide the search-bar upon an event activation */
374 hide_search_bar (EMPATHY_ROSTER_WINDOW (user_data
));
378 button_account_settings_clicked_cb (GtkButton
*button
,
379 EmpathyRosterWindow
*self
)
381 empathy_accounts_dialog_show_application (gdk_screen_get_default (),
386 button_online_clicked_cb (GtkButton
*button
,
387 EmpathyRosterWindow
*self
)
389 EmpathyPresenceManager
*mgr
;
391 mgr
= empathy_presence_manager_dup_singleton ();
393 empathy_presence_manager_set_state (mgr
,
394 TP_CONNECTION_PRESENCE_TYPE_AVAILABLE
);
396 g_object_unref (mgr
);
400 button_show_offline_clicked_cb (GtkButton
*button
,
401 EmpathyRosterWindow
*self
)
403 g_settings_set_boolean (self
->priv
->gsettings_ui
,
404 EMPATHY_PREFS_UI_SHOW_OFFLINE
, TRUE
);
408 button_add_contact_clicked_cb (GtkButton
*button
,
409 EmpathyRosterWindow
*self
)
411 empathy_new_individual_dialog_show (GTK_WINDOW (self
));
416 PAGE_MESSAGE_FLAG_NONE
= 0,
417 PAGE_MESSAGE_FLAG_ACCOUNTS
= 1 << 0,
418 PAGE_MESSAGE_FLAG_SPINNER
= 1 << 2,
419 PAGE_MESSAGE_FLAG_ONLINE
= 1 << 3,
420 PAGE_MESSAGE_FLAG_SHOW_OFFLINE
= 1 << 4,
421 PAGE_MESSAGE_FLAG_ADD_CONTACT
= 1 << 5,
425 can_add_contact (EmpathyRosterWindow
*self
)
428 gboolean result
= FALSE
;
430 accounts
= tp_account_manager_dup_valid_accounts (
431 self
->priv
->account_manager
);
432 for (l
= accounts
; l
!= NULL
&& !result
; l
= g_list_next (l
))
434 TpAccount
*account
= TP_ACCOUNT (l
->data
);
437 conn
= tp_account_get_connection (account
);
441 if (tp_connection_get_can_change_contact_list (conn
))
445 g_list_free_full (accounts
, g_object_unref
);
450 display_page_message (EmpathyRosterWindow
*self
,
452 PageMessageFlags flags
)
458 tmp
= g_strdup_printf ("<b><span size='xx-large'>%s</span></b>", msg
);
460 gtk_label_set_markup (GTK_LABEL (self
->priv
->no_entry_label
), tmp
);
463 gtk_label_set_line_wrap (GTK_LABEL (self
->priv
->no_entry_label
), TRUE
);
464 gtk_widget_show (self
->priv
->no_entry_label
);
468 gtk_widget_hide (self
->priv
->no_entry_label
);
471 gtk_widget_set_visible (self
->priv
->button_account_settings
,
472 (flags
& PAGE_MESSAGE_FLAG_ACCOUNTS
) != 0);
473 gtk_widget_set_visible (self
->priv
->spinner_loading
,
474 (flags
& PAGE_MESSAGE_FLAG_SPINNER
) != 0);
475 gtk_widget_set_visible (self
->priv
->button_online
,
476 (flags
& PAGE_MESSAGE_FLAG_ONLINE
) != 0);
477 gtk_widget_set_visible (self
->priv
->button_show_offline
,
478 (flags
& PAGE_MESSAGE_FLAG_SHOW_OFFLINE
) != 0);
479 gtk_widget_set_visible (self
->priv
->button_add_contact
,
480 (flags
& PAGE_MESSAGE_FLAG_ADD_CONTACT
) != 0);
482 if ((flags
& PAGE_MESSAGE_FLAG_ADD_CONTACT
) != 0)
483 gtk_widget_set_sensitive (self
->priv
->button_add_contact
,
484 can_add_contact (self
));
486 gtk_notebook_set_current_page (GTK_NOTEBOOK (self
->priv
->notebook
),
491 display_page_no_account (EmpathyRosterWindow
*self
)
493 display_page_message (self
,
494 _("You need to set up an account to see contacts here."),
495 PAGE_MESSAGE_FLAG_ACCOUNTS
);
499 display_page_contact_list (EmpathyRosterWindow
*self
)
501 if (!empathy_individual_manager_get_contacts_loaded (
502 self
->priv
->individual_manager
))
503 /* We'll display the contact list once we're done loading */
506 gtk_notebook_set_current_page (GTK_NOTEBOOK (self
->priv
->notebook
),
511 roster_window_remove_error (EmpathyRosterWindow
*self
,
514 GtkWidget
*error_widget
;
516 error_widget
= g_hash_table_lookup (self
->priv
->errors
, account
);
517 if (error_widget
!= NULL
)
519 gtk_widget_destroy (error_widget
);
520 g_hash_table_remove (self
->priv
->errors
, account
);
525 roster_window_account_disabled_cb (TpAccountManager
*manager
,
527 EmpathyRosterWindow
*self
)
529 roster_window_remove_error (self
, account
);
534 ERROR_RESPONSE_RETRY
,
536 ERROR_RESPONSE_CLOSE
,
537 ERROR_RESPONSE_UPGRADE
,
541 roster_window_error_response_cb (GtkInfoBar
*infobar
,
543 EmpathyRosterWindow
*self
)
547 account
= g_object_get_data (G_OBJECT (infobar
), "account");
551 case ERROR_RESPONSE_RETRY
:
552 tp_account_reconnect_async (account
, NULL
, NULL
);
555 case ERROR_RESPONSE_EDIT
:
556 empathy_accounts_dialog_show_application (
557 gtk_widget_get_screen (GTK_WIDGET (infobar
)),
558 account
, FALSE
, FALSE
);
561 case ERROR_RESPONSE_CLOSE
:
564 case ERROR_RESPONSE_UPGRADE
:
568 dialog
= gtk_message_dialog_new (GTK_WINDOW (self
),
569 GTK_DIALOG_MODAL
, GTK_MESSAGE_ERROR
, GTK_BUTTONS_OK
,
570 _("Sorry, %s accounts can’t be used until your %s software is updated."),
571 tp_account_get_protocol_name (account
),
572 tp_account_get_protocol_name (account
));
574 g_signal_connect_swapped (dialog
, "response",
575 G_CALLBACK (gtk_widget_destroy
),
578 gtk_widget_show (dialog
);
582 roster_window_remove_error (self
, account
);
586 roster_window_error_create_info_bar (EmpathyRosterWindow
*self
,
588 GtkMessageType message_type
,
589 const gchar
*message_markup
)
592 GtkWidget
*content_area
;
593 GtkWidget
*action_area
;
596 const gchar
*icon_name
;
598 /* If there are other errors, remove them */
599 roster_window_remove_error (self
, account
);
601 info_bar
= gtk_info_bar_new ();
602 gtk_info_bar_set_message_type (GTK_INFO_BAR (info_bar
), message_type
);
604 gtk_widget_set_no_show_all (info_bar
, TRUE
);
605 gtk_box_pack_start (GTK_BOX (self
->priv
->errors_vbox
), info_bar
, FALSE
, TRUE
, 0);
606 gtk_widget_show (info_bar
);
608 icon_name
= tp_account_get_icon_name (account
);
609 image
= gtk_image_new_from_icon_name (icon_name
, GTK_ICON_SIZE_SMALL_TOOLBAR
);
610 gtk_widget_show (image
);
612 label
= gtk_label_new (message_markup
);
613 gtk_label_set_use_markup (GTK_LABEL (label
), TRUE
);
614 gtk_label_set_line_wrap (GTK_LABEL (label
), TRUE
);
615 gtk_label_set_ellipsize (GTK_LABEL (label
), PANGO_ELLIPSIZE_END
);
616 gtk_misc_set_alignment (GTK_MISC (label
), 0, 0.5);
617 gtk_widget_show (label
);
619 content_area
= gtk_info_bar_get_content_area (GTK_INFO_BAR (info_bar
));
620 gtk_box_pack_start (GTK_BOX (content_area
), image
, FALSE
, FALSE
, 0);
621 gtk_box_pack_start (GTK_BOX (content_area
), label
, TRUE
, TRUE
, 0);
623 action_area
= gtk_info_bar_get_action_area (GTK_INFO_BAR (info_bar
));
624 gtk_orientable_set_orientation (GTK_ORIENTABLE (action_area
),
625 GTK_ORIENTATION_HORIZONTAL
);
626 gtk_style_context_add_class (gtk_widget_get_style_context (action_area
),
627 "empathy-roster-window-error-button");
629 g_object_set_data_full (G_OBJECT (info_bar
),
630 "account", g_object_ref (account
),
633 g_signal_connect (info_bar
, "response",
634 G_CALLBACK (roster_window_error_response_cb
), self
);
636 gtk_widget_show (self
->priv
->errors_vbox
);
638 g_hash_table_insert (self
->priv
->errors
, g_object_ref (account
), info_bar
);
644 roster_window_error_add_stock_button (GtkInfoBar
*info_bar
,
645 const gchar
*stock_id
,
646 const gchar
*tooltip
,
647 ErrorResponse response_id
)
652 image
= gtk_image_new_from_stock (stock_id
, GTK_ICON_SIZE_BUTTON
);
653 button
= gtk_button_new ();
654 gtk_button_set_image (GTK_BUTTON (button
), image
);
655 gtk_widget_set_tooltip_text (button
, tooltip
);
656 gtk_widget_show (button
);
658 gtk_info_bar_add_action_widget (info_bar
, button
, response_id
);
663 uoa_account_display_string (TpAccount
*account
)
665 const gchar
*service
;
667 service
= tp_account_get_service (account
);
669 /* Use well known service name, if available */
670 if (!tp_strdiff (service
, "windows-live"))
671 return _("Windows Live");
672 else if (!tp_strdiff (service
, "google-talk"))
673 return _("Google Talk");
674 else if (!tp_strdiff (service
, "facebook"))
675 return _("Facebook");
677 return tp_account_get_display_name (account
);
681 roster_window_uoa_auth_error (EmpathyRosterWindow
*self
,
689 /* translators: %s is an account name like 'Facebook' or 'Google Talk' */
690 str
= g_strdup_printf (_("%s account requires authorisation"),
691 uoa_account_display_string (account
));
693 info_bar
= roster_window_error_create_info_bar (self
, account
,
694 GTK_MESSAGE_OTHER
, str
);
697 image
= gtk_image_new_from_icon_name ("credentials-preferences",
698 GTK_ICON_SIZE_BUTTON
);
699 button
= gtk_button_new ();
700 gtk_button_set_image (GTK_BUTTON (button
), image
);
701 gtk_widget_set_tooltip_text (button
, _("Online Accounts"));
702 gtk_widget_show (button
);
704 gtk_info_bar_add_action_widget (GTK_INFO_BAR (info_bar
), button
,
705 ERROR_RESPONSE_EDIT
);
710 roster_window_error_display (EmpathyRosterWindow
*self
,
713 const gchar
*error_message
;
714 gboolean user_requested
;
719 empathy_account_get_error_message (account
, &user_requested
);
725 if (!tp_strdiff (TP_ERROR_STR_AUTHENTICATION_FAILED
,
726 tp_account_get_detailed_error (account
, NULL
)) &&
727 !tp_strdiff (tp_account_get_storage_provider (account
),
728 EMPATHY_UOA_PROVIDER
))
730 roster_window_uoa_auth_error (self
, account
);
735 str
= g_markup_printf_escaped ("<b>%s</b>\n%s",
736 tp_account_get_display_name (account
), error_message
);
738 info_bar
= roster_window_error_create_info_bar (self
, account
,
739 GTK_MESSAGE_ERROR
, str
);
742 gtk_widget_set_tooltip_text (self
->priv
->errors_vbox
, error_message
);
744 if (!tp_strdiff (TP_ERROR_STR_SOFTWARE_UPGRADE_REQUIRED
,
745 tp_account_get_detailed_error (account
, NULL
)))
747 roster_window_error_add_stock_button (GTK_INFO_BAR (info_bar
),
748 GTK_STOCK_REFRESH
, _("Update software…"),
749 ERROR_RESPONSE_RETRY
);
753 roster_window_error_add_stock_button (GTK_INFO_BAR (info_bar
),
754 GTK_STOCK_REFRESH
, _("Reconnect"),
755 ERROR_RESPONSE_RETRY
);
757 roster_window_error_add_stock_button (GTK_INFO_BAR (info_bar
),
758 GTK_STOCK_EDIT
, _("Edit Account"),
759 ERROR_RESPONSE_EDIT
);
762 roster_window_error_add_stock_button (GTK_INFO_BAR (info_bar
),
763 GTK_STOCK_CLOSE
, _("Close"),
764 ERROR_RESPONSE_CLOSE
);
768 roster_window_update_status (EmpathyRosterWindow
*self
)
770 gboolean connected
, connecting
;
774 connected
= empathy_account_manager_get_accounts_connected (&connecting
);
776 /* Update the spinner state */
779 gtk_spinner_start (GTK_SPINNER (self
->priv
->throbber
));
780 gtk_widget_show (self
->priv
->throbber
);
784 gtk_spinner_stop (GTK_SPINNER (self
->priv
->throbber
));
785 gtk_widget_hide (self
->priv
->throbber
);
788 /* Update widgets sensibility */
789 for (l
= self
->priv
->actions_connected
; l
; l
= l
->next
)
790 g_simple_action_set_enabled (l
->data
, connected
);
792 action
= g_action_map_lookup_action (G_ACTION_MAP (self
), "chat_add_contact");
793 if (!can_add_contact (self
))
794 g_simple_action_set_enabled (G_SIMPLE_ACTION (action
), FALSE
);
798 roster_window_balance_update_balance (EmpathyRosterWindow
*self
,
804 guint scale
= G_MAXINT32
;
805 const gchar
*currency
= "";
808 conn
= tp_account_get_connection (account
);
812 if (!tp_connection_get_balance (conn
, &amount
, &scale
, ¤cy
))
816 scale
== G_MAXINT32
&&
817 tp_str_empty (currency
))
819 /* unknown balance */
820 money
= g_strdup ("--");
824 char *tmp
= empathy_format_currency (amount
, scale
, currency
);
826 money
= g_strdup_printf ("%s %s", currency
, tmp
);
830 /* update the money label in the roster */
831 label
= g_object_get_data (G_OBJECT (account
), "balance-money-label");
833 gtk_label_set_text (GTK_LABEL (label
), money
);
838 roster_window_balance_changed_cb (TpConnection
*conn
,
841 const gchar
*currency
,
842 EmpathyRosterWindow
*self
)
846 account
= tp_connection_get_account (conn
);
850 roster_window_balance_update_balance (self
, account
);
854 roster_window_setup_balance (EmpathyRosterWindow
*self
,
857 TpConnection
*conn
= tp_account_get_connection (account
);
858 GtkWidget
*hbox
, *image
, *label
;
864 if (!tp_proxy_is_prepared (conn
, TP_CONNECTION_FEATURE_BALANCE
))
867 DEBUG ("Setting up balance for acct: %s",
868 tp_account_get_display_name (account
));
870 /* create the display widget */
871 hbox
= gtk_box_new (GTK_ORIENTATION_HORIZONTAL
, 3);
872 gtk_container_set_border_width (GTK_CONTAINER (hbox
), 3);
875 image
= gtk_image_new ();
876 gtk_box_pack_start (GTK_BOX (hbox
), image
, FALSE
, TRUE
, 0);
877 g_object_bind_property (account
, "icon-name", image
, "icon-name",
878 G_BINDING_SYNC_CREATE
);
880 /* account name label */
881 label
= gtk_label_new ("");
882 gtk_misc_set_alignment (GTK_MISC (label
), 0.0, 0.5);
883 gtk_label_set_ellipsize (GTK_LABEL (label
), PANGO_ELLIPSIZE_END
);
884 gtk_box_pack_start (GTK_BOX (hbox
), label
, TRUE
, TRUE
, 0);
885 g_object_bind_property (account
, "display-name", label
, "label",
886 G_BINDING_SYNC_CREATE
);
889 label
= gtk_label_new ("");
890 gtk_misc_set_alignment (GTK_MISC (label
), 0.0, 0.5);
891 gtk_box_pack_start (GTK_BOX (hbox
), label
, FALSE
, TRUE
, 0);
894 uri
= tp_connection_get_balance_uri (conn
);
896 if (!tp_str_empty (uri
))
900 button
= gtk_button_new ();
901 gtk_container_add (GTK_CONTAINER (button
),
902 gtk_image_new_from_icon_name ("emblem-symbolic-link",
903 GTK_ICON_SIZE_SMALL_TOOLBAR
));
904 gtk_button_set_relief (GTK_BUTTON (button
), GTK_RELIEF_NONE
);
905 gtk_widget_set_tooltip_text (button
, _("Top up account"));
906 gtk_box_pack_start (GTK_BOX (hbox
), button
, FALSE
, TRUE
, 0);
908 g_signal_connect_data (button
, "clicked",
909 G_CALLBACK (empathy_url_show
),
910 g_strdup (uri
), (GClosureNotify
) g_free
,
914 gtk_box_pack_start (GTK_BOX (self
->priv
->balance_vbox
), hbox
, FALSE
, TRUE
, 0);
915 gtk_widget_show_all (hbox
);
917 g_object_set_data (G_OBJECT (account
), "balance-money-label", label
);
918 g_object_set_data (G_OBJECT (account
), "balance-money-hbox", hbox
);
920 roster_window_balance_update_balance (self
, account
);
922 g_signal_connect (conn
, "balance-changed",
923 G_CALLBACK (roster_window_balance_changed_cb
), self
);
927 roster_window_remove_balance_action (EmpathyRosterWindow
*self
,
931 g_object_get_data (G_OBJECT (account
), "balance-money-hbox");
936 g_return_if_fail (GTK_IS_BOX (hbox
));
938 gtk_widget_destroy (hbox
);
941 static void set_notebook_page (EmpathyRosterWindow
*self
);
944 roster_window_connection_changed_cb (TpAccount
*account
,
948 gchar
*dbus_error_name
,
950 EmpathyRosterWindow
*self
)
952 roster_window_update_status (self
);
953 set_notebook_page (self
);
955 if (current
== TP_CONNECTION_STATUS_DISCONNECTED
&&
956 reason
!= TP_CONNECTION_STATUS_REASON_REQUESTED
)
958 roster_window_error_display (self
, account
);
961 if (current
== TP_CONNECTION_STATUS_DISCONNECTED
)
963 empathy_sound_manager_play (self
->priv
->sound_mgr
, GTK_WIDGET (self
),
964 EMPATHY_SOUND_ACCOUNT_DISCONNECTED
);
967 if (current
== TP_CONNECTION_STATUS_CONNECTED
)
969 empathy_sound_manager_play (self
->priv
->sound_mgr
, GTK_WIDGET (self
),
970 EMPATHY_SOUND_ACCOUNT_CONNECTED
);
972 /* Account connected without error, remove error message if any */
973 roster_window_remove_error (self
, account
);
978 roster_window_accels_load (void)
982 filename
= g_build_filename (g_get_user_config_dir (),
983 PACKAGE_NAME
, ACCELS_FILENAME
, NULL
);
984 if (g_file_test (filename
, G_FILE_TEST_EXISTS
))
986 DEBUG ("Loading from:'%s'", filename
);
987 gtk_accel_map_load (filename
);
994 roster_window_accels_save (void)
997 gchar
*file_with_path
;
999 dir
= g_build_filename (g_get_user_config_dir (), PACKAGE_NAME
, NULL
);
1000 g_mkdir_with_parents (dir
, S_IRUSR
| S_IWUSR
| S_IXUSR
);
1001 file_with_path
= g_build_filename (dir
, ACCELS_FILENAME
, NULL
);
1004 DEBUG ("Saving to:'%s'", file_with_path
);
1005 gtk_accel_map_save (file_with_path
);
1007 g_free (file_with_path
);
1011 empathy_roster_window_finalize (GObject
*window
)
1013 EmpathyRosterWindow
*self
= EMPATHY_ROSTER_WINDOW (window
);
1014 GHashTableIter iter
;
1015 gpointer key
, value
;
1017 /* Save user-defined accelerators. */
1018 roster_window_accels_save ();
1020 g_list_free (self
->priv
->actions_connected
);
1022 g_object_unref (self
->priv
->account_manager
);
1023 g_object_unref (self
->priv
->sound_mgr
);
1024 g_hash_table_unref (self
->priv
->errors
);
1025 g_hash_table_unref (self
->priv
->auths
);
1027 /* disconnect all handlers of status-changed signal */
1028 g_hash_table_iter_init (&iter
, self
->priv
->status_changed_handlers
);
1029 while (g_hash_table_iter_next (&iter
, &key
, &value
))
1030 g_signal_handler_disconnect (TP_ACCOUNT (key
), GPOINTER_TO_UINT (value
));
1032 g_hash_table_unref (self
->priv
->status_changed_handlers
);
1034 g_object_unref (self
->priv
->call_observer
);
1035 g_object_unref (self
->priv
->event_manager
);
1036 g_object_unref (self
->priv
->chatroom_manager
);
1038 g_object_unref (self
->priv
->gsettings_ui
);
1039 g_object_unref (self
->priv
->individual_manager
);
1041 g_object_unref (self
->priv
->menumodel
);
1042 g_object_unref (self
->priv
->rooms_section
);
1044 g_clear_object (&self
->priv
->tooltip_widget
);
1046 G_OBJECT_CLASS (empathy_roster_window_parent_class
)->finalize (window
);
1050 roster_window_key_press_event_cb (GtkWidget
*window
,
1052 EmpathyRosterWindow
*self
)
1054 if (event
->keyval
== GDK_KEY_T
1055 && event
->state
& GDK_SHIFT_MASK
1056 && event
->state
& GDK_CONTROL_MASK
)
1057 empathy_chat_manager_call_undo_closed_chat ();
1059 if (event
->keyval
== GDK_KEY_f
1060 && event
->state
& GDK_CONTROL_MASK
)
1061 gtk_widget_show (self
->priv
->search_bar
);
1067 unprepare_cb (GObject
*source
,
1068 GAsyncResult
*result
,
1071 GtkWidget
*self
= user_data
;
1073 gtk_widget_destroy (self
);
1077 roster_window_chat_quit_cb (GSimpleAction
*action
,
1078 GVariant
*parameter
,
1081 EmpathyRosterWindow
*self
= user_data
;
1083 /* Destroying the window will make us leave the main loop and so exit the
1084 * process. Before doing so we want to unprepare the individual manager.
1085 * Just hide the window now and actually destroy it once Folks is done.
1087 gtk_widget_hide (GTK_WIDGET (self
));
1089 empathy_individual_manager_unprepare_async (self
->priv
->individual_manager
,
1090 unprepare_cb
, self
);
1094 roster_window_view_history_cb (GSimpleAction
*action
,
1095 GVariant
*parameter
,
1098 EmpathyRosterWindow
*self
= user_data
;
1100 empathy_log_window_show (NULL
, NULL
, FALSE
, GTK_WINDOW (self
));
1104 roster_window_chat_new_message_cb (GSimpleAction
*action
,
1105 GVariant
*parameter
,
1108 EmpathyRosterWindow
*self
= user_data
;
1110 empathy_new_message_dialog_show (GTK_WINDOW (self
));
1114 roster_window_chat_new_call_cb (GSimpleAction
*action
,
1115 GVariant
*parameter
,
1118 EmpathyRosterWindow
*self
= user_data
;
1120 empathy_new_call_dialog_show (GTK_WINDOW (self
));
1124 roster_window_chat_add_contact_cb (GSimpleAction
*action
,
1125 GVariant
*parameter
,
1128 EmpathyRosterWindow
*self
= user_data
;
1130 empathy_new_individual_dialog_show (GTK_WINDOW (self
));
1134 roster_window_chat_search_contacts_cb (GSimpleAction
*action
,
1135 GVariant
*parameter
,
1138 EmpathyRosterWindow
*self
= user_data
;
1141 dialog
= empathy_contact_search_dialog_new (
1144 gtk_widget_show (dialog
);
1148 roster_window_view_show_ft_manager (GSimpleAction
*action
,
1149 GVariant
*parameter
,
1152 empathy_ft_manager_show ();
1156 join_chatroom (EmpathyChatroom
*chatroom
,
1162 account
= empathy_chatroom_get_account (chatroom
);
1163 room
= empathy_chatroom_get_room (chatroom
);
1165 DEBUG ("Requesting channel for '%s'", room
);
1166 empathy_join_muc (account
, room
, timestamp
);
1172 EmpathyChatroom
*chatroom
;
1176 } join_fav_account_sig_ctx
;
1178 static join_fav_account_sig_ctx
*
1179 join_fav_account_sig_ctx_new (TpAccount
*account
,
1180 EmpathyChatroom
*chatroom
,
1183 join_fav_account_sig_ctx
*ctx
= g_slice_new0 (
1184 join_fav_account_sig_ctx
);
1186 ctx
->account
= g_object_ref (account
);
1187 ctx
->chatroom
= g_object_ref (chatroom
);
1188 ctx
->timestamp
= timestamp
;
1193 join_fav_account_sig_ctx_free (join_fav_account_sig_ctx
*ctx
)
1195 g_object_unref (ctx
->account
);
1196 g_object_unref (ctx
->chatroom
);
1197 g_slice_free (join_fav_account_sig_ctx
, ctx
);
1201 account_status_changed_cb (TpAccount
*account
,
1202 TpConnectionStatus old_status
,
1203 TpConnectionStatus new_status
,
1205 gchar
*dbus_error_name
,
1206 GHashTable
*details
,
1209 join_fav_account_sig_ctx
*ctx
= user_data
;
1213 case TP_CONNECTION_STATUS_DISCONNECTED
:
1214 /* Don't wait any longer */
1218 case TP_CONNECTION_STATUS_CONNECTING
:
1222 case TP_CONNECTION_STATUS_CONNECTED
:
1223 /* We can join the room */
1227 g_assert_not_reached ();
1230 join_chatroom (ctx
->chatroom
, ctx
->timestamp
);
1233 g_source_remove (ctx
->timeout
);
1234 g_signal_handler_disconnect (account
, ctx
->sig_id
);
1237 #define JOIN_FAVORITE_TIMEOUT 5
1240 join_favorite_timeout_cb (gpointer data
)
1242 join_fav_account_sig_ctx
*ctx
= data
;
1244 /* stop waiting for joining the favorite room */
1245 g_signal_handler_disconnect (ctx
->account
, ctx
->sig_id
);
1250 roster_window_favorite_chatroom_join (EmpathyChatroom
*chatroom
)
1254 account
= empathy_chatroom_get_account (chatroom
);
1255 if (tp_account_get_connection_status (account
, NULL
) !=
1256 TP_CONNECTION_STATUS_CONNECTED
)
1258 join_fav_account_sig_ctx
*ctx
;
1260 ctx
= join_fav_account_sig_ctx_new (account
, chatroom
,
1261 empathy_get_current_action_time ());
1263 ctx
->sig_id
= g_signal_connect_data (account
, "status-changed",
1264 G_CALLBACK (account_status_changed_cb
), ctx
,
1265 (GClosureNotify
) join_fav_account_sig_ctx_free
, 0);
1267 ctx
->timeout
= g_timeout_add_seconds (JOIN_FAVORITE_TIMEOUT
,
1268 join_favorite_timeout_cb
, ctx
);
1272 join_chatroom (chatroom
, empathy_get_current_action_time ());
1276 roster_window_join_chatroom_menu_activate_cb (GSimpleAction
*action
,
1277 GVariant
*parameter
,
1280 EmpathyRosterWindow
*self
= user_data
;
1281 const gchar
*room
, *path
;
1282 EmpathyClientFactory
*factory
;
1284 GError
*error
= NULL
;
1285 EmpathyChatroom
*chatroom
;
1287 g_variant_get (parameter
, "(&s&s)", &room
, &path
);
1289 factory
= empathy_client_factory_dup ();
1291 account
= tp_simple_client_factory_ensure_account (
1292 TP_SIMPLE_CLIENT_FACTORY (factory
), path
, NULL
, &error
);
1293 if (account
== NULL
)
1295 DEBUG ("Failed to get account '%s': %s", path
, error
->message
);
1296 g_error_free (error
);
1300 chatroom
= empathy_chatroom_manager_find (self
->priv
->chatroom_manager
,
1302 if (chatroom
== NULL
)
1304 DEBUG ("Failed to get chatroom '%s' on '%s'",
1309 roster_window_favorite_chatroom_join (chatroom
);
1312 g_object_unref (factory
);
1316 roster_window_favorite_chatroom_menu_add (EmpathyRosterWindow
*self
,
1317 EmpathyChatroom
*chatroom
)
1320 const gchar
*name
, *account_name
, *account_path
;
1324 account
= empathy_chatroom_get_account (chatroom
);
1326 name
= empathy_chatroom_get_name (chatroom
);
1327 account_name
= tp_account_get_display_name (account
);
1328 account_path
= tp_proxy_get_object_path (account
);
1330 label
= g_strdup_printf ("%s (%s)", name
, account_name
);
1332 item
= g_menu_item_new (label
, NULL
);
1333 g_menu_item_set_action_and_target (item
, "win.join", "(ss)",
1334 name
, account_path
);
1335 g_menu_item_set_attribute (item
, "room-name", "s", name
);
1336 g_menu_item_set_attribute (item
, "account-path", "s", account_path
);
1337 g_menu_append_item (self
->priv
->rooms_section
, item
);
1343 roster_window_favorite_chatroom_menu_added_cb (EmpathyChatroomManager
*manager
,
1344 EmpathyChatroom
*chatroom
,
1345 EmpathyRosterWindow
*self
)
1347 roster_window_favorite_chatroom_menu_add (self
, chatroom
);
1351 roster_window_favorite_chatroom_menu_removed_cb (
1352 EmpathyChatroomManager
*manager
,
1353 EmpathyChatroom
*chatroom
,
1354 EmpathyRosterWindow
*self
)
1359 const gchar
*account_path
;
1361 account
= empathy_chatroom_get_account (chatroom
);
1362 account_path
= tp_proxy_get_object_path (account
);
1364 n
= g_menu_model_get_n_items (G_MENU_MODEL (self
->priv
->rooms_section
));
1366 for (i
= 0; i
< n
; i
++)
1370 if (!g_menu_model_get_item_attribute (
1371 G_MENU_MODEL (self
->priv
->rooms_section
), i
,
1372 "room-name", "s", &tmp
))
1375 if (tp_strdiff (tmp
, empathy_chatroom_get_name (chatroom
)))
1383 if (!g_menu_model_get_item_attribute (
1384 G_MENU_MODEL (self
->priv
->rooms_section
), i
,
1385 "account-path", "s", &tmp
))
1388 if (tp_strdiff (tmp
, account_path
))
1394 g_menu_remove (self
->priv
->rooms_section
, i
);
1399 chatrooms
= empathy_chatroom_manager_get_chatrooms (
1400 self
->priv
->chatroom_manager
, NULL
);
1402 g_list_free (chatrooms
);
1406 roster_window_favorite_chatroom_menu_setup (EmpathyRosterWindow
*self
)
1408 GList
*chatrooms
, *l
;
1410 self
->priv
->chatroom_manager
= empathy_chatroom_manager_dup_singleton (NULL
);
1412 chatrooms
= empathy_chatroom_manager_get_chatrooms (
1413 self
->priv
->chatroom_manager
, NULL
);
1415 for (l
= chatrooms
; l
; l
= l
->next
)
1416 roster_window_favorite_chatroom_menu_add (self
, l
->data
);
1418 g_signal_connect (self
->priv
->chatroom_manager
, "chatroom-added",
1419 G_CALLBACK (roster_window_favorite_chatroom_menu_added_cb
),
1422 g_signal_connect (self
->priv
->chatroom_manager
, "chatroom-removed",
1423 G_CALLBACK (roster_window_favorite_chatroom_menu_removed_cb
),
1426 g_list_free (chatrooms
);
1430 roster_window_room_join_new_cb (GSimpleAction
*action
,
1431 GVariant
*parameter
,
1434 EmpathyRosterWindow
*self
= user_data
;
1436 empathy_new_chatroom_dialog_show (GTK_WINDOW (self
));
1440 roster_window_room_join_favorites_cb (GSimpleAction
*action
,
1441 GVariant
*parameter
,
1444 EmpathyRosterWindow
*self
= user_data
;
1445 GList
*chatrooms
, *l
;
1447 chatrooms
= empathy_chatroom_manager_get_chatrooms (self
->priv
->chatroom_manager
,
1450 for (l
= chatrooms
; l
; l
= l
->next
)
1451 roster_window_favorite_chatroom_join (l
->data
);
1453 g_list_free (chatrooms
);
1457 roster_window_room_manage_favorites_cb (GSimpleAction
*action
,
1458 GVariant
*parameter
,
1461 EmpathyRosterWindow
*self
= user_data
;
1463 empathy_chatrooms_window_show (GTK_WINDOW (self
));
1467 roster_window_edit_accounts_cb (GSimpleAction
*action
,
1468 GVariant
*parameter
,
1471 empathy_accounts_dialog_show_application (gdk_screen_get_default (),
1472 NULL
, FALSE
, FALSE
);
1476 roster_window_edit_blocked_contacts_cb (GSimpleAction
*action
,
1477 GVariant
*parameter
,
1480 EmpathyRosterWindow
*self
= user_data
;
1483 dialog
= empathy_contact_blocking_dialog_new (GTK_WINDOW (self
));
1484 gtk_widget_show (dialog
);
1486 g_signal_connect (dialog
, "response",
1487 G_CALLBACK (gtk_widget_destroy
), NULL
);
1491 empathy_roster_window_show_preferences (EmpathyRosterWindow
*self
,
1494 if (self
->priv
->preferences
== NULL
)
1496 self
->priv
->preferences
= empathy_preferences_new (GTK_WINDOW (self
),
1497 self
->priv
->shell_running
);
1498 g_object_add_weak_pointer (G_OBJECT (self
->priv
->preferences
),
1499 (gpointer
) &self
->priv
->preferences
);
1501 gtk_widget_show (self
->priv
->preferences
);
1505 gtk_window_present (GTK_WINDOW (self
->priv
->preferences
));
1509 empathy_preferences_show_tab (
1510 EMPATHY_PREFERENCES (self
->priv
->preferences
), tab
);
1514 roster_window_edit_preferences_cb (GSimpleAction
*action
,
1515 GVariant
*parameter
,
1518 EmpathyRosterWindow
*self
= user_data
;
1520 empathy_roster_window_show_preferences (self
, NULL
);
1524 roster_window_help_about_cb (GSimpleAction
*action
,
1525 GVariant
*parameter
,
1528 EmpathyRosterWindow
*self
= user_data
;
1530 empathy_about_dialog_new (GTK_WINDOW (self
));
1534 roster_window_help_contents_cb (GSimpleAction
*action
,
1535 GVariant
*parameter
,
1538 EmpathyRosterWindow
*self
= user_data
;
1540 empathy_url_show (GTK_WIDGET (self
), "help:empathy");
1544 roster_window_throbber_button_press_event_cb (GtkWidget
*throbber
,
1545 GdkEventButton
*event
,
1546 EmpathyRosterWindow
*self
)
1548 if (event
->type
!= GDK_BUTTON_PRESS
||
1552 empathy_accounts_dialog_show_application (
1553 gtk_widget_get_screen (GTK_WIDGET (throbber
)),
1554 NULL
, FALSE
, FALSE
);
1560 roster_window_account_removed_cb (TpAccountManager
*manager
,
1562 EmpathyRosterWindow
*self
)
1564 /* remove errors if any */
1565 roster_window_remove_error (self
, account
);
1567 /* remove the balance action if required */
1568 roster_window_remove_balance_action (self
, account
);
1572 account_connection_notify_cb (TpAccount
*account
,
1574 EmpathyRosterWindow
*self
)
1578 conn
= tp_account_get_connection (account
);
1582 roster_window_setup_balance (self
, account
);
1586 /* remove balance action if required */
1587 roster_window_remove_balance_action (self
, account
);
1592 add_account (EmpathyRosterWindow
*self
,
1597 handler_id
= GPOINTER_TO_UINT (g_hash_table_lookup (
1598 self
->priv
->status_changed_handlers
, account
));
1600 /* connect signal only if it was not connected yet */
1601 if (handler_id
!= 0)
1604 handler_id
= g_signal_connect (account
, "status-changed",
1605 G_CALLBACK (roster_window_connection_changed_cb
), self
);
1607 g_hash_table_insert (self
->priv
->status_changed_handlers
,
1608 account
, GUINT_TO_POINTER (handler_id
));
1610 /* roster_window_setup_balance() relies on the TpConnection to be ready on
1611 * the TpAccount so we connect this signal as well. */
1612 tp_g_signal_connect_object (account
, "notify::connection",
1613 G_CALLBACK (account_connection_notify_cb
), self
, 0);
1615 roster_window_setup_balance (self
, account
);
1618 /* @account: if not %NULL, the only account which can be enabled */
1620 display_page_account_not_enabled (EmpathyRosterWindow
*self
,
1623 if (account
== NULL
)
1625 display_page_message (self
,
1626 _("You need to enable one of your accounts to see contacts here."),
1627 PAGE_MESSAGE_FLAG_ACCOUNTS
);
1633 /* translators: argument is an account name */
1634 tmp
= g_strdup_printf (_("You need to enable %s to see contacts here."),
1635 tp_account_get_display_name (account
));
1637 display_page_message (self
, tmp
, PAGE_MESSAGE_FLAG_ACCOUNTS
);
1642 has_enabled_account (GList
*accounts
)
1646 for (l
= accounts
; l
!= NULL
; l
= g_list_next (l
))
1648 TpAccount
*account
= l
->data
;
1650 if (tp_account_is_enabled (account
))
1658 set_notebook_page (EmpathyRosterWindow
*self
)
1662 TpConnectionPresenceType presence
;
1663 gboolean connected
, connecting
;
1665 connected
= empathy_account_manager_get_accounts_connected (&connecting
);
1667 /* Display the loading page if either:
1668 * - We are fetching contacts from Folks (startup)
1669 * - There is no account connected but at least one is connecting
1671 if (!empathy_individual_manager_get_contacts_loaded (
1672 self
->priv
->individual_manager
) ||
1673 (!connected
&& connecting
))
1675 display_page_message (self
, NULL
, PAGE_MESSAGE_FLAG_SPINNER
);
1676 gtk_spinner_start (GTK_SPINNER (self
->priv
->spinner_loading
));
1680 gtk_spinner_stop (GTK_SPINNER (self
->priv
->spinner_loading
));
1682 accounts
= tp_account_manager_dup_valid_accounts (
1683 self
->priv
->account_manager
);
1685 len
= g_list_length (accounts
);
1690 display_page_no_account (self
);
1694 if (!has_enabled_account (accounts
))
1696 TpAccount
*account
= NULL
;
1698 /* Pass the account if there is only one which can be enabled */
1700 account
= accounts
->data
;
1702 display_page_account_not_enabled (self
, account
);
1706 presence
= tp_account_manager_get_most_available_presence (
1707 self
->priv
->account_manager
, NULL
, NULL
);
1709 if (presence
== TP_CONNECTION_PRESENCE_TYPE_OFFLINE
)
1711 display_page_message (self
,
1712 _("Change your presence to see contacts here"),
1713 PAGE_MESSAGE_FLAG_ONLINE
);
1717 if (empathy_roster_view_is_empty (self
->priv
->view
))
1719 if (empathy_roster_view_is_searching (self
->priv
->view
))
1721 display_page_message (self
, _("No match found"),
1722 PAGE_MESSAGE_FLAG_NONE
);
1726 if (g_settings_get_boolean (self
->priv
->gsettings_ui
,
1727 EMPATHY_PREFS_UI_SHOW_OFFLINE
))
1728 display_page_message (self
, _("You haven't added any contacts yet"),
1729 PAGE_MESSAGE_FLAG_ADD_CONTACT
);
1731 display_page_message (self
, _("No online contacts"),
1732 PAGE_MESSAGE_FLAG_SHOW_OFFLINE
);
1737 display_page_contact_list (self
);
1740 g_list_free_full (accounts
, g_object_unref
);
1744 roster_window_account_validity_changed_cb (TpAccountManager
*manager
,
1747 EmpathyRosterWindow
*self
)
1750 add_account (self
, account
);
1752 roster_window_account_removed_cb (manager
, account
, self
);
1754 set_notebook_page (self
);
1758 roster_window_connection_items_setup (EmpathyRosterWindow
*self
)
1761 const gchar
*actions_connected
[] = {
1763 "room_join_favorites",
1766 "chat_search_contacts",
1768 "edit_blocked_contacts",
1771 for (i
= 0; i
< G_N_ELEMENTS (actions_connected
); i
++)
1775 action
= g_action_map_lookup_action (G_ACTION_MAP (self
),
1776 actions_connected
[i
]);
1778 self
->priv
->actions_connected
= g_list_prepend (
1779 self
->priv
->actions_connected
, action
);
1784 account_enabled_cb (TpAccountManager
*manager
,
1786 EmpathyRosterWindow
*self
)
1788 set_notebook_page (self
);
1792 account_disabled_cb (TpAccountManager
*manager
,
1794 EmpathyRosterWindow
*self
)
1796 set_notebook_page (self
);
1800 account_removed_cb (TpAccountManager
*manager
,
1802 EmpathyRosterWindow
*self
)
1804 set_notebook_page (self
);
1808 account_manager_prepared_cb (GObject
*source_object
,
1809 GAsyncResult
*result
,
1812 GList
*accounts
, *j
;
1813 TpAccountManager
*manager
= TP_ACCOUNT_MANAGER (source_object
);
1814 EmpathyRosterWindow
*self
= user_data
;
1815 GError
*error
= NULL
;
1817 if (!tp_proxy_prepare_finish (manager
, result
, &error
))
1819 DEBUG ("Failed to prepare account manager: %s", error
->message
);
1820 g_error_free (error
);
1824 accounts
= tp_account_manager_dup_valid_accounts (
1825 self
->priv
->account_manager
);
1826 for (j
= accounts
; j
!= NULL
; j
= j
->next
)
1828 TpAccount
*account
= TP_ACCOUNT (j
->data
);
1830 add_account (self
, account
);
1833 g_signal_connect (manager
, "account-validity-changed",
1834 G_CALLBACK (roster_window_account_validity_changed_cb
), self
);
1835 tp_g_signal_connect_object (manager
, "account-removed",
1836 G_CALLBACK (account_removed_cb
), self
, 0);
1837 tp_g_signal_connect_object (manager
, "account-disabled",
1838 G_CALLBACK (account_disabled_cb
), self
, 0);
1839 tp_g_signal_connect_object (manager
, "account-enabled",
1840 G_CALLBACK (account_enabled_cb
), self
, 0);
1842 roster_window_update_status (self
);
1844 set_notebook_page (self
);
1846 g_list_free_full (accounts
, g_object_unref
);
1850 empathy_roster_window_set_shell_running (EmpathyRosterWindow
*self
,
1851 gboolean shell_running
)
1853 if (self
->priv
->shell_running
== shell_running
)
1856 self
->priv
->shell_running
= shell_running
;
1857 g_object_notify (G_OBJECT (self
), "shell-running");
1861 empathy_roster_window_constructor (GType type
,
1862 guint n_construct_params
,
1863 GObjectConstructParam
*construct_params
)
1865 static GObject
*window
= NULL
;
1868 return g_object_ref (window
);
1870 window
= G_OBJECT_CLASS (empathy_roster_window_parent_class
)->constructor (
1871 type
, n_construct_params
, construct_params
);
1873 g_object_add_weak_pointer (window
, (gpointer
) &window
);
1878 static GActionEntry menubar_entries
[] = {
1879 { "chat_new_message", roster_window_chat_new_message_cb
, NULL
, NULL
, NULL
},
1880 { "chat_new_call", roster_window_chat_new_call_cb
, NULL
, NULL
, NULL
},
1881 { "chat_add_contact", roster_window_chat_add_contact_cb
, NULL
, NULL
, NULL
},
1882 { "chat_search_contacts", roster_window_chat_search_contacts_cb
, NULL
, NULL
, NULL
},
1883 { "chat_quit", roster_window_chat_quit_cb
, NULL
, NULL
, NULL
},
1885 { "edit_accounts", roster_window_edit_accounts_cb
, NULL
, NULL
, NULL
},
1886 { "edit_blocked_contacts", roster_window_edit_blocked_contacts_cb
, NULL
, NULL
, NULL
},
1887 { "edit_preferences", roster_window_edit_preferences_cb
, NULL
, NULL
, NULL
},
1889 { "view_history", roster_window_view_history_cb
, NULL
, NULL
, NULL
},
1890 { "view_show_ft_manager", roster_window_view_show_ft_manager
, NULL
, NULL
, NULL
},
1892 { "room_join_new", roster_window_room_join_new_cb
, NULL
, NULL
, NULL
},
1893 { "room_join_favorites", roster_window_room_join_favorites_cb
, NULL
, NULL
, NULL
},
1894 { "join", roster_window_join_chatroom_menu_activate_cb
, "(ss)", NULL
, NULL
},
1895 { "room_manage_favorites", roster_window_room_manage_favorites_cb
, NULL
, NULL
, NULL
},
1897 { "help_contents", roster_window_help_contents_cb
, NULL
, NULL
, NULL
},
1898 { "help_about", roster_window_help_about_cb
, NULL
, NULL
, NULL
},
1902 empathy_roster_window_set_property (GObject
*object
,
1904 const GValue
*value
,
1907 EmpathyRosterWindow
*self
= EMPATHY_ROSTER_WINDOW (object
);
1909 switch (property_id
)
1911 case PROP_SHELL_RUNNING
:
1912 self
->priv
->shell_running
= g_value_get_boolean (value
);
1915 G_OBJECT_WARN_INVALID_PROPERTY_ID (object
, property_id
, pspec
);
1921 empathy_roster_window_get_property (GObject
*object
,
1926 EmpathyRosterWindow
*self
= EMPATHY_ROSTER_WINDOW (object
);
1928 switch (property_id
)
1930 case PROP_SHELL_RUNNING
:
1931 g_value_set_boolean (value
, self
->priv
->shell_running
);
1934 G_OBJECT_WARN_INVALID_PROPERTY_ID (object
, property_id
, pspec
);
1940 empathy_roster_window_constructed (GObject
*self
)
1942 G_OBJECT_CLASS (empathy_roster_window_parent_class
)->constructed (self
);
1946 empathy_roster_window_class_init (EmpathyRosterWindowClass
*klass
)
1948 GObjectClass
*object_class
= G_OBJECT_CLASS (klass
);
1951 object_class
->finalize
= empathy_roster_window_finalize
;
1952 object_class
->constructor
= empathy_roster_window_constructor
;
1953 object_class
->constructed
= empathy_roster_window_constructed
;
1955 object_class
->set_property
= empathy_roster_window_set_property
;
1956 object_class
->get_property
= empathy_roster_window_get_property
;
1958 pspec
= g_param_spec_boolean ("shell-running",
1960 "Whether the Shell is running or not",
1962 G_PARAM_READWRITE
| G_PARAM_STATIC_STRINGS
);
1963 g_object_class_install_property (object_class
, PROP_SHELL_RUNNING
, pspec
);
1965 g_type_class_add_private (object_class
, sizeof (EmpathyRosterWindowPriv
));
1969 contacts_loaded_cb (EmpathyIndividualManager
*manager
,
1970 EmpathyRosterWindow
*self
)
1972 set_notebook_page (self
);
1976 roster_window_setup_actions (EmpathyRosterWindow
*self
)
1980 #define ADD_GSETTINGS_ACTION(schema, key) \
1981 action = g_settings_create_action (self->priv->gsettings_##schema, \
1982 EMPATHY_PREFS_##key); \
1983 g_action_map_add_action (G_ACTION_MAP (self), action); \
1984 g_object_unref (action);
1986 ADD_GSETTINGS_ACTION (ui
, UI_SHOW_OFFLINE
);
1988 #undef ADD_GSETTINGS_ACTION
1992 menu_deactivate_cb (GtkMenuShell
*menushell
,
1995 /* FIXME: we shouldn't have to disconnect the signal (bgo #641327) */
1996 g_signal_handlers_disconnect_by_func (menushell
,
1997 menu_deactivate_cb
, user_data
);
1999 gtk_menu_detach (GTK_MENU (menushell
));
2003 menu_item_activated_cb (GtkMenuShell
*menushell
,
2006 EmpathyRosterWindow
*roster_window
= EMPATHY_ROSTER_WINDOW (user_data
);
2008 hide_search_bar (roster_window
);
2012 popup_individual_menu_cb (EmpathyRosterView
*view
,
2013 const gchar
*active_group
,
2014 FolksIndividual
*individual
,
2020 EmpathyIndividualFeatureFlags features
= EMPATHY_INDIVIDUAL_FEATURE_CHAT
|
2021 EMPATHY_INDIVIDUAL_FEATURE_CALL
|
2022 EMPATHY_INDIVIDUAL_FEATURE_EDIT
|
2023 EMPATHY_INDIVIDUAL_FEATURE_INFO
|
2024 EMPATHY_INDIVIDUAL_FEATURE_LOG
|
2025 EMPATHY_INDIVIDUAL_FEATURE_SMS
|
2026 EMPATHY_INDIVIDUAL_FEATURE_CALL_PHONE
|
2027 EMPATHY_INDIVIDUAL_FEATURE_REMOVE
|
2028 EMPATHY_INDIVIDUAL_FEATURE_FILE_TRANSFER
;
2030 menu
= empathy_individual_menu_new (individual
, active_group
,
2033 /* menu is initially unowned but gtk_menu_attach_to_widget() takes its
2034 * floating ref. We can either wait for the view to release its ref
2035 * when it is destroyed (when leaving Empathy) or explicitly
2036 * detach the menu when it's not displayed any more.
2037 * We go for the latter as we don't want to keep useless menus in memory
2038 * during the whole lifetime of Empathy. */
2039 g_signal_connect (menu
, "deactivate", G_CALLBACK (menu_deactivate_cb
),
2041 g_signal_connect (menu
, "menu-item-activated",
2042 G_CALLBACK (menu_item_activated_cb
), user_data
);
2044 gtk_menu_attach_to_widget (GTK_MENU (menu
), GTK_WIDGET (view
), NULL
);
2045 gtk_menu_popup (GTK_MENU (menu
), NULL
, NULL
, NULL
, NULL
, button
, time
);
2049 view_empty_cb (EmpathyRosterView
*view
,
2051 EmpathyRosterWindow
*self
)
2053 set_notebook_page (self
);
2055 if (!empathy_roster_view_is_empty (view
))
2057 gtk_widget_grab_focus (GTK_WIDGET (self
->priv
->view
));
2059 /* The store is being filled, it will be done after an idle cb.
2060 * So we can then get events. If we do that too soon, event's
2061 * contact is not yet in the store and it won't get marked as
2063 g_idle_add (roster_window_load_events_idle_cb
, self
);
2068 tooltip_destroy_cb (GtkWidget
*widget
,
2069 EmpathyRosterWindow
*self
)
2071 g_clear_object (&self
->priv
->tooltip_widget
);
2075 individual_tooltip_cb (EmpathyRosterView
*view
,
2076 FolksIndividual
*individual
,
2077 gboolean keyboard_mode
,
2078 GtkTooltip
*tooltip
,
2079 EmpathyRosterWindow
*self
)
2081 if (self
->priv
->tooltip_widget
== NULL
)
2083 self
->priv
->tooltip_widget
= empathy_individual_widget_new (individual
,
2084 EMPATHY_INDIVIDUAL_WIDGET_FOR_TOOLTIP
|
2085 EMPATHY_INDIVIDUAL_WIDGET_SHOW_LOCATION
|
2086 EMPATHY_INDIVIDUAL_WIDGET_SHOW_CLIENT_TYPES
);
2088 gtk_container_set_border_width (
2089 GTK_CONTAINER (self
->priv
->tooltip_widget
), 8);
2091 g_object_ref (self
->priv
->tooltip_widget
);
2093 tp_g_signal_connect_object (self
->priv
->tooltip_widget
, "destroy",
2094 G_CALLBACK (tooltip_destroy_cb
), self
, 0);
2096 gtk_widget_show (self
->priv
->tooltip_widget
);
2100 empathy_individual_widget_set_individual (
2101 EMPATHY_INDIVIDUAL_WIDGET (self
->priv
->tooltip_widget
), individual
);
2104 gtk_tooltip_set_custom (tooltip
, self
->priv
->tooltip_widget
);
2111 DND_DRAG_TYPE_INVALID
= -1,
2112 DND_DRAG_TYPE_URI_LIST
,
2115 #define DRAG_TYPE(T,I) \
2116 { (gchar *) T, 0, I }
2118 static const GtkTargetEntry drag_types_dest
[] = {
2119 DRAG_TYPE ("text/path-list", DND_DRAG_TYPE_URI_LIST
),
2120 DRAG_TYPE ("text/uri-list", DND_DRAG_TYPE_URI_LIST
),
2123 static GdkAtom drag_atoms_dest
[G_N_ELEMENTS (drag_types_dest
)];
2126 get_drag_type (GtkWidget
*widget
,
2127 GdkDragContext
*context
)
2132 target
= gtk_drag_dest_find_target (widget
, context
, NULL
);
2134 for (i
= 0; i
< G_N_ELEMENTS (drag_atoms_dest
); i
++)
2136 if (target
== drag_atoms_dest
[i
])
2137 return drag_types_dest
[i
].info
;
2140 return DND_DRAG_TYPE_INVALID
;
2144 individual_supports_ft (FolksIndividual
*individual
)
2146 EmpathyContact
*contact
;
2147 EmpathyCapabilities caps
;
2150 contact
= empathy_contact_dup_from_folks_individual (individual
);
2151 if (contact
== NULL
)
2154 caps
= empathy_contact_get_capabilities (contact
);
2155 result
= (caps
& EMPATHY_CAPABILITIES_FT
);
2157 g_object_unref (contact
);
2162 view_drag_motion_cb (GtkWidget
*widget
,
2163 GdkDragContext
*context
,
2167 EmpathyRosterWindow
*self
)
2171 type
= get_drag_type (widget
, context
);
2173 if (type
== DND_DRAG_TYPE_URI_LIST
)
2175 /* Check if contact supports FT */
2176 FolksIndividual
*individual
;
2179 individual
= empathy_roster_view_get_individual_at_y (self
->priv
->view
,
2181 if (individual
== NULL
)
2184 if (!individual_supports_ft (individual
))
2187 gtk_list_box_drag_highlight_row (GTK_LIST_BOX (widget
), row
);
2192 gtk_list_box_drag_unhighlight_row (GTK_LIST_BOX (widget
));
2197 view_drag_drop_cb (GtkWidget
*widget
,
2198 GdkDragContext
*context
,
2202 EmpathyRosterWindow
*self
)
2205 FolksIndividual
*individual
;
2207 type
= get_drag_type (widget
, context
);
2208 if (type
== DND_DRAG_TYPE_INVALID
)
2211 individual
= empathy_roster_view_get_individual_at_y (self
->priv
->view
, y
,
2213 if (individual
== NULL
)
2216 if (!individual_supports_ft (individual
))
2219 gtk_drag_get_data (widget
, context
,
2220 gtk_drag_dest_find_target (widget
, context
, NULL
), time_
);
2226 view_drag_data_received_cb (GtkWidget
*widget
,
2227 GdkDragContext
*context
,
2230 GtkSelectionData
*selection
,
2233 EmpathyRosterWindow
*self
)
2235 gboolean success
= FALSE
;
2237 if (selection
== NULL
)
2240 if (info
== DND_DRAG_TYPE_URI_LIST
)
2243 FolksIndividual
*individual
;
2244 EmpathyContact
*contact
;
2246 individual
= empathy_roster_view_get_individual_at_y (self
->priv
->view
,
2248 g_return_if_fail (individual
!= NULL
);
2250 path
= (const gchar
*) gtk_selection_data_get_data (selection
);
2252 contact
= empathy_contact_dup_from_folks_individual (individual
);
2253 empathy_send_file_from_uri_list (contact
, path
);
2255 g_object_unref (contact
);
2261 gtk_drag_finish (context
, success
, FALSE
, time_
);
2265 roster_window_most_available_presence_changed_cb (TpAccountManager
*manager
,
2266 TpConnectionPresenceType presence
,
2267 const gchar
*status
,
2268 const gchar
*message
,
2269 EmpathyRosterWindow
*self
)
2271 set_notebook_page (self
);
2275 show_offline_changed_cb (GSettings
*settings
,
2277 EmpathyRosterWindow
*self
)
2279 set_notebook_page (self
);
2283 empathy_roster_window_init (EmpathyRosterWindow
*self
)
2288 GtkWidget
*search_vbox
;
2290 EmpathyRosterModel
*model
;
2292 self
->priv
= G_TYPE_INSTANCE_GET_PRIVATE (self
,
2293 EMPATHY_TYPE_ROSTER_WINDOW
, EmpathyRosterWindowPriv
);
2295 empathy_set_css_provider (GTK_WIDGET (self
));
2297 self
->priv
->gsettings_ui
= g_settings_new (EMPATHY_PREFS_UI_SCHEMA
);
2299 self
->priv
->sound_mgr
= empathy_sound_manager_dup_singleton ();
2301 gtk_window_set_title (GTK_WINDOW (self
), _("Contact List"));
2302 gtk_window_set_role (GTK_WINDOW (self
), "contact_list");
2303 gtk_window_set_default_size (GTK_WINDOW (self
), 225, 325);
2305 /* don't finalize the widget on delete-event, just hide it */
2306 g_signal_connect (self
, "delete-event",
2307 G_CALLBACK (gtk_widget_hide_on_delete
), NULL
);
2309 /* Set up interface */
2310 filename
= empathy_file_lookup ("empathy-roster-window.ui", "src");
2311 gui
= tpaw_builder_get_file (filename
,
2312 "main_vbox", &self
->priv
->main_vbox
,
2313 "balance_vbox", &self
->priv
->balance_vbox
,
2314 "errors_vbox", &self
->priv
->errors_vbox
,
2315 "auth_vbox", &self
->priv
->auth_vbox
,
2316 "search_vbox", &search_vbox
,
2317 "presence_toolbar", &self
->priv
->presence_toolbar
,
2318 "notebook", &self
->priv
->notebook
,
2319 "no_entry_label", &self
->priv
->no_entry_label
,
2320 "roster_scrolledwindow", &sw
,
2321 "button_account_settings", &self
->priv
->button_account_settings
,
2322 "button_online", &self
->priv
->button_online
,
2323 "button_show_offline", &self
->priv
->button_show_offline
,
2324 "button_add_contact", &self
->priv
->button_add_contact
,
2325 "spinner_loading", &self
->priv
->spinner_loading
,
2329 gtk_container_add (GTK_CONTAINER (self
), self
->priv
->main_vbox
);
2330 gtk_widget_show (self
->priv
->main_vbox
);
2332 g_signal_connect (self
, "key-press-event",
2333 G_CALLBACK (roster_window_key_press_event_cb
), self
);
2335 g_object_unref (gui
);
2337 self
->priv
->account_manager
= tp_account_manager_dup ();
2339 tp_proxy_prepare_async (self
->priv
->account_manager
, NULL
,
2340 account_manager_prepared_cb
, self
);
2342 self
->priv
->errors
= g_hash_table_new_full (g_direct_hash
, g_direct_equal
,
2343 g_object_unref
, NULL
);
2345 self
->priv
->auths
= g_hash_table_new (NULL
, NULL
);
2347 self
->priv
->status_changed_handlers
= g_hash_table_new_full (g_direct_hash
,
2348 g_direct_equal
, NULL
, NULL
);
2351 g_action_map_add_action_entries (G_ACTION_MAP (self
),
2352 menubar_entries
, G_N_ELEMENTS (menubar_entries
), self
);
2353 roster_window_setup_actions (self
);
2355 filename
= empathy_file_lookup ("empathy-roster-window-menubar.ui", "src");
2356 gui
= tpaw_builder_get_file (filename
,
2357 "appmenu", &self
->priv
->menumodel
,
2358 "rooms", &self
->priv
->rooms_section
,
2362 g_object_ref (self
->priv
->menumodel
);
2363 g_object_ref (self
->priv
->rooms_section
);
2365 /* Set up connection related actions. */
2366 roster_window_connection_items_setup (self
);
2367 roster_window_favorite_chatroom_menu_setup (self
);
2369 g_object_unref (gui
);
2371 /* Set up contact list. */
2372 empathy_status_presets_get_all ();
2374 /* Set up presence chooser */
2375 self
->priv
->presence_chooser
= empathy_presence_chooser_new ();
2376 gtk_widget_show (self
->priv
->presence_chooser
);
2377 gtk_box_pack_start (GTK_BOX (self
->priv
->presence_toolbar
),
2378 self
->priv
->presence_chooser
,
2381 /* Set up the throbber */
2382 self
->priv
->throbber
= gtk_spinner_new ();
2383 gtk_widget_set_size_request (self
->priv
->throbber
, 16, -1);
2384 gtk_widget_set_events (self
->priv
->throbber
, GDK_BUTTON_PRESS_MASK
);
2385 g_signal_connect (self
->priv
->throbber
, "button-press-event",
2386 G_CALLBACK (roster_window_throbber_button_press_event_cb
),
2388 gtk_box_pack_start (GTK_BOX (self
->priv
->presence_toolbar
),
2389 self
->priv
->throbber
,
2392 self
->priv
->individual_manager
= empathy_individual_manager_dup_singleton ();
2394 model
= EMPATHY_ROSTER_MODEL (empathy_roster_model_manager_new (self
->priv
->individual_manager
));
2396 tp_g_signal_connect_object (self
->priv
->individual_manager
,
2397 "contacts-loaded", G_CALLBACK (contacts_loaded_cb
), self
, 0);
2399 self
->priv
->view
= EMPATHY_ROSTER_VIEW (
2400 empathy_roster_view_new (model
));
2402 g_object_unref (model
);
2404 gtk_widget_show (GTK_WIDGET (self
->priv
->view
));
2406 gtk_container_add (GTK_CONTAINER (sw
), GTK_WIDGET (self
->priv
->view
));
2408 g_signal_connect (self
->priv
->view
, "individual-activated",
2409 G_CALLBACK (individual_activated_cb
), self
);
2410 g_signal_connect (self
->priv
->view
, "event-activated",
2411 G_CALLBACK (event_activated_cb
), self
);
2412 g_signal_connect (self
->priv
->view
, "popup-individual-menu",
2413 G_CALLBACK (popup_individual_menu_cb
), self
);
2414 g_signal_connect (self
->priv
->view
, "notify::empty",
2415 G_CALLBACK (view_empty_cb
), self
);
2416 g_signal_connect (self
->priv
->view
, "individual-tooltip",
2417 G_CALLBACK (individual_tooltip_cb
), self
);
2419 /* DnD - destination */
2420 gtk_drag_dest_set (GTK_WIDGET (self
->priv
->view
), GTK_DEST_DEFAULT_MOTION
,
2421 drag_types_dest
, G_N_ELEMENTS (drag_types_dest
), GDK_ACTION_COPY
);
2423 for (i
= 0; i
< G_N_ELEMENTS (drag_types_dest
); ++i
)
2424 drag_atoms_dest
[i
] = gdk_atom_intern (drag_types_dest
[i
].target
, FALSE
);
2426 g_signal_connect (self
->priv
->view
, "drag-motion",
2427 G_CALLBACK (view_drag_motion_cb
), self
);
2428 g_signal_connect (self
->priv
->view
, "drag-drop",
2429 G_CALLBACK (view_drag_drop_cb
), self
);
2430 g_signal_connect (self
->priv
->view
, "drag-data-received",
2431 G_CALLBACK (view_drag_data_received_cb
), self
);
2433 gtk_widget_set_has_tooltip (GTK_WIDGET (self
->priv
->view
), TRUE
);
2435 /* Set up search bar */
2436 self
->priv
->search_bar
= tpaw_live_search_new (
2437 GTK_WIDGET (self
->priv
->view
));
2438 empathy_roster_view_set_live_search (self
->priv
->view
,
2439 TPAW_LIVE_SEARCH (self
->priv
->search_bar
));
2440 gtk_box_pack_start (GTK_BOX (search_vbox
), self
->priv
->search_bar
,
2443 g_signal_connect_swapped (self
, "map",
2444 G_CALLBACK (gtk_widget_grab_focus
), self
->priv
->view
);
2446 /* Load user-defined accelerators. */
2447 roster_window_accels_load ();
2449 gtk_window_set_default_size (GTK_WINDOW (self
), -1, 600);
2450 /* Set window size. */
2451 empathy_geometry_bind (GTK_WINDOW (self
), GEOMETRY_NAME
);
2453 /* Enable event handling */
2454 self
->priv
->call_observer
= empathy_call_observer_dup_singleton ();
2455 self
->priv
->event_manager
= empathy_event_manager_dup_singleton ();
2457 tp_g_signal_connect_object (self
->priv
->event_manager
, "event-added",
2458 G_CALLBACK (roster_window_event_added_cb
), self
, 0);
2459 tp_g_signal_connect_object (self
->priv
->event_manager
, "event-removed",
2460 G_CALLBACK (roster_window_event_removed_cb
), self
, 0);
2462 g_signal_connect (self
->priv
->account_manager
, "account-validity-changed",
2463 G_CALLBACK (roster_window_account_validity_changed_cb
), self
);
2464 g_signal_connect (self
->priv
->account_manager
, "account-removed",
2465 G_CALLBACK (roster_window_account_removed_cb
), self
);
2466 g_signal_connect (self
->priv
->account_manager
, "account-disabled",
2467 G_CALLBACK (roster_window_account_disabled_cb
), self
);
2468 g_signal_connect (self
->priv
->account_manager
,
2469 "most-available-presence-changed",
2470 G_CALLBACK (roster_window_most_available_presence_changed_cb
), self
);
2472 g_settings_bind (self
->priv
->gsettings_ui
, EMPATHY_PREFS_UI_SHOW_OFFLINE
,
2473 self
->priv
->view
, "show-offline",
2474 G_SETTINGS_BIND_GET
);
2475 tp_g_signal_connect_object (self
->priv
->gsettings_ui
,
2476 "changed::" EMPATHY_PREFS_UI_SHOW_OFFLINE
,
2477 G_CALLBACK (show_offline_changed_cb
), self
, 0);
2478 g_settings_bind (self
->priv
->gsettings_ui
, EMPATHY_PREFS_UI_SHOW_GROUPS
,
2479 self
->priv
->view
, "show-groups",
2480 G_SETTINGS_BIND_GET
);
2481 g_settings_bind (self
->priv
->gsettings_ui
, "show-balance-in-roster",
2482 self
->priv
->balance_vbox
, "visible",
2483 G_SETTINGS_BIND_GET
);
2485 g_signal_connect (self
->priv
->button_account_settings
, "clicked",
2486 G_CALLBACK (button_account_settings_clicked_cb
), self
);
2487 g_signal_connect (self
->priv
->button_online
, "clicked",
2488 G_CALLBACK (button_online_clicked_cb
), self
);
2489 g_signal_connect (self
->priv
->button_show_offline
, "clicked",
2490 G_CALLBACK (button_show_offline_clicked_cb
), self
);
2491 g_signal_connect (self
->priv
->button_add_contact
, "clicked",
2492 G_CALLBACK (button_add_contact_clicked_cb
), self
);
2496 empathy_roster_window_new (GtkApplication
*app
)
2498 return g_object_new (EMPATHY_TYPE_ROSTER_WINDOW
,
2504 empathy_roster_window_get_menu_model (EmpathyRosterWindow
*self
)
2506 g_return_val_if_fail (EMPATHY_IS_ROSTER_WINDOW (self
), NULL
);
2508 return G_MENU_MODEL (self
->priv
->menumodel
);