2 #include "empathy-roster-contact.h"
4 #include <glib/gi18n-lib.h>
5 #include <tp-account-widgets/tpaw-images.h>
6 #include <tp-account-widgets/tpaw-pixbuf-utils.h>
8 #include "empathy-ui-utils.h"
9 #include "empathy-utils.h"
11 G_DEFINE_TYPE (EmpathyRosterContact
, empathy_roster_contact
, GTK_TYPE_LIST_BOX_ROW
)
13 #define AVATAR_SIZE 48
30 static guint signals[LAST_SIGNAL];
33 struct _EmpathyRosterContactPriv
35 FolksIndividual
*individual
;
39 GtkWidget
*first_line_alig
;
41 GtkWidget
*presence_msg
;
42 GtkWidget
*presence_icon
;
43 GtkWidget
*phone_icon
;
45 /* If not NULL, used instead of the individual's presence icon */
52 get_alias (EmpathyRosterContact
*self
)
54 return folks_alias_details_get_alias (FOLKS_ALIAS_DETAILS (
55 self
->priv
->individual
));
59 empathy_roster_contact_get_property (GObject
*object
,
64 EmpathyRosterContact
*self
= EMPATHY_ROSTER_CONTACT (object
);
68 case PROP_INDIVIDIUAL
:
69 g_value_set_object (value
, self
->priv
->individual
);
72 g_value_set_string (value
, self
->priv
->group
);
75 g_value_set_boolean (value
, self
->priv
->online
);
78 g_value_set_string (value
, get_alias (self
));
81 G_OBJECT_WARN_INVALID_PROPERTY_ID (object
, property_id
, pspec
);
87 empathy_roster_contact_set_property (GObject
*object
,
92 EmpathyRosterContact
*self
= EMPATHY_ROSTER_CONTACT (object
);
96 case PROP_INDIVIDIUAL
:
97 g_assert (self
->priv
->individual
== NULL
); /* construct only */
98 self
->priv
->individual
= g_value_dup_object (value
);
101 g_assert (self
->priv
->group
== NULL
); /* construct only */
102 self
->priv
->group
= g_value_dup_string (value
);
105 G_OBJECT_WARN_INVALID_PROPERTY_ID (object
, property_id
, pspec
);
111 avatar_loaded_cb (GObject
*source
,
112 GAsyncResult
*result
,
115 TpWeakRef
*wr
= user_data
;
116 EmpathyRosterContact
*self
;
119 self
= tp_weak_ref_dup_object (wr
);
123 pixbuf
= empathy_pixbuf_avatar_from_individual_scaled_finish (
124 FOLKS_INDIVIDUAL (source
), result
, NULL
);
128 pixbuf
= tpaw_pixbuf_from_icon_name_sized (
129 TPAW_IMAGE_AVATAR_DEFAULT
, AVATAR_SIZE
);
132 gtk_image_set_from_pixbuf (GTK_IMAGE (self
->priv
->avatar
), pixbuf
);
133 g_object_unref (pixbuf
);
135 g_object_unref (self
);
138 tp_weak_ref_destroy (wr
);
142 update_avatar (EmpathyRosterContact
*self
)
144 empathy_pixbuf_avatar_from_individual_scaled_async (self
->priv
->individual
,
145 AVATAR_SIZE
, AVATAR_SIZE
, NULL
, avatar_loaded_cb
,
146 tp_weak_ref_new (self
, NULL
, NULL
));
150 avatar_changed_cb (FolksIndividual
*individual
,
152 EmpathyRosterContact
*self
)
154 update_avatar (self
);
158 update_alias (EmpathyRosterContact
*self
)
160 gtk_label_set_text (GTK_LABEL (self
->priv
->alias
), get_alias (self
));
162 g_object_notify (G_OBJECT (self
), "alias");
166 alias_changed_cb (FolksIndividual
*individual
,
168 EmpathyRosterContact
*self
)
174 update_presence_msg (EmpathyRosterContact
*self
)
179 msg
= folks_presence_details_get_presence_message (
180 FOLKS_PRESENCE_DETAILS (self
->priv
->individual
));
182 if (tp_str_empty (msg
))
184 /* Just display the alias in the center of the row */
185 gtk_alignment_set (GTK_ALIGNMENT (self
->priv
->first_line_alig
),
188 gtk_widget_hide (self
->priv
->presence_msg
);
192 FolksPresenceType type
;
194 type
= folks_presence_details_get_presence_type (
195 FOLKS_PRESENCE_DETAILS (self
->priv
->individual
));
196 if (type
== FOLKS_PRESENCE_TYPE_ERROR
)
200 /* Add a prefix explaining that something goes wrong when trying to
201 * fetch contact's presence. */
202 tmp
= g_strdup_printf (_("Server cannot find contact: %s"), msg
);
203 gtk_label_set_text (GTK_LABEL (self
->priv
->presence_msg
), tmp
);
209 gtk_label_set_text (GTK_LABEL (self
->priv
->presence_msg
), msg
);
212 gtk_alignment_set (GTK_ALIGNMENT (self
->priv
->first_line_alig
),
214 gtk_misc_set_alignment (GTK_MISC (self
->priv
->presence_msg
), 0, 0.25);
216 gtk_widget_show (self
->priv
->presence_msg
);
219 types
= (GStrv
) empathy_individual_get_client_types (self
->priv
->individual
);
221 gtk_widget_set_visible (self
->priv
->phone_icon
,
222 empathy_client_types_contains_mobile_device (types
));
226 presence_message_changed_cb (FolksIndividual
*individual
,
228 EmpathyRosterContact
*self
)
230 update_presence_msg (self
);
234 update_presence_icon (EmpathyRosterContact
*self
)
238 if (self
->priv
->event_icon
== NULL
)
239 icon
= empathy_icon_name_for_individual (self
->priv
->individual
);
241 icon
= self
->priv
->event_icon
;
243 gtk_image_set_from_icon_name (GTK_IMAGE (self
->priv
->presence_icon
), icon
,
248 update_online (EmpathyRosterContact
*self
)
250 FolksPresenceType presence
;
253 presence
= folks_presence_details_get_presence_type (
254 FOLKS_PRESENCE_DETAILS (self
->priv
->individual
));
258 case FOLKS_PRESENCE_TYPE_UNSET
:
259 case FOLKS_PRESENCE_TYPE_OFFLINE
:
260 case FOLKS_PRESENCE_TYPE_UNKNOWN
:
261 case FOLKS_PRESENCE_TYPE_ERROR
:
265 case FOLKS_PRESENCE_TYPE_AVAILABLE
:
266 case FOLKS_PRESENCE_TYPE_AWAY
:
267 case FOLKS_PRESENCE_TYPE_EXTENDED_AWAY
:
268 case FOLKS_PRESENCE_TYPE_HIDDEN
:
269 case FOLKS_PRESENCE_TYPE_BUSY
:
274 g_warning ("Unknown FolksPresenceType: %d", presence
);
278 if (self
->priv
->online
== online
)
281 self
->priv
->online
= online
;
282 g_object_notify (G_OBJECT (self
), "online");
286 presence_status_changed_cb (FolksIndividual
*individual
,
288 EmpathyRosterContact
*self
)
290 update_presence_icon (self
);
291 update_online (self
);
295 empathy_roster_contact_constructed (GObject
*object
)
297 EmpathyRosterContact
*self
= EMPATHY_ROSTER_CONTACT (object
);
298 void (*chain_up
) (GObject
*) =
299 ((GObjectClass
*) empathy_roster_contact_parent_class
)->constructed
;
301 if (chain_up
!= NULL
)
304 g_assert (FOLKS_IS_INDIVIDUAL (self
->priv
->individual
));
306 tp_g_signal_connect_object (self
->priv
->individual
, "notify::avatar",
307 G_CALLBACK (avatar_changed_cb
), self
, 0);
308 tp_g_signal_connect_object (self
->priv
->individual
, "notify::alias",
309 G_CALLBACK (alias_changed_cb
), self
, 0);
310 tp_g_signal_connect_object (self
->priv
->individual
,
311 "notify::presence-message",
312 G_CALLBACK (presence_message_changed_cb
), self
, 0);
313 tp_g_signal_connect_object (self
->priv
->individual
, "notify::presence-status",
314 G_CALLBACK (presence_status_changed_cb
), self
, 0);
316 update_avatar (self
);
318 update_presence_msg (self
);
319 update_presence_icon (self
);
321 update_online (self
);
325 empathy_roster_contact_dispose (GObject
*object
)
327 EmpathyRosterContact
*self
= EMPATHY_ROSTER_CONTACT (object
);
328 void (*chain_up
) (GObject
*) =
329 ((GObjectClass
*) empathy_roster_contact_parent_class
)->dispose
;
331 g_clear_object (&self
->priv
->individual
);
333 if (chain_up
!= NULL
)
338 empathy_roster_contact_finalize (GObject
*object
)
340 EmpathyRosterContact
*self
= EMPATHY_ROSTER_CONTACT (object
);
341 void (*chain_up
) (GObject
*) =
342 ((GObjectClass
*) empathy_roster_contact_parent_class
)->finalize
;
344 g_free (self
->priv
->group
);
345 g_free (self
->priv
->event_icon
);
347 if (chain_up
!= NULL
)
352 empathy_roster_contact_class_init (
353 EmpathyRosterContactClass
*klass
)
355 GObjectClass
*oclass
= G_OBJECT_CLASS (klass
);
358 oclass
->get_property
= empathy_roster_contact_get_property
;
359 oclass
->set_property
= empathy_roster_contact_set_property
;
360 oclass
->constructed
= empathy_roster_contact_constructed
;
361 oclass
->dispose
= empathy_roster_contact_dispose
;
362 oclass
->finalize
= empathy_roster_contact_finalize
;
364 spec
= g_param_spec_object ("individual", "Individual",
366 FOLKS_TYPE_INDIVIDUAL
,
367 G_PARAM_READWRITE
| G_PARAM_CONSTRUCT_ONLY
| G_PARAM_STATIC_STRINGS
);
368 g_object_class_install_property (oclass
, PROP_INDIVIDIUAL
, spec
);
370 spec
= g_param_spec_string ("group", "Group",
371 "Group of this widget, or NULL",
373 G_PARAM_READWRITE
| G_PARAM_CONSTRUCT_ONLY
| G_PARAM_STATIC_STRINGS
);
374 g_object_class_install_property (oclass
, PROP_GROUP
, spec
);
376 spec
= g_param_spec_boolean ("online", "Online",
377 "TRUE if Individual is online",
379 G_PARAM_READABLE
| G_PARAM_STATIC_STRINGS
);
380 g_object_class_install_property (oclass
, PROP_ONLINE
, spec
);
382 spec
= g_param_spec_string ("alias", "Alias",
383 "The Alias of the individual displayed in the widget",
385 G_PARAM_READABLE
| G_PARAM_STATIC_STRINGS
);
386 g_object_class_install_property (oclass
, PROP_ALIAS
, spec
);
388 g_type_class_add_private (klass
, sizeof (EmpathyRosterContactPriv
));
392 empathy_roster_contact_init (EmpathyRosterContact
*self
)
394 GtkWidget
*alig
, *main_box
, *box
, *first_line_box
;
395 GtkStyleContext
*context
;
397 self
->priv
= G_TYPE_INSTANCE_GET_PRIVATE (self
,
398 EMPATHY_TYPE_ROSTER_CONTACT
, EmpathyRosterContactPriv
);
400 alig
= gtk_alignment_new (0.5, 0.5, 1, 1);
401 gtk_widget_show (alig
);
402 gtk_alignment_set_padding (GTK_ALIGNMENT (alig
), 4, 4, 4, 12);
404 main_box
= gtk_box_new (GTK_ORIENTATION_HORIZONTAL
, 8);
407 self
->priv
->avatar
= gtk_image_new ();
409 gtk_widget_set_size_request (self
->priv
->avatar
, AVATAR_SIZE
, AVATAR_SIZE
);
411 gtk_box_pack_start (GTK_BOX (main_box
), self
->priv
->avatar
, FALSE
, FALSE
, 0);
412 gtk_widget_show (self
->priv
->avatar
);
414 box
= gtk_box_new (GTK_ORIENTATION_VERTICAL
, 0);
416 /* Alias and phone icon */
417 self
->priv
->first_line_alig
= gtk_alignment_new (0, 0.5, 1, 1);
418 first_line_box
= gtk_box_new (GTK_ORIENTATION_HORIZONTAL
, 0);
420 self
->priv
->alias
= gtk_label_new (NULL
);
421 gtk_label_set_ellipsize (GTK_LABEL (self
->priv
->alias
), PANGO_ELLIPSIZE_END
);
422 gtk_box_pack_start (GTK_BOX (first_line_box
), self
->priv
->alias
,
424 gtk_misc_set_alignment (GTK_MISC (self
->priv
->alias
), 0, 0.5);
425 gtk_widget_show (self
->priv
->alias
);
427 self
->priv
->phone_icon
= gtk_image_new_from_icon_name ("phone-symbolic",
429 gtk_misc_set_alignment (GTK_MISC (self
->priv
->phone_icon
), 0, 0.5);
430 gtk_box_pack_start (GTK_BOX (first_line_box
), self
->priv
->phone_icon
,
433 gtk_container_add (GTK_CONTAINER (self
->priv
->first_line_alig
),
435 gtk_widget_show (self
->priv
->first_line_alig
);
437 gtk_box_pack_start (GTK_BOX (box
), self
->priv
->first_line_alig
,
439 gtk_widget_show (first_line_box
);
441 gtk_box_pack_start (GTK_BOX (main_box
), box
, TRUE
, TRUE
, 0);
442 gtk_widget_show (box
);
445 self
->priv
->presence_msg
= gtk_label_new (NULL
);
446 gtk_label_set_ellipsize (GTK_LABEL (self
->priv
->presence_msg
),
447 PANGO_ELLIPSIZE_END
);
448 gtk_box_pack_start (GTK_BOX (box
), self
->priv
->presence_msg
, TRUE
, TRUE
, 0);
449 gtk_widget_show (self
->priv
->presence_msg
);
451 context
= gtk_widget_get_style_context (self
->priv
->presence_msg
);
452 gtk_style_context_add_class (context
, GTK_STYLE_CLASS_DIM_LABEL
);
455 self
->priv
->presence_icon
= gtk_image_new ();
457 gtk_box_pack_start (GTK_BOX (main_box
), self
->priv
->presence_icon
,
459 gtk_widget_show (self
->priv
->presence_icon
);
461 gtk_container_add (GTK_CONTAINER (self
), alig
);
462 gtk_container_add (GTK_CONTAINER (alig
), main_box
);
463 gtk_widget_show (main_box
);
467 empathy_roster_contact_new (FolksIndividual
*individual
,
470 g_return_val_if_fail (FOLKS_IS_INDIVIDUAL (individual
), NULL
);
472 return g_object_new (EMPATHY_TYPE_ROSTER_CONTACT
,
473 "individual", individual
,
479 empathy_roster_contact_get_individual (EmpathyRosterContact
*self
)
481 return self
->priv
->individual
;
485 empathy_roster_contact_is_online (EmpathyRosterContact
*self
)
487 return self
->priv
->online
;
491 empathy_roster_contact_get_group (EmpathyRosterContact
*self
)
493 return self
->priv
->group
;
497 empathy_roster_contact_set_event_icon (EmpathyRosterContact
*self
,
500 if (!tp_strdiff (self
->priv
->event_icon
, icon
))
503 g_free (self
->priv
->event_icon
);
504 self
->priv
->event_icon
= g_strdup (icon
);
506 update_presence_icon (self
);
510 empathy_roster_contact_get_avatar_pixbuf (EmpathyRosterContact
*self
)
512 return gtk_image_get_pixbuf (GTK_IMAGE (self
->priv
->avatar
));