]> git.0d.be Git - empathy.git/blob - libempathy/empathy-contact-monitor.c
Yet more style fixes.
[empathy.git] / libempathy / empathy-contact-monitor.c
1 /*
2  * Copyright (C) 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: Cosimo Cecchi <cosimo.cecchi@collabora.co.uk>
19  */
20
21 #include "config.h"
22
23 #include <glib-object.h>
24 #include <libmissioncontrol/mc-enum-types.h>
25
26 #include "empathy-contact-monitor.h"
27 #include "empathy-contact-list.h"
28
29 #include "empathy-contact.h"
30 #include "empathy-utils.h"
31 #include "empathy-marshal.h"
32
33 #define GET_PRIV(obj) EMPATHY_GET_PRIV (obj, EmpathyContactMonitor)
34
35 typedef struct {
36   EmpathyContactList *proxy;
37   GPtrArray *contacts;
38
39   gboolean dispose_run;
40 } EmpathyContactMonitorPriv;
41
42 enum {
43   CONTACT_ADDED,
44   CONTACT_AVATAR_CHANGED,
45   CONTACT_CAPABILITIES_CHANGED,
46   CONTACT_NAME_CHANGED,
47   CONTACT_PRESENCE_CHANGED,
48   CONTACT_PRESENCE_MESSAGE_CHANGED,
49   CONTACT_REMOVED,
50   LAST_SIGNAL
51 };
52
53 enum {
54   PROP_0,
55   PROP_PROXY
56 };
57
58 static void  contact_remove_foreach (EmpathyContact *contact,
59     EmpathyContactMonitor *monitor);
60 static void  cl_members_changed_cb  (EmpathyContactList    *cl,
61     EmpathyContact *contact, EmpathyContact *actor, guint reason,
62     gchar *message, gboolean is_member, EmpathyContactMonitor *monitor);
63
64 static guint signals[LAST_SIGNAL];
65
66 G_DEFINE_TYPE (EmpathyContactMonitor, empathy_contact_monitor, G_TYPE_OBJECT);
67
68 static void
69 do_set_property (GObject      *object,
70                  guint         param_id,
71                  const GValue *value,
72                  GParamSpec   *pspec)
73 {
74   switch (param_id)
75     {
76       case PROP_PROXY:
77         empathy_contact_monitor_set_proxy (EMPATHY_CONTACT_MONITOR (object),
78                                            g_value_get_object (value));
79         break;
80       default:
81         G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
82         break;
83     };
84 }
85
86 static void
87 do_get_property (GObject    *object,
88                  guint       param_id,
89                  GValue     *value,
90                  GParamSpec *pspec)
91 {
92   EmpathyContactMonitorPriv *priv = GET_PRIV (object);
93
94   switch (param_id)
95     {
96       case PROP_PROXY:
97         g_value_set_object (value, priv->proxy);
98         break;
99       default:
100         G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
101         break;
102     };
103 }
104
105 static void
106 do_finalize (GObject *obj)
107 {
108   EmpathyContactMonitorPriv *priv;
109
110   priv = GET_PRIV (obj);
111
112   if (priv->contacts)
113     {
114       g_ptr_array_free (priv->contacts, TRUE);
115       priv->contacts = NULL;
116     }
117
118   if (priv->proxy)
119     g_signal_handlers_disconnect_by_func (priv->proxy,
120                                           cl_members_changed_cb, obj);
121
122   G_OBJECT_CLASS (empathy_contact_monitor_parent_class)->finalize (obj);
123 }
124
125 static void
126 do_dispose (GObject *obj)
127 {
128   EmpathyContactMonitorPriv *priv;
129
130   priv = GET_PRIV (obj);
131
132   if (priv->dispose_run)
133     return;
134
135   priv->dispose_run = TRUE;
136
137   if (priv->contacts)
138     g_ptr_array_foreach (priv->contacts,
139                          (GFunc) contact_remove_foreach, obj);
140
141   if (priv->proxy)
142     g_signal_handlers_disconnect_by_func (priv->proxy,
143                                           cl_members_changed_cb, obj);
144
145   G_OBJECT_CLASS (empathy_contact_monitor_parent_class)->dispose (obj);
146 }
147
148 static void
149 empathy_contact_monitor_class_init (EmpathyContactMonitorClass *klass)
150 {
151   GObjectClass *oclass = G_OBJECT_CLASS (klass);
152
153   oclass->finalize = do_finalize;
154   oclass->dispose = do_dispose;
155   oclass->get_property = do_get_property;
156   oclass->set_property = do_set_property;
157
158   g_object_class_install_property (oclass,
159                                    PROP_PROXY,
160                                    g_param_spec_object ("proxy",
161                                                         "Monitor's proxy",
162                                                         "The contact list associated we're monitoring",
163                                                         EMPATHY_TYPE_CONTACT_LIST,
164                                                         G_PARAM_READWRITE |
165                                                         G_PARAM_CONSTRUCT_ONLY |
166                                                         G_PARAM_STATIC_STRINGS));
167
168   signals[CONTACT_ADDED] =
169     g_signal_new ("contact-added",
170                   G_TYPE_FROM_CLASS (klass),
171                   G_SIGNAL_RUN_LAST,
172                   0,
173                   NULL, NULL,
174                   g_cclosure_marshal_VOID__OBJECT,
175                   G_TYPE_NONE,
176                   1, EMPATHY_TYPE_CONTACT);
177   signals[CONTACT_AVATAR_CHANGED] =
178     g_signal_new ("contact-avatar-changed",
179                   G_TYPE_FROM_CLASS (klass),
180                   G_SIGNAL_RUN_LAST,
181                   0,
182                   NULL, NULL,
183                   g_cclosure_marshal_VOID__OBJECT,
184                   G_TYPE_NONE,
185                   1, EMPATHY_TYPE_CONTACT);
186   signals[CONTACT_CAPABILITIES_CHANGED] =
187     g_signal_new ("contact-capabilities-changed",
188                   G_TYPE_FROM_CLASS (klass),
189                   G_SIGNAL_RUN_LAST,
190                   0,
191                   NULL, NULL,
192                   g_cclosure_marshal_VOID__OBJECT,
193                   G_TYPE_NONE,
194                   1, EMPATHY_TYPE_CONTACT);
195   signals[CONTACT_NAME_CHANGED] =
196     g_signal_new ("contact-name-changed",
197                   G_TYPE_FROM_CLASS (klass),
198                   G_SIGNAL_RUN_LAST,
199                   0,
200                   NULL, NULL,
201                   _empathy_marshal_VOID__OBJECT_STRING,
202                   G_TYPE_NONE,
203                   2, EMPATHY_TYPE_CONTACT,
204                   G_TYPE_STRING);
205   signals[CONTACT_PRESENCE_CHANGED] =
206     g_signal_new ("contact-presence-changed",
207                   G_TYPE_FROM_CLASS (klass),
208                   G_SIGNAL_RUN_LAST,
209                   0,
210                   NULL, NULL,
211                   _empathy_marshal_VOID__OBJECT_ENUM_ENUM,
212                   G_TYPE_NONE,
213                   3, EMPATHY_TYPE_CONTACT,
214                   MC_TYPE_PRESENCE,
215                   MC_TYPE_PRESENCE);
216   signals[CONTACT_PRESENCE_MESSAGE_CHANGED] =
217     g_signal_new ("contact-presence-message-changed",
218                   G_TYPE_FROM_CLASS (klass),
219                   G_SIGNAL_RUN_LAST,
220                   0,
221                   NULL, NULL,
222                   _empathy_marshal_VOID__OBJECT_STRING,
223                   G_TYPE_NONE,
224                   2, EMPATHY_TYPE_CONTACT,
225                   G_TYPE_STRING);
226   signals[CONTACT_REMOVED] =
227     g_signal_new ("contact-removed",
228                   G_TYPE_FROM_CLASS (klass),
229                   G_SIGNAL_RUN_LAST,
230                   0,
231                   NULL, NULL,
232                   g_cclosure_marshal_VOID__OBJECT,
233                   G_TYPE_NONE,
234                   1, EMPATHY_TYPE_CONTACT);
235
236   g_type_class_add_private (klass, sizeof (EmpathyContactMonitorPriv));
237 }
238
239 static void
240 empathy_contact_monitor_init (EmpathyContactMonitor *self)
241 {
242   EmpathyContactMonitorPriv *priv =
243       G_TYPE_INSTANCE_GET_PRIVATE (self, EMPATHY_TYPE_CONTACT_MONITOR,
244                                    EmpathyContactMonitorPriv);
245
246   self->priv = priv;
247   priv->contacts = NULL;
248   priv->proxy = NULL;
249   priv->dispose_run = FALSE;
250 }
251
252 static void
253 contact_monitor_presence_changed_cb (EmpathyContact *contact,
254                                      McPresence current_presence,
255                                      McPresence previous_presence,
256                                      EmpathyContactMonitor *self)
257 {
258   g_signal_emit (self, signals[CONTACT_PRESENCE_CHANGED], 0, contact,
259                  current_presence, previous_presence);
260 }
261
262 static void
263 contact_monitor_presence_message_changed_cb (EmpathyContact *contact,
264                                              GParamSpec *pspec,
265                                              EmpathyContactMonitor *self)
266 {
267   const char *status;
268
269   /* use the status so that we always have a presence message */
270   status = empathy_contact_get_status (contact);
271
272   g_signal_emit (self, signals[CONTACT_PRESENCE_MESSAGE_CHANGED], 0,
273                  contact, status);
274 }
275
276 static void
277 contact_monitor_name_changed_cb (EmpathyContact *contact,
278                                  GParamSpec *pspec,
279                                  EmpathyContactMonitor *self)
280 {
281   const char *name;
282
283   name = empathy_contact_get_name (contact);
284
285   g_signal_emit (self, signals[CONTACT_NAME_CHANGED], 0, contact, name);
286 }
287
288 static void
289 contact_monitor_avatar_changed_cb (EmpathyContact *contact,
290                                    GParamSpec *pspec,
291                                    EmpathyContactMonitor *self)
292 {
293   /* don't emit a pixbuf in the signal, as we don't know how large
294    * a client would like it to be.
295    */
296
297   g_signal_emit (self, signals[CONTACT_AVATAR_CHANGED], 0, contact);
298 }
299
300 static void
301 contact_monitor_capabilities_changed_cb (EmpathyContact *contact,
302                                          GParamSpec *pspec,
303                                          EmpathyContactMonitor *self)
304 {
305   g_signal_emit (self, signals[CONTACT_CAPABILITIES_CHANGED], 0, contact);
306 }
307
308 static void
309 contact_add (EmpathyContactMonitor *monitor,
310              EmpathyContact *contact)
311 {
312   EmpathyContactMonitorPriv *priv = GET_PRIV (monitor);
313
314   g_signal_connect (contact, "presence-changed",
315                     G_CALLBACK (contact_monitor_presence_changed_cb),
316                     monitor);
317   g_signal_connect (contact, "notify::presence-message",
318                     G_CALLBACK (contact_monitor_presence_message_changed_cb),
319                     monitor);
320   g_signal_connect (contact, "notify::name",
321                     G_CALLBACK (contact_monitor_name_changed_cb),
322                     monitor);
323   g_signal_connect (contact, "notify::avatar",
324                     G_CALLBACK (contact_monitor_avatar_changed_cb),
325                     monitor);
326   g_signal_connect (contact, "notify::capabilities",
327                     G_CALLBACK (contact_monitor_capabilities_changed_cb),
328                     monitor);
329
330   g_ptr_array_add (priv->contacts, g_object_ref (contact));
331
332   g_signal_emit (monitor, signals[CONTACT_ADDED], 0, contact);
333 }
334
335 static void
336 contact_remove (EmpathyContactMonitor *monitor,
337                 EmpathyContact *contact)
338 {
339   EmpathyContactMonitorPriv *priv = GET_PRIV (monitor);
340
341   g_signal_handlers_disconnect_by_func (contact,
342                                         G_CALLBACK (contact_monitor_presence_changed_cb),
343                                         monitor);
344   g_signal_handlers_disconnect_by_func (contact,
345                                         G_CALLBACK (contact_monitor_presence_message_changed_cb),
346                                         monitor);
347   g_signal_handlers_disconnect_by_func (contact,
348                                         G_CALLBACK (contact_monitor_name_changed_cb),
349                                         monitor);
350   g_signal_handlers_disconnect_by_func (contact,
351                                         G_CALLBACK (contact_monitor_avatar_changed_cb),
352                                         monitor);
353   g_signal_handlers_disconnect_by_func (contact,
354                                         G_CALLBACK (contact_monitor_capabilities_changed_cb),
355                                         monitor);
356
357   g_ptr_array_remove (priv->contacts, contact);
358
359   g_signal_emit (monitor, signals[CONTACT_REMOVED], 0, contact);
360
361   g_object_unref (contact);
362 }
363
364 static void
365 contact_remove_foreach (EmpathyContact *contact,
366                         EmpathyContactMonitor *monitor)
367 {
368   contact_remove (monitor, contact);
369 }
370
371 static void
372 cl_members_changed_cb (EmpathyContactList    *cl,
373                        EmpathyContact        *contact,
374                        EmpathyContact        *actor,
375                        guint                  reason,
376                        gchar                 *message,
377                        gboolean               is_member,
378                        EmpathyContactMonitor *monitor)
379 {
380   if (is_member)
381     contact_add (monitor, contact);
382   else
383     contact_remove (monitor, contact);
384 }
385
386 /* public methods */
387
388 void
389 empathy_contact_monitor_set_proxy (EmpathyContactMonitor *self,
390                                    EmpathyContactList *proxy)
391 {
392   EmpathyContactMonitorPriv *priv;
393
394   g_assert (EMPATHY_IS_CONTACT_MONITOR (self));
395   g_assert (EMPATHY_IS_CONTACT_LIST (proxy));
396
397   priv = GET_PRIV (self);
398
399   if (priv->contacts != NULL)
400     {
401       g_ptr_array_foreach (priv->contacts,
402                            (GFunc) contact_remove_foreach, self);
403       g_ptr_array_free (priv->contacts, TRUE);
404       priv->contacts = NULL;
405     }
406
407   priv->proxy = proxy;
408   priv->contacts = g_ptr_array_new ();
409
410   g_signal_connect (proxy, "members-changed",
411                     G_CALLBACK (cl_members_changed_cb), self);
412 }
413
414 EmpathyContactMonitor *
415 empathy_contact_monitor_new_for_proxy (EmpathyContactList *proxy)
416 {
417   EmpathyContactMonitor *retval;
418
419   g_assert (EMPATHY_IS_CONTACT_LIST (proxy));
420
421   retval = g_object_new (EMPATHY_TYPE_CONTACT_MONITOR,
422                          "proxy", proxy, NULL);
423
424   return retval;
425 }
426