Update Slovak translation
[empathy-mirror.git] / src / empathy-status-icon.c
blob2f71fa13d52ab04ecd79926ac4d446f7b1e8cc4b
1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
2 /*
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>
22 #include "config.h"
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)
43 typedef struct {
44 GtkStatusIcon *icon;
45 TpAccountManager *account_manager;
46 gboolean showing_event_icon;
47 guint blink_timeout;
48 EmpathyEventManager *event_manager;
49 EmpathyEvent *event;
50 GSettings *gsettings_ui;
52 GtkWidget *window;
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);
62 static void
63 status_icon_update_tooltip (EmpathyStatusIcon *icon)
65 EmpathyStatusIconPriv *priv = GET_PRIV (icon);
67 if (priv->event) {
68 gchar *tooltip = NULL;
70 if (priv->event->message != NULL)
71 tooltip = g_markup_printf_escaped ("<i>%s</i>\n%s",
72 priv->event->header,
73 priv->event->message);
74 else
75 tooltip = g_markup_printf_escaped ("<i>%s</i>",
76 priv->event->header);
77 gtk_status_icon_set_tooltip_markup (priv->icon, tooltip);
78 g_free (tooltip);
79 } else {
80 TpConnectionPresenceType type;
81 gchar *msg;
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);
89 else {
90 gtk_status_icon_set_tooltip_text (priv->icon,
91 empathy_presence_get_default_message (type));
94 g_free (msg);
98 static void
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;
106 } else {
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
113 * to be offline. */
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);
125 static gboolean
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);
133 return TRUE;
135 static void
136 status_icon_event_added_cb (EmpathyEventManager *manager,
137 EmpathyEvent *event,
138 EmpathyStatusIcon *icon)
140 EmpathyStatusIconPriv *priv = GET_PRIV (icon);
142 if (priv->event) {
143 return;
146 DEBUG ("New event %p", event);
148 priv->event = 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,
158 icon);
162 static void
163 status_icon_event_removed_cb (EmpathyEventManager *manager,
164 EmpathyEvent *event,
165 EmpathyStatusIcon *icon)
167 EmpathyStatusIconPriv *priv = GET_PRIV (icon);
169 if (event != priv->event) {
170 return;
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;
184 static void
185 status_icon_event_updated_cb (EmpathyEventManager *manager,
186 EmpathyEvent *event,
187 EmpathyStatusIcon *icon)
189 EmpathyStatusIconPriv *priv = GET_PRIV (icon);
191 if (event != priv->event) {
192 return;
195 status_icon_update_tooltip (icon);
198 static void
199 status_icon_set_visibility (EmpathyStatusIcon *icon,
200 gboolean visible,
201 gboolean store)
203 EmpathyStatusIconPriv *priv = GET_PRIV (icon);
205 if (store) {
206 g_settings_set_boolean (priv->gsettings_ui,
207 EMPATHY_PREFS_UI_MAIN_WINDOW_HIDDEN,
208 !visible);
211 if (!visible) {
212 gtk_widget_hide (priv->window);
213 } else {
214 tpaw_window_present (GTK_WINDOW (priv->window));
218 static void
219 status_icon_notify_visibility_cb (GSettings *gsettings,
220 const gchar *key,
221 gpointer user_data)
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);
230 static void
231 status_icon_toggle_visibility (EmpathyStatusIcon *icon)
233 EmpathyStatusIconPriv *priv = GET_PRIV (icon);
234 gboolean visible;
236 visible = gtk_window_is_active (GTK_WINDOW (priv->window));
237 status_icon_set_visibility (icon, !visible, TRUE);
240 static void
241 status_icon_presence_changed_cb (EmpathyStatusIcon *icon)
243 status_icon_update_icon (icon);
244 status_icon_update_tooltip (icon);
247 static gboolean
248 status_icon_delete_event_cb (GtkWidget *widget,
249 GdkEvent *event,
250 EmpathyStatusIcon *icon)
252 status_icon_set_visibility (icon, FALSE, TRUE);
253 return TRUE;
256 static gboolean
257 status_icon_key_press_event_cb (GtkWidget *window,
258 GdkEventKey *event,
259 EmpathyStatusIcon *icon)
261 if (event->keyval == GDK_KEY_Escape) {
262 status_icon_set_visibility (icon, FALSE, TRUE);
264 return FALSE;
267 static void
268 status_icon_activate_cb (GtkStatusIcon *status_icon,
269 EmpathyStatusIcon *icon)
271 EmpathyStatusIconPriv *priv = GET_PRIV (icon);
273 DEBUG ("%s", priv->event ? "event" : "toggle");
275 if (priv->event) {
276 empathy_event_activate (priv->event);
277 } else {
278 status_icon_toggle_visibility (icon);
282 static void
283 status_icon_show_hide_window_cb (GtkToggleAction *action,
284 EmpathyStatusIcon *icon)
286 gboolean visible;
288 visible = gtk_toggle_action_get_active (action);
289 status_icon_set_visibility (icon, visible, TRUE);
292 static void
293 status_icon_new_message_cb (GtkAction *action,
294 EmpathyStatusIcon *icon)
296 empathy_new_message_dialog_show (NULL);
299 static void
300 status_icon_new_call_cb (GtkAction *action,
301 EmpathyStatusIcon *icon)
303 empathy_new_call_dialog_show (NULL);
306 static void
307 status_icon_quit_cb (GtkAction *action,
308 EmpathyStatusIcon *icon)
310 EmpathyStatusIconPriv *priv = GET_PRIV (icon);
312 gtk_widget_destroy (priv->window);
315 static void
316 status_icon_popup_menu_cb (GtkStatusIcon *status_icon,
317 guint button,
318 guint activate_time,
319 EmpathyStatusIcon *icon)
321 EmpathyStatusIconPriv *priv = GET_PRIV (icon);
322 GtkWidget *menu_item;
323 GtkWidget *submenu;
324 gboolean show;
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,
330 icon);
331 gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (priv->show_window_item),
332 show);
333 g_signal_handlers_unblock_by_func (priv->show_window_item,
334 status_icon_show_hide_window_cb,
335 icon);
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),
342 NULL, NULL,
343 gtk_status_icon_position_menu,
344 priv->icon,
345 button,
346 activate_time);
349 static void
350 status_icon_create_menu (EmpathyStatusIcon *icon)
352 EmpathyStatusIconPriv *priv = GET_PRIV (icon);
353 GtkBuilder *gui;
354 gchar *filename;
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,
363 NULL);
364 g_free (filename);
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,
371 NULL);
373 g_object_ref (priv->ui_manager);
374 g_object_unref (gui);
377 static void
378 status_icon_status_changed_cb (TpAccount *account,
379 TpConnectionStatus current,
380 TpConnectionStatus previous,
381 TpConnectionStatusReason reason,
382 gchar *dbus_error_name,
383 GHashTable *details,
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));
392 static void
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);
409 static void
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));
419 static void
420 account_manager_prepared_cb (GObject *source_object,
421 GAsyncResult *result,
422 gpointer user_data)
424 GList *list, *l;
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);
432 return;
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),
439 icon, 0);
441 g_list_free_full (list, g_object_unref);
443 status_icon_presence_changed_cb (icon);
446 static void
447 empathy_status_icon_init (EmpathyStatusIcon *icon)
449 EmpathyStatusIconPriv *priv = G_TYPE_INSTANCE_GET_PRIVATE (icon,
450 EMPATHY_TYPE_STATUS_ICON, EmpathyStatusIconPriv);
452 icon->priv = priv;
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),
465 icon);
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),
472 icon);
473 g_signal_connect (priv->event_manager, "event-added",
474 G_CALLBACK (status_icon_event_added_cb),
475 icon);
476 g_signal_connect (priv->event_manager, "event-removed",
477 G_CALLBACK (status_icon_event_removed_cb),
478 icon);
479 g_signal_connect (priv->event_manager, "event-updated",
480 G_CALLBACK (status_icon_event_updated_cb),
481 icon);
482 g_signal_connect (priv->icon, "activate",
483 G_CALLBACK (status_icon_activate_cb),
484 icon);
485 g_signal_connect (priv->icon, "popup-menu",
486 G_CALLBACK (status_icon_popup_menu_cb),
487 icon);
490 EmpathyStatusIcon *
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),
506 icon);
508 g_signal_connect (priv->window, "delete-event",
509 G_CALLBACK (status_icon_delete_event_cb),
510 icon);
512 if (!hide_contact_list) {
513 should_hide = g_settings_get_boolean (priv->gsettings_ui,
514 EMPATHY_PREFS_UI_MAIN_WINDOW_HIDDEN);
515 } else {
516 should_hide = TRUE;
519 status_icon_set_visibility (icon, !should_hide, FALSE);
521 return icon;