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

« back to all changes in this revision

Viewing changes to src/empathy-notifications-approver.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
/* * Copyright (C) 2009 Collabora Ltd.
 
2
 *
 
3
 * This library is free software; you can redistribute it and/or
 
4
 * modify it under the terms of the GNU Lesser General Public
 
5
 * License as published by the Free Software Foundation; either
 
6
 * version 2.1 of the License, or (at your option) any later version.
 
7
 *
 
8
 * This library is distributed in the hope that it will be useful,
 
9
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 
10
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 
11
 * Lesser General Public License for more details.
 
12
 *
 
13
 * You should have received a copy of the GNU Lesser General Public
 
14
 * License along with this library; if not, write to the Free Software
 
15
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 
16
 *
 
17
 * Authors: Guillaume Desmottes <guillaume.desmottes@collabora.co.uk>
 
18
 */
 
19
 
 
20
#include <config.h>
 
21
#include <string.h>
 
22
 
 
23
#include <glib/gi18n.h>
 
24
#include <libnotify/notification.h>
 
25
#include <libnotify/notify.h>
 
26
#include <telepathy-glib/telepathy-glib.h>
 
27
 
 
28
#include <libempathy/empathy-contact-manager.h>
 
29
 
 
30
#include <libempathy-gtk/empathy-notify-manager.h>
 
31
 
 
32
#include "empathy-event-manager.h"
 
33
 
 
34
#define DEBUG_FLAG EMPATHY_DEBUG_OTHER
 
35
#include <libempathy/empathy-debug.h>
 
36
 
 
37
#include "empathy-notifications-approver.h"
 
38
 
 
39
struct _EmpathyNotificationsApproverPrivate
 
40
{
 
41
  EmpathyEventManager *event_mgr;
 
42
  EmpathyNotifyManager *notify_mgr;
 
43
 
 
44
  NotifyNotification *notification;
 
45
  EmpathyEvent *event;
 
46
};
 
47
 
 
48
G_DEFINE_TYPE (EmpathyNotificationsApprover, empathy_notifications_approver,
 
49
    G_TYPE_OBJECT);
 
50
 
 
51
static EmpathyNotificationsApprover *notifications_approver = NULL;
 
52
 
 
53
static GObject *
 
54
notifications_approver_constructor (GType type,
 
55
    guint n_construct_params,
 
56
    GObjectConstructParam *construct_params)
 
57
{
 
58
  GObject *retval;
 
59
 
 
60
  if (notifications_approver != NULL)
 
61
    return g_object_ref (notifications_approver);
 
62
 
 
63
  retval = G_OBJECT_CLASS (empathy_notifications_approver_parent_class)->
 
64
      constructor (type, n_construct_params, construct_params);
 
65
 
 
66
  notifications_approver = EMPATHY_NOTIFICATIONS_APPROVER (retval);
 
67
  g_object_add_weak_pointer (retval, (gpointer) &notifications_approver);
 
68
 
 
69
  return retval;
 
70
}
 
71
 
 
72
static void
 
73
notifications_approver_dispose (GObject *object)
 
74
{
 
75
  EmpathyNotificationsApprover *self = (EmpathyNotificationsApprover *) object;
 
76
 
 
77
  tp_clear_object (&self->priv->event_mgr);
 
78
  tp_clear_object (&self->priv->notify_mgr);
 
79
 
 
80
  if (self->priv->notification != NULL)
 
81
    {
 
82
      notify_notification_close (self->priv->notification, NULL);
 
83
      tp_clear_object (&self->priv->notification);
 
84
    }
 
85
 
 
86
  G_OBJECT_CLASS (empathy_notifications_approver_parent_class)->dispose (
 
87
      object);
 
88
}
 
89
 
 
90
static void
 
91
empathy_notifications_approver_class_init (
 
92
    EmpathyNotificationsApproverClass *klass)
 
93
{
 
94
  GObjectClass *object_class = G_OBJECT_CLASS (klass);
 
95
 
 
96
  object_class->dispose = notifications_approver_dispose;
 
97
  object_class->constructor = notifications_approver_constructor;
 
98
 
 
99
  g_type_class_add_private (object_class,
 
100
      sizeof (EmpathyNotificationsApproverPrivate));
 
101
}
 
