]> git.0d.be Git - empathy.git/blob - src/empathy-event-manager.c
Make notifications for unfocused chat windows work properly.
[empathy.git] / src / empathy-event-manager.c
1 /*
2  * Copyright (C) 2007-2008 Collabora Ltd.
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Lesser General Public
6  * License as published by the Free Software Foundation; either
7  * version 2.1 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Lesser General Public License for more details.
13  *
14  * You should have received a copy of the GNU Lesser General Public
15  * License along with this library; if not, write to the Free Software
16  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
17  * 
18  * Authors: Xavier Claessens <xclaesse@gmail.com>
19  *          Sjoerd Simons <sjoerd.simons@collabora.co.uk>
20  */
21
22 #include <config.h>
23
24 #include <string.h>
25 #include <glib/gi18n.h>
26
27 #include <telepathy-glib/util.h>
28
29 #include <libempathy/empathy-dispatcher.h>
30 #include <libempathy/empathy-contact-factory.h>
31 #include <libempathy/empathy-contact-manager.h>
32 #include <libempathy/empathy-tp-chat.h>
33 #include <libempathy/empathy-tp-call.h>
34 #include <libempathy/empathy-utils.h>
35
36 #include <extensions/extensions.h>
37
38 #include <libempathy-gtk/empathy-images.h>
39 #include <libempathy-gtk/empathy-contact-dialogs.h>
40
41 #include "empathy-event-manager.h"
42 #include "empathy-tube-dispatch.h"
43
44 #define DEBUG_FLAG EMPATHY_DEBUG_DISPATCHER
45 #include <libempathy/empathy-debug.h>
46
47 #define GET_PRIV(obj) EMPATHY_GET_PRIV (obj, EmpathyEventManager)
48
49 typedef struct {
50   EmpathyEventManager *manager;
51   EmpathyDispatchOperation *operation;
52   gulong approved_handler;
53   gulong claimed_handler;
54   gulong invalidated_handler;
55   /* Remove contact if applicable */
56   EmpathyContact *contact;
57   /* Tube dispatcher if applicable */
58   EmpathyTubeDispatch *tube_dispatch;
59   /* option signal handler */
60   gulong handler;
61 } EventManagerApproval;
62
63 typedef struct {
64   EmpathyDispatcher *dispatcher;
65   EmpathyContactManager *contact_manager;
66   GSList *events;
67   /* Ongoing approvals */
68   GSList *approvals;
69 } EmpathyEventManagerPriv;
70
71 typedef struct _EventPriv EventPriv;
72 typedef void (*EventFunc) (EventPriv *event);
73
74 struct _EventPriv {
75   EmpathyEvent public;
76   EmpathyEventManager *manager;
77   EventManagerApproval *approval;
78   EventFunc func;
79   gboolean inhibit;
80   gpointer user_data;
81 };
82
83 enum {
84   EVENT_ADDED,
85   EVENT_REMOVED,
86   EVENT_UPDATED,
87   LAST_SIGNAL
88 };
89
90 static guint signals[LAST_SIGNAL];
91
92 G_DEFINE_TYPE (EmpathyEventManager, empathy_event_manager, G_TYPE_OBJECT);
93
94 static EmpathyEventManager * manager_singleton = NULL;
95
96 static EventManagerApproval *
97 event_manager_approval_new (EmpathyEventManager *manager,
98   EmpathyDispatchOperation *operation)
99 {
100   EventManagerApproval *result = g_slice_new0 (EventManagerApproval);
101   result->operation = g_object_ref (operation);
102   result->manager = manager;
103
104   return result;
105 }
106
107 static void
108 event_manager_approval_free (EventManagerApproval *approval)
109 {
110   g_signal_handler_disconnect (approval->operation,
111     approval->approved_handler);
112   g_signal_handler_disconnect (approval->operation,
113     approval->claimed_handler);
114   g_signal_handler_disconnect (approval->operation,
115     approval->invalidated_handler);
116   g_object_unref (approval->operation);
117
118   if (approval->contact != NULL)
119     g_object_unref (approval->contact);
120
121   if (approval->tube_dispatch != NULL)
122     g_object_unref (approval->tube_dispatch);
123
124   g_slice_free (EventManagerApproval, approval);
125 }
126
127 static void event_remove (EventPriv *event);
128
129 static void
130 event_free (EventPriv *event)
131 {
132   g_free (event->public.icon_name);
133   g_free (event->public.header);
134   g_free (event->public.message);
135
136   if (event->public.contact)
137     {
138       g_object_unref (event->public.contact);
139     }
140
141   g_slice_free (EventPriv, event);
142 }
143
144 static void
145 event_remove (EventPriv *event)
146 {
147   EmpathyEventManagerPriv *priv = GET_PRIV (event->manager);
148
149   DEBUG ("Removing event %p", event);
150   priv->events = g_slist_remove (priv->events, event);
151   g_signal_emit (event->manager, signals[EVENT_REMOVED], 0, event);
152   event_free (event);
153 }
154
155 static void
156 event_manager_add (EmpathyEventManager *manager, EmpathyContact *contact,
157   const gchar *icon_name, const gchar *header, const gchar *message,
158   EventManagerApproval *approval, EventFunc func, gpointer user_data)
159 {
160   EmpathyEventManagerPriv *priv = GET_PRIV (manager);
161   EventPriv               *event;
162
163   event = g_slice_new0 (EventPriv);
164   event->public.contact = contact ? g_object_ref (contact) : NULL;
165   event->public.icon_name = g_strdup (icon_name);
166   event->public.header = g_strdup (header);
167   event->public.message = g_strdup (message);
168   event->inhibit = FALSE;
169   event->func = func;
170   event->user_data = user_data;
171   event->manager = manager;
172   event->approval = approval;
173
174   DEBUG ("Adding event %p", event);
175   priv->events = g_slist_prepend (priv->events, event);
176   g_signal_emit (event->manager, signals[EVENT_ADDED], 0, event);
177 }
178
179 static void
180 event_channel_process_func (EventPriv *event)
181 {
182   empathy_dispatch_operation_approve (event->approval->operation);
183 }
184
185 static void
186 event_text_channel_process_func (EventPriv *event)
187 {
188   EmpathyTpChat *tp_chat;
189
190   if (event->approval->handler != 0)
191     {
192       tp_chat = EMPATHY_TP_CHAT
193         (empathy_dispatch_operation_get_channel_wrapper (event->approval->operation));
194   
195       g_signal_handler_disconnect (tp_chat, event->approval->handler);
196       event->approval->handler = 0;
197     }
198
199   empathy_dispatch_operation_approve (event->approval->operation);
200 }
201
202 static EventPriv *
203 event_lookup_by_approval (EmpathyEventManager *manager,
204   EventManagerApproval *approval)
205 {
206   EmpathyEventManagerPriv *priv = GET_PRIV (manager);
207   GSList *l;
208   EventPriv *retval = NULL;
209
210   for (l = priv->events; l; l = l->next)
211     {
212       EventPriv *event = l->data;
213
214       if (event->approval == approval)
215         {
216           retval = event;
217           break;
218         }
219     }
220
221   return retval;
222 }
223
224 static void
225 event_update (EmpathyEventManager *manager, EventPriv *event,
226   const char *icon_name, const char *header, const char *msg)
227 {
228   g_free (event->public.icon_name);
229   g_free (event->public.header);
230   g_free (event->public.message);
231
232   event->public.icon_name = g_strdup (icon_name);
233   event->public.header = g_strdup (header);
234   event->public.message = g_strdup (msg);
235
236   g_signal_emit (manager, signals[EVENT_UPDATED], 0, event);
237 }
238
239 static void
240 event_manager_chat_message_received_cb (EmpathyTpChat *tp_chat,
241   EmpathyMessage *message, EventManagerApproval *approval)
242 {
243   EmpathyContact  *sender;
244   gchar           *header;
245   const gchar     *msg;
246   TpChannel       *channel;
247   EventPriv       *event;
248
249   /* try to update the event if it's referring to a chat which is already in the
250    * queue. */
251   event = event_lookup_by_approval (approval->manager, approval);
252
253   if (event != NULL && event->inhibit && approval->handler != 0)
254     {
255       g_signal_handler_disconnect (tp_chat, approval->handler);
256       approval->handler = 0;
257       return;
258     }
259
260   sender = empathy_message_get_sender (message);
261   header = g_strdup_printf (_("New message from %s"),
262                             empathy_contact_get_name (sender));
263   msg = empathy_message_get_body (message);
264
265   channel = empathy_tp_chat_get_channel (tp_chat);
266
267   if (event != NULL)
268     event_update (approval->manager, event, EMPATHY_IMAGE_NEW_MESSAGE, header, msg);
269   else
270     event_manager_add (approval->manager, sender, EMPATHY_IMAGE_NEW_MESSAGE, header,
271       msg, approval, event_text_channel_process_func, NULL);
272
273   g_free (header);
274 }
275
276 static void
277 event_manager_approval_done (EventManagerApproval *approval)
278 {
279   EmpathyEventManagerPriv *priv = GET_PRIV (approval->manager);
280   GSList                  *l;
281
282   priv->approvals = g_slist_remove (priv->approvals, approval);
283
284   for (l = priv->events; l; l = l->next)
285     {
286       EventPriv *event = l->data;
287
288       if (event->approval == approval)
289         {
290           event_remove (event);
291           break;
292         }
293     }
294
295   event_manager_approval_free (approval);
296 }
297
298 static void
299 event_manager_operation_approved_cb (EmpathyDispatchOperation *operation,
300   EventManagerApproval *approval)
301 {
302   event_manager_approval_done (approval);
303 }
304
305 static void
306 event_manager_operation_claimed_cb (EmpathyDispatchOperation *operation,
307   EventManagerApproval *approval)
308 {
309   event_manager_approval_done (approval);
310 }
311
312 static void
313 event_manager_operation_invalidated_cb (EmpathyDispatchOperation *operation,
314   guint domain, gint code, gchar *message,
315   EventManagerApproval *approval)
316 {
317   event_manager_approval_done (approval);
318 }
319
320 static void
321 event_manager_media_channel_got_name_cb (EmpathyContact *contact,
322   const GError *error, gpointer user_data, GObject *object)
323 {
324   EventManagerApproval *approval = user_data;
325   gchar *header;
326
327   if (error != NULL)
328     {
329       /* FIXME just returning assuming the operation will be invalidated as
330        * well */
331       return;
332     }
333
334   header = g_strdup_printf (_("Incoming call from %s"),
335     empathy_contact_get_name (contact));
336
337   event_manager_add (approval->manager,
338     approval->contact, EMPATHY_IMAGE_VOIP, header, NULL,
339     approval, event_channel_process_func, NULL);
340
341   g_free (header);
342 }
343
344 static void
345 event_manager_media_channel_got_contact (EventManagerApproval *approval)
346 {
347   empathy_contact_call_when_ready (approval->contact,
348      EMPATHY_CONTACT_READY_NAME, event_manager_media_channel_got_name_cb,
349         approval, NULL, G_OBJECT (approval->manager));
350 }
351
352 static void
353 event_manager_media_channel_contact_changed_cb (EmpathyTpCall *call,
354   GParamSpec *param, EventManagerApproval *approval)
355 {
356   EmpathyContact *contact;
357
358   g_object_get (G_OBJECT (call), "contact", &contact, NULL);
359
360   if (contact == NULL)
361     return;
362
363   approval->contact = contact;
364   event_manager_media_channel_got_contact (approval);
365 }
366
367 static void
368 event_manager_tube_approved_cb (EventPriv *event)
369 {
370   empathy_tube_dispatch_handle (event->approval->tube_dispatch);
371 }
372
373 static void
374 event_manager_add_tube_approval (EventManagerApproval *approval,
375   EmpathyTubeDispatchAbility ability)
376 {
377   const gchar *icon_name;
378   gchar       *header;
379   const gchar *msg;
380
381   header = g_strdup_printf (_("%s is offering you an invitation"),
382     empathy_contact_get_name (approval->contact));
383
384   if (ability == EMPATHY_TUBE_DISPATCHABILITY_POSSIBLE)
385     {
386       icon_name = GTK_STOCK_EXECUTE;
387       msg = _("An external application will be started to handle it.");
388     }
389   else
390     {
391       icon_name = GTK_STOCK_DIALOG_ERROR;
392       msg = _("You don't have the needed external "
393               "application to handle it.");
394     }
395
396   event_manager_add (approval->manager, approval->contact, icon_name, header,
397     msg, approval, event_manager_tube_approved_cb, approval);
398
399   g_free (header);
400 }
401
402 static void
403 event_manager_tube_dispatch_ability_cb (GObject *object,
404    GParamSpec *spec, gpointer user_data)
405 {
406   EventManagerApproval *approval = (EventManagerApproval *)user_data;
407   EmpathyTubeDispatchAbility dispatchability;
408
409   dispatchability =
410     empathy_tube_dispatch_is_dispatchable (approval->tube_dispatch);
411
412   if (dispatchability != EMPATHY_TUBE_DISPATCHABILITY_UNKNOWN)
413     {
414       event_manager_add_tube_approval (approval, dispatchability);
415       g_signal_handler_disconnect (object, approval->handler);
416       approval->handler = 0;
417     }
418 }
419
420 static void
421 event_manager_tube_got_contact_name_cb (EmpathyContact *contact,
422   const GError *error, gpointer user_data, GObject *object)
423 {
424   EventManagerApproval *approval = (EventManagerApproval *)user_data;
425   EmpathyTubeDispatchAbility dispatchability;
426
427   if (error != NULL)
428     {
429       /* FIXME?, we assume that the operation gets invalidated as well (if it
430        * didn't already */
431        return;
432     }
433
434   dispatchability = empathy_tube_dispatch_is_dispatchable
435     (approval->tube_dispatch);
436
437
438   switch (dispatchability)
439     {
440       case EMPATHY_TUBE_DISPATCHABILITY_UNKNOWN:
441         approval->handler = g_signal_connect (approval->tube_dispatch,
442           "notify::dispatchability",
443           G_CALLBACK (event_manager_tube_dispatch_ability_cb), approval);
444         break;
445       case EMPATHY_TUBE_DISPATCHABILITY_POSSIBLE:
446         /* fallthrough */
447       case EMPATHY_TUBE_DISPATCHABILITY_IMPOSSIBLE:
448         event_manager_add_tube_approval (approval, dispatchability);
449         break;
450     }
451 }
452
453 static void
454 event_manager_approve_channel_cb (EmpathyDispatcher *dispatcher,
455   EmpathyDispatchOperation  *operation, EmpathyEventManager *manager)
456 {
457   const gchar *channel_type;
458   EventManagerApproval *approval;
459   EmpathyEventManagerPriv *priv = GET_PRIV (manager);
460
461   channel_type = empathy_dispatch_operation_get_channel_type (operation);
462
463   approval = event_manager_approval_new (manager, operation);
464   priv->approvals = g_slist_prepend (priv->approvals, approval);
465
466   approval->approved_handler = g_signal_connect (operation, "approved",
467     G_CALLBACK (event_manager_operation_approved_cb), approval);
468
469   approval->claimed_handler = g_signal_connect (operation, "claimed",
470      G_CALLBACK (event_manager_operation_claimed_cb), approval);
471
472   approval->invalidated_handler = g_signal_connect (operation, "invalidated",
473      G_CALLBACK (event_manager_operation_invalidated_cb), approval);
474
475   if (!tp_strdiff (channel_type, TP_IFACE_CHANNEL_TYPE_TEXT))
476     {
477       EmpathyTpChat *tp_chat =
478         EMPATHY_TP_CHAT (
479           empathy_dispatch_operation_get_channel_wrapper (operation));
480
481       approval->handler = g_signal_connect (tp_chat, "message-received",
482         G_CALLBACK (event_manager_chat_message_received_cb), approval);
483
484     }
485   else if (!tp_strdiff (channel_type, TP_IFACE_CHANNEL_TYPE_STREAMED_MEDIA))
486     {
487       EmpathyContact *contact;
488       EmpathyTpCall *call = EMPATHY_TP_CALL (
489           empathy_dispatch_operation_get_channel_wrapper (operation));
490
491       g_object_get (G_OBJECT (call), "contact", &contact, NULL);
492
493       if (contact == NULL)
494         {
495           g_signal_connect (call, "notify::contact",
496             G_CALLBACK (event_manager_media_channel_contact_changed_cb),
497             approval);
498         }
499       else
500         {
501           approval->contact = contact;
502           event_manager_media_channel_got_contact (approval);
503         }
504
505     }
506   else if (!tp_strdiff (channel_type, EMP_IFACE_CHANNEL_TYPE_FILE_TRANSFER))
507     {
508       EmpathyContact        *contact;
509       gchar                 *header;
510       TpHandle               handle;
511       McAccount             *account;
512       EmpathyContactFactory *factory;
513       TpChannel *channel = empathy_dispatch_operation_get_channel (operation);
514
515       factory = empathy_contact_factory_dup_singleton ();
516       handle = tp_channel_get_handle (channel, NULL);
517       account = empathy_channel_get_account (channel);
518
519       contact = empathy_contact_factory_get_from_handle (factory, account,
520         handle);
521
522       empathy_contact_run_until_ready (contact,
523         EMPATHY_CONTACT_READY_NAME, NULL);
524
525       header = g_strdup_printf (_("Incoming file transfer from %s"),
526         empathy_contact_get_name (contact));
527
528       event_manager_add (manager, contact, EMPATHY_IMAGE_DOCUMENT_SEND,
529         header, NULL, approval, event_channel_process_func, NULL);
530
531       g_object_unref (factory);
532       g_object_unref (account);
533       g_free (header);
534     }
535   else if (!tp_strdiff (channel_type, EMP_IFACE_CHANNEL_TYPE_STREAM_TUBE) ||
536       !tp_strdiff (channel_type, EMP_IFACE_CHANNEL_TYPE_DBUS_TUBE))
537     {
538       EmpathyContact        *contact;
539       TpHandle               handle;
540       TpHandleType           handle_type;
541       McAccount             *account;
542       EmpathyContactFactory *factory;
543       EmpathyTubeDispatch *tube_dispatch;
544       TpChannel *channel;
545
546       channel = empathy_dispatch_operation_get_channel (operation);
547
548       handle = tp_channel_get_handle (channel, &handle_type);
549
550       /* Only understand p2p tubes */
551       if (handle_type != TP_HANDLE_TYPE_CONTACT)
552         return;
553
554       factory = empathy_contact_factory_dup_singleton ();
555       account = empathy_channel_get_account (channel);
556
557       contact = empathy_contact_factory_get_from_handle (factory, account,
558         handle);
559
560       tube_dispatch = empathy_tube_dispatch_new (operation);
561
562       approval->contact = contact;
563       approval->tube_dispatch = tube_dispatch;
564
565       empathy_contact_call_when_ready (contact,
566         EMPATHY_CONTACT_READY_NAME, event_manager_tube_got_contact_name_cb,
567         approval, NULL, G_OBJECT (manager));
568
569       g_object_unref (factory);
570       g_object_unref (account);
571     }
572   else
573     {
574       DEBUG ("Unknown channel type, ignoring..");
575     }
576 }
577
578 static void
579 event_pending_subscribe_func (EventPriv *event)
580 {
581   empathy_subscription_dialog_show (event->public.contact, NULL);
582   event_remove (event);
583 }
584
585 static void
586 event_manager_pendings_changed_cb (EmpathyContactList  *list,
587   EmpathyContact *contact, EmpathyContact *actor,
588   guint reason, gchar *message, gboolean is_pending,
589   EmpathyEventManager *manager)
590 {
591   EmpathyEventManagerPriv *priv = GET_PRIV (manager);
592   gchar                   *header, *event_msg;
593
594   if (!is_pending)
595     {
596       GSList *l;
597
598       for (l = priv->events; l; l = l->next)
599         {
600           EventPriv *event = l->data;
601
602       if (event->public.contact == contact &&
603           event->func == event_pending_subscribe_func)
604         {
605           event_remove (event);
606           break;
607         }
608       }
609
610       return;
611     }
612
613   empathy_contact_run_until_ready (contact, EMPATHY_CONTACT_READY_NAME, NULL);
614
615   header = g_strdup_printf (_("Subscription requested by %s"),
616     empathy_contact_get_name (contact));
617
618   if (!EMP_STR_EMPTY (message))
619     event_msg = g_strdup_printf (_("\nMessage: %s"), message);
620   else
621     event_msg = NULL;
622
623   event_manager_add (manager, contact, GTK_STOCK_DIALOG_QUESTION, header,
624     event_msg, NULL, event_pending_subscribe_func, NULL);
625
626   g_free (event_msg);
627   g_free (header);
628 }
629
630 static GObject *
631 event_manager_constructor (GType type,
632                            guint n_props,
633                            GObjectConstructParam *props)
634 {
635         GObject *retval;
636
637         if (manager_singleton) {
638                 retval = g_object_ref (manager_singleton);
639         } else {
640                 retval = G_OBJECT_CLASS (empathy_event_manager_parent_class)->constructor
641                         (type, n_props, props);
642
643                 manager_singleton = EMPATHY_EVENT_MANAGER (retval);
644                 g_object_add_weak_pointer (retval, (gpointer *) &manager_singleton);
645         }
646
647         return retval;
648 }
649
650 static void
651 event_manager_finalize (GObject *object)
652 {
653   EmpathyEventManagerPriv *priv = GET_PRIV (object);
654
655   g_slist_foreach (priv->events, (GFunc) event_free, NULL);
656   g_slist_free (priv->events);
657   g_slist_foreach (priv->approvals, (GFunc) event_manager_approval_free, NULL);
658   g_slist_free (priv->approvals);
659   g_object_unref (priv->contact_manager);
660   g_object_unref (priv->dispatcher);
661 }
662
663 static void
664 empathy_event_manager_class_init (EmpathyEventManagerClass *klass)
665 {
666   GObjectClass *object_class = G_OBJECT_CLASS (klass);
667
668   object_class->finalize = event_manager_finalize;
669   object_class->constructor = event_manager_constructor;
670
671   signals[EVENT_ADDED] =
672     g_signal_new ("event-added",
673       G_TYPE_FROM_CLASS (klass),
674       G_SIGNAL_RUN_LAST,
675       0,
676       NULL, NULL,
677       g_cclosure_marshal_VOID__POINTER,
678       G_TYPE_NONE,
679       1, G_TYPE_POINTER);
680
681   signals[EVENT_REMOVED] =
682   g_signal_new ("event-removed",
683       G_TYPE_FROM_CLASS (klass),
684       G_SIGNAL_RUN_LAST,
685       0,
686       NULL, NULL,
687       g_cclosure_marshal_VOID__POINTER,
688       G_TYPE_NONE, 1, G_TYPE_POINTER);
689
690   signals[EVENT_UPDATED] =
691   g_signal_new ("event-updated",
692       G_TYPE_FROM_CLASS (klass),
693       G_SIGNAL_RUN_LAST,
694       0,
695       NULL, NULL,
696       g_cclosure_marshal_VOID__POINTER,
697       G_TYPE_NONE, 1, G_TYPE_POINTER);
698
699
700   g_type_class_add_private (object_class, sizeof (EmpathyEventManagerPriv));
701 }
702
703 static void
704 empathy_event_manager_init (EmpathyEventManager *manager)
705 {
706   EmpathyEventManagerPriv *priv = G_TYPE_INSTANCE_GET_PRIVATE (manager,
707     EMPATHY_TYPE_EVENT_MANAGER, EmpathyEventManagerPriv);
708
709   manager->priv = priv;
710
711   priv->dispatcher = empathy_dispatcher_dup_singleton ();
712   priv->contact_manager = empathy_contact_manager_dup_singleton ();
713   g_signal_connect (priv->dispatcher, "approve",
714     G_CALLBACK (event_manager_approve_channel_cb), manager);
715   g_signal_connect (priv->contact_manager, "pendings-changed",
716     G_CALLBACK (event_manager_pendings_changed_cb), manager);
717 }
718
719 EmpathyEventManager *
720 empathy_event_manager_dup_singleton (void)
721 {
722   return g_object_new (EMPATHY_TYPE_EVENT_MANAGER, NULL);
723 }
724
725 GSList *
726 empathy_event_manager_get_events (EmpathyEventManager *manager)
727 {
728   EmpathyEventManagerPriv *priv = GET_PRIV (manager);
729
730   g_return_val_if_fail (EMPATHY_IS_EVENT_MANAGER (manager), NULL);
731
732   return priv->events;
733 }
734
735 EmpathyEvent *
736 empathy_event_manager_get_top_event (EmpathyEventManager *manager)
737 {
738   EmpathyEventManagerPriv *priv = GET_PRIV (manager);
739
740   g_return_val_if_fail (EMPATHY_IS_EVENT_MANAGER (manager), NULL);
741
742   return priv->events ? priv->events->data : NULL;
743 }
744
745 void
746 empathy_event_activate (EmpathyEvent *event_public)
747 {
748   EventPriv *event = (EventPriv*) event_public;
749
750   g_return_if_fail (event_public != NULL);
751
752   if (event->func)
753     event->func (event);
754   else
755     event_remove (event);
756 }
757
758 void
759 empathy_event_inhibit_updates (EmpathyEvent *event_public)
760 {
761   EventPriv *event = (EventPriv *) event_public;
762
763   g_return_if_fail (event_public != NULL);
764
765   event->inhibit = TRUE;
766 }
767