]> git.0d.be Git - empathy.git/blob - src/empathy-status-icon.c
Merge branch 'subscription-msg-630707'
[empathy.git] / src / empathy-status-icon.c
1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
2 /*
3  * Copyright (C) 2007-2008 Collabora Ltd.
4  *
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.
9  *
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.
14  *
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
18  *
19  * Authors: Xavier Claessens <xclaesse@gmail.com>
20  */
21
22 #include <config.h>
23
24 #include <string.h>
25
26 #include <glib.h>
27
28 #include <gtk/gtk.h>
29 #include <gdk/gdkkeysyms.h>
30 #include <glib/gi18n.h>
31
32 #include <libnotify/notification.h>
33 #include <libnotify/notify.h>
34
35 #include <telepathy-glib/account-manager.h>
36 #include <telepathy-glib/util.h>
37
38 #include <libempathy/empathy-contact-manager.h>
39 #include <libempathy/empathy-gsettings.h>
40 #include <libempathy/empathy-utils.h>
41
42 #include <libempathy-gtk/empathy-presence-chooser.h>
43 #include <libempathy-gtk/empathy-ui-utils.h>
44 #include <libempathy-gtk/empathy-images.h>
45 #include <libempathy-gtk/empathy-new-message-dialog.h>
46 #include <libempathy-gtk/empathy-new-call-dialog.h>
47 #include <libempathy-gtk/empathy-notify-manager.h>
48
49 #include "empathy-accounts-dialog.h"
50 #include "empathy-status-icon.h"
51 #include "empathy-preferences.h"
52 #include "empathy-event-manager.h"
53
54 #define DEBUG_FLAG EMPATHY_DEBUG_DISPATCHER
55 #include <libempathy/empathy-debug.h>
56
57 /* Number of ms to wait when blinking */
58 #define BLINK_TIMEOUT 500
59
60 #define GET_PRIV(obj) EMPATHY_GET_PRIV (obj, EmpathyStatusIcon)
61 typedef struct {
62         GtkStatusIcon       *icon;
63         TpAccountManager    *account_manager;
64         EmpathyNotifyManager *notify_mgr;
65         gboolean             showing_event_icon;
66         guint                blink_timeout;
67         EmpathyEventManager *event_manager;
68         EmpathyEvent        *event;
69         NotifyNotification  *notification;
70         GSettings           *gsettings_ui;
71
72         GtkWindow           *window;
73         GtkUIManager        *ui_manager;
74         GtkWidget           *popup_menu;
75         GtkAction           *show_window_item;
76         GtkAction           *new_message_item;
77         GtkAction           *status_item;
78 } EmpathyStatusIconPriv;
79
80 G_DEFINE_TYPE (EmpathyStatusIcon, empathy_status_icon, G_TYPE_OBJECT);
81
82 static void
83 status_icon_notification_closed_cb (NotifyNotification *notification,
84                                     EmpathyStatusIcon  *icon)
85 {
86         EmpathyStatusIconPriv *priv = GET_PRIV (icon);
87
88         g_object_unref (notification);
89
90         if (priv->notification == notification) {
91                 priv->notification = NULL;
92         }
93
94         if (!priv->event) {
95                 return;
96         }
97
98         /* inhibit other updates for this event */
99         empathy_event_inhibit_updates (priv->event);
100 }
101
102 static void
103 notification_close_helper (EmpathyStatusIconPriv *priv)
104 {
105         if (priv->notification != NULL) {
106                 notify_notification_close (priv->notification, NULL);
107                 priv->notification = NULL;
108         }
109 }
110
111 static void
112 notification_approve_cb (NotifyNotification *notification,
113                         gchar              *action,
114                         EmpathyStatusIcon  *icon)
115 {
116         EmpathyStatusIconPriv *priv = GET_PRIV (icon);
117
118         if (priv->event)
119                 empathy_event_approve (priv->event);
120 }
121
122 static void
123 notification_decline_cb (NotifyNotification *notification,
124                         gchar              *action,
125                         EmpathyStatusIcon  *icon)
126 {
127         EmpathyStatusIconPriv *priv = GET_PRIV (icon);
128
129         if (priv->event)
130                 empathy_event_decline (priv->event);
131 }
132
133 static void
134 notification_decline_subscription_cb (NotifyNotification *notification,
135                         gchar              *action,
136                         EmpathyStatusIcon  *icon)
137 {
138         EmpathyStatusIconPriv *priv = GET_PRIV (icon);
139         EmpathyContactManager *manager;
140
141         if (priv->event == NULL)
142                 return;
143
144
145         manager = empathy_contact_manager_dup_singleton ();
146         empathy_contact_list_remove (EMPATHY_CONTACT_LIST (manager),
147                                      priv->event->contact, "");
148
149         empathy_event_remove (priv->event);
150
151         g_object_unref (manager);
152 }
153
154 static void
155 notification_accept_subscription_cb (NotifyNotification *notification,
156                         gchar              *action,
157                         EmpathyStatusIcon  *icon)
158 {
159         EmpathyStatusIconPriv *priv = GET_PRIV (icon);
160         EmpathyContactManager *manager;
161
162         if (priv->event == NULL)
163                 return;
164
165
166         manager = empathy_contact_manager_dup_singleton ();
167         empathy_contact_list_add (EMPATHY_CONTACT_LIST (manager),
168                                   priv->event->contact, "");
169
170         empathy_event_remove (priv->event);
171
172         g_object_unref (manager);
173 }
174
175 static void
176 add_notification_actions (EmpathyStatusIcon *self,
177                           NotifyNotification *notification)
178 {
179         EmpathyStatusIconPriv *priv = GET_PRIV (self);
180
181         switch (priv->event->type) {
182                 case EMPATHY_EVENT_TYPE_CHAT:
183                         notify_notification_add_action (notification,
184                                 "respond", _("Respond"), (NotifyActionCallback) notification_approve_cb,
185                                         self, NULL);
186                         break;
187
188                 case EMPATHY_EVENT_TYPE_VOIP:
189                         notify_notification_add_action (notification,
190                                 "reject", _("Reject"), (NotifyActionCallback) notification_decline_cb,
191                                         self, NULL);
192
193                         notify_notification_add_action (notification,
194                                 "answer", _("Answer"), (NotifyActionCallback) notification_approve_cb,
195                                         self, NULL);
196                         break;
197
198                 case EMPATHY_EVENT_TYPE_TRANSFER:
199                 case EMPATHY_EVENT_TYPE_INVITATION:
200                         notify_notification_add_action (notification,
201                                 "decline", _("Decline"), (NotifyActionCallback) notification_decline_cb,
202                                         self, NULL);
203
204                         notify_notification_add_action (notification,
205                                 "accept", _("Accept"), (NotifyActionCallback) notification_approve_cb,
206                                         self, NULL);
207                         break;
208
209                 case EMPATHY_EVENT_TYPE_SUBSCRIPTION:
210                         notify_notification_add_action (notification,
211                                 "decline", _("Decline"),
212                                         (NotifyActionCallback) notification_decline_subscription_cb,
213                                         self, NULL);
214
215                         notify_notification_add_action (notification,
216                                 "accept", _("Accept"),
217                                         (NotifyActionCallback) notification_accept_subscription_cb,
218                                         self, NULL);
219
220                 default:
221                         break;
222         }
223 }
224
225 static void
226 status_icon_update_notification (EmpathyStatusIcon *icon)
227 {
228         EmpathyStatusIconPriv *priv = GET_PRIV (icon);
229         GdkPixbuf *pixbuf = NULL;
230
231         if (!empathy_notify_manager_notification_is_enabled (priv->notify_mgr)) {
232                 /* always close the notification if this happens */
233                 notification_close_helper (priv);
234                 return;
235         }
236
237         if (priv->event) {
238                 gchar *message_esc = NULL;
239                 gboolean has_x_canonical_append;
240                 NotifyNotification *notification = priv->notification;
241
242                 if (priv->event->message != NULL)
243                         message_esc = g_markup_escape_text (priv->event->message, -1);
244
245                 has_x_canonical_append =
246                                 empathy_notify_manager_has_capability (priv->notify_mgr,
247                                         EMPATHY_NOTIFY_MANAGER_CAP_X_CANONICAL_APPEND);
248
249                 if (notification != NULL && ! has_x_canonical_append) {
250                         /* if the notification server supports x-canonical-append, it is
251                            better to not use notify_notification_update to avoid
252                            overwriting the current notification message */
253                         notify_notification_update (notification,
254                                                     priv->event->header, message_esc,
255                                                     NULL);
256                 } else {
257                         /* if the notification server supports x-canonical-append,
258                            the hint will be added, so that the message from the
259                            just created notification will be automatically appended
260                            to an existing notification with the same title.
261                            In this way the previous message will not be lost: the new
262                            message will appear below it, in the same notification */
263                         notification = notify_notification_new
264                                 (priv->event->header, message_esc, NULL);
265
266                         if (priv->notification == NULL) {
267                                 priv->notification = notification;
268                         }
269
270                         notify_notification_set_timeout (notification,
271                                                          NOTIFY_EXPIRES_DEFAULT);
272
273                         if (has_x_canonical_append) {
274                                 notify_notification_set_hint_string (notification,
275                                         EMPATHY_NOTIFY_MANAGER_CAP_X_CANONICAL_APPEND, "");
276                         }
277
278                         if (empathy_notify_manager_has_capability (priv->notify_mgr,
279                                    EMPATHY_NOTIFY_MANAGER_CAP_ACTIONS))
280                                 add_notification_actions (icon, notification);
281
282                         g_signal_connect (notification, "closed",
283                                           G_CALLBACK (status_icon_notification_closed_cb), icon);
284                 }
285
286                 pixbuf = empathy_notify_manager_get_pixbuf_for_notification (
287                                                                    priv->notify_mgr, priv->event->contact,
288                                                                    priv->event->icon_name);
289
290                 if (pixbuf != NULL) {
291                         notify_notification_set_icon_from_pixbuf (notification, pixbuf);
292                         g_object_unref (pixbuf);
293                 }
294
295                 notify_notification_show (notification, NULL);
296
297                 g_free (message_esc);
298         } else {
299                 notification_close_helper (priv);
300         }
301 }
302
303 static void
304 status_icon_update_tooltip (EmpathyStatusIcon *icon)
305 {
306         EmpathyStatusIconPriv *priv = GET_PRIV (icon);
307
308         if (priv->event) {
309                 gchar *tooltip = NULL;
310
311                 if (priv->event->message != NULL)
312                                 tooltip = g_markup_printf_escaped ("<i>%s</i>\n%s",
313                                                                    priv->event->header,
314                                                                    priv->event->message);
315                 else
316                                 tooltip = g_markup_printf_escaped ("<i>%s</i>",
317                                                                    priv->event->header);
318                 gtk_status_icon_set_tooltip_markup (priv->icon, tooltip);
319                 g_free (tooltip);
320         } else {
321                 TpConnectionPresenceType type;
322                 gchar *msg;
323
324                 type = tp_account_manager_get_most_available_presence (
325                         priv->account_manager, NULL, &msg);
326
327                 if (!EMP_STR_EMPTY (msg)) {
328                         gtk_status_icon_set_tooltip_text (priv->icon, msg);
329                 }
330                 else {
331                         gtk_status_icon_set_tooltip_text (priv->icon,
332                                                 empathy_presence_get_default_message (type));
333                 }
334
335                 g_free (msg);
336         }
337 }
338
339 static void
340 status_icon_update_icon (EmpathyStatusIcon *icon)
341 {
342         EmpathyStatusIconPriv *priv = GET_PRIV (icon);
343         const gchar           *icon_name;
344
345         if (priv->event && priv->showing_event_icon) {
346                 icon_name = priv->event->icon_name;
347         } else {
348                 TpConnectionPresenceType state;
349
350                 state = tp_account_manager_get_most_available_presence (
351                         priv->account_manager, NULL, NULL);
352
353                 /* An unset presence type here doesn't make sense. Force it
354                  * to be offline. */
355                 if (state == TP_CONNECTION_PRESENCE_TYPE_UNSET) {
356                         state = TP_CONNECTION_PRESENCE_TYPE_OFFLINE;
357                 }
358
359                 icon_name = empathy_icon_name_for_presence (state);
360         }
361
362         if (icon_name != NULL)
363                 gtk_status_icon_set_from_icon_name (priv->icon, icon_name);
364 }
365
366 static gboolean
367 status_icon_blink_timeout_cb (EmpathyStatusIcon *icon)
368 {
369         EmpathyStatusIconPriv *priv = GET_PRIV (icon);
370
371         priv->showing_event_icon = !priv->showing_event_icon;
372         status_icon_update_icon (icon);
373
374         return TRUE;
375 }
376 static void
377 status_icon_event_added_cb (EmpathyEventManager *manager,
378                             EmpathyEvent        *event,
379                             EmpathyStatusIcon   *icon)
380 {
381         EmpathyStatusIconPriv *priv = GET_PRIV (icon);
382
383         if (priv->event) {
384                 return;
385         }
386
387         DEBUG ("New event %p", event);
388
389         priv->event = event;
390         if (event->must_ack) {
391                 priv->showing_event_icon = TRUE;
392                 status_icon_update_icon (icon);
393                 status_icon_update_tooltip (icon);
394         }
395         status_icon_update_notification (icon);
396
397         if (!priv->blink_timeout && priv->showing_event_icon) {
398                 priv->blink_timeout = g_timeout_add (BLINK_TIMEOUT,
399                                                      (GSourceFunc) status_icon_blink_timeout_cb,
400                                                      icon);
401         }
402 }
403
404 static void
405 status_icon_event_removed_cb (EmpathyEventManager *manager,
406                               EmpathyEvent        *event,
407                               EmpathyStatusIcon   *icon)
408 {
409         EmpathyStatusIconPriv *priv = GET_PRIV (icon);
410
411         if (event != priv->event) {
412                 return;
413         }
414
415         priv->event = empathy_event_manager_get_top_event (priv->event_manager);
416
417         status_icon_update_tooltip (icon);
418         status_icon_update_icon (icon);
419
420         /* update notification anyway, as it's safe and we might have been
421          * changed presence in the meanwhile
422          */
423         status_icon_update_notification (icon);
424
425         if (!priv->event && priv->blink_timeout) {
426                 g_source_remove (priv->blink_timeout);
427                 priv->blink_timeout = 0;
428         }
429 }
430
431 static void
432 status_icon_event_updated_cb (EmpathyEventManager *manager,
433                               EmpathyEvent        *event,
434                               EmpathyStatusIcon   *icon)
435 {
436         EmpathyStatusIconPriv *priv = GET_PRIV (icon);
437
438         if (event != priv->event) {
439                 return;
440         }
441
442         if (empathy_notify_manager_notification_is_enabled (priv->notify_mgr)) {
443                 status_icon_update_notification (icon);
444         }
445
446         status_icon_update_tooltip (icon);
447 }
448
449 static void
450 status_icon_set_visibility (EmpathyStatusIcon *icon,
451                             gboolean           visible,
452                             gboolean           store)
453 {
454         EmpathyStatusIconPriv *priv = GET_PRIV (icon);
455
456         if (store) {
457                 g_settings_set_boolean (priv->gsettings_ui,
458                                         EMPATHY_PREFS_UI_MAIN_WINDOW_HIDDEN,
459                                         !visible);
460         }
461
462         if (!visible) {
463                 empathy_window_iconify (priv->window, priv->icon);
464         } else {
465                 empathy_window_present (GTK_WINDOW (priv->window));
466         }
467 }
468
469 static void
470 status_icon_notify_visibility_cb (GSettings   *gsettings,
471                                   const gchar *key,
472                                   gpointer     user_data)
473 {
474         EmpathyStatusIcon *icon = user_data;
475         gboolean           hidden = FALSE;
476
477         hidden = g_settings_get_boolean (gsettings, key);
478         status_icon_set_visibility (icon, !hidden, FALSE);
479 }
480
481 static void
482 status_icon_toggle_visibility (EmpathyStatusIcon *icon)
483 {
484         EmpathyStatusIconPriv *priv = GET_PRIV (icon);
485         gboolean               visible;
486
487         visible = gtk_window_is_active (priv->window);
488         status_icon_set_visibility (icon, !visible, TRUE);
489 }
490
491 static void
492 status_icon_presence_changed_cb (EmpathyStatusIcon *icon)
493 {
494         EmpathyStatusIconPriv *priv = GET_PRIV (icon);
495
496         status_icon_update_icon (icon);
497         status_icon_update_tooltip (icon);
498
499         if (!empathy_notify_manager_notification_is_enabled (priv->notify_mgr)) {
500                 /* dismiss the outstanding notification if present */
501
502                 if (priv->notification) {
503                         notify_notification_close (priv->notification, NULL);
504                         priv->notification = NULL;
505                 }
506         }
507 }
508
509 static gboolean
510 status_icon_delete_event_cb (GtkWidget         *widget,
511                              GdkEvent          *event,
512                              EmpathyStatusIcon *icon)
513 {
514         status_icon_set_visibility (icon, FALSE, TRUE);
515         return TRUE;
516 }
517
518 static gboolean
519 status_icon_key_press_event_cb  (GtkWidget *window,
520                                  GdkEventKey *event,
521                                  EmpathyStatusIcon *icon)
522 {
523         if (event->keyval == GDK_KEY_Escape) {
524                 status_icon_set_visibility (icon, FALSE, TRUE);
525         }
526         return FALSE;
527 }
528
529 static void
530 status_icon_activate_cb (GtkStatusIcon     *status_icon,
531                          EmpathyStatusIcon *icon)
532 {
533         EmpathyStatusIconPriv *priv = GET_PRIV (icon);
534
535         DEBUG ("%s", priv->event ? "event" : "toggle");
536
537         if (priv->event) {
538                 empathy_event_activate (priv->event);
539         } else {
540                 status_icon_toggle_visibility (icon);
541         }
542 }
543
544 static void
545 status_icon_show_hide_window_cb (GtkToggleAction   *action,
546                                  EmpathyStatusIcon *icon)
547 {
548         gboolean visible;
549
550         visible = gtk_toggle_action_get_active (action);
551         status_icon_set_visibility (icon, visible, TRUE);
552 }
553
554 static void
555 status_icon_new_message_cb (GtkAction         *action,
556                             EmpathyStatusIcon *icon)
557 {
558         empathy_new_message_dialog_show (NULL);
559 }
560
561 static void
562 status_icon_new_call_cb (GtkAction         *action,
563                             EmpathyStatusIcon *icon)
564 {
565         empathy_new_call_dialog_show (NULL);
566 }
567
568 static void
569 status_icon_quit_cb (GtkAction         *action,
570                      EmpathyStatusIcon *icon)
571 {
572         gtk_main_quit ();
573 }
574
575 static void
576 status_icon_popup_menu_cb (GtkStatusIcon     *status_icon,
577                            guint              button,
578                            guint              activate_time,
579                            EmpathyStatusIcon *icon)
580 {
581         EmpathyStatusIconPriv *priv = GET_PRIV (icon);
582         GtkWidget             *menu_item;
583         GtkWidget             *submenu;
584         gboolean               show;
585
586         show = empathy_window_get_is_visible (GTK_WINDOW (priv->window));
587
588         g_signal_handlers_block_by_func (priv->show_window_item,
589                                          status_icon_show_hide_window_cb,
590                                          icon);
591         gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (priv->show_window_item),
592                                       show);
593         g_signal_handlers_unblock_by_func (priv->show_window_item,
594                                            status_icon_show_hide_window_cb,
595                                            icon);
596
597         menu_item = gtk_ui_manager_get_widget (priv->ui_manager, "/menu/status");
598         submenu = empathy_presence_chooser_create_menu ();
599         gtk_menu_item_set_submenu (GTK_MENU_ITEM (menu_item), submenu);
600
601         gtk_menu_popup (GTK_MENU (priv->popup_menu),
602                         NULL, NULL,
603                         gtk_status_icon_position_menu,
604                         priv->icon,
605                         button,
606                         activate_time);
607 }
608
609 static void
610 status_icon_create_menu (EmpathyStatusIcon *icon)
611 {
612         EmpathyStatusIconPriv *priv = GET_PRIV (icon);
613         GtkBuilder            *gui;
614         gchar                 *filename;
615
616         filename = empathy_file_lookup ("empathy-status-icon.ui", "src");
617         gui = empathy_builder_get_file (filename,
618                                         "ui_manager", &priv->ui_manager,
619                                         "menu", &priv->popup_menu,
620                                         "show_list", &priv->show_window_item,
621                                         "new_message", &priv->new_message_item,
622                                         "status", &priv->status_item,
623                                        NULL);
624         g_free (filename);
625
626         empathy_builder_connect (gui, icon,
627                               "show_list", "toggled", status_icon_show_hide_window_cb,
628                               "new_message", "activate", status_icon_new_message_cb,
629                               "new_call", "activate", status_icon_new_call_cb,
630                               "quit", "activate", status_icon_quit_cb,
631                               NULL);
632
633         g_object_ref (priv->ui_manager);
634         g_object_unref (gui);
635 }
636
637 static void
638 status_icon_status_changed_cb (TpAccount *account,
639                                TpConnectionStatus current,
640                                TpConnectionStatus previous,
641                                TpConnectionStatusReason reason,
642                                gchar *dbus_error_name,
643                                GHashTable *details,
644                                EmpathyStatusIcon *icon)
645 {
646         EmpathyStatusIconPriv *priv = GET_PRIV (icon);
647
648         gtk_action_set_sensitive (priv->new_message_item,
649                                   empathy_account_manager_get_accounts_connected (NULL));
650 }
651
652 static void
653 status_icon_finalize (GObject *object)
654 {
655         EmpathyStatusIconPriv *priv = GET_PRIV (object);
656
657         if (priv->blink_timeout) {
658                 g_source_remove (priv->blink_timeout);
659         }
660
661         if (priv->notification) {
662                 notify_notification_close (priv->notification, NULL);
663                 g_object_unref (priv->notification);
664                 priv->notification = NULL;
665         }
666
667         g_object_unref (priv->icon);
668         g_object_unref (priv->account_manager);
669         g_object_unref (priv->event_manager);
670         g_object_unref (priv->ui_manager);
671         g_object_unref (priv->notify_mgr);
672         g_object_unref (priv->gsettings_ui);
673         g_object_unref (priv->window);
674 }
675
676 static void
677 empathy_status_icon_class_init (EmpathyStatusIconClass *klass)
678 {
679         GObjectClass *object_class = G_OBJECT_CLASS (klass);
680
681         object_class->finalize = status_icon_finalize;
682
683         g_type_class_add_private (object_class, sizeof (EmpathyStatusIconPriv));
684 }
685
686 static void
687 account_manager_prepared_cb (GObject *source_object,
688                              GAsyncResult *result,
689                              gpointer user_data)
690 {
691         GList *list, *l;
692         TpAccountManager *account_manager = TP_ACCOUNT_MANAGER (source_object);
693         EmpathyStatusIcon *icon = user_data;
694         GError *error = NULL;
695
696         if (!tp_account_manager_prepare_finish (account_manager, result, &error)) {
697                 DEBUG ("Failed to prepare account manager: %s", error->message);
698                 g_error_free (error);
699                 return;
700         }
701
702         list = tp_account_manager_get_valid_accounts (account_manager);
703         for (l = list; l != NULL; l = l->next) {
704                 tp_g_signal_connect_object (l->data, "status-changed",
705                                              G_CALLBACK (status_icon_status_changed_cb),
706                                              icon, 0);
707         }
708         g_list_free (list);
709
710         status_icon_presence_changed_cb (icon);
711 }
712
713 static void
714 empathy_status_icon_init (EmpathyStatusIcon *icon)
715 {
716         EmpathyStatusIconPriv *priv = G_TYPE_INSTANCE_GET_PRIVATE (icon,
717                 EMPATHY_TYPE_STATUS_ICON, EmpathyStatusIconPriv);
718
719         icon->priv = priv;
720         priv->icon = gtk_status_icon_new ();
721         priv->account_manager = tp_account_manager_dup ();
722         priv->event_manager = empathy_event_manager_dup_singleton ();
723
724         tp_account_manager_prepare_async (priv->account_manager, NULL,
725             account_manager_prepared_cb, icon);
726
727         /* make icon listen and respond to MAIN_WINDOW_HIDDEN changes */
728         priv->gsettings_ui = g_settings_new (EMPATHY_PREFS_UI_SCHEMA);
729         g_signal_connect (priv->gsettings_ui,
730                           "changed::" EMPATHY_PREFS_UI_MAIN_WINDOW_HIDDEN,
731                           G_CALLBACK (status_icon_notify_visibility_cb),
732                           icon);
733
734         status_icon_create_menu (icon);
735
736         g_signal_connect_swapped (priv->account_manager,
737                                   "most-available-presence-changed",
738                                   G_CALLBACK (status_icon_presence_changed_cb),
739                                   icon);
740         g_signal_connect (priv->event_manager, "event-added",
741                           G_CALLBACK (status_icon_event_added_cb),
742                           icon);
743         g_signal_connect (priv->event_manager, "event-removed",
744                           G_CALLBACK (status_icon_event_removed_cb),
745                           icon);
746         g_signal_connect (priv->event_manager, "event-updated",
747                           G_CALLBACK (status_icon_event_updated_cb),
748                           icon);
749         g_signal_connect (priv->icon, "activate",
750                           G_CALLBACK (status_icon_activate_cb),
751                           icon);
752         g_signal_connect (priv->icon, "popup-menu",
753                           G_CALLBACK (status_icon_popup_menu_cb),
754                           icon);
755
756         priv->notification = NULL;
757         priv->notify_mgr = empathy_notify_manager_dup_singleton ();
758 }
759
760 EmpathyStatusIcon *
761 empathy_status_icon_new (GtkWindow *window, gboolean hide_contact_list)
762 {
763         EmpathyStatusIconPriv *priv;
764         EmpathyStatusIcon     *icon;
765         gboolean               should_hide;
766
767         g_return_val_if_fail (GTK_IS_WINDOW (window), NULL);
768
769         icon = g_object_new (EMPATHY_TYPE_STATUS_ICON, NULL);
770         priv = GET_PRIV (icon);
771
772         priv->window = g_object_ref (window);
773
774         g_signal_connect_after (priv->window, "key-press-event",
775                           G_CALLBACK (status_icon_key_press_event_cb),
776                           icon);
777
778         g_signal_connect (priv->window, "delete-event",
779                           G_CALLBACK (status_icon_delete_event_cb),
780                           icon);
781
782         if (!hide_contact_list) {
783                 should_hide = g_settings_get_boolean (priv->gsettings_ui,
784                         EMPATHY_PREFS_UI_MAIN_WINDOW_HIDDEN);
785         } else {
786                 should_hide = TRUE;
787         }
788
789         status_icon_set_visibility (icon, !should_hide, FALSE);
790
791         return icon;
792 }
793