1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
3 * Copyright (C) 2007-2008 Collabora Ltd.
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public
7 * License as published by the Free Software Foundation; either
8 * version 2.1 of the License, or (at your option) any later version.
10 * This library 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 * Lesser General Public License for more details.
15 * You should have received a copy of the GNU Lesser General Public
16 * License along with this library; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
19 * Authors: Xavier Claessens <xclaesse@gmail.com>
23 #include "empathy-status-icon.h"
25 #include <tp-account-widgets/tpaw-builder.h>
26 #include <tp-account-widgets/tpaw-utils.h>
28 #include "empathy-event-manager.h"
29 #include "empathy-gsettings.h"
30 #include "empathy-new-call-dialog.h"
31 #include "empathy-new-message-dialog.h"
32 #include "empathy-presence-chooser.h"
33 #include "empathy-ui-utils.h"
34 #include "empathy-utils.h"
36 #define DEBUG_FLAG EMPATHY_DEBUG_DISPATCHER
37 #include "empathy-debug.h"
39 /* Number of ms to wait when blinking */
40 #define BLINK_TIMEOUT 500
42 #define GET_PRIV(obj) EMPATHY_GET_PRIV (obj, EmpathyStatusIcon)
45 TpAccountManager
*account_manager
;
46 gboolean showing_event_icon
;
48 EmpathyEventManager
*event_manager
;
50 GSettings
*gsettings_ui
;
53 GtkUIManager
*ui_manager
;
54 GtkWidget
*popup_menu
;
55 GtkAction
*show_window_item
;
56 GtkAction
*new_message_item
;
57 GtkAction
*status_item
;
58 } EmpathyStatusIconPriv
;
60 G_DEFINE_TYPE (EmpathyStatusIcon
, empathy_status_icon
, G_TYPE_OBJECT
);
63 status_icon_update_tooltip (EmpathyStatusIcon
*icon
)
65 EmpathyStatusIconPriv
*priv
= GET_PRIV (icon
);
68 gchar
*tooltip
= NULL
;
70 if (priv
->event
->message
!= NULL
)
71 tooltip
= g_markup_printf_escaped ("<i>%s</i>\n%s",
73 priv
->event
->message
);
75 tooltip
= g_markup_printf_escaped ("<i>%s</i>",
77 gtk_status_icon_set_tooltip_markup (priv
->icon
, tooltip
);
80 TpConnectionPresenceType type
;
83 type
= tp_account_manager_get_most_available_presence (
84 priv
->account_manager
, NULL
, &msg
);
86 if (!TPAW_STR_EMPTY (msg
)) {
87 gtk_status_icon_set_tooltip_text (priv
->icon
, msg
);
90 gtk_status_icon_set_tooltip_text (priv
->icon
,
91 empathy_presence_get_default_message (type
));
99 status_icon_update_icon (EmpathyStatusIcon
*icon
)
101 EmpathyStatusIconPriv
*priv
= GET_PRIV (icon
);
102 const gchar
*icon_name
;
104 if (priv
->event
&& priv
->showing_event_icon
) {
105 icon_name
= priv
->event
->icon_name
;
107 TpConnectionPresenceType state
;
109 state
= tp_account_manager_get_most_available_presence (
110 priv
->account_manager
, NULL
, NULL
);
112 /* An unset presence type here doesn't make sense. Force it
114 if (state
== TP_CONNECTION_PRESENCE_TYPE_UNSET
) {
115 state
= TP_CONNECTION_PRESENCE_TYPE_OFFLINE
;
118 icon_name
= empathy_icon_name_for_presence (state
);
121 if (icon_name
!= NULL
)
122 gtk_status_icon_set_from_icon_name (priv
->icon
, icon_name
);
126 status_icon_blink_timeout_cb (EmpathyStatusIcon
*icon
)
128 EmpathyStatusIconPriv
*priv
= GET_PRIV (icon
);
130 priv
->showing_event_icon
= !priv
->showing_event_icon
;
131 status_icon_update_icon (icon
);
136 status_icon_event_added_cb (EmpathyEventManager
*manager
,
138 EmpathyStatusIcon
*icon
)
140 EmpathyStatusIconPriv
*priv
= GET_PRIV (icon
);
146 DEBUG ("New event %p", event
);
149 if (event
->must_ack
|| event
->type
== EMPATHY_EVENT_TYPE_AUTH
) {
150 priv
->showing_event_icon
= TRUE
;
151 status_icon_update_icon (icon
);
152 status_icon_update_tooltip (icon
);
155 if (!priv
->blink_timeout
&& priv
->showing_event_icon
) {
156 priv
->blink_timeout
= g_timeout_add (BLINK_TIMEOUT
,
157 (GSourceFunc
) status_icon_blink_timeout_cb
,
163 status_icon_event_removed_cb (EmpathyEventManager
*manager
,
165 EmpathyStatusIcon
*icon
)
167 EmpathyStatusIconPriv
*priv
= GET_PRIV (icon
);
169 if (event
!= priv
->event
) {
173 priv
->event
= empathy_event_manager_get_top_event (priv
->event_manager
);
175 status_icon_update_tooltip (icon
);
176 status_icon_update_icon (icon
);
178 if (!priv
->event
&& priv
->blink_timeout
) {
179 g_source_remove (priv
->blink_timeout
);
180 priv
->blink_timeout
= 0;
185 status_icon_event_updated_cb (EmpathyEventManager
*manager
,
187 EmpathyStatusIcon
*icon
)
189 EmpathyStatusIconPriv
*priv
= GET_PRIV (icon
);
191 if (event
!= priv
->event
) {
195 status_icon_update_tooltip (icon
);
199 status_icon_set_visibility (EmpathyStatusIcon
*icon
,
203 EmpathyStatusIconPriv
*priv
= GET_PRIV (icon
);
206 g_settings_set_boolean (priv
->gsettings_ui
,
207 EMPATHY_PREFS_UI_MAIN_WINDOW_HIDDEN
,
212 gtk_widget_hide (priv
->window
);
214 tpaw_window_present (GTK_WINDOW (priv
->window
));
219 status_icon_notify_visibility_cb (GSettings
*gsettings
,
223 EmpathyStatusIcon
*icon
= user_data
;
224 gboolean hidden
= FALSE
;
226 hidden
= g_settings_get_boolean (gsettings
, key
);
227 status_icon_set_visibility (icon
, !hidden
, FALSE
);
231 status_icon_toggle_visibility (EmpathyStatusIcon
*icon
)
233 EmpathyStatusIconPriv
*priv
= GET_PRIV (icon
);
236 visible
= gtk_window_is_active (GTK_WINDOW (priv
->window
));
237 status_icon_set_visibility (icon
, !visible
, TRUE
);
241 status_icon_presence_changed_cb (EmpathyStatusIcon
*icon
)
243 status_icon_update_icon (icon
);
244 status_icon_update_tooltip (icon
);
248 status_icon_delete_event_cb (GtkWidget
*widget
,
250 EmpathyStatusIcon
*icon
)
252 status_icon_set_visibility (icon
, FALSE
, TRUE
);
257 status_icon_key_press_event_cb (GtkWidget
*window
,
259 EmpathyStatusIcon
*icon
)
261 if (event
->keyval
== GDK_KEY_Escape
) {
262 status_icon_set_visibility (icon
, FALSE
, TRUE
);
268 status_icon_activate_cb (GtkStatusIcon
*status_icon
,
269 EmpathyStatusIcon
*icon
)
271 EmpathyStatusIconPriv
*priv
= GET_PRIV (icon
);
273 DEBUG ("%s", priv
->event
? "event" : "toggle");
276 empathy_event_activate (priv
->event
);
278 status_icon_toggle_visibility (icon
);
283 status_icon_show_hide_window_cb (GtkToggleAction
*action
,
284 EmpathyStatusIcon
*icon
)
288 visible
= gtk_toggle_action_get_active (action
);
289 status_icon_set_visibility (icon
, visible
, TRUE
);
293 status_icon_new_message_cb (GtkAction
*action
,
294 EmpathyStatusIcon
*icon
)
296 empathy_new_message_dialog_show (NULL
);
300 status_icon_new_call_cb (GtkAction
*action
,
301 EmpathyStatusIcon
*icon
)
303 empathy_new_call_dialog_show (NULL
);
307 status_icon_quit_cb (GtkAction
*action
,
308 EmpathyStatusIcon
*icon
)
310 EmpathyStatusIconPriv
*priv
= GET_PRIV (icon
);
312 gtk_widget_destroy (priv
->window
);
316 status_icon_popup_menu_cb (GtkStatusIcon
*status_icon
,
319 EmpathyStatusIcon
*icon
)
321 EmpathyStatusIconPriv
*priv
= GET_PRIV (icon
);
322 GtkWidget
*menu_item
;
326 show
= gtk_widget_get_visible (priv
->window
);
328 g_signal_handlers_block_by_func (priv
->show_window_item
,
329 status_icon_show_hide_window_cb
,
331 gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (priv
->show_window_item
),
333 g_signal_handlers_unblock_by_func (priv
->show_window_item
,
334 status_icon_show_hide_window_cb
,
337 menu_item
= gtk_ui_manager_get_widget (priv
->ui_manager
, "/menu/status");
338 submenu
= empathy_presence_chooser_create_menu ();
339 gtk_menu_item_set_submenu (GTK_MENU_ITEM (menu_item
), submenu
);
341 gtk_menu_popup (GTK_MENU (priv
->popup_menu
),
343 gtk_status_icon_position_menu
,
350 status_icon_create_menu (EmpathyStatusIcon
*icon
)
352 EmpathyStatusIconPriv
*priv
= GET_PRIV (icon
);
356 filename
= empathy_file_lookup ("empathy-status-icon.ui", "src");
357 gui
= tpaw_builder_get_file (filename
,
358 "ui_manager", &priv
->ui_manager
,
359 "menu", &priv
->popup_menu
,
360 "show_list", &priv
->show_window_item
,
361 "new_message", &priv
->new_message_item
,
362 "status", &priv
->status_item
,
366 tpaw_builder_connect (gui
, icon
,
367 "show_list", "toggled", status_icon_show_hide_window_cb
,
368 "new_message", "activate", status_icon_new_message_cb
,
369 "new_call", "activate", status_icon_new_call_cb
,
370 "quit", "activate", status_icon_quit_cb
,
373 g_object_ref (priv
->ui_manager
);
374 g_object_unref (gui
);
378 status_icon_status_changed_cb (TpAccount
*account
,
379 TpConnectionStatus current
,
380 TpConnectionStatus previous
,
381 TpConnectionStatusReason reason
,
382 gchar
*dbus_error_name
,
384 EmpathyStatusIcon
*icon
)
386 EmpathyStatusIconPriv
*priv
= GET_PRIV (icon
);
388 gtk_action_set_sensitive (priv
->new_message_item
,
389 empathy_account_manager_get_accounts_connected (NULL
));
393 status_icon_finalize (GObject
*object
)
395 EmpathyStatusIconPriv
*priv
= GET_PRIV (object
);
397 if (priv
->blink_timeout
) {
398 g_source_remove (priv
->blink_timeout
);
401 g_object_unref (priv
->icon
);
402 g_object_unref (priv
->account_manager
);
403 g_object_unref (priv
->event_manager
);
404 g_object_unref (priv
->ui_manager
);
405 g_object_unref (priv
->gsettings_ui
);
406 g_object_unref (priv
->window
);
410 empathy_status_icon_class_init (EmpathyStatusIconClass
*klass
)
412 GObjectClass
*object_class
= G_OBJECT_CLASS (klass
);
414 object_class
->finalize
= status_icon_finalize
;
416 g_type_class_add_private (object_class
, sizeof (EmpathyStatusIconPriv
));
420 account_manager_prepared_cb (GObject
*source_object
,
421 GAsyncResult
*result
,
425 TpAccountManager
*account_manager
= TP_ACCOUNT_MANAGER (source_object
);
426 EmpathyStatusIcon
*icon
= user_data
;
427 GError
*error
= NULL
;
429 if (!tp_proxy_prepare_finish (account_manager
, result
, &error
)) {
430 DEBUG ("Failed to prepare account manager: %s", error
->message
);
431 g_error_free (error
);
435 list
= tp_account_manager_dup_valid_accounts (account_manager
);
436 for (l
= list
; l
!= NULL
; l
= l
->next
) {
437 tp_g_signal_connect_object (l
->data
, "status-changed",
438 G_CALLBACK (status_icon_status_changed_cb
),
441 g_list_free_full (list
, g_object_unref
);
443 status_icon_presence_changed_cb (icon
);
447 empathy_status_icon_init (EmpathyStatusIcon
*icon
)
449 EmpathyStatusIconPriv
*priv
= G_TYPE_INSTANCE_GET_PRIVATE (icon
,
450 EMPATHY_TYPE_STATUS_ICON
, EmpathyStatusIconPriv
);
453 priv
->icon
= gtk_status_icon_new ();
454 priv
->account_manager
= tp_account_manager_dup ();
455 priv
->event_manager
= empathy_event_manager_dup_singleton ();
457 tp_proxy_prepare_async (priv
->account_manager
, NULL
,
458 account_manager_prepared_cb
, icon
);
460 /* make icon listen and respond to MAIN_WINDOW_HIDDEN changes */
461 priv
->gsettings_ui
= g_settings_new (EMPATHY_PREFS_UI_SCHEMA
);
462 g_signal_connect (priv
->gsettings_ui
,
463 "changed::" EMPATHY_PREFS_UI_MAIN_WINDOW_HIDDEN
,
464 G_CALLBACK (status_icon_notify_visibility_cb
),
467 status_icon_create_menu (icon
);
469 g_signal_connect_swapped (priv
->account_manager
,
470 "most-available-presence-changed",
471 G_CALLBACK (status_icon_presence_changed_cb
),
473 g_signal_connect (priv
->event_manager
, "event-added",
474 G_CALLBACK (status_icon_event_added_cb
),
476 g_signal_connect (priv
->event_manager
, "event-removed",
477 G_CALLBACK (status_icon_event_removed_cb
),
479 g_signal_connect (priv
->event_manager
, "event-updated",
480 G_CALLBACK (status_icon_event_updated_cb
),
482 g_signal_connect (priv
->icon
, "activate",
483 G_CALLBACK (status_icon_activate_cb
),
485 g_signal_connect (priv
->icon
, "popup-menu",
486 G_CALLBACK (status_icon_popup_menu_cb
),
491 empathy_status_icon_new (GtkWindow
*window
, gboolean hide_contact_list
)
493 EmpathyStatusIconPriv
*priv
;
494 EmpathyStatusIcon
*icon
;
495 gboolean should_hide
;
497 g_return_val_if_fail (GTK_IS_WINDOW (window
), NULL
);
499 icon
= g_object_new (EMPATHY_TYPE_STATUS_ICON
, NULL
);
500 priv
= GET_PRIV (icon
);
502 priv
->window
= g_object_ref (window
);
504 g_signal_connect_after (priv
->window
, "key-press-event",
505 G_CALLBACK (status_icon_key_press_event_cb
),
508 g_signal_connect (priv
->window
, "delete-event",
509 G_CALLBACK (status_icon_delete_event_cb
),
512 if (!hide_contact_list
) {
513 should_hide
= g_settings_get_boolean (priv
->gsettings_ui
,
514 EMPATHY_PREFS_UI_MAIN_WINDOW_HIDDEN
);
519 status_icon_set_visibility (icon
, !should_hide
, FALSE
);