fixed a crash when creating account
[empathy-mirror.git] / libempathy / empathy-contact-monitor.c
blobf41b8bd5c11df45b9188c1ead1596ce5d3b22d31
1 /*
2 * Copyright (C) 2008 Collabora Ltd.
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.
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.
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
18 * Authors: Cosimo Cecchi <cosimo.cecchi@collabora.co.uk>
21 #include "config.h"
23 #include <glib-object.h>
25 #include "empathy-contact-monitor.h"
26 #include "empathy-contact-list.h"
28 #include "empathy-contact.h"
29 #include "empathy-utils.h"
30 #include "empathy-marshal.h"
32 #define GET_PRIV(obj) EMPATHY_GET_PRIV (obj, EmpathyContactMonitor)
34 typedef struct {
35 EmpathyContactList *iface;
36 GList *contacts;
38 gboolean dispose_run;
39 } EmpathyContactMonitorPriv;
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
52 enum {
53 PROP_0,
54 PROP_IFACE
57 static guint signals[LAST_SIGNAL];
59 G_DEFINE_TYPE (EmpathyContactMonitor, empathy_contact_monitor, G_TYPE_OBJECT);
61 static void
62 contact_monitor_presence_changed_cb (EmpathyContact *contact,
63 TpConnectionPresenceType current_presence,
64 TpConnectionPresenceType previous_presence,
65 EmpathyContactMonitor *self)
67 g_signal_emit (self, signals[CONTACT_PRESENCE_CHANGED], 0, contact,
68 current_presence, previous_presence);
71 static void
72 contact_monitor_presence_message_changed_cb (EmpathyContact *contact,
73 GParamSpec *pspec,
74 EmpathyContactMonitor *self)
76 const char *status;
78 /* use the status so that we always have a presence message */
79 status = empathy_contact_get_status (contact);
81 g_signal_emit (self, signals[CONTACT_PRESENCE_MESSAGE_CHANGED], 0,
82 contact, status);
85 static void
86 contact_monitor_name_changed_cb (EmpathyContact *contact,
87 GParamSpec *pspec,
88 EmpathyContactMonitor *self)
90 const char *name;
92 name = empathy_contact_get_name (contact);
94 g_signal_emit (self, signals[CONTACT_NAME_CHANGED], 0, contact, name);
97 static void
98 contact_monitor_avatar_changed_cb (EmpathyContact *contact,
99 GParamSpec *pspec,
100 EmpathyContactMonitor *self)
102 /* don't emit a pixbuf in the signal, as we don't depend on GTK+ here
105 g_signal_emit (self, signals[CONTACT_AVATAR_CHANGED], 0, contact);
108 static void
109 contact_monitor_capabilities_changed_cb (EmpathyContact *contact,
110 GParamSpec *pspec,
111 EmpathyContactMonitor *self)
113 g_signal_emit (self, signals[CONTACT_CAPABILITIES_CHANGED], 0, contact);
116 static void
117 contact_add (EmpathyContactMonitor *monitor,
118 EmpathyContact *contact)
120 EmpathyContactMonitorPriv *priv = GET_PRIV (monitor);
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);
138 priv->contacts = g_list_prepend (priv->contacts, g_object_ref (contact));
140 g_signal_emit (monitor, signals[CONTACT_ADDED], 0, contact);
143 static void
144 contact_remove (EmpathyContactMonitor *monitor,
145 EmpathyContact *contact)
147 EmpathyContactMonitorPriv *priv = GET_PRIV (monitor);
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);
165 priv->contacts = g_list_remove (priv->contacts, contact);
167 g_signal_emit (monitor, signals[CONTACT_REMOVED], 0, contact);
169 g_object_unref (contact);
172 static void
173 contact_remove_foreach (EmpathyContact *contact,
174 EmpathyContactMonitor *monitor)
176 contact_remove (monitor, contact);
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)
188 if (is_member)
189 contact_add (monitor, contact);
190 else
191 contact_remove (monitor, contact);
194 static void
195 do_set_property (GObject *object,
196 guint param_id,
197 const GValue *value,
198 GParamSpec *pspec)
200 switch (param_id)
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;
212 static void
213 do_get_property (GObject *object,
214 guint param_id,
215 GValue *value,
216 GParamSpec *pspec)
218 EmpathyContactMonitorPriv *priv = GET_PRIV (object);
220 switch (param_id)
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;
231 static void
232 do_finalize (GObject *obj)
234 EmpathyContactMonitorPriv *priv;
236 priv = GET_PRIV (obj);
238 if (priv->contacts)
240 g_list_free (priv->contacts);
241 priv->contacts = NULL;
244 if (priv->iface)
245 g_signal_handlers_disconnect_by_func (priv->iface,
246 cl_members_changed_cb, obj);
248 G_OBJECT_CLASS (empathy_contact_monitor_parent_class)->finalize (obj);
251 static void
252 do_dispose (GObject *obj)
254 EmpathyContactMonitorPriv *priv;
256 priv = GET_PRIV (obj);
258 if (priv->dispose_run)
259 return;
261 priv->dispose_run = TRUE;
263 if (priv->contacts)
264 g_list_foreach (priv->contacts,
265 (GFunc) contact_remove_foreach, obj);
267 if (priv->iface)
268 g_signal_handlers_disconnect_by_func (priv->iface,
269 cl_members_changed_cb, obj);
271 G_OBJECT_CLASS (empathy_contact_monitor_parent_class)->dispose (obj);
274 static void
275 empathy_contact_monitor_class_init (EmpathyContactMonitorClass *klass)
277 GObjectClass *oclass = G_OBJECT_CLASS (klass);
279 oclass->finalize = do_finalize;
280 oclass->dispose = do_dispose;
281 oclass->get_property = do_get_property;
282 oclass->set_property = do_set_property;
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));
294 signals[CONTACT_ADDED] =
295 g_signal_new ("contact-added",
296 G_TYPE_FROM_CLASS (klass),
297 G_SIGNAL_RUN_LAST,
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,
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,
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,
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,
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,
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,
357 NULL, NULL,
358 g_cclosure_marshal_VOID__OBJECT,
359 G_TYPE_NONE,
360 1, EMPATHY_TYPE_CONTACT);
362 g_type_class_add_private (klass, sizeof (EmpathyContactMonitorPriv));
365 static void
366 empathy_contact_monitor_init (EmpathyContactMonitor *self)
368 EmpathyContactMonitorPriv *priv =
369 G_TYPE_INSTANCE_GET_PRIVATE (self, EMPATHY_TYPE_CONTACT_MONITOR,
370 EmpathyContactMonitorPriv);
372 self->priv = priv;
373 priv->contacts = NULL;
374 priv->iface = NULL;
375 priv->dispose_run = FALSE;
378 /* public methods */
380 void
381 empathy_contact_monitor_set_iface (EmpathyContactMonitor *self,
382 EmpathyContactList *iface)
384 EmpathyContactMonitorPriv *priv;
386 g_return_if_fail (EMPATHY_IS_CONTACT_MONITOR (self));
387 g_return_if_fail (EMPATHY_IS_CONTACT_LIST (iface));
389 priv = GET_PRIV (self);
391 if (priv->contacts != NULL)
393 g_list_foreach (priv->contacts,
394 (GFunc) contact_remove_foreach, self);
395 g_list_free (priv->contacts);
396 priv->contacts = NULL;
399 priv->iface = iface;
401 g_signal_connect (iface, "members-changed",
402 G_CALLBACK (cl_members_changed_cb), self);
405 EmpathyContactMonitor *
406 empathy_contact_monitor_new_for_iface (EmpathyContactList *iface)
408 EmpathyContactMonitor *retval;
410 g_return_val_if_fail (EMPATHY_IS_CONTACT_LIST (iface), NULL);
412 retval = g_object_new (EMPATHY_TYPE_CONTACT_MONITOR,
413 "iface", iface, NULL);
415 return retval;