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 update_presence_msg (EmpathyRosterContact
*self
)
182 msg
= folks_presence_details_get_presence_message (
183 FOLKS_PRESENCE_DETAILS (self
->priv
->individual
));
185 if (tp_str_empty (msg
))
187 /* Just display the alias in the center of the row */
188 gtk_alignment_set (GTK_ALIGNMENT (self
->priv
->first_line_alig
),
191 gtk_widget_hide (self
->priv
->presence_msg
);
195 FolksPresenceType type
;
197 type
= folks_presence_details_get_presence_type (
198 FOLKS_PRESENCE_DETAILS (self
->priv
->individual
));
199 if (type
== FOLKS_PRESENCE_TYPE_ERROR
)
203 /* Add a prefix explaining that something goes wrong when trying to
204 * fetch contact's presence. */
205 tmp
= g_strdup_printf (_("Server cannot find contact: %s"), msg
);
206 gtk_label_set_text (GTK_LABEL (self
->priv
->presence_msg
), tmp
);
212 gtk_label_set_text (GTK_LABEL (self
->priv
->presence_msg
), msg
);
215 gtk_alignment_set (GTK_ALIGNMENT (self
->priv
->first_line_alig
),
217 gtk_misc_set_alignment (GTK_MISC (self
->priv
->presence_msg
), 0, 0.25);
219 gtk_widget_show (self
->priv
->presence_msg
);
222 types
= (GStrv
) empathy_individual_get_client_types (self
->priv
->individual
);
224 gtk_widget_set_visible (self
->priv
->phone_icon
,
225 empathy_client_types_contains_mobile_device (types
));
229 presence_message_changed_cb (FolksIndividual
*individual
,
231 EmpathyRosterContact
*self
)
233 update_presence_msg (self
);
237 update_presence_icon (EmpathyRosterContact
*self
)
241 if (self
->priv
->event_icon
== NULL
)
242 icon
= empathy_icon_name_for_individual (self
->priv
->individual
);
244 icon
= self
->priv
->event_icon
;
246 gtk_image_set_from_icon_name (GTK_IMAGE (self
->priv
->presence_icon
), icon
,
251 update_online (EmpathyRosterContact
*self
)
253 FolksPresenceType presence
;
256 presence
= folks_presence_details_get_presence_type (
257 FOLKS_PRESENCE_DETAILS (self
->priv
->individual
));
261 case FOLKS_PRESENCE_TYPE_UNSET
:
262 case FOLKS_PRESENCE_TYPE_OFFLINE
:
263 case FOLKS_PRESENCE_TYPE_UNKNOWN
:
264 case FOLKS_PRESENCE_TYPE_ERROR
:
268 case FOLKS_PRESENCE_TYPE_AVAILABLE
:
269 case FOLKS_PRESENCE_TYPE_AWAY
:
270 case FOLKS_PRESENCE_TYPE_EXTENDED_AWAY
:
271 case FOLKS_PRESENCE_TYPE_HIDDEN
:
272 case FOLKS_PRESENCE_TYPE_BUSY
:
277 g_warning ("Unknown FolksPresenceType: %d", presence
);
281 if (self
->priv
->online
== online
)
284 self
->priv
->online
= online
;
285 g_object_notify (G_OBJECT (self
), "online");
289 presence_status_changed_cb (FolksIndividual
*individual
,
291 EmpathyRosterContact
*self
)
293 update_presence_icon (self
);
294 update_online (self
);
298 empathy_roster_contact_constructed (GObject
*object
)
300 EmpathyRosterContact
*self
= EMPATHY_ROSTER_CONTACT (object
);
301 void (*chain_up
) (GObject
*) =
302 ((GObjectClass
*) empathy_roster_contact_parent_class
)->constructed
;
304 if (chain_up
!= NULL
)
307 g_assert (FOLKS_IS_INDIVIDUAL (self
->priv
->individual
));
309 tp_g_signal_connect_object (self
->priv
->individual
, "notify::avatar",
310 G_CALLBACK (avatar_changed_cb
), self
, 0);
311 tp_g_signal_connect_object (self
->priv
->individual
, "notify::alias",
312 G_CALLBACK (alias_changed_cb
), self
, 0);
313 tp_g_signal_connect_object (self
->priv
->individual
,
314 "notify::presence-message",
315 G_CALLBACK (presence_message_changed_cb
), self
, 0);
316 tp_g_signal_connect_object (self
->priv
->individual
, "notify::presence-status",
317 G_CALLBACK (presence_status_changed_cb
), self
, 0);
319 update_avatar (self
);
321 update_presence_msg (self
);
322 update_presence_icon (self
);
324 update_online (self
);
328 empathy_roster_contact_dispose (GObject
*object
)
330 EmpathyRosterContact
*self
= EMPATHY_ROSTER_CONTACT (object
);
331 void (*chain_up
) (GObject
*) =
332 ((GObjectClass
*) empathy_roster_contact_parent_class
)->dispose
;
334 g_clear_object (&self
->priv
->individual
);
336 if (chain_up
!= NULL
)
341 empathy_roster_contact_finalize (GObject
*object
)
343 EmpathyRosterContact
*self
= EMPATHY_ROSTER_CONTACT (object
);
344 void (*chain_up
) (GObject
*) =
345 ((GObjectClass
*) empathy_roster_contact_parent_class
)->finalize
;
347 g_free (self
->priv
->group
);
348 g_free (self
->priv
->event_icon
);
350 if (chain_up
!= NULL
)
355 empathy_roster_contact_class_init (
356 EmpathyRosterContactClass
*klass
)
358 GObjectClass
*oclass
= G_OBJECT_CLASS (klass
);
361 oclass
->get_property
= empathy_roster_contact_get_property
;
362 oclass
->set_property
= empathy_roster_contact_set_property
;
363 oclass
->constructed
= empathy_roster_contact_constructed
;
364 oclass
->dispose
= empathy_roster_contact_dispose
;
365 oclass
->finalize
= empathy_roster_contact_finalize
;
367 spec
= g_param_spec_object ("individual", "Individual",
369 FOLKS_TYPE_INDIVIDUAL
,
370 G_PARAM_READWRITE
| G_PARAM_CONSTRUCT_ONLY
| G_PARAM_STATIC_STRINGS
);
371 g_object_class_install_property (oclass
, PROP_INDIVIDIUAL
, spec
);
373 spec
= g_param_spec_string ("group", "Group",
374 "Group of this widget, or NULL",
376 G_PARAM_READWRITE
| G_PARAM_CONSTRUCT_ONLY
| G_PARAM_STATIC_STRINGS
);
377 g_object_class_install_property (oclass
, PROP_GROUP
, spec
);
379 spec
= g_param_spec_boolean ("online", "Online",
380 "TRUE if Individual is online",
382 G_PARAM_READABLE
| G_PARAM_STATIC_STRINGS
);
383 g_object_class_install_property (oclass
, PROP_ONLINE
, spec
);
385 spec
= g_param_spec_string ("alias", "Alias",
386 "The Alias of the individual displayed in the widget",
388 G_PARAM_READABLE
| G_PARAM_STATIC_STRINGS
);
389 g_object_class_install_property (oclass
, PROP_ALIAS
, spec
);
391 g_type_class_add_private (klass
, sizeof (EmpathyRosterContactPriv
));
395 empathy_roster_contact_init (EmpathyRosterContact
*self
)
397 GtkWidget
*main_box
, *box
, *first_line_box
;
398 GtkStyleContext
*context
;
400 self
->priv
= G_TYPE_INSTANCE_GET_PRIVATE (self
,
401 EMPATHY_TYPE_ROSTER_CONTACT
, EmpathyRosterContactPriv
);
403 main_box
= gtk_box_new (GTK_ORIENTATION_HORIZONTAL
, 8);
406 self
->priv
->avatar
= gtk_image_new ();
408 gtk_widget_set_size_request (self
->priv
->avatar
, AVATAR_SIZE
, AVATAR_SIZE
);
410 gtk_box_pack_start (GTK_BOX (main_box
), self
->priv
->avatar
, FALSE
, FALSE
, 0);
411 gtk_widget_show (self
->priv
->avatar
);
413 box
= gtk_box_new (GTK_ORIENTATION_VERTICAL
, 0);
415 /* Alias and phone icon */
416 self
->priv
->first_line_alig
= gtk_alignment_new (0, 0.5, 1, 1);
417 first_line_box
= gtk_box_new (GTK_ORIENTATION_HORIZONTAL
, 0);
419 self
->priv
->alias
= gtk_label_new (NULL
);
420 gtk_label_set_ellipsize (GTK_LABEL (self
->priv
->alias
), PANGO_ELLIPSIZE_END
);
421 gtk_box_pack_start (GTK_BOX (first_line_box
), self
->priv
->alias
,
423 gtk_misc_set_alignment (GTK_MISC (self
->priv
->alias
), 0, 0.5);
424 gtk_widget_show (self
->priv
->alias
);
426 self
->priv
->phone_icon
= gtk_image_new_from_icon_name ("phone-symbolic",
428 gtk_misc_set_alignment (GTK_MISC (self
->priv
->phone_icon
), 0, 0.5);
429 gtk_box_pack_start (GTK_BOX (first_line_box
), self
->priv
->phone_icon
,
432 gtk_container_add (GTK_CONTAINER (self
->priv
->first_line_alig
),
434 gtk_widget_show (self
->priv
->first_line_alig
);
436 gtk_box_pack_start (GTK_BOX (box
), self
->priv
->first_line_alig
,
438 gtk_widget_show (first_line_box
);
440 gtk_box_pack_start (GTK_BOX (main_box
), box
, TRUE
, TRUE
, 0);
441 gtk_widget_show (box
);
444 self
->priv
->presence_msg
= gtk_label_new (NULL
);
445 gtk_label_set_ellipsize (GTK_LABEL (self
->priv
->presence_msg
),
446 PANGO_ELLIPSIZE_END
);
447 gtk_box_pack_start (GTK_BOX (box
), self
->priv
->presence_msg
, TRUE
, TRUE
, 0);
448 gtk_widget_show (self
->priv
->presence_msg
);
450 context
= gtk_widget_get_style_context (self
->priv
->presence_msg
);
451 gtk_style_context_add_class (context
, GTK_STYLE_CLASS_DIM_LABEL
);
454 self
->priv
->presence_icon
= gtk_image_new ();
456 gtk_box_pack_start (GTK_BOX (main_box
), self
->priv
->presence_icon
,
458 gtk_widget_show (self
->priv
->presence_icon
);
460 gtk_container_add (GTK_CONTAINER (self
), main_box
);
461 gtk_widget_show (main_box
);
465 empathy_roster_contact_new (FolksIndividual
*individual
,
468 g_return_val_if_fail (FOLKS_IS_INDIVIDUAL (individual
), NULL
);
470 return g_object_new (EMPATHY_TYPE_ROSTER_CONTACT
,
471 "individual", individual
,
481 empathy_roster_contact_get_individual (EmpathyRosterContact
*self
)
483 return self
->priv
->individual
;
487 empathy_roster_contact_is_online (EmpathyRosterContact
*self
)
489 return self
->priv
->online
;
493 empathy_roster_contact_get_group (EmpathyRosterContact
*self
)
495 return self
->priv
->group
;
499 empathy_roster_contact_set_event_icon (EmpathyRosterContact
*self
,
502 if (!tp_strdiff (self
->priv
->event_icon
, icon
))
505 g_free (self
->priv
->event_icon
);
506 self
->priv
->event_icon
= g_strdup (icon
);
508 update_presence_icon (self
);
512 empathy_roster_contact_get_avatar_pixbuf (EmpathyRosterContact
*self
)
514 return gtk_image_get_pixbuf (GTK_IMAGE (self
->priv
->avatar
));