102
 
 
103
static void
 
104
notification_closed_cb (NotifyNotification *notification,
 
105
    EmpathyNotificationsApprover *self)
 
106
{
 
107
  if (self->priv->notification == notification)
 
108
    tp_clear_object (&self->priv->notification);
 
109
}
 
110
 
 
111
static void
 
112
notification_close_helper (EmpathyNotificationsApprover *self)
 
113
{
 
114
  if (self->priv->notification != NULL)
 
115
    {
 
116
      notify_notification_close (self->priv->notification, NULL);
 
117
      tp_clear_object (&self->priv->notification);
 
118
    }
 
119
}
 
120
 
 
121
static void
 
122
notification_approve_cb (NotifyNotification *notification,
 
123
    gchar *action,
 
124
    EmpathyNotificationsApprover *self)
 
125
{
 
126
  if (self->priv->event != NULL)
 
127
    empathy_event_approve (self->priv->event);
 
128
}
 
129
 
 
130
static void
 
131
notification_decline_cb (NotifyNotification *notification,
 
132
    gchar *action,
 
133
    EmpathyNotificationsApprover  *self)
 
134
{
 
135
  if (self->priv->event != NULL)
 
136
    empathy_event_decline (self->priv->event);
 
137
}
 
138
 
 
139
static void
 
140
notification_decline_subscription_cb (NotifyNotification *notification,
 
141
    gchar *action,
 
142
    EmpathyNotificationsApprover *self)
 
143
{
 
144
  EmpathyContactManager *manager;
 
145
 
 
146
  if (self->priv->event == NULL)
 
147
    return;
 
148
 
 
149
  manager = empathy_contact_manager_dup_singleton ();
 
150
  empathy_contact_list_remove (EMPATHY_CONTACT_LIST (manager),
 
151
      self->priv->event->contact, "");
 
152
 
 
153
  empathy_event_remove (self->priv->event);
 
154
 
 
155
  g_object_unref (manager);
 
156
}
 
157
 
 
158
static void
 
159
notification_accept_subscription_cb (NotifyNotification *notification,
 
160
    gchar *action,
 
161
    EmpathyNotificationsApprover *self)
 
162
{
 
163
  EmpathyContactManager *manager;
 
164
 
 
165
  if (self->priv->event == NULL)
 
166
    return;
 
167
 
 
168
  manager = empathy_contact_manager_dup_singleton ();
 
169
  empathy_contact_list_add (EMPATHY_CONTACT_LIST (manager),
 
170
      self->priv->event->contact, "");
 
171
 
 
172
  empathy_event_remove (self->priv->event);
 
173
 
 
174
  g_object_unref (manager);
 
175
}
 
176
 
 
177
static void
 
178
add_notification_actions (EmpathyNotificationsApprover *self,
 
179
    NotifyNotification *notification)
 
180
{
 
181
  switch (self->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
      break;
 
220
 
 
221
    case EMPATHY_EVENT_TYPE_AUTH:
 
222
      /* translators: the 'Provide' button is displayed in a notification
 
223
       * bubble when Empathy is asking for an account password; clicking on it
 
224
       * brings the password popup. */
 
225
      notify_notification_add_action (notification,
 
226
        "provide", _("Provide"), (NotifyActionCallback) notification_approve_cb,
 
227
          self, NULL);
 
228
      break;
 
229
 
 
230
    default:
 
231
      break;
 
232
  }
 
233
}
 
234
 
 
235
static gboolean
 
236
notification_is_urgent (EmpathyNotificationsApprover *self,
 
237
    NotifyNotification *notification)
 
238
{
 
239
  /* Mark as urgent all the notifications with which user should
 
240
   * interact ASAP */
 
241
  switch (self->priv->event->type) {
 
242
    case EMPATHY_EVENT_TYPE_CHAT:
 
243
    case EMPATHY_EVENT_TYPE_VOIP:
 
244
    case EMPATHY_EVENT_TYPE_TRANSFER:
 
245
    case EMPATHY_EVENT_TYPE_INVITATION:
 
246
    case EMPATHY_EVENT_TYPE_AUTH:
 
247
      return TRUE;
 
248
 
 
249
    case EMPATHY_EVENT_TYPE_SUBSCRIPTION:
 
250
    case EMPATHY_EVENT_TYPE_PRESENCE_ONLINE:
 
251
    case EMPATHY_EVENT_TYPE_PRESENCE_OFFLINE:
 
252
      return FALSE;
 
253
  }
 
254
 
 
255
  return FALSE;
 
256
}
 
