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

« back to all changes in this revision

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