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-chat-window.h"
36 #include "empathy-chatroom-manager.h"
37 #include "empathy-chatrooms-window.h"
38 #include "empathy-client-factory.h"
39 #include "empathy-contact-blocking-dialog.h"
40 #include "empathy-contact-search-dialog.h"
41 #include "empathy-event-manager.h"
42 #include "empathy-ft-manager.h"
43 #include "empathy-geometry.h"
44 #include "empathy-gsettings.h"
45 #include "empathy-gsettings.h"
46 #include "empathy-gtk-enum-types.h"
47 #include "empathy-individual-dialogs.h"
48 #include "empathy-log-window.h"
49 #include "empathy-new-call-dialog.h"
50 #include "empathy-new-chatroom-dialog.h"
51 #include "empathy-new-message-dialog.h"
52 #include "empathy-preferences.h"
53 #include "empathy-presence-chooser.h"
54 #include "empathy-presence-manager.h"
55 #include "empathy-request-util.h"
56 #include "empathy-roster-model-manager.h"
57 #include "empathy-roster-view.h"
58 #include "empathy-status-presets.h"
59 #include "empathy-theme-manager.h"
60 #include "empathy-theme-manager.h"
61 #include "empathy-ui-utils.h"
62 #include "empathy-utils.h"
64 #define DEBUG_FLAG EMPATHY_DEBUG_OTHER
65 #include "empathy-debug.h"
67 /* Flashing delay for icons (milliseconds). */
68 #define FLASH_TIMEOUT 500
70 /* Minimum width of roster window if something goes wrong. */
73 /* Accels (menu shortcuts) can be configured and saved */
74 #define ACCELS_FILENAME "accels.txt"
76 /* Name in the geometry file */
77 #define GEOMETRY_NAME "roster-window"
81 PAGE_CONTACT_LIST
= 0,
91 G_DEFINE_TYPE (EmpathyRosterWindow
, empathy_roster_window
, GTK_TYPE_APPLICATION_WINDOW
)
93 struct _EmpathyRosterWindowPriv
{
94 EmpathyRosterView
*view
;
95 TpAccountManager
*account_manager
;
96 EmpathyChatManager
*chat_manager
;
97 EmpathyThemeManager
*theme_manager
;
98 EmpathyChatroomManager
*chatroom_manager
;
99 EmpathyEventManager
*event_manager
;
100 EmpathySoundManager
*sound_mgr
;
101 EmpathyCallObserver
*call_observer
;
102 EmpathyIndividualManager
*individual_manager
;
103 guint flash_timeout_id
;
106 GSettings
*gsettings_ui
;
108 GtkWidget
*preferences
;
109 GtkWidget
*main_vbox
;
111 GtkWidget
*presence_toolbar
;
112 GtkWidget
*presence_chooser
;
113 GtkWidget
*errors_vbox
;
114 GtkWidget
*auth_vbox
;
115 GtkWidget
*search_bar
;
117 GtkWidget
*no_entry_label
;
118 GtkWidget
*button_account_settings
;
119 //GtkWidget *button_online;
120 GtkWidget
*button_show_offline
;
121 GtkWidget
*button_add_contact
;
122 GtkWidget
*spinner_loading
;
123 GtkWidget
*tooltip_widget
;
124 GtkWidget
*chat_window
;
127 GMenu
*rooms_section
;
129 GtkWidget
*balance_vbox
;
131 guint size_timeout_id
;
133 /* reffed TpAccount* => visible GtkInfoBar* */
136 /* EmpathyEvent* => visible GtkInfoBar* */
139 /* stores a mapping from TpAccount to Handler ID to prevent
140 * to listen more than once to the status-changed signal */
141 GHashTable
*status_changed_handlers
;
143 /* Actions that are enabled when there are connected accounts */
144 GList
*actions_connected
;
146 gboolean shell_running
;
150 roster_window_remove_auth (EmpathyRosterWindow
*self
,
153 GtkWidget
*error_widget
;
155 error_widget
= g_hash_table_lookup (self
->priv
->auths
, event
);
156 if (error_widget
!= NULL
)
158 gtk_widget_destroy (error_widget
);
159 g_hash_table_remove (self
->priv
->auths
, event
);
164 roster_window_auth_add_clicked_cb (GtkButton
*button
,
165 EmpathyRosterWindow
*self
)
169 event
= g_object_get_data (G_OBJECT (button
), "event");
171 empathy_event_approve (event
);
173 roster_window_remove_auth (self
, event
);
177 roster_window_auth_close_clicked_cb (GtkButton
*button
,
178 EmpathyRosterWindow
*self
)
182 event
= g_object_get_data (G_OBJECT (button
), "event");
184 empathy_event_decline (event
);
185 roster_window_remove_auth (self
, event
);
189 roster_window_auth_display (EmpathyRosterWindow
*self
,
192 TpAccount
*account
= event
->account
;
194 GtkWidget
*content_area
;
197 GtkWidget
*add_button
;
198 GtkWidget
*close_button
;
199 GtkWidget
*action_area
;
200 GtkWidget
*action_grid
;
201 const gchar
*icon_name
;
204 if (g_hash_table_lookup (self
->priv
->auths
, event
) != NULL
)
207 info_bar
= gtk_info_bar_new ();
208 gtk_info_bar_set_message_type (GTK_INFO_BAR (info_bar
), GTK_MESSAGE_QUESTION
);
210 gtk_widget_set_no_show_all (info_bar
, TRUE
);
211 gtk_container_add (GTK_CONTAINER (self
->priv
->auth_vbox
), info_bar
);
212 gtk_widget_show (info_bar
);
214 icon_name
= tp_account_get_icon_name (account
);
215 image
= gtk_image_new_from_icon_name (icon_name
, GTK_ICON_SIZE_SMALL_TOOLBAR
);
216 gtk_widget_show (image
);
218 str
= g_markup_printf_escaped ("<b>%s</b>\n%s",
219 tp_account_get_display_name (account
),
220 _("Password required"));
222 label
= gtk_label_new (str
);
223 gtk_label_set_use_markup (GTK_LABEL (label
), TRUE
);
224 gtk_label_set_ellipsize (GTK_LABEL (label
), PANGO_ELLIPSIZE_END
);
225 gtk_misc_set_alignment (GTK_MISC (label
), 0, 0.5);
226 gtk_widget_show (label
);
230 content_area
= gtk_info_bar_get_content_area (GTK_INFO_BAR (info_bar
));
231 gtk_container_add (GTK_CONTAINER (content_area
), image
);
232 gtk_container_add (GTK_CONTAINER (content_area
), label
);
234 image
= gtk_image_new_from_stock (GTK_STOCK_ADD
, GTK_ICON_SIZE_BUTTON
);
235 add_button
= gtk_button_new ();
236 gtk_button_set_image (GTK_BUTTON (add_button
), image
);
237 gtk_widget_set_tooltip_text (add_button
, _("Provide Password"));
238 gtk_widget_show (add_button
);
240 image
= gtk_image_new_from_stock (GTK_STOCK_CLOSE
, GTK_ICON_SIZE_BUTTON
);
241 close_button
= gtk_button_new ();
242 gtk_button_set_image (GTK_BUTTON (close_button
), image
);
243 gtk_widget_set_tooltip_text (close_button
, _("Disconnect"));
244 gtk_widget_show (close_button
);
246 action_grid
= gtk_grid_new ();
247 gtk_grid_set_column_spacing (GTK_GRID (action_grid
), 6);
248 gtk_widget_show (action_grid
);
250 action_area
= gtk_info_bar_get_action_area (GTK_INFO_BAR (info_bar
));
251 gtk_container_add (GTK_CONTAINER (action_area
), action_grid
);
253 gtk_grid_attach (GTK_GRID (action_grid
), add_button
, 0, 0, 1, 1);
254 gtk_grid_attach (GTK_GRID (action_grid
), close_button
, 1, 0, 1, 1);
256 g_object_set_data_full (G_OBJECT (info_bar
),
257 "event", event
, NULL
);
258 g_object_set_data_full (G_OBJECT (add_button
),
259 "event", event
, NULL
);
260 g_object_set_data_full (G_OBJECT (close_button
),
261 "event", event
, NULL
);
263 g_signal_connect (add_button
, "clicked",
264 G_CALLBACK (roster_window_auth_add_clicked_cb
), self
);
265 g_signal_connect (close_button
, "clicked",
266 G_CALLBACK (roster_window_auth_close_clicked_cb
), self
);
268 gtk_widget_show (self
->priv
->auth_vbox
);
270 g_hash_table_insert (self
->priv
->auths
, event
, info_bar
);
273 static FolksIndividual
*
274 ensure_individual_for_event (EmpathyEvent
*event
)
278 contact
= empathy_contact_get_tp_contact (event
->contact
);
282 return empathy_ensure_individual_from_tp_contact (contact
);
286 roster_window_event_added_cb (EmpathyEventManager
*manager
,
288 EmpathyRosterWindow
*self
)
292 FolksIndividual
*individual
;
294 individual
= ensure_individual_for_event (event
);
295 if (individual
== NULL
)
298 event
->roster_view_id
= empathy_roster_view_add_event (self
->priv
->view
,
299 individual
, event
->icon_name
, event
);
301 g_object_unref (individual
);
303 else if (event
->type
== EMPATHY_EVENT_TYPE_AUTH
)
305 roster_window_auth_display (self
, event
);
310 roster_window_event_removed_cb (EmpathyEventManager
*manager
,
312 EmpathyRosterWindow
*self
)
314 if (event
->type
== EMPATHY_EVENT_TYPE_AUTH
)
316 roster_window_remove_auth (self
, event
);
320 empathy_roster_view_remove_event (self
->priv
->view
, event
->roster_view_id
);
324 roster_window_load_events_idle_cb (gpointer user_data
)
326 EmpathyRosterWindow
*self
= user_data
;
329 l
= empathy_event_manager_get_events (self
->priv
->event_manager
);
332 roster_window_event_added_cb (self
->priv
->event_manager
, l
->data
,
341 hide_search_bar (EmpathyRosterWindow
*roster_window
)
343 if (TPAW_IS_LIVE_SEARCH (roster_window
->priv
->search_bar
) &&
344 gtk_widget_is_visible (roster_window
->priv
->search_bar
))
345 gtk_widget_hide (roster_window
->priv
->search_bar
);
349 individual_activated_cb (EmpathyRosterView
*self
,
350 FolksIndividual
*individual
,
353 EmpathyContact
*contact
;
355 contact
= empathy_contact_dup_best_for_action (individual
,
356 EMPATHY_ACTION_CHAT
);
361 DEBUG ("Starting a chat");
363 empathy_chat_with_contact (contact
, gtk_get_current_event_time ());
365 g_object_unref (contact
);
367 /* Hide the search-bar upon hitting "Enter" on an individual */
368 hide_search_bar (EMPATHY_ROSTER_WINDOW (user_data
));
372 event_activated_cb (EmpathyRosterView
*self
,
373 FolksIndividual
*individual
,
377 empathy_event_activate (event
);
379 /* Hide the search-bar upon an event activation */
380 hide_search_bar (EMPATHY_ROSTER_WINDOW (user_data
));
384 button_account_settings_clicked_cb (GtkButton
*button
,
385 EmpathyRosterWindow
*self
)
387 empathy_accounts_dialog_show_application (gdk_screen_get_default (),
392 button_online_clicked_cb (GtkButton *button,
393 EmpathyRosterWindow *self)
395 EmpathyPresenceManager *mgr;
397 mgr = empathy_presence_manager_dup_singleton ();
399 empathy_presence_manager_set_state (mgr,
400 TP_CONNECTION_PRESENCE_TYPE_AVAILABLE);
402 g_object_unref (mgr);
406 button_show_offline_clicked_cb (GtkButton
*button
,
407 EmpathyRosterWindow
*self
)
409 g_settings_set_boolean (self
->priv
->gsettings_ui
,
410 EMPATHY_PREFS_UI_SHOW_OFFLINE
, TRUE
);
414 button_add_contact_clicked_cb (GtkButton
*button
,
415 EmpathyRosterWindow
*self
)
417 empathy_new_individual_dialog_show (GTK_WINDOW (self
));
422 PAGE_MESSAGE_FLAG_NONE
= 0,
423 PAGE_MESSAGE_FLAG_ACCOUNTS
= 1 << 0,
424 PAGE_MESSAGE_FLAG_SPINNER
= 1 << 2,
425 PAGE_MESSAGE_FLAG_ONLINE
= 1 << 3,
426 PAGE_MESSAGE_FLAG_SHOW_OFFLINE
= 1 << 4,
427 PAGE_MESSAGE_FLAG_ADD_CONTACT
= 1 << 5,
431 can_add_contact (EmpathyRosterWindow
*self
)
434 gboolean result
= FALSE
;
436 accounts
= tp_account_manager_dup_valid_accounts (
437 self
->priv
->account_manager
);
438 for (l
= accounts
; l
!= NULL
&& !result
; l
= g_list_next (l
))
440 TpAccount
*account
= TP_ACCOUNT (l
->data
);
443 conn
= tp_account_get_connection (account
);
447 if (tp_connection_get_can_change_contact_list (conn
))
451 g_list_free_full (accounts
, g_object_unref
);
456 display_page_message (EmpathyRosterWindow
*self
,
458 PageMessageFlags flags
)
464 tmp
= g_strdup_printf ("<b><span size='xx-large'>%s</span></b>", msg
);
466 gtk_label_set_markup (GTK_LABEL (self
->priv
->no_entry_label
), tmp
);
469 gtk_label_set_line_wrap (GTK_LABEL (self
->priv
->no_entry_label
), TRUE
);
470 gtk_widget_show (self
->priv
->no_entry_label
);
474 gtk_widget_hide (self
->priv
->no_entry_label
);
477 gtk_widget_set_visible (self
->priv
->button_account_settings
,
478 (flags
& PAGE_MESSAGE_FLAG_ACCOUNTS
) != 0);
479 gtk_widget_set_visible (self
->priv
->spinner_loading
,
480 (flags
& PAGE_MESSAGE_FLAG_SPINNER
) != 0);
481 // gtk_widget_set_visible (self->priv->button_online,
482 // (flags & PAGE_MESSAGE_FLAG_ONLINE) != 0);
483 gtk_widget_set_visible (self
->priv
->button_show_offline
,
484 (flags
& PAGE_MESSAGE_FLAG_SHOW_OFFLINE
) != 0);
485 gtk_widget_set_visible (self
->priv
->button_add_contact
,
486 (flags
& PAGE_MESSAGE_FLAG_ADD_CONTACT
) != 0);
488 if ((flags
& PAGE_MESSAGE_FLAG_ADD_CONTACT
) != 0)
489 gtk_widget_set_sensitive (self
->priv
->button_add_contact
,
490 can_add_contact (self
));
492 gtk_notebook_set_current_page (GTK_NOTEBOOK (self
->priv
->notebook
),
497 display_page_no_account (EmpathyRosterWindow
*self
)
499 display_page_message (self
,
500 _("You need to set up an account to see contacts here."),
501 PAGE_MESSAGE_FLAG_ACCOUNTS
);
505 display_page_contact_list (EmpathyRosterWindow
*self
)
507 if (!empathy_individual_manager_get_contacts_loaded (
508 self
->priv
->individual_manager
))
509 /* We'll display the contact list once we're done loading */
512 gtk_notebook_set_current_page (GTK_NOTEBOOK (self
->priv
->notebook
),
517 roster_window_remove_error (EmpathyRosterWindow
*self
,
520 GtkWidget
*error_widget
;
522 error_widget
= g_hash_table_lookup (self
->priv
->errors
, account
);
523 if (error_widget
!= NULL
)
525 gtk_widget_destroy (error_widget
);
526 g_hash_table_remove (self
->priv
->errors
, account
);
531 roster_window_account_disabled_cb (TpAccountManager
*manager
,
533 EmpathyRosterWindow
*self
)
535 roster_window_remove_error (self
, account
);
540 ERROR_RESPONSE_RETRY
,
542 ERROR_RESPONSE_CLOSE
,
543 ERROR_RESPONSE_UPGRADE
,
547 roster_window_error_response_cb (GtkInfoBar
*infobar
,
549 EmpathyRosterWindow
*self
)
553 account
= g_object_get_data (G_OBJECT (infobar
), "account");
557 case ERROR_RESPONSE_RETRY
:
558 tp_account_reconnect_async (account
, NULL
, NULL
);
561 case ERROR_RESPONSE_EDIT
:
562 empathy_accounts_dialog_show_application (
563 gtk_widget_get_screen (GTK_WIDGET (infobar
)),
564 account
, FALSE
, FALSE
);
567 case ERROR_RESPONSE_CLOSE
:
570 case ERROR_RESPONSE_UPGRADE
:
574 dialog
= gtk_message_dialog_new (GTK_WINDOW (self
),
575 GTK_DIALOG_MODAL
, GTK_MESSAGE_ERROR
, GTK_BUTTONS_OK
,
576 _("Sorry, %s accounts can’t be used until your %s software is updated."),
577 tp_account_get_protocol_name (account
),
578 tp_account_get_protocol_name (account
));
580 g_signal_connect_swapped (dialog
, "response",
581 G_CALLBACK (gtk_widget_destroy
),
584 gtk_widget_show (dialog
);
588 roster_window_remove_error (self
, account
);
592 roster_window_error_create_info_bar (EmpathyRosterWindow
*self
,
594 GtkMessageType message_type
,
595 const gchar
*message_markup
)
598 GtkWidget
*content_area
;
599 GtkWidget
*action_area
;
602 const gchar
*icon_name
;
604 /* If there are other errors, remove them */
605 roster_window_remove_error (self
, account
);
607 info_bar
= gtk_info_bar_new ();
608 gtk_info_bar_set_message_type (GTK_INFO_BAR (info_bar
), message_type
);
610 gtk_widget_set_no_show_all (info_bar
, TRUE
);
611 gtk_container_add (GTK_CONTAINER (self
->priv
->errors_vbox
), info_bar
);
612 gtk_widget_show (info_bar
);
614 icon_name
= tp_account_get_icon_name (account
);
615 image
= gtk_image_new_from_icon_name (icon_name
, GTK_ICON_SIZE_SMALL_TOOLBAR
);
616 gtk_widget_show (image
);
618 label
= gtk_label_new (message_markup
);
619 gtk_label_set_use_markup (GTK_LABEL (label
), TRUE
);
620 gtk_label_set_line_wrap (GTK_LABEL (label
), TRUE
);
621 gtk_label_set_ellipsize (GTK_LABEL (label
), PANGO_ELLIPSIZE_END
);
622 gtk_misc_set_alignment (GTK_MISC (label
), 0, 0.5);
623 gtk_widget_show (label
);
625 content_area
= gtk_info_bar_get_content_area (GTK_INFO_BAR (info_bar
));
626 gtk_container_add (GTK_CONTAINER (content_area
), image
);
627 gtk_container_add (GTK_CONTAINER (content_area
), label
);
629 action_area
= gtk_info_bar_get_action_area (GTK_INFO_BAR (info_bar
));
630 gtk_orientable_set_orientation (GTK_ORIENTABLE (action_area
),
631 GTK_ORIENTATION_HORIZONTAL
);
632 gtk_style_context_add_class (gtk_widget_get_style_context (action_area
),
633 "empathy-roster-window-error-button");
635 g_object_set_data_full (G_OBJECT (info_bar
),
636 "account", g_object_ref (account
),
639 g_signal_connect (info_bar
, "response",
640 G_CALLBACK (roster_window_error_response_cb
), self
);
642 gtk_widget_show (self
->priv
->errors_vbox
);
644 g_hash_table_insert (self
->priv
->errors
, g_object_ref (account
), info_bar
);
650 roster_window_error_add_stock_button (GtkInfoBar
*info_bar
,
651 const gchar
*stock_id
,
652 const gchar
*tooltip
,
653 ErrorResponse response_id
)
658 image
= gtk_image_new_from_stock (stock_id
, GTK_ICON_SIZE_BUTTON
);
659 button
= gtk_button_new ();
660 gtk_button_set_image (GTK_BUTTON (button
), image
);
661 gtk_widget_set_tooltip_text (button
, tooltip
);
662 gtk_widget_show (button
);
664 gtk_info_bar_add_action_widget (info_bar
, button
, response_id
);
669 uoa_account_display_string (TpAccount
*account
)
671 const gchar
*service
;
673 service
= tp_account_get_service (account
);
675 /* Use well known service name, if available */
676 if (!tp_strdiff (service
, "windows-live"))
677 return _("Windows Live");
678 else if (!tp_strdiff (service
, "google-talk"))
679 return _("Google Talk");
680 else if (!tp_strdiff (service
, "facebook"))
681 return _("Facebook");
683 return tp_account_get_display_name (account
);
687 roster_window_uoa_auth_error (EmpathyRosterWindow
*self
,
695 /* translators: %s is an account name like 'Facebook' or 'Google Talk' */
696 str
= g_strdup_printf (_("%s account requires authorisation"),
697 uoa_account_display_string (account
));
699 info_bar
= roster_window_error_create_info_bar (self
, account
,
700 GTK_MESSAGE_OTHER
, str
);
703 image
= gtk_image_new_from_icon_name ("credentials-preferences",
704 GTK_ICON_SIZE_BUTTON
);
705 button
= gtk_button_new ();
706 gtk_button_set_image (GTK_BUTTON (button
), image
);
707 gtk_widget_set_tooltip_text (button
, _("Online Accounts"));
708 gtk_widget_show (button
);
710 gtk_info_bar_add_action_widget (GTK_INFO_BAR (info_bar
), button
,
711 ERROR_RESPONSE_EDIT
);
716 roster_window_error_display (EmpathyRosterWindow
*self
,
719 const gchar
*error_message
;
720 gboolean user_requested
;
725 empathy_account_get_error_message (account
, &user_requested
);
731 if (!tp_strdiff (TP_ERROR_STR_AUTHENTICATION_FAILED
,
732 tp_account_get_detailed_error (account
, NULL
)) &&
733 !tp_strdiff (tp_account_get_storage_provider (account
),
734 EMPATHY_UOA_PROVIDER
))
736 roster_window_uoa_auth_error (self
, account
);
741 str
= g_markup_printf_escaped ("<b>%s</b>\n%s",
742 tp_account_get_display_name (account
), error_message
);
744 info_bar
= roster_window_error_create_info_bar (self
, account
,
745 GTK_MESSAGE_ERROR
, str
);
748 gtk_widget_set_tooltip_text (self
->priv
->errors_vbox
, error_message
);
750 if (!tp_strdiff (TP_ERROR_STR_SOFTWARE_UPGRADE_REQUIRED
,
751 tp_account_get_detailed_error (account
, NULL
)))
753 roster_window_error_add_stock_button (GTK_INFO_BAR (info_bar
),
754 GTK_STOCK_REFRESH
, _("Update software…"),
755 ERROR_RESPONSE_RETRY
);
759 roster_window_error_add_stock_button (GTK_INFO_BAR (info_bar
),
760 GTK_STOCK_REFRESH
, _("Reconnect"),
761 ERROR_RESPONSE_RETRY
);
763 roster_window_error_add_stock_button (GTK_INFO_BAR (info_bar
),
764 GTK_STOCK_EDIT
, _("Edit Account"),
765 ERROR_RESPONSE_EDIT
);
768 roster_window_error_add_stock_button (GTK_INFO_BAR (info_bar
),
769 GTK_STOCK_CLOSE
, _("Close"),
770 ERROR_RESPONSE_CLOSE
);
774 roster_window_update_status (EmpathyRosterWindow
*self
)
776 gboolean connected
, connecting
;
780 connected
= empathy_account_manager_get_accounts_connected (&connecting
);
782 /* Update the spinner state */
785 gtk_spinner_start (GTK_SPINNER (self
->priv
->throbber
));
786 gtk_widget_show (self
->priv
->throbber
);
790 gtk_spinner_stop (GTK_SPINNER (self
->priv
->throbber
));
791 gtk_widget_hide (self
->priv
->throbber
);
794 /* Update widgets sensibility */
795 for (l
= self
->priv
->actions_connected
; l
; l
= l
->next
)
796 g_simple_action_set_enabled (l
->data
, connected
);
798 action
= g_action_map_lookup_action (G_ACTION_MAP (self
), "chat-add-contact");
799 if (!can_add_contact (self
))
800 g_simple_action_set_enabled (G_SIMPLE_ACTION (action
), FALSE
);
804 roster_window_balance_update_balance (EmpathyRosterWindow
*self
,
810 guint scale
= G_MAXINT32
;
811 const gchar
*currency
= "";
814 conn
= tp_account_get_connection (account
);
818 if (!tp_connection_get_balance (conn
, &amount
, &scale
, ¤cy
))
822 scale
== G_MAXINT32
&&
823 tp_str_empty (currency
))
825 /* unknown balance */
826 money
= g_strdup ("--");
830 char *tmp
= empathy_format_currency (amount
, scale
, currency
);
832 money
= g_strdup_printf ("%s %s", currency
, tmp
);
836 /* update the money label in the roster */
837 label
= g_object_get_data (G_OBJECT (account
), "balance-money-label");
839 gtk_label_set_text (GTK_LABEL (label
), money
);
844 roster_window_balance_changed_cb (TpConnection
*conn
,
847 const gchar
*currency
,
848 EmpathyRosterWindow
*self
)
852 account
= tp_connection_get_account (conn
);
856 roster_window_balance_update_balance (self
, account
);
860 roster_window_setup_balance (EmpathyRosterWindow
*self
,
863 TpConnection
*conn
= tp_account_get_connection (account
);
864 GtkWidget
*hbox
, *image
, *label
;
870 if (!tp_proxy_is_prepared (conn
, TP_CONNECTION_FEATURE_BALANCE
))
873 DEBUG ("Setting up balance for acct: %s",
874 tp_account_get_display_name (account
));
876 /* create the display widget */
877 hbox
= gtk_box_new (GTK_ORIENTATION_HORIZONTAL
, 3);
878 gtk_container_set_border_width (GTK_CONTAINER (hbox
), 3);
881 image
= gtk_image_new ();
882 gtk_container_add (GTK_CONTAINER (hbox
), image
);
883 g_object_bind_property (account
, "icon-name", image
, "icon-name",
884 G_BINDING_SYNC_CREATE
);
886 /* account name label */
887 label
= gtk_label_new ("");
888 gtk_misc_set_alignment (GTK_MISC (label
), 0.0, 0.5);
889 gtk_label_set_ellipsize (GTK_LABEL (label
), PANGO_ELLIPSIZE_END
);
890 gtk_container_add (GTK_CONTAINER (hbox
), label
);
891 g_object_bind_property (account
, "display-name", label
, "label",
892 G_BINDING_SYNC_CREATE
);
895 label
= gtk_label_new ("");
896 gtk_misc_set_alignment (GTK_MISC (label
), 0.0, 0.5);
897 gtk_container_add (GTK_CONTAINER (hbox
), label
);
900 uri
= tp_connection_get_balance_uri (conn
);
902 if (!tp_str_empty (uri
))
906 button
= gtk_button_new ();
907 gtk_container_add (GTK_CONTAINER (button
),
908 gtk_image_new_from_icon_name ("emblem-symbolic-link",
909 GTK_ICON_SIZE_SMALL_TOOLBAR
));
910 gtk_button_set_relief (GTK_BUTTON (button
), GTK_RELIEF_NONE
);
911 gtk_widget_set_tooltip_text (button
, _("Top up account"));
912 gtk_container_add (GTK_CONTAINER (hbox
), button
);
914 g_signal_connect_data (button
, "clicked",
915 G_CALLBACK (empathy_url_show
),
916 g_strdup (uri
), (GClosureNotify
) g_free
,
920 gtk_container_add (GTK_CONTAINER (self
->priv
->balance_vbox
), hbox
);
921 gtk_widget_show_all (hbox
);
923 g_object_set_data (G_OBJECT (account
), "balance-money-label", label
);
924 g_object_set_data (G_OBJECT (account
), "balance-money-hbox", hbox
);
926 roster_window_balance_update_balance (self
, account
);
928 g_signal_connect (conn
, "balance-changed",
929 G_CALLBACK (roster_window_balance_changed_cb
), self
);
933 roster_window_remove_balance_action (EmpathyRosterWindow
*self
,
937 g_object_get_data (G_OBJECT (account
), "balance-money-hbox");
942 g_return_if_fail (GTK_IS_BOX (hbox
));
944 gtk_widget_destroy (hbox
);
947 static void set_notebook_page (EmpathyRosterWindow
*self
);
950 roster_window_connection_changed_cb (TpAccount
*account
,
954 gchar
*dbus_error_name
,
956 EmpathyRosterWindow
*self
)
958 roster_window_update_status (self
);
959 set_notebook_page (self
);
961 if (current
== TP_CONNECTION_STATUS_DISCONNECTED
&&
962 reason
!= TP_CONNECTION_STATUS_REASON_REQUESTED
)
964 roster_window_error_display (self
, account
);
967 if (current
== TP_CONNECTION_STATUS_DISCONNECTED
)
969 empathy_sound_manager_play (self
->priv
->sound_mgr
, GTK_WIDGET (self
),
970 EMPATHY_SOUND_ACCOUNT_DISCONNECTED
);
973 if (current
== TP_CONNECTION_STATUS_CONNECTED
)
975 empathy_sound_manager_play (self
->priv
->sound_mgr
, GTK_WIDGET (self
),
976 EMPATHY_SOUND_ACCOUNT_CONNECTED
);
978 /* Account connected without error, remove error message if any */
979 roster_window_remove_error (self
, account
);
984 roster_window_accels_load (void)
988 filename
= g_build_filename (g_get_user_config_dir (),
989 PACKAGE_NAME
, ACCELS_FILENAME
, NULL
);
990 if (g_file_test (filename
, G_FILE_TEST_EXISTS
))
992 DEBUG ("Loading from:'%s'", filename
);
993 gtk_accel_map_load (filename
);
1000 roster_window_accels_save (void)
1003 gchar
*file_with_path
;
1005 dir
= g_build_filename (g_get_user_config_dir (), PACKAGE_NAME
, NULL
);
1006 g_mkdir_with_parents (dir
, S_IRUSR
| S_IWUSR
| S_IXUSR
);
1007 file_with_path
= g_build_filename (dir
, ACCELS_FILENAME
, NULL
);
1010 DEBUG ("Saving to:'%s'", file_with_path
);
1011 gtk_accel_map_save (file_with_path
);
1013 g_free (file_with_path
);
1017 empathy_roster_window_finalize (GObject
*window
)
1019 EmpathyRosterWindow
*self
= EMPATHY_ROSTER_WINDOW (window
);
1020 GHashTableIter iter
;
1021 gpointer key
, value
;
1023 /* Save user-defined accelerators. */
1024 roster_window_accels_save ();
1026 g_list_free (self
->priv
->actions_connected
);
1028 g_object_unref (self
->priv
->account_manager
);
1029 g_object_unref (self
->priv
->sound_mgr
);
1030 g_hash_table_unref (self
->priv
->errors
);
1031 g_hash_table_unref (self
->priv
->auths
);
1033 /* disconnect all handlers of status-changed signal */
1034 g_hash_table_iter_init (&iter
, self
->priv
->status_changed_handlers
);
1035 while (g_hash_table_iter_next (&iter
, &key
, &value
))
1036 g_signal_handler_disconnect (TP_ACCOUNT (key
), GPOINTER_TO_UINT (value
));
1038 g_hash_table_unref (self
->priv
->status_changed_handlers
);
1040 g_object_unref (self
->priv
->call_observer
);
1041 g_object_unref (self
->priv
->event_manager
);
1042 g_object_unref (self
->priv
->chat_manager
);
1043 g_object_unref (self
->priv
->theme_manager
);
1044 g_object_unref (self
->priv
->chatroom_manager
);
1046 g_object_unref (self
->priv
->gsettings_ui
);
1047 g_object_unref (self
->priv
->individual_manager
);
1049 g_object_unref (self
->priv
->menumodel
);
1050 g_object_unref (self
->priv
->rooms_section
);
1052 g_clear_object (&self
->priv
->tooltip_widget
);
1054 G_OBJECT_CLASS (empathy_roster_window_parent_class
)->finalize (window
);
1058 roster_window_key_press_event_cb (GtkWidget
*window
,
1060 EmpathyRosterWindow
*self
)
1062 if (event
->keyval
== GDK_KEY_T
1063 && event
->state
& GDK_SHIFT_MASK
1064 && event
->state
& GDK_CONTROL_MASK
)
1065 empathy_chat_manager_call_undo_closed_chat ();
1067 if (event
->keyval
== GDK_KEY_f
1068 && event
->state
& GDK_CONTROL_MASK
)
1069 gtk_widget_show (self
->priv
->search_bar
);
1075 unprepare_cb (GObject
*source
,
1076 GAsyncResult
*result
,
1079 GtkWidget
*self
= user_data
;
1081 gtk_widget_destroy (self
);
1085 roster_window_chat_quit_cb (GSimpleAction
*action
,
1086 GVariant
*parameter
,
1089 EmpathyRosterWindow
*self
= user_data
;
1091 /* Destroying the window will make us leave the main loop and so exit the
1092 * process. Before doing so we want to unprepare the individual manager.
1093 * Just hide the window now and actually destroy it once Folks is done.
1095 gtk_widget_hide (GTK_WIDGET (self
));
1097 empathy_individual_manager_unprepare_async (self
->priv
->individual_manager
,
1098 unprepare_cb
, self
);
1102 roster_window_view_history_cb (GSimpleAction
*action
,
1103 GVariant
*parameter
,
1106 EmpathyRosterWindow
*self
= user_data
;
1108 empathy_log_window_show (NULL
, NULL
, FALSE
, GTK_WINDOW (self
));
1112 roster_window_chat_new_message_cb (GSimpleAction
*action
,
1113 GVariant
*parameter
,
1116 EmpathyRosterWindow
*self
= user_data
;
1118 empathy_new_message_dialog_show (GTK_WINDOW (self
));
1122 roster_window_chat_new_call_cb (GSimpleAction
*action
,
1123 GVariant
*parameter
,
1126 EmpathyRosterWindow
*self
= user_data
;
1128 empathy_new_call_dialog_show (GTK_WINDOW (self
));
1132 roster_window_chat_add_contact_cb (GSimpleAction
*action
,
1133 GVariant
*parameter
,
1136 EmpathyRosterWindow
*self
= user_data
;
1138 empathy_new_individual_dialog_show (GTK_WINDOW (self
));
1142 roster_window_chat_search_contacts_cb (GSimpleAction
*action
,
1143 GVariant
*parameter
,
1146 EmpathyRosterWindow
*self
= user_data
;
1149 dialog
= empathy_contact_search_dialog_new (
1152 gtk_widget_show (dialog
);
1156 roster_window_view_show_ft_manager (GSimpleAction
*action
,
1157 GVariant
*parameter
,
1160 empathy_ft_manager_show ();
1164 join_chatroom (EmpathyChatroom
*chatroom
,
1170 account
= empathy_chatroom_get_account (chatroom
);
1171 room
= empathy_chatroom_get_room (chatroom
);
1173 DEBUG ("Requesting channel for '%s'", room
);
1174 empathy_join_muc (account
, room
, timestamp
);
1180 EmpathyChatroom
*chatroom
;
1184 } join_fav_account_sig_ctx
;
1186 static join_fav_account_sig_ctx
*
1187 join_fav_account_sig_ctx_new (TpAccount
*account
,
1188 EmpathyChatroom
*chatroom
,
1191 join_fav_account_sig_ctx
*ctx
= g_slice_new0 (
1192 join_fav_account_sig_ctx
);
1194 ctx
->account
= g_object_ref (account
);
1195 ctx
->chatroom
= g_object_ref (chatroom
);
1196 ctx
->timestamp
= timestamp
;
1201 join_fav_account_sig_ctx_free (join_fav_account_sig_ctx
*ctx
)
1203 g_object_unref (ctx
->account
);
1204 g_object_unref (ctx
->chatroom
);
1205 g_slice_free (join_fav_account_sig_ctx
, ctx
);
1209 account_status_changed_cb (TpAccount
*account
,
1210 TpConnectionStatus old_status
,
1211 TpConnectionStatus new_status
,
1213 gchar
*dbus_error_name
,
1214 GHashTable
*details
,
1217 join_fav_account_sig_ctx
*ctx
= user_data
;
1221 case TP_CONNECTION_STATUS_DISCONNECTED
:
1222 /* Don't wait any longer */
1226 case TP_CONNECTION_STATUS_CONNECTING
:
1230 case TP_CONNECTION_STATUS_CONNECTED
:
1231 /* We can join the room */
1235 g_assert_not_reached ();
1238 join_chatroom (ctx
->chatroom
, ctx
->timestamp
);
1241 g_source_remove (ctx
->timeout
);
1242 g_signal_handler_disconnect (account
, ctx
->sig_id
);
1245 #define JOIN_FAVORITE_TIMEOUT 5
1248 join_favorite_timeout_cb (gpointer data
)
1250 join_fav_account_sig_ctx
*ctx
= data
;
1252 /* stop waiting for joining the favorite room */
1253 g_signal_handler_disconnect (ctx
->account
, ctx
->sig_id
);
1258 roster_window_favorite_chatroom_join (EmpathyChatroom
*chatroom
)
1262 account
= empathy_chatroom_get_account (chatroom
);
1263 if (tp_account_get_connection_status (account
, NULL
) !=
1264 TP_CONNECTION_STATUS_CONNECTED
)
1266 join_fav_account_sig_ctx
*ctx
;
1268 ctx
= join_fav_account_sig_ctx_new (account
, chatroom
,
1269 empathy_get_current_action_time ());
1271 ctx
->sig_id
= g_signal_connect_data (account
, "status-changed",
1272 G_CALLBACK (account_status_changed_cb
), ctx
,
1273 (GClosureNotify
) join_fav_account_sig_ctx_free
, 0);
1275 ctx
->timeout
= g_timeout_add_seconds (JOIN_FAVORITE_TIMEOUT
,
1276 join_favorite_timeout_cb
, ctx
);
1280 join_chatroom (chatroom
, empathy_get_current_action_time ());
1284 roster_window_join_chatroom_menu_activate_cb (GSimpleAction
*action
,
1285 GVariant
*parameter
,
1288 EmpathyRosterWindow
*self
= user_data
;
1289 const gchar
*room
, *path
;
1290 EmpathyClientFactory
*factory
;
1292 GError
*error
= NULL
;
1293 EmpathyChatroom
*chatroom
;
1295 g_variant_get (parameter
, "(&s&s)", &room
, &path
);
1297 factory
= empathy_client_factory_dup ();
1299 account
= tp_simple_client_factory_ensure_account (
1300 TP_SIMPLE_CLIENT_FACTORY (factory
), path
, NULL
, &error
);
1301 if (account
== NULL
)
1303 DEBUG ("Failed to get account '%s': %s", path
, error
->message
);
1304 g_error_free (error
);
1308 chatroom
= empathy_chatroom_manager_find (self
->priv
->chatroom_manager
,
1310 if (chatroom
== NULL
)
1312 DEBUG ("Failed to get chatroom '%s' on '%s'",
1317 roster_window_favorite_chatroom_join (chatroom
);
1320 g_object_unref (factory
);
1324 roster_window_favorite_chatroom_menu_add (EmpathyRosterWindow
*self
,
1325 EmpathyChatroom
*chatroom
)
1328 const gchar
*name
, *account_name
, *account_path
;
1332 account
= empathy_chatroom_get_account (chatroom
);
1334 name
= empathy_chatroom_get_name (chatroom
);
1335 account_name
= tp_account_get_display_name (account
);
1336 account_path
= tp_proxy_get_object_path (account
);
1338 label
= g_strdup_printf ("%s (%s)", name
, account_name
);
1340 item
= g_menu_item_new (label
, NULL
);
1341 g_menu_item_set_action_and_target (item
, "win.join", "(ss)",
1342 name
, account_path
);
1343 g_menu_item_set_attribute (item
, "room-name", "s", name
);
1344 g_menu_item_set_attribute (item
, "account-path", "s", account_path
);
1345 g_menu_append_item (self
->priv
->rooms_section
, item
);
1351 roster_window_favorite_chatroom_menu_added_cb (EmpathyChatroomManager
*manager
,
1352 EmpathyChatroom
*chatroom
,
1353 EmpathyRosterWindow
*self
)
1355 roster_window_favorite_chatroom_menu_add (self
, chatroom
);
1359 roster_window_favorite_chatroom_menu_removed_cb (
1360 EmpathyChatroomManager
*manager
,
1361 EmpathyChatroom
*chatroom
,
1362 EmpathyRosterWindow
*self
)
1367 const gchar
*account_path
;
1369 account
= empathy_chatroom_get_account (chatroom
);
1370 account_path
= tp_proxy_get_object_path (account
);
1372 n
= g_menu_model_get_n_items (G_MENU_MODEL (self
->priv
->rooms_section
));
1374 for (i
= 0; i
< n
; i
++)
1378 if (!g_menu_model_get_item_attribute (
1379 G_MENU_MODEL (self
->priv
->rooms_section
), i
,
1380 "room-name", "s", &tmp
))
1383 if (tp_strdiff (tmp
, empathy_chatroom_get_name (chatroom
)))
1391 if (!g_menu_model_get_item_attribute (
1392 G_MENU_MODEL (self
->priv
->rooms_section
), i
,
1393 "account-path", "s", &tmp
))
1396 if (tp_strdiff (tmp
, account_path
))
1402 g_menu_remove (self
->priv
->rooms_section
, i
);
1407 chatrooms
= empathy_chatroom_manager_get_chatrooms (
1408 self
->priv
->chatroom_manager
, NULL
);
1410 g_list_free (chatrooms
);
1414 roster_window_favorite_chatroom_menu_setup (EmpathyRosterWindow
*self
)
1416 GList
*chatrooms
, *l
;
1418 self
->priv
->chatroom_manager
= empathy_chatroom_manager_dup_singleton (NULL
);
1420 chatrooms
= empathy_chatroom_manager_get_chatrooms (
1421 self
->priv
->chatroom_manager
, NULL
);
1423 for (l
= chatrooms
; l
; l
= l
->next
)
1424 roster_window_favorite_chatroom_menu_add (self
, l
->data
);
1426 g_signal_connect (self
->priv
->chatroom_manager
, "chatroom-added",
1427 G_CALLBACK (roster_window_favorite_chatroom_menu_added_cb
),
1430 g_signal_connect (self
->priv
->chatroom_manager
, "chatroom-removed",
1431 G_CALLBACK (roster_window_favorite_chatroom_menu_removed_cb
),
1434 g_list_free (chatrooms
);
1438 roster_window_room_join_new_cb (GSimpleAction
*action
,
1439 GVariant
*parameter
,
1442 EmpathyRosterWindow
*self
= user_data
;
1444 empathy_new_chatroom_dialog_show (GTK_WINDOW (self
));
1448 roster_window_room_join_favorites_cb (GSimpleAction
*action
,
1449 GVariant
*parameter
,
1452 EmpathyRosterWindow
*self
= user_data
;
1453 GList
*chatrooms
, *l
;
1455 chatrooms
= empathy_chatroom_manager_get_chatrooms (self
->priv
->chatroom_manager
,
1458 for (l
= chatrooms
; l
; l
= l
->next
)
1459 roster_window_favorite_chatroom_join (l
->data
);
1461 g_list_free (chatrooms
);
1465 roster_window_room_manage_favorites_cb (GSimpleAction
*action
,
1466 GVariant
*parameter
,
1469 EmpathyRosterWindow
*self
= user_data
;
1471 empathy_chatrooms_window_show (GTK_WINDOW (self
));
1475 roster_window_edit_accounts_cb (GSimpleAction
*action
,
1476 GVariant
*parameter
,
1479 empathy_accounts_dialog_show_application (gdk_screen_get_default (),
1480 NULL
, FALSE
, FALSE
);
1484 roster_window_edit_blocked_contacts_cb (GSimpleAction
*action
,
1485 GVariant
*parameter
,
1488 EmpathyRosterWindow
*self
= user_data
;
1491 dialog
= empathy_contact_blocking_dialog_new (GTK_WINDOW (self
));
1492 gtk_widget_show (dialog
);
1494 g_signal_connect (dialog
, "response",
1495 G_CALLBACK (gtk_widget_destroy
), NULL
);
1499 empathy_roster_window_show_preferences (EmpathyRosterWindow
*self
,
1502 if (self
->priv
->preferences
== NULL
)
1504 self
->priv
->preferences
= empathy_preferences_new (GTK_WINDOW (self
),
1505 self
->priv
->shell_running
);
1506 g_object_add_weak_pointer (G_OBJECT (self
->priv
->preferences
),
1507 (gpointer
) &self
->priv
->preferences
);
1509 gtk_widget_show (self
->priv
->preferences
);
1513 gtk_window_present (GTK_WINDOW (self
->priv
->preferences
));
1517 empathy_preferences_show_tab (
1518 EMPATHY_PREFERENCES (self
->priv
->preferences
), tab
);
1522 roster_window_edit_preferences_cb (GSimpleAction
*action
,
1523 GVariant
*parameter
,
1526 EmpathyRosterWindow
*self
= user_data
;
1528 empathy_roster_window_show_preferences (self
, NULL
);
1532 roster_window_help_about_cb (GSimpleAction
*action
,
1533 GVariant
*parameter
,
1536 EmpathyRosterWindow
*self
= user_data
;
1538 empathy_about_dialog_new (GTK_WINDOW (self
));
1542 roster_window_help_contents_cb (GSimpleAction
*action
,
1543 GVariant
*parameter
,
1546 EmpathyRosterWindow
*self
= user_data
;
1548 empathy_url_show (GTK_WIDGET (self
), "help:empathy");
1552 next_tab_cb (GSimpleAction
*action
,
1553 GVariant
*parameter
,
1556 EmpathyRosterWindow
*self
= user_data
;
1557 empathy_chat_window_next_tab (EMPATHY_CHAT_WINDOW (self
->priv
->chat_window
));
1561 prev_tab_cb (GSimpleAction
*action
,
1562 GVariant
*parameter
,
1565 EmpathyRosterWindow
*self
= user_data
;
1566 empathy_chat_window_prev_tab (EMPATHY_CHAT_WINDOW (self
->priv
->chat_window
));
1571 roster_window_throbber_button_press_event_cb (GtkWidget
*throbber
,
1572 GdkEventButton
*event
,
1573 EmpathyRosterWindow
*self
)
1575 if (event
->type
!= GDK_BUTTON_PRESS
||
1579 empathy_accounts_dialog_show_application (
1580 gtk_widget_get_screen (GTK_WIDGET (throbber
)),
1581 NULL
, FALSE
, FALSE
);
1587 roster_window_account_removed_cb (TpAccountManager
*manager
,
1589 EmpathyRosterWindow
*self
)
1591 /* remove errors if any */
1592 roster_window_remove_error (self
, account
);
1594 /* remove the balance action if required */
1595 roster_window_remove_balance_action (self
, account
);
1599 account_connection_notify_cb (TpAccount
*account
,
1601 EmpathyRosterWindow
*self
)
1605 conn
= tp_account_get_connection (account
);
1609 roster_window_setup_balance (self
, account
);
1613 /* remove balance action if required */
1614 roster_window_remove_balance_action (self
, account
);
1619 add_account (EmpathyRosterWindow
*self
,
1624 handler_id
= GPOINTER_TO_UINT (g_hash_table_lookup (
1625 self
->priv
->status_changed_handlers
, account
));
1627 /* connect signal only if it was not connected yet */
1628 if (handler_id
!= 0)
1631 handler_id
= g_signal_connect (account
, "status-changed",
1632 G_CALLBACK (roster_window_connection_changed_cb
), self
);
1634 g_hash_table_insert (self
->priv
->status_changed_handlers
,
1635 account
, GUINT_TO_POINTER (handler_id
));
1637 /* roster_window_setup_balance() relies on the TpConnection to be ready on
1638 * the TpAccount so we connect this signal as well. */
1639 tp_g_signal_connect_object (account
, "notify::connection",
1640 G_CALLBACK (account_connection_notify_cb
), self
, 0);
1642 roster_window_setup_balance (self
, account
);
1645 /* @account: if not %NULL, the only account which can be enabled */
1647 display_page_account_not_enabled (EmpathyRosterWindow
*self
,
1650 if (account
== NULL
)
1652 display_page_message (self
,
1653 _("You need to enable one of your accounts to see contacts here."),
1654 PAGE_MESSAGE_FLAG_ACCOUNTS
);
1660 /* translators: argument is an account name */
1661 tmp
= g_strdup_printf (_("You need to enable %s to see contacts here."),
1662 tp_account_get_display_name (account
));
1664 display_page_message (self
, tmp
, PAGE_MESSAGE_FLAG_ACCOUNTS
);
1669 has_enabled_account (GList
*accounts
)
1673 for (l
= accounts
; l
!= NULL
; l
= g_list_next (l
))
1675 TpAccount
*account
= l
->data
;
1677 if (tp_account_is_enabled (account
))
1685 set_notebook_page (EmpathyRosterWindow
*self
)
1689 TpConnectionPresenceType presence
;
1690 gboolean connected
, connecting
;
1692 connected
= empathy_account_manager_get_accounts_connected (&connecting
);
1694 /* Display the loading page if either:
1695 * - We are fetching contacts from Folks (startup)
1696 * - There is no account connected but at least one is connecting
1698 if (!empathy_individual_manager_get_contacts_loaded (
1699 self
->priv
->individual_manager
) ||
1700 (!connected
&& connecting
))
1702 display_page_message (self
, NULL
, PAGE_MESSAGE_FLAG_SPINNER
);
1703 gtk_spinner_start (GTK_SPINNER (self
->priv
->spinner_loading
));
1707 gtk_spinner_stop (GTK_SPINNER (self
->priv
->spinner_loading
));
1709 accounts
= tp_account_manager_dup_valid_accounts (
1710 self
->priv
->account_manager
);
1712 len
= g_list_length (accounts
);
1717 display_page_no_account (self
);
1721 if (!has_enabled_account (accounts
))
1723 TpAccount
*account
= NULL
;
1725 /* Pass the account if there is only one which can be enabled */
1727 account
= accounts
->data
;
1729 display_page_account_not_enabled (self
, account
);
1733 presence
= tp_account_manager_get_most_available_presence (
1734 self
->priv
->account_manager
, NULL
, NULL
);
1736 if (presence
== TP_CONNECTION_PRESENCE_TYPE_OFFLINE
)
1738 // This message shows up always. WTF telepathy?
1739 // display_page_message (self,
1740 // _("Change your presence to see contacts here"),
1741 // PAGE_MESSAGE_FLAG_ONLINE);
1745 if (empathy_roster_view_is_empty (self
->priv
->view
))
1747 if (empathy_roster_view_is_searching (self
->priv
->view
))
1749 display_page_message (self
, _("No match found"),
1750 PAGE_MESSAGE_FLAG_NONE
);
1754 if (g_settings_get_boolean (self
->priv
->gsettings_ui
,
1755 EMPATHY_PREFS_UI_SHOW_OFFLINE
))
1756 display_page_message (self
, _("You haven’t added any contacts yet"),
1757 PAGE_MESSAGE_FLAG_ADD_CONTACT
);
1759 display_page_message (self
, _("No online contacts"),
1760 PAGE_MESSAGE_FLAG_SHOW_OFFLINE
);
1765 display_page_contact_list (self
);
1768 g_list_free_full (accounts
, g_object_unref
);
1772 roster_window_account_validity_changed_cb (TpAccountManager
*manager
,
1775 EmpathyRosterWindow
*self
)
1778 add_account (self
, account
);
1780 roster_window_account_removed_cb (manager
, account
, self
);
1782 set_notebook_page (self
);
1786 roster_window_connection_items_setup (EmpathyRosterWindow
*self
)
1789 const gchar
*actions_connected
[] = {
1791 "room-join-favorites",
1794 "chat-search-contacts",
1796 "edit-blocked-contacts",
1799 for (i
= 0; i
< G_N_ELEMENTS (actions_connected
); i
++)
1803 action
= g_action_map_lookup_action (G_ACTION_MAP (self
),
1804 actions_connected
[i
]);
1806 self
->priv
->actions_connected
= g_list_prepend (
1807 self
->priv
->actions_connected
, action
);
1812 account_enabled_cb (TpAccountManager
*manager
,
1814 EmpathyRosterWindow
*self
)
1816 set_notebook_page (self
);
1820 account_disabled_cb (TpAccountManager
*manager
,
1822 EmpathyRosterWindow
*self
)
1824 set_notebook_page (self
);
1828 account_removed_cb (TpAccountManager
*manager
,
1830 EmpathyRosterWindow
*self
)
1832 set_notebook_page (self
);
1836 account_manager_prepared_cb (GObject
*source_object
,
1837 GAsyncResult
*result
,
1840 GList
*accounts
, *j
;
1841 TpAccountManager
*manager
= TP_ACCOUNT_MANAGER (source_object
);
1842 EmpathyRosterWindow
*self
= user_data
;
1843 GError
*error
= NULL
;
1845 if (!tp_proxy_prepare_finish (manager
, result
, &error
))
1847 DEBUG ("Failed to prepare account manager: %s", error
->message
);
1848 g_error_free (error
);
1852 accounts
= tp_account_manager_dup_valid_accounts (
1853 self
->priv
->account_manager
);
1854 for (j
= accounts
; j
!= NULL
; j
= j
->next
)
1856 TpAccount
*account
= TP_ACCOUNT (j
->data
);
1858 add_account (self
, account
);
1861 g_signal_connect (manager
, "account-validity-changed",
1862 G_CALLBACK (roster_window_account_validity_changed_cb
), self
);
1863 tp_g_signal_connect_object (manager
, "account-removed",
1864 G_CALLBACK (account_removed_cb
), self
, 0);
1865 tp_g_signal_connect_object (manager
, "account-disabled",
1866 G_CALLBACK (account_disabled_cb
), self
, 0);
1867 tp_g_signal_connect_object (manager
, "account-enabled",
1868 G_CALLBACK (account_enabled_cb
), self
, 0);
1870 roster_window_update_status (self
);
1872 set_notebook_page (self
);
1874 g_list_free_full (accounts
, g_object_unref
);
1878 empathy_roster_window_set_shell_running (EmpathyRosterWindow
*self
,
1879 gboolean shell_running
)
1881 if (self
->priv
->shell_running
== shell_running
)
1884 self
->priv
->shell_running
= shell_running
;
1885 g_object_notify (G_OBJECT (self
), "shell-running");
1889 empathy_roster_window_constructor (GType type
,
1890 guint n_construct_params
,
1891 GObjectConstructParam
*construct_params
)
1893 static GObject
*window
= NULL
;
1896 return g_object_ref (window
);
1898 window
= G_OBJECT_CLASS (empathy_roster_window_parent_class
)->constructor (
1899 type
, n_construct_params
, construct_params
);
1901 g_object_add_weak_pointer (window
, (gpointer
) &window
);
1906 static GActionEntry menubar_entries
[] = {
1907 {"chat-new-message", roster_window_chat_new_message_cb
},
1908 {"chat-new-call", roster_window_chat_new_call_cb
},
1909 {"chat-add-contact", roster_window_chat_add_contact_cb
},
1910 {"chat-search-contacts", roster_window_chat_search_contacts_cb
},
1911 {"chat-quit", roster_window_chat_quit_cb
},
1913 {"edit-accounts", roster_window_edit_accounts_cb
},
1914 {"edit-blocked-contacts", roster_window_edit_blocked_contacts_cb
},
1915 {"edit-preferences", roster_window_edit_preferences_cb
},
1917 {"view-history", roster_window_view_history_cb
},
1918 {"view-show-ft-manager", roster_window_view_show_ft_manager
},
1920 {"room-join-new", roster_window_room_join_new_cb
},
1921 {"room-join-favorites", roster_window_room_join_favorites_cb
},
1922 {"join", roster_window_join_chatroom_menu_activate_cb
, "(ss)"},
1923 {"room-manage-favorites", roster_window_room_manage_favorites_cb
},
1925 {"help-contents", roster_window_help_contents_cb
},
1926 {"help-about", roster_window_help_about_cb
},
1929 static GActionEntry app_entries
[] =
1931 { "tab-next", next_tab_cb
},
1932 { "tab-prev", prev_tab_cb
}
1937 empathy_roster_window_set_property (GObject
*object
,
1939 const GValue
*value
,
1942 EmpathyRosterWindow
*self
= EMPATHY_ROSTER_WINDOW (object
);
1944 switch (property_id
)
1946 case PROP_SHELL_RUNNING
:
1947 self
->priv
->shell_running
= g_value_get_boolean (value
);
1950 G_OBJECT_WARN_INVALID_PROPERTY_ID (object
, property_id
, pspec
);
1956 empathy_roster_window_get_property (GObject
*object
,
1961 EmpathyRosterWindow
*self
= EMPATHY_ROSTER_WINDOW (object
);
1963 switch (property_id
)
1965 case PROP_SHELL_RUNNING
:
1966 g_value_set_boolean (value
, self
->priv
->shell_running
);
1969 G_OBJECT_WARN_INVALID_PROPERTY_ID (object
, property_id
, pspec
);
1975 empathy_roster_window_constructed (GObject
*self
)
1977 G_OBJECT_CLASS (empathy_roster_window_parent_class
)->constructed (self
);
1981 empathy_roster_window_class_init (EmpathyRosterWindowClass
*klass
)
1983 GObjectClass
*object_class
= G_OBJECT_CLASS (klass
);
1986 object_class
->finalize
= empathy_roster_window_finalize
;
1987 object_class
->constructor
= empathy_roster_window_constructor
;
1988 object_class
->constructed
= empathy_roster_window_constructed
;
1990 object_class
->set_property
= empathy_roster_window_set_property
;
1991 object_class
->get_property
= empathy_roster_window_get_property
;
1993 pspec
= g_param_spec_boolean ("shell-running",
1995 "Whether the Shell is running or not",
1997 G_PARAM_READWRITE
| G_PARAM_STATIC_STRINGS
);
1998 g_object_class_install_property (object_class
, PROP_SHELL_RUNNING
, pspec
);
2000 g_type_class_add_private (object_class
, sizeof (EmpathyRosterWindowPriv
));
2004 contacts_loaded_cb (EmpathyIndividualManager
*manager
,
2005 EmpathyRosterWindow
*self
)
2007 set_notebook_page (self
);
2011 roster_window_setup_actions (EmpathyRosterWindow
*self
)
2015 #define ADD_GSETTINGS_ACTION(schema, key) \
2016 action = g_settings_create_action (self->priv->gsettings_##schema, \
2017 EMPATHY_PREFS_##key); \
2018 g_action_map_add_action (G_ACTION_MAP (self), action); \
2019 g_object_unref (action);
2021 ADD_GSETTINGS_ACTION (ui
, UI_SHOW_OFFLINE
);
2023 #undef ADD_GSETTINGS_ACTION
2027 menu_deactivate_cb (GtkMenuShell
*menushell
,
2030 /* FIXME: we shouldn't have to disconnect the signal (bgo #641327) */
2031 g_signal_handlers_disconnect_by_func (menushell
,
2032 menu_deactivate_cb
, user_data
);
2034 gtk_menu_detach (GTK_MENU (menushell
));
2038 menu_item_activated_cb (GtkMenuShell
*menushell
,
2041 EmpathyRosterWindow
*roster_window
= EMPATHY_ROSTER_WINDOW (user_data
);
2043 hide_search_bar (roster_window
);
2047 popup_individual_menu_cb (EmpathyRosterView
*view
,
2048 const gchar
*active_group
,
2049 FolksIndividual
*individual
,
2055 EmpathyIndividualFeatureFlags features
= EMPATHY_INDIVIDUAL_FEATURE_CHAT
|
2056 EMPATHY_INDIVIDUAL_FEATURE_CALL
|
2057 EMPATHY_INDIVIDUAL_FEATURE_EDIT
|
2058 EMPATHY_INDIVIDUAL_FEATURE_INFO
|
2059 EMPATHY_INDIVIDUAL_FEATURE_LOG
|
2060 EMPATHY_INDIVIDUAL_FEATURE_SMS
|
2061 EMPATHY_INDIVIDUAL_FEATURE_CALL_PHONE
|
2062 EMPATHY_INDIVIDUAL_FEATURE_REMOVE
|
2063 EMPATHY_INDIVIDUAL_FEATURE_FILE_TRANSFER
;
2065 menu
= empathy_individual_menu_new (individual
, active_group
,
2068 /* menu is initially unowned but gtk_menu_attach_to_widget() takes its
2069 * floating ref. We can either wait for the view to release its ref
2070 * when it is destroyed (when leaving Empathy) or explicitly
2071 * detach the menu when it's not displayed any more.
2072 * We go for the latter as we don't want to keep useless menus in memory
2073 * during the whole lifetime of Empathy. */
2074 g_signal_connect (menu
, "deactivate", G_CALLBACK (menu_deactivate_cb
),
2076 g_signal_connect (menu
, "menu-item-activated",
2077 G_CALLBACK (menu_item_activated_cb
), user_data
);
2079 gtk_menu_attach_to_widget (GTK_MENU (menu
), GTK_WIDGET (view
), NULL
);
2080 gtk_menu_popup (GTK_MENU (menu
), NULL
, NULL
, NULL
, NULL
, button
, time
);
2084 view_empty_cb (EmpathyRosterView
*view
,
2086 EmpathyRosterWindow
*self
)
2088 set_notebook_page (self
);
2090 if (!empathy_roster_view_is_empty (view
))
2092 gtk_widget_grab_focus (GTK_WIDGET (self
->priv
->view
));
2094 /* The store is being filled, it will be done after an idle cb.
2095 * So we can then get events. If we do that too soon, event's
2096 * contact is not yet in the store and it won't get marked as
2098 g_idle_add (roster_window_load_events_idle_cb
, self
);
2103 tooltip_destroy_cb (GtkWidget
*widget
,
2104 EmpathyRosterWindow
*self
)
2106 g_clear_object (&self
->priv
->tooltip_widget
);
2110 individual_tooltip_cb (EmpathyRosterView
*view
,
2111 FolksIndividual
*individual
,
2112 gboolean keyboard_mode
,
2113 GtkTooltip
*tooltip
,
2114 EmpathyRosterWindow
*self
)
2116 if (self
->priv
->tooltip_widget
== NULL
)
2118 self
->priv
->tooltip_widget
= empathy_individual_widget_new (individual
,
2119 EMPATHY_INDIVIDUAL_WIDGET_FOR_TOOLTIP
|
2120 EMPATHY_INDIVIDUAL_WIDGET_SHOW_LOCATION
|
2121 EMPATHY_INDIVIDUAL_WIDGET_SHOW_CLIENT_TYPES
);
2123 gtk_container_set_border_width (
2124 GTK_CONTAINER (self
->priv
->tooltip_widget
), 8);
2126 g_object_ref (self
->priv
->tooltip_widget
);
2128 tp_g_signal_connect_object (self
->priv
->tooltip_widget
, "destroy",
2129 G_CALLBACK (tooltip_destroy_cb
), self
, 0);
2131 gtk_widget_show (self
->priv
->tooltip_widget
);
2135 empathy_individual_widget_set_individual (
2136 EMPATHY_INDIVIDUAL_WIDGET (self
->priv
->tooltip_widget
), individual
);
2139 gtk_tooltip_set_custom (tooltip
, self
->priv
->tooltip_widget
);
2146 DND_DRAG_TYPE_INVALID
= -1,
2147 DND_DRAG_TYPE_URI_LIST
,
2150 #define DRAG_TYPE(T,I) \
2151 { (gchar *) T, 0, I }
2153 static const GtkTargetEntry drag_types_dest
[] = {
2154 DRAG_TYPE ("text/path-list", DND_DRAG_TYPE_URI_LIST
),
2155 DRAG_TYPE ("text/uri-list", DND_DRAG_TYPE_URI_LIST
),
2158 static GdkAtom drag_atoms_dest
[G_N_ELEMENTS (drag_types_dest
)];
2161 get_drag_type (GtkWidget
*widget
,
2162 GdkDragContext
*context
)
2167 target
= gtk_drag_dest_find_target (widget
, context
, NULL
);
2169 for (i
= 0; i
< G_N_ELEMENTS (drag_atoms_dest
); i
++)
2171 if (target
== drag_atoms_dest
[i
])
2172 return drag_types_dest
[i
].info
;
2175 return DND_DRAG_TYPE_INVALID
;
2179 individual_supports_ft (FolksIndividual
*individual
)
2181 EmpathyContact
*contact
;
2182 EmpathyCapabilities caps
;
2185 contact
= empathy_contact_dup_from_folks_individual (individual
);
2186 if (contact
== NULL
)
2189 caps
= empathy_contact_get_capabilities (contact
);
2190 result
= (caps
& EMPATHY_CAPABILITIES_FT
);
2192 g_object_unref (contact
);
2197 view_drag_motion_cb (GtkWidget
*widget
,
2198 GdkDragContext
*context
,
2202 EmpathyRosterWindow
*self
)
2206 type
= get_drag_type (widget
, context
);
2208 if (type
== DND_DRAG_TYPE_URI_LIST
)
2210 /* Check if contact supports FT */
2211 FolksIndividual
*individual
;
2214 individual
= empathy_roster_view_get_individual_at_y (self
->priv
->view
,
2216 if (individual
== NULL
)
2219 if (!individual_supports_ft (individual
))
2222 gtk_list_box_drag_highlight_row (GTK_LIST_BOX (widget
), row
);
2227 gtk_list_box_drag_unhighlight_row (GTK_LIST_BOX (widget
));
2232 view_drag_drop_cb (GtkWidget
*widget
,
2233 GdkDragContext
*context
,
2237 EmpathyRosterWindow
*self
)
2240 FolksIndividual
*individual
;
2242 type
= get_drag_type (widget
, context
);
2243 if (type
== DND_DRAG_TYPE_INVALID
)
2246 individual
= empathy_roster_view_get_individual_at_y (self
->priv
->view
, y
,
2248 if (individual
== NULL
)
2251 if (!individual_supports_ft (individual
))
2254 gtk_drag_get_data (widget
, context
,
2255 gtk_drag_dest_find_target (widget
, context
, NULL
), time_
);
2261 view_drag_data_received_cb (GtkWidget
*widget
,
2262 GdkDragContext
*context
,
2265 GtkSelectionData
*selection
,
2268 EmpathyRosterWindow
*self
)
2270 gboolean success
= FALSE
;
2272 if (selection
== NULL
)
2275 if (info
== DND_DRAG_TYPE_URI_LIST
)
2278 FolksIndividual
*individual
;
2279 EmpathyContact
*contact
;
2281 individual
= empathy_roster_view_get_individual_at_y (self
->priv
->view
,
2283 g_return_if_fail (individual
!= NULL
);
2285 path
= (const gchar
*) gtk_selection_data_get_data (selection
);
2287 contact
= empathy_contact_dup_from_folks_individual (individual
);
2288 empathy_send_file_from_uri_list (contact
, path
);
2290 g_object_unref (contact
);
2296 gtk_drag_finish (context
, success
, FALSE
, time_
);
2300 roster_window_most_available_presence_changed_cb (TpAccountManager
*manager
,
2301 TpConnectionPresenceType presence
,
2302 const gchar
*status
,
2303 const gchar
*message
,
2304 EmpathyRosterWindow
*self
)
2306 set_notebook_page (self
);
2310 empathy_roster_window_init (EmpathyRosterWindow
*self
)
2315 GtkWidget
*header_bar
;
2316 GtkWidget
*new_conversation_button
;
2318 GtkWidget
*chat_vbox
;
2320 EmpathyRosterModel
*model
;
2322 self
->priv
= G_TYPE_INSTANCE_GET_PRIVATE (self
,
2323 EMPATHY_TYPE_ROSTER_WINDOW
, EmpathyRosterWindowPriv
);
2325 empathy_set_css_provider (GTK_WIDGET (self
));
2327 self
->priv
->gsettings_ui
= g_settings_new (EMPATHY_PREFS_UI_SCHEMA
);
2329 self
->priv
->sound_mgr
= empathy_sound_manager_dup_singleton ();
2331 gtk_window_set_title (GTK_WINDOW (self
), _("Contact List"));
2332 gtk_window_set_role (GTK_WINDOW (self
), "contact_list");
2333 gtk_window_set_default_size (GTK_WINDOW (self
), 225, 325);
2335 /* Set up interface */
2336 filename
= empathy_file_lookup ("empathy-roster-window.ui", "src");
2337 gui
= tpaw_builder_get_file (filename
,
2338 "main_vbox", &self
->priv
->main_vbox
,
2339 "chat_vbox", &chat_vbox
,
2340 "balance_vbox", &self
->priv
->balance_vbox
,
2341 "errors_vbox", &self
->priv
->errors_vbox
,
2342 "auth_vbox", &self
->priv
->auth_vbox
,
2343 "presence_toolbar", &self
->priv
->presence_toolbar
,
2344 "notebook", &self
->priv
->notebook
,
2345 "no_entry_label", &self
->priv
->no_entry_label
,
2346 "roster_scrolledwindow", &sw
,
2347 "button_account_settings", &self
->priv
->button_account_settings
,
2348 // "button_online", &self->priv->button_online,
2349 "button_show_offline", &self
->priv
->button_show_offline
,
2350 "button_add_contact", &self
->priv
->button_add_contact
,
2351 "spinner_loading", &self
->priv
->spinner_loading
,
2355 header_bar
= gtk_header_bar_new ();
2356 gtk_header_bar_set_title (GTK_HEADER_BAR(header_bar
), _("Conversations"));
2357 gtk_header_bar_set_show_close_button (GTK_HEADER_BAR(header_bar
), TRUE
);
2359 image
= gtk_image_new_from_icon_name ("list-add-symbolic", GTK_ICON_SIZE_BUTTON
);
2360 new_conversation_button
= gtk_button_new ();
2361 g_signal_connect (new_conversation_button
, "clicked",
2362 G_CALLBACK (roster_window_chat_new_message_cb
), self
);
2363 gtk_button_set_image (GTK_BUTTON (new_conversation_button
), image
);
2364 gtk_widget_set_tooltip_text (new_conversation_button
, _("New Conversation"));
2365 gtk_window_set_titlebar (GTK_WINDOW (self
), header_bar
);
2366 gtk_container_add (GTK_CONTAINER (header_bar
), new_conversation_button
);
2367 gtk_widget_show_all (header_bar
);
2369 gtk_container_add (GTK_CONTAINER (self
), self
->priv
->main_vbox
);
2370 gtk_widget_show (self
->priv
->main_vbox
);
2372 g_signal_connect (self
, "key-press-event",
2373 G_CALLBACK (roster_window_key_press_event_cb
), self
);
2375 g_object_unref (gui
);
2377 self
->priv
->account_manager
= tp_account_manager_dup ();
2379 tp_proxy_prepare_async (self
->priv
->account_manager
, NULL
,
2380 account_manager_prepared_cb
, self
);
2382 self
->priv
->errors
= g_hash_table_new_full (g_direct_hash
, g_direct_equal
,
2383 g_object_unref
, NULL
);
2385 self
->priv
->auths
= g_hash_table_new (NULL
, NULL
);
2387 self
->priv
->status_changed_handlers
= g_hash_table_new_full (g_direct_hash
,
2388 g_direct_equal
, NULL
, NULL
);
2390 /* set up accelerators */
2391 g_action_map_add_action_entries (G_ACTION_MAP (self
),
2392 app_entries
, G_N_ELEMENTS (app_entries
), self
);
2395 g_action_map_add_action_entries (G_ACTION_MAP (self
),
2396 menubar_entries
, G_N_ELEMENTS (menubar_entries
), self
);
2397 roster_window_setup_actions (self
);
2399 filename
= empathy_file_lookup ("empathy-roster-window-menubar.ui", "src");
2400 gui
= tpaw_builder_get_file (filename
,
2401 "appmenu", &self
->priv
->menumodel
,
2402 "rooms", &self
->priv
->rooms_section
,
2406 g_object_ref (self
->priv
->menumodel
);
2407 g_object_ref (self
->priv
->rooms_section
);
2409 /* Set up connection related actions. */
2410 roster_window_connection_items_setup (self
);
2411 roster_window_favorite_chatroom_menu_setup (self
);
2413 g_object_unref (gui
);
2415 /* Set up contact list. */
2416 empathy_status_presets_get_all ();
2418 /* Set up presence chooser */
2419 self
->priv
->presence_chooser
= empathy_presence_chooser_new ();
2420 gtk_widget_show (self
->priv
->presence_chooser
);
2421 gtk_container_add (GTK_CONTAINER (self
->priv
->presence_toolbar
), self
->priv
->presence_chooser
);
2423 /* Set up the throbber */
2424 self
->priv
->throbber
= gtk_spinner_new ();
2425 gtk_widget_set_size_request (self
->priv
->throbber
, 16, -1);
2426 gtk_widget_set_events (self
->priv
->throbber
, GDK_BUTTON_PRESS_MASK
);
2427 g_signal_connect (self
->priv
->throbber
, "button-press-event",
2428 G_CALLBACK (roster_window_throbber_button_press_event_cb
),
2430 gtk_container_add (GTK_CONTAINER (self
->priv
->presence_toolbar
), self
->priv
->throbber
);
2432 self
->priv
->individual_manager
= empathy_individual_manager_dup_singleton ();
2434 model
= EMPATHY_ROSTER_MODEL (empathy_roster_model_manager_new (self
->priv
->individual_manager
));
2436 tp_g_signal_connect_object (self
->priv
->individual_manager
,
2437 "contacts-loaded", G_CALLBACK (contacts_loaded_cb
), self
, 0);
2439 self
->priv
->view
= EMPATHY_ROSTER_VIEW (
2440 empathy_roster_view_new (model
));
2443 g_object_unref (model
);
2445 gtk_widget_show (GTK_WIDGET (self
->priv
->view
));
2447 gtk_container_add (GTK_CONTAINER (sw
), GTK_WIDGET (self
->priv
->view
));
2449 g_signal_connect (self
->priv
->view
, "individual-activated",
2450 G_CALLBACK (individual_activated_cb
), self
);
2451 g_signal_connect (self
->priv
->view
, "event-activated",
2452 G_CALLBACK (event_activated_cb
), self
);
2453 g_signal_connect (self
->priv
->view
, "popup-individual-menu",
2454 G_CALLBACK (popup_individual_menu_cb
), self
);
2455 g_signal_connect (self
->priv
->view
, "notify::empty",
2456 G_CALLBACK (view_empty_cb
), self
);
2457 g_signal_connect (self
->priv
->view
, "individual-tooltip",
2458 G_CALLBACK (individual_tooltip_cb
), self
);
2460 /* DnD - destination */
2461 gtk_drag_dest_set (GTK_WIDGET (self
->priv
->view
), GTK_DEST_DEFAULT_MOTION
,
2462 drag_types_dest
, G_N_ELEMENTS (drag_types_dest
), GDK_ACTION_COPY
);
2464 for (i
= 0; i
< G_N_ELEMENTS (drag_types_dest
); ++i
)
2465 drag_atoms_dest
[i
] = gdk_atom_intern (drag_types_dest
[i
].target
, FALSE
);
2467 g_signal_connect (self
->priv
->view
, "drag-motion",
2468 G_CALLBACK (view_drag_motion_cb
), self
);
2469 g_signal_connect (self
->priv
->view
, "drag-drop",
2470 G_CALLBACK (view_drag_drop_cb
), self
);
2471 g_signal_connect (self
->priv
->view
, "drag-data-received",
2472 G_CALLBACK (view_drag_data_received_cb
), self
);
2474 gtk_widget_set_has_tooltip (GTK_WIDGET (self
->priv
->view
), TRUE
);
2476 /* Set up search bar */
2477 self
->priv
->search_bar
= tpaw_live_search_new (
2478 GTK_WIDGET (self
->priv
->view
));
2479 empathy_roster_view_set_live_search (self
->priv
->view
,
2480 TPAW_LIVE_SEARCH (self
->priv
->search_bar
));
2482 g_signal_connect_swapped (self
, "map",
2483 G_CALLBACK (gtk_widget_grab_focus
), self
->priv
->view
);
2485 /* Load user-defined accelerators. */
2486 roster_window_accels_load ();
2488 gtk_window_set_default_size (GTK_WINDOW (self
), 900, 600);
2489 /* Set window size. */
2490 empathy_geometry_bind (GTK_WINDOW (self
), GEOMETRY_NAME
);
2492 self
->priv
->chat_window
= GTK_WIDGET (empathy_chat_window_new ());
2493 gtk_widget_show (GTK_WIDGET (self
->priv
->chat_window
) );
2494 gtk_container_add (GTK_CONTAINER (chat_vbox
), self
->priv
->chat_window
);
2496 /* Enable event handling */
2497 self
->priv
->call_observer
= empathy_call_observer_dup_singleton ();
2498 self
->priv
->event_manager
= empathy_event_manager_dup_singleton ();
2499 self
->priv
->chat_manager
= empathy_chat_manager_dup_singleton ();
2501 self
->priv
->theme_manager
= empathy_theme_manager_dup_singleton ();
2503 tp_g_signal_connect_object (self
->priv
->event_manager
, "event-added",
2504 G_CALLBACK (roster_window_event_added_cb
), self
, 0);
2505 tp_g_signal_connect_object (self
->priv
->event_manager
, "event-removed",
2506 G_CALLBACK (roster_window_event_removed_cb
), self
, 0);
2508 g_signal_connect (self
->priv
->account_manager
, "account-validity-changed",
2509 G_CALLBACK (roster_window_account_validity_changed_cb
), self
);
2510 g_signal_connect (self
->priv
->account_manager
, "account-removed",
2511 G_CALLBACK (roster_window_account_removed_cb
), self
);
2512 g_signal_connect (self
->priv
->account_manager
, "account-disabled",
2513 G_CALLBACK (roster_window_account_disabled_cb
), self
);
2514 g_signal_connect (self
->priv
->account_manager
,
2515 "most-available-presence-changed",
2516 G_CALLBACK (roster_window_most_available_presence_changed_cb
), self
);
2518 g_object_set (G_OBJECT (self
->priv
->view
),
2519 "show-offline", TRUE
,
2520 "show-groups", FALSE
,
2523 g_settings_bind (self
->priv
->gsettings_ui
, "show-balance-in-roster",
2524 self
->priv
->balance_vbox
, "visible",
2525 G_SETTINGS_BIND_GET
);
2527 g_signal_connect (self
->priv
->button_account_settings
, "clicked",
2528 G_CALLBACK (button_account_settings_clicked_cb
), self
);
2529 // g_signal_connect (self->priv->button_online, "clicked",
2530 // G_CALLBACK (button_online_clicked_cb), self);
2531 g_signal_connect (self
->priv
->button_show_offline
, "clicked",
2532 G_CALLBACK (button_show_offline_clicked_cb
), self
);
2533 g_signal_connect (self
->priv
->button_add_contact
, "clicked",
2534 G_CALLBACK (button_add_contact_clicked_cb
), self
);
2538 empathy_roster_window_new (GtkApplication
*app
)
2540 return g_object_new (EMPATHY_TYPE_ROSTER_WINDOW
,
2546 empathy_roster_window_get_menu_model (EmpathyRosterWindow
*self
)
2548 g_return_val_if_fail (EMPATHY_IS_ROSTER_WINDOW (self
), NULL
);
2550 return G_MENU_MODEL (self
->priv
->menumodel
);