~ubuntu-branches/ubuntu/precise/empathy/precise-proposed-201205180810

« back to all changes in this revision

Viewing changes to .pc/20_libindicate.patch/src/empathy-status-icon.c

  • Committer: Bazaar Package Importer
  • Author(s): Brian Curtis, Brian Curtis, Ken VanDine
  • Date: 2011-06-01 10:35:24 UTC
  • mfrom: (1.1.70 upstream) (6.3.44 experimental)
  • Revision ID: james.westby@ubuntu.com-20110601103524-wx3wgp71394730jt
Tags: 3.1.1-1ubuntu1
[ Brian Curtis ]
* Merge with Debian experimental, remaining Ubuntu changes:
* debian/control:
  - Drop geoclue/mapping build-depends (they are in Universe)
  - Add Vcz-Bzr link
  - Add Suggests on telepathy-idle
  - Bump telepathy-butterfly, telepathy-haze to recommends
  - Don't recommend the freedesktop sound theme we have an ubuntu one
  - Add build depend for libunity-dev
* debian/rules:
  - Use autoreconf.mk
  - Disable map and location
* debian/empathy.install:
  - Install message indicator configuration
* debian/indicators/empathy:
  - Message indicator configuration
* debian/patches/01_lpi.patch:
  - Add Launchpad integration
* debian/patches/10_use_notify_osd_icons.patch:
  - Use the notify-osd image for new messages
* debian/patches/34_start_raised_execpt_in_session.patch
  - If not started with the session, we should always raise
* debian/patches/36_chat_window_default_size.patch:
  - Make the default chat window size larger
* debian/patches/37_facebook_default.patch:
  - Make facebook the default chat account type
* debian/patches/38_lp_569289.patch
  - Set freenode as default IRC network for new IRC accounts 
* debian/patches/41_unity_launcher_progress.patch
  - Display file transfer progress in the unity launcher

[ Ken VanDine ]
* debian/control
  - build depend on libgcr-3-dev instead of libgcr-dev
  - dropped build depends for libindicate, we will use telepathy-indicator
  - Depend on dconf-gsettings-backend | gsettings-backend
  - Added a Recommends for telepathy-indicator
* +debian/empathy.gsettings-override
  - Added an override for notifications-focus
* debian/patches/series
  - commented out 23_idomessagedialog_for_voip_and_ft.patch, until ido has 
    been ported to gtk3

Show diffs side-by-side

added added

removed removed

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