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