3 #include <glib/gi18n-lib.h>
5 #include "empathy-roster-contact.h"
7 #include <telepathy-glib/telepathy-glib.h>
9 #include <libempathy/empathy-utils.h>
11 #include <libempathy-gtk/empathy-images.h>
12 #include <libempathy-gtk/empathy-ui-utils.h>
14 G_DEFINE_TYPE (EmpathyRosterContact, empathy_roster_contact, GTK_TYPE_ALIGNMENT)
16 #define AVATAR_SIZE 48
33 static guint signals[LAST_SIGNAL];
36 struct _EmpathyRosterContactPriv
38 FolksIndividual *individual;
42 GtkWidget *first_line_alig;
44 GtkWidget *presence_msg;
45 GtkWidget *presence_icon;
46 GtkWidget *phone_icon;
48 /* If not NULL, used instead of the individual's presence icon */
55 get_alias (EmpathyRosterContact *self)
57 return folks_alias_details_get_alias (FOLKS_ALIAS_DETAILS (
58 self->priv->individual));
62 empathy_roster_contact_get_property (GObject *object,
67 EmpathyRosterContact *self = EMPATHY_ROSTER_CONTACT (object);
71 case PROP_INDIVIDIUAL:
72 g_value_set_object (value, self->priv->individual);
75 g_value_set_string (value, self->priv->group);
78 g_value_set_boolean (value, self->priv->online);
81 g_value_set_string (value, get_alias (self));
84 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
90 empathy_roster_contact_set_property (GObject *object,
95 EmpathyRosterContact *self = EMPATHY_ROSTER_CONTACT (object);
99 case PROP_INDIVIDIUAL:
100 g_assert (self->priv->individual == NULL); /* construct only */
101 self->priv->individual = g_value_dup_object (value);
104 g_assert (self->priv->group == NULL); /* construct only */
105 self->priv->group = g_value_dup_string (value);
108 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
114 avatar_loaded_cb (GObject *source,
115 GAsyncResult *result,
118 TpWeakRef *wr = user_data;
119 EmpathyRosterContact *self;
122 self = tp_weak_ref_dup_object (wr);
126 pixbuf = empathy_pixbuf_avatar_from_individual_scaled_finish (
127 FOLKS_INDIVIDUAL (source), result, NULL);
131 pixbuf = empathy_pixbuf_from_icon_name_sized (
132 EMPATHY_IMAGE_AVATAR_DEFAULT, AVATAR_SIZE);
135 gtk_image_set_from_pixbuf (GTK_IMAGE (self->priv->avatar), pixbuf);
136 g_object_unref (pixbuf);
138 g_object_unref (self);
141 tp_weak_ref_destroy (wr);
145 update_avatar (EmpathyRosterContact *self)
147 empathy_pixbuf_avatar_from_individual_scaled_async (self->priv->individual,
148 AVATAR_SIZE, AVATAR_SIZE, NULL, avatar_loaded_cb,
149 tp_weak_ref_new (self, NULL, NULL));
153 avatar_changed_cb (FolksIndividual *individual,
155 EmpathyRosterContact *self)
157 update_avatar (self);
161 update_alias (EmpathyRosterContact *self)
163 gtk_label_set_text (GTK_LABEL (self->priv->alias), get_alias (self));
165 g_object_notify (G_OBJECT (self), "alias");
169 alias_changed_cb (FolksIndividual *individual,
171 EmpathyRosterContact *self)
177 is_phone (FolksIndividual *individual)
179 const gchar * const *types;
181 types = empathy_individual_get_client_types (individual);
185 if (g_strv_length ((GStrv) types) <= 0)
188 return !tp_strdiff (types[0], "phone");
192 update_presence_msg (EmpathyRosterContact *self)
196 msg = folks_presence_details_get_presence_message (
197 FOLKS_PRESENCE_DETAILS (self->priv->individual));
199 if (tp_str_empty (msg))
201 /* Just display the alias in the center of the row */
202 gtk_alignment_set (GTK_ALIGNMENT (self->priv->first_line_alig),
205 gtk_widget_hide (self->priv->presence_msg);
209 FolksPresenceType type;
211 type = folks_presence_details_get_presence_type (
212 FOLKS_PRESENCE_DETAILS (self->priv->individual));
213 if (type == FOLKS_PRESENCE_TYPE_ERROR)
217 /* Add a prefix explaining that something goes wrong when trying to
218 * fetch contact's presence. */
219 tmp = g_strdup_printf (_("Server cannot find contact: %s"), msg);
220 gtk_label_set_text (GTK_LABEL (self->priv->presence_msg), tmp);
226 gtk_label_set_text (GTK_LABEL (self->priv->presence_msg), msg);
229 gtk_alignment_set (GTK_ALIGNMENT (self->priv->first_line_alig),
231 gtk_misc_set_alignment (GTK_MISC (self->priv->presence_msg), 0, 0.25);
233 gtk_widget_show (self->priv->presence_msg);
236 gtk_widget_set_visible (self->priv->phone_icon,
237 is_phone (self->priv->individual));
241 presence_message_changed_cb (FolksIndividual *individual,
243 EmpathyRosterContact *self)
245 update_presence_msg (self);
249 update_presence_icon (EmpathyRosterContact *self)
253 if (self->priv->event_icon == NULL)
254 icon = empathy_icon_name_for_individual (self->priv->individual);
256 icon = self->priv->event_icon;
258 gtk_image_set_from_icon_name (GTK_IMAGE (self->priv->presence_icon), icon,
263 update_online (EmpathyRosterContact *self)
265 FolksPresenceType presence;
268 presence = folks_presence_details_get_presence_type (
269 FOLKS_PRESENCE_DETAILS (self->priv->individual));
273 case FOLKS_PRESENCE_TYPE_UNSET:
274 case FOLKS_PRESENCE_TYPE_OFFLINE:
275 case FOLKS_PRESENCE_TYPE_UNKNOWN:
276 case FOLKS_PRESENCE_TYPE_ERROR:
280 case FOLKS_PRESENCE_TYPE_AVAILABLE:
281 case FOLKS_PRESENCE_TYPE_AWAY:
282 case FOLKS_PRESENCE_TYPE_EXTENDED_AWAY:
283 case FOLKS_PRESENCE_TYPE_HIDDEN:
284 case FOLKS_PRESENCE_TYPE_BUSY:
289 g_warning ("Unknown FolksPresenceType: %d", presence);
293 if (self->priv->online == online)
296 self->priv->online = online;
297 g_object_notify (G_OBJECT (self), "online");
301 presence_status_changed_cb (FolksIndividual *individual,
303 EmpathyRosterContact *self)
305 update_presence_icon (self);
306 update_online (self);
310 empathy_roster_contact_constructed (GObject *object)
312 EmpathyRosterContact *self = EMPATHY_ROSTER_CONTACT (object);
313 void (*chain_up) (GObject *) =
314 ((GObjectClass *) empathy_roster_contact_parent_class)->constructed;
316 if (chain_up != NULL)
319 g_assert (FOLKS_IS_INDIVIDUAL (self->priv->individual));
321 tp_g_signal_connect_object (self->priv->individual, "notify::avatar",
322 G_CALLBACK (avatar_changed_cb), self, 0);
323 tp_g_signal_connect_object (self->priv->individual, "notify::alias",
324 G_CALLBACK (alias_changed_cb), self, 0);
325 tp_g_signal_connect_object (self->priv->individual,
326 "notify::presence-message",
327 G_CALLBACK (presence_message_changed_cb), self, 0);
328 tp_g_signal_connect_object (self->priv->individual, "notify::presence-status",
329 G_CALLBACK (presence_status_changed_cb), self, 0);
331 update_avatar (self);
333 update_presence_msg (self);
334 update_presence_icon (self);
336 update_online (self);
340 empathy_roster_contact_dispose (GObject *object)
342 EmpathyRosterContact *self = EMPATHY_ROSTER_CONTACT (object);
343 void (*chain_up) (GObject *) =
344 ((GObjectClass *) empathy_roster_contact_parent_class)->dispose;
346 g_clear_object (&self->priv->individual);
348 if (chain_up != NULL)
353 empathy_roster_contact_finalize (GObject *object)
355 EmpathyRosterContact *self = EMPATHY_ROSTER_CONTACT (object);
356 void (*chain_up) (GObject *) =
357 ((GObjectClass *) empathy_roster_contact_parent_class)->finalize;
359 g_free (self->priv->group);
360 g_free (self->priv->event_icon);
362 if (chain_up != NULL)
367 empathy_roster_contact_class_init (
368 EmpathyRosterContactClass *klass)
370 GObjectClass *oclass = G_OBJECT_CLASS (klass);
373 oclass->get_property = empathy_roster_contact_get_property;
374 oclass->set_property = empathy_roster_contact_set_property;
375 oclass->constructed = empathy_roster_contact_constructed;
376 oclass->dispose = empathy_roster_contact_dispose;
377 oclass->finalize = empathy_roster_contact_finalize;
379 spec = g_param_spec_object ("individual", "Individual",
381 FOLKS_TYPE_INDIVIDUAL,
382 G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS);
383 g_object_class_install_property (oclass, PROP_INDIVIDIUAL, spec);
385 spec = g_param_spec_string ("group", "Group",
386 "Group of this widget, or NULL",
388 G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS);
389 g_object_class_install_property (oclass, PROP_GROUP, spec);
391 spec = g_param_spec_boolean ("online", "Online",
392 "TRUE if Individual is online",
394 G_PARAM_READABLE | G_PARAM_STATIC_STRINGS);
395 g_object_class_install_property (oclass, PROP_ONLINE, spec);
397 spec = g_param_spec_string ("alias", "Alias",
398 "The Alias of the individual displayed in the widget",
400 G_PARAM_READABLE | G_PARAM_STATIC_STRINGS);
401 g_object_class_install_property (oclass, PROP_ALIAS, spec);
403 g_type_class_add_private (klass, sizeof (EmpathyRosterContactPriv));
407 empathy_roster_contact_init (EmpathyRosterContact *self)
409 GtkWidget *main_box, *box, *first_line_box;
410 GtkStyleContext *context;
412 self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self,
413 EMPATHY_TYPE_ROSTER_CONTACT, EmpathyRosterContactPriv);
415 main_box = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 8);
418 self->priv->avatar = gtk_image_new ();
420 gtk_widget_set_size_request (self->priv->avatar, AVATAR_SIZE, AVATAR_SIZE);
422 gtk_box_pack_start (GTK_BOX (main_box), self->priv->avatar, FALSE, FALSE, 0);
423 gtk_widget_show (self->priv->avatar);
425 box = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0);
427 /* Alias and phone icon */
428 self->priv->first_line_alig = gtk_alignment_new (0, 0.5, 1, 1);
429 first_line_box = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0);
431 self->priv->alias = gtk_label_new (NULL);
432 gtk_label_set_ellipsize (GTK_LABEL (self->priv->alias), PANGO_ELLIPSIZE_END);
433 gtk_box_pack_start (GTK_BOX (first_line_box), self->priv->alias,
435 gtk_misc_set_alignment (GTK_MISC (self->priv->alias), 0, 0.5);
436 gtk_widget_show (self->priv->alias);
438 self->priv->phone_icon = gtk_image_new_from_icon_name ("phone-symbolic",
440 gtk_misc_set_alignment (GTK_MISC (self->priv->phone_icon), 0, 0.5);
441 gtk_box_pack_start (GTK_BOX (first_line_box), self->priv->phone_icon,
444 gtk_container_add (GTK_CONTAINER (self->priv->first_line_alig),
446 gtk_widget_show (self->priv->first_line_alig);
448 gtk_box_pack_start (GTK_BOX (box), self->priv->first_line_alig,
450 gtk_widget_show (first_line_box);
452 gtk_box_pack_start (GTK_BOX (main_box), box, TRUE, TRUE, 0);
453 gtk_widget_show (box);
456 self->priv->presence_msg = gtk_label_new (NULL);
457 gtk_label_set_ellipsize (GTK_LABEL (self->priv->presence_msg),
458 PANGO_ELLIPSIZE_END);
459 gtk_box_pack_start (GTK_BOX (box), self->priv->presence_msg, TRUE, TRUE, 0);
460 gtk_widget_show (self->priv->presence_msg);
462 context = gtk_widget_get_style_context (self->priv->presence_msg);
463 gtk_style_context_add_class (context, GTK_STYLE_CLASS_DIM_LABEL);
466 self->priv->presence_icon = gtk_image_new ();
468 gtk_box_pack_start (GTK_BOX (main_box), self->priv->presence_icon,
470 gtk_widget_show (self->priv->presence_icon);
472 gtk_container_add (GTK_CONTAINER (self), main_box);
473 gtk_widget_show (main_box);
477 empathy_roster_contact_new (FolksIndividual *individual,
480 g_return_val_if_fail (FOLKS_IS_INDIVIDUAL (individual), NULL);
482 return g_object_new (EMPATHY_TYPE_ROSTER_CONTACT,
483 "individual", individual,
493 empathy_roster_contact_get_individual (EmpathyRosterContact *self)
495 return self->priv->individual;
499 empathy_roster_contact_is_online (EmpathyRosterContact *self)
501 return self->priv->online;
505 empathy_roster_contact_get_group (EmpathyRosterContact *self)
507 return self->priv->group;
511 empathy_roster_contact_set_event_icon (EmpathyRosterContact *self,
514 if (!tp_strdiff (self->priv->event_icon, icon))
517 g_free (self->priv->event_icon);
518 self->priv->event_icon = g_strdup (icon);
520 update_presence_icon (self);
524 empathy_roster_contact_get_avatar_pixbuf (EmpathyRosterContact *self)
526 return gtk_image_get_pixbuf (GTK_IMAGE (self->priv->avatar));