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>
23 #include <glib-object.h>
24 #include <libmissioncontrol/mc-enum-types.h>
26 #include "empathy-contact-monitor.h"
27 #include "empathy-contact-list.h"
29 #include "empathy-contact.h"
30 #include "empathy-utils.h"
31 #include "empathy-marshal.h"
33 #define GET_PRIV(obj) EMPATHY_GET_PRIV (obj, EmpathyContactMonitor)
36 EmpathyContactList *proxy;
40 } EmpathyContactMonitorPriv;
44 CONTACT_AVATAR_CHANGED,
45 CONTACT_CAPABILITIES_CHANGED,
47 CONTACT_PRESENCE_CHANGED,
48 CONTACT_PRESENCE_MESSAGE_CHANGED,
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);
64 static guint signals[LAST_SIGNAL];
66 G_DEFINE_TYPE (EmpathyContactMonitor, empathy_contact_monitor, G_TYPE_OBJECT);
69 do_set_property (GObject *object,
77 empathy_contact_monitor_set_proxy (EMPATHY_CONTACT_MONITOR (object),
78 g_value_get_object (value));
81 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
87 do_get_property (GObject *object,
92 EmpathyContactMonitorPriv *priv = GET_PRIV (object);
97 g_value_set_object (value, priv->proxy);
100 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
106 do_finalize (GObject *obj)
108 EmpathyContactMonitorPriv *priv;
110 priv = GET_PRIV (obj);
114 g_ptr_array_free (priv->contacts, TRUE);
115 priv->contacts = NULL;
119 g_signal_handlers_disconnect_by_func (priv->proxy,
120 cl_members_changed_cb, obj);
122 G_OBJECT_CLASS (empathy_contact_monitor_parent_class)->finalize (obj);
126 do_dispose (GObject *obj)
128 EmpathyContactMonitorPriv *priv;
130 priv = GET_PRIV (obj);
132 if (priv->dispose_run)
135 priv->dispose_run = TRUE;
138 g_ptr_array_foreach (priv->contacts,
139 (GFunc) contact_remove_foreach, obj);
142 g_signal_handlers_disconnect_by_func (priv->proxy,
143 cl_members_changed_cb, obj);
145 G_OBJECT_CLASS (empathy_contact_monitor_parent_class)->dispose (obj);
149 empathy_contact_monitor_class_init (EmpathyContactMonitorClass *klass)
151 GObjectClass *oclass = G_OBJECT_CLASS (klass);
153 oclass->finalize = do_finalize;
154 oclass->dispose = do_dispose;
155 oclass->get_property = do_get_property;
156 oclass->set_property = do_set_property;
158 g_object_class_install_property (oclass,
160 g_param_spec_object ("proxy",
162 "The contact list associated we're monitoring",
163 EMPATHY_TYPE_CONTACT_LIST,
165 G_PARAM_CONSTRUCT_ONLY |
166 G_PARAM_STATIC_STRINGS));
168 signals[CONTACT_ADDED] =
169 g_signal_new ("contact-added",
170 G_TYPE_FROM_CLASS (klass),
174 g_cclosure_marshal_VOID__OBJECT,
176 1, EMPATHY_TYPE_CONTACT);
177 signals[CONTACT_AVATAR_CHANGED] =
178 g_signal_new ("contact-avatar-changed",
179 G_TYPE_FROM_CLASS (klass),
183 g_cclosure_marshal_VOID__OBJECT,
185 1, EMPATHY_TYPE_CONTACT);
186 signals[CONTACT_CAPABILITIES_CHANGED] =
187 g_signal_new ("contact-capabilities-changed",
188 G_TYPE_FROM_CLASS (klass),
192 g_cclosure_marshal_VOID__OBJECT,
194 1, EMPATHY_TYPE_CONTACT);
195 signals[CONTACT_NAME_CHANGED] =
196 g_signal_new ("contact-name-changed",
197 G_TYPE_FROM_CLASS (klass),
201 _empathy_marshal_VOID__OBJECT_STRING,
203 2, EMPATHY_TYPE_CONTACT,
205 signals[CONTACT_PRESENCE_CHANGED] =
206 g_signal_new ("contact-presence-changed",
207 G_TYPE_FROM_CLASS (klass),
211 _empathy_marshal_VOID__OBJECT_ENUM_ENUM,
213 3, EMPATHY_TYPE_CONTACT,
216 signals[CONTACT_PRESENCE_MESSAGE_CHANGED] =
217 g_signal_new ("contact-presence-message-changed",
218 G_TYPE_FROM_CLASS (klass),
222 _empathy_marshal_VOID__OBJECT_STRING,
224 2, EMPATHY_TYPE_CONTACT,
226 signals[CONTACT_REMOVED] =
227 g_signal_new ("contact-removed",
228 G_TYPE_FROM_CLASS (klass),
232 g_cclosure_marshal_VOID__OBJECT,
234 1, EMPATHY_TYPE_CONTACT);
236 g_type_class_add_private (klass, sizeof (EmpathyContactMonitorPriv));
240 empathy_contact_monitor_init (EmpathyContactMonitor *self)
242 EmpathyContactMonitorPriv *priv =
243 G_TYPE_INSTANCE_GET_PRIVATE (self, EMPATHY_TYPE_CONTACT_MONITOR,
244 EmpathyContactMonitorPriv);
247 priv->contacts = NULL;
249 priv->dispose_run = FALSE;
253 contact_monitor_presence_changed_cb (EmpathyContact *contact,
254 McPresence current_presence,
255 McPresence previous_presence,
256 EmpathyContactMonitor *self)
258 g_signal_emit (self, signals[CONTACT_PRESENCE_CHANGED], 0, contact,
259 current_presence, previous_presence);
263 contact_monitor_presence_message_changed_cb (EmpathyContact *contact,
265 EmpathyContactMonitor *self)
269 /* use the status so that we always have a presence message */
270 status = empathy_contact_get_status (contact);
272 g_signal_emit (self, signals[CONTACT_PRESENCE_MESSAGE_CHANGED], 0,
277 contact_monitor_name_changed_cb (EmpathyContact *contact,
279 EmpathyContactMonitor *self)
283 name = empathy_contact_get_name (contact);
285 g_signal_emit (self, signals[CONTACT_NAME_CHANGED], 0, contact, name);
289 contact_monitor_avatar_changed_cb (EmpathyContact *contact,
291 EmpathyContactMonitor *self)
293 /* don't emit a pixbuf in the signal, as we don't know how large
294 * a client would like it to be.
297 g_signal_emit (self, signals[CONTACT_AVATAR_CHANGED], 0, contact);
301 contact_monitor_capabilities_changed_cb (EmpathyContact *contact,
303 EmpathyContactMonitor *self)
305 g_signal_emit (self, signals[CONTACT_CAPABILITIES_CHANGED], 0, contact);
309 contact_add (EmpathyContactMonitor *monitor,
310 EmpathyContact *contact)
312 EmpathyContactMonitorPriv *priv = GET_PRIV (monitor);
314 g_signal_connect (contact, "presence-changed",
315 G_CALLBACK (contact_monitor_presence_changed_cb),
317 g_signal_connect (contact, "notify::presence-message",
318 G_CALLBACK (contact_monitor_presence_message_changed_cb),
320 g_signal_connect (contact, "notify::name",
321 G_CALLBACK (contact_monitor_name_changed_cb),
323 g_signal_connect (contact, "notify::avatar",
324 G_CALLBACK (contact_monitor_avatar_changed_cb),
326 g_signal_connect (contact, "notify::capabilities",
327 G_CALLBACK (contact_monitor_capabilities_changed_cb),
330 g_ptr_array_add (priv->contacts, g_object_ref (contact));
332 g_signal_emit (monitor, signals[CONTACT_ADDED], 0, contact);
336 contact_remove (EmpathyContactMonitor *monitor,
337 EmpathyContact *contact)
339 EmpathyContactMonitorPriv *priv = GET_PRIV (monitor);
341 g_signal_handlers_disconnect_by_func (contact,
342 G_CALLBACK (contact_monitor_presence_changed_cb),
344 g_signal_handlers_disconnect_by_func (contact,
345 G_CALLBACK (contact_monitor_presence_message_changed_cb),
347 g_signal_handlers_disconnect_by_func (contact,
348 G_CALLBACK (contact_monitor_name_changed_cb),
350 g_signal_handlers_disconnect_by_func (contact,
351 G_CALLBACK (contact_monitor_avatar_changed_cb),
353 g_signal_handlers_disconnect_by_func (contact,
354 G_CALLBACK (contact_monitor_capabilities_changed_cb),
357 g_ptr_array_remove (priv->contacts, contact);
359 g_signal_emit (monitor, signals[CONTACT_REMOVED], 0, contact);
361 g_object_unref (contact);
365 contact_remove_foreach (EmpathyContact *contact,
366 EmpathyContactMonitor *monitor)
368 contact_remove (monitor, contact);
372 cl_members_changed_cb (EmpathyContactList *cl,
373 EmpathyContact *contact,
374 EmpathyContact *actor,
378 EmpathyContactMonitor *monitor)
381 contact_add (monitor, contact);
383 contact_remove (monitor, contact);
389 empathy_contact_monitor_set_proxy (EmpathyContactMonitor *self,
390 EmpathyContactList *proxy)
392 EmpathyContactMonitorPriv *priv;
394 g_assert (EMPATHY_IS_CONTACT_MONITOR (self));
395 g_assert (EMPATHY_IS_CONTACT_LIST (proxy));
397 priv = GET_PRIV (self);
399 if (priv->contacts != NULL)
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;
408 priv->contacts = g_ptr_array_new ();
410 g_signal_connect (proxy, "members-changed",
411 G_CALLBACK (cl_members_changed_cb), self);
414 EmpathyContactMonitor *
415 empathy_contact_monitor_new_for_proxy (EmpathyContactList *proxy)
417 EmpathyContactMonitor *retval;
419 g_assert (EMPATHY_IS_CONTACT_LIST (proxy));
421 retval = g_object_new (EMPATHY_TYPE_CONTACT_MONITOR,
422 "proxy", proxy, NULL);