257
 
 
258
static const gchar *
 
259
get_category_for_event_type (EmpathyEventType type)
 
260
{
 
261
  switch (type) {
 
262
    case EMPATHY_EVENT_TYPE_CHAT:
 
263
      return "im.received";
 
264
    case EMPATHY_EVENT_TYPE_PRESENCE_ONLINE:
 
265
      return "presence.online";
 
266
    case EMPATHY_EVENT_TYPE_PRESENCE_OFFLINE:
 
267
      return "presence.offline";
 
268
    case EMPATHY_EVENT_TYPE_VOIP:
 
269
    case EMPATHY_EVENT_TYPE_TRANSFER:
 
270
    case EMPATHY_EVENT_TYPE_INVITATION:
 
271
    case EMPATHY_EVENT_TYPE_AUTH:
 
272
    case EMPATHY_EVENT_TYPE_SUBSCRIPTION:
 
273
      return NULL;
 
274
  }
 
275
 
 
276
  return NULL;
 
277
}
 
278
 
 
279
static void
 
280
update_notification (EmpathyNotificationsApprover *self)
 
281
{
 
282
  GdkPixbuf *pixbuf = NULL;
 
283
  gchar *message_esc = NULL;
 
284
  gboolean has_x_canonical_append;
 
285
  NotifyNotification *notification;
 
286
 
 
287
  if (!empathy_notify_manager_notification_is_enabled (self->priv->notify_mgr))
 
288
    {
 
289
      /* always close the notification if this happens */
 
290
      notification_close_helper (self);
 
291
      return;
 
292
    }
 
293
 
 
294
  if (self->priv->event == NULL)
 
295
    {
 
296
      notification_close_helper (self);
 
297
      return;
 
298
     }
 
299
 
 
300
  if (self->priv->event->message != NULL)
 
301
    message_esc = g_markup_escape_text (self->priv->event->message, -1);
 
302
 
 
303
  has_x_canonical_append = empathy_notify_manager_has_capability (
 
304
      self->priv->notify_mgr, EMPATHY_NOTIFY_MANAGER_CAP_X_CANONICAL_APPEND);
 
305
 
 
306
  if (self->priv->notification != NULL && ! has_x_canonical_append)
 
307
    {
 
308
      /* if the notification server does NOT supports x-canonical-append, it is
 
309
       * better to not use notify_notification_update to avoid
 
310
       * overwriting the current notification message */
 
311
      notification = g_object_ref (self->priv->notification);
 
312
 
 
313
      notify_notification_update (notification,
 
314
          self->priv->event->header, message_esc, NULL);
 
315
    }
 
316
  else
 
317
    {
 
318
      const gchar *category;
 
319
 
 
320
      /* if the notification server supports x-canonical-append,
 
321
       * the hint will be added, so that the message from the
 
322
       * just created notification will be automatically appended
 
323
       * to an existing notification with the same title.
 
324
       * In this way the previous message will not be lost: the new
 
325
       * message will appear below it, in the same notification */
 
326
      notification = notify_notification_new (self->priv->event->header,
 
327
           message_esc, NULL);
 
328
 
 
329
      if (self->priv->notification == NULL)
 
330
        {
 
331
          self->priv->notification = g_object_ref (notification);
 
332
 
 
333
          g_signal_connect (notification, "closed",
 
334
              G_CALLBACK (notification_closed_cb), self);
 
335
        }
 
336
 
 
337
      notify_notification_set_timeout (notification,
 
338
          NOTIFY_EXPIRES_DEFAULT);
 
339
 
 
340
      if (has_x_canonical_append)
 
341
        /* We have to set a not empty string to keep libnotify happy */
 
342
        notify_notification_set_hint_string (notification,
 
343
            EMPATHY_NOTIFY_MANAGER_CAP_X_CANONICAL_APPEND, "1");
 
344
 
 
345
      if (empathy_notify_manager_has_capability (self->priv->notify_mgr,
 
346
            EMPATHY_NOTIFY_MANAGER_CAP_ACTIONS))
 
347
        add_notification_actions (self, notification);
 
348
 
 
349
      if (notification_is_urgent (self, notification))
 
350
        notify_notification_set_urgency (notification, NOTIFY_URGENCY_CRITICAL);
 
351
 
 
352
      category = get_category_for_event_type (self->priv->event->type);
 
353
      if (category != NULL)
 
354
        notify_notification_set_hint_string (notification,
 
355
            EMPATHY_NOTIFY_MANAGER_CAP_CATEGORY, category);
 
356
    }
 
357
 
 
358
  pixbuf = empathy_notify_manager_get_pixbuf_for_notification (
 
359
      self->priv->notify_mgr, self->priv->event->contact,
 
360
      self->priv->event->icon_name);
 
361
 
 
362
  if (pixbuf != NULL)
 
363
    {
 
364
      notify_notification_set_icon_from_pixbuf (notification, pixbuf);
 
365
      g_object_unref (pixbuf);
 
366
    }
 
367
 
 
368
  notify_notification_show (notification, NULL);
 
369
 
 
370
  g_free (message_esc);
 
371
  g_object_unref (notification);
 
372
}
 
373
 
 
374
static void
 
375
event_added_cb (EmpathyEventManager *manager,
 
376
    EmpathyEvent *event,
 
377
    EmpathyNotificationsApprover *self)
 
378
{
 
379
  if (self->priv->event != NULL)
 
380
    return;
 
381
 
 
382
  self->priv->event = event;
 
383
 
 
384
  update_notification (self);
 
385
}
 
386
 
 
387
static void
 
388
event_removed_cb (EmpathyEventManager *manager,
 
389
    EmpathyEvent *event,
 
390
    EmpathyNotificationsApprover *self)
 
391
{
 
392
  if (event != self->priv->event)
 
393
    return;
 
394
 
 
395
  self->priv->event = empathy_event_manager_get_top_event (
 
396
      self->priv->event_mgr);
 
397
 
 
398
  update_notification (self);
 
399
}
 
400
 
 
401
static void
 
402
event_updated_cb (EmpathyEventManager *manager,
 
403
    EmpathyEvent *event,
 
404
    EmpathyNotificationsApprover *self)
 
405
{
 
406
  if (event != self->priv->event)
 
407
    return;
 
408
 
 
409
  if (empathy_notify_manager_notification_is_enabled (self->priv->notify_mgr))
 
410
    update_notification (self);
 
411
}
 
412
 
 
413
static void
 
414
empathy_notifications_approver_init (EmpathyNotificationsApprover *self)
 
415
{
 
416
  EmpathyNotificationsApproverPrivate *priv = G_TYPE_INSTANCE_GET_PRIVATE (self,
 
417
    EMPATHY_TYPE_NOTIFICATIONS_APPROVER, EmpathyNotificationsApproverPrivate);
 
418
 
 
419
  self->priv = priv;
 
420
 
 
421
  self->priv->event_mgr = empathy_event_manager_dup_singleton ();
 
422
  self->priv->notify_mgr = empathy_notify_manager_dup_singleton ();
 
423
 
 
424
  tp_g_signal_connect_object (self->priv->event_mgr, "event-added",
 
425
      G_CALLBACK (event_added_cb), self, 0);
 
426
  tp_g_signal_connect_object (priv->event_mgr, "event-removed",
 
427
      G_CALLBACK (event_removed_cb), self, 0);
 
428
  tp_g_signal_connect_object (priv->event_mgr, "event-updated",
 
429
      G_CALLBACK (event_updated_cb), self, 0);
 
430
}
 
431
 
 
432
EmpathyNotificationsApprover *
 
433
empathy_notifications_approver_dup_singleton (void)
 
434
{
 
435
  return g_object_new (EMPATHY_TYPE_NOTIFICATIONS_APPROVER, NULL);
 
436
}