typedef struct
{
EmpathyIndividualManager *manager;
- gboolean show_offline;
gboolean show_avatars;
gboolean show_groups;
gboolean is_compact;
guint setup_idle_id;
gboolean dispose_has_run;
GHashTable *status_icons;
+ /* List of owned GCancellables for each pending avatar load operation */
+ GList *avatar_cancellables;
} EmpathyIndividualStorePriv;
typedef struct
EmpathyIndividualStore *self;
FolksIndividual *individual;
gboolean remove;
+ guint timeout;
} ShowActiveData;
enum
{
PROP_0,
PROP_INDIVIDUAL_MANAGER,
- PROP_SHOW_OFFLINE,
PROP_SHOW_AVATARS,
PROP_SHOW_PROTOCOLS,
PROP_SHOW_GROUPS,
G_DEFINE_TYPE (EmpathyIndividualStore, empathy_individual_store,
GTK_TYPE_TREE_STORE);
+/* Calculate whether the Individual can do audio or video calls.
+ * FIXME: We can remove this once libfolks has grown capabilities support
+ * again: bgo#626179. */
+static void
+individual_can_audio_video_call (FolksIndividual *individual,
+ gboolean *can_audio_call,
+ gboolean *can_video_call)
+{
+ GList *personas, *l;
+ gboolean can_audio = FALSE, can_video = FALSE;
+
+ personas = folks_individual_get_personas (individual);
+ for (l = personas; l != NULL; l = l->next)
+ {
+ TpContact *tp_contact;
+ EmpathyContact *contact;
+
+ if (!TPF_IS_PERSONA (l->data))
+ continue;
+
+ tp_contact = tpf_persona_get_contact (TPF_PERSONA (l->data));
+ contact = empathy_contact_dup_from_tp_contact (tp_contact);
+ empathy_contact_set_persona (contact, FOLKS_PERSONA (l->data));
+
+ can_audio = can_audio || empathy_contact_get_capabilities (contact) &
+ EMPATHY_CAPABILITIES_AUDIO;
+ can_video = can_video || empathy_contact_get_capabilities (contact) &
+ EMPATHY_CAPABILITIES_VIDEO;
+
+ g_object_unref (contact);
+
+ if (can_audio && can_video)
+ break;
+ }
+
+ *can_audio_call = can_audio;
+ *can_video_call = can_video;
+}
+
+static const gchar * const *
+individual_get_client_types (FolksIndividual *individual)
+{
+ GList *personas, *l;
+ const gchar * const *types = NULL;
+ FolksPresenceType presence_type = FOLKS_PRESENCE_TYPE_UNSET;
+
+ personas = folks_individual_get_personas (individual);
+ for (l = personas; l != NULL; l = l->next)
+ {
+ FolksPresence *presence;
+
+ /* We only want personas which implement FolksPresence */
+ if (!FOLKS_IS_PRESENCE (l->data))
+ continue;
+
+ presence = FOLKS_PRESENCE (l->data);
+
+ if (folks_presence_typecmp (folks_presence_get_presence_type (presence),
+ presence_type) > 0)
+ {
+ TpContact *tp_contact;
+
+ presence_type = folks_presence_get_presence_type (presence);
+
+ tp_contact = tpf_persona_get_contact (TPF_PERSONA (l->data));
+ types = tp_contact_get_client_types (tp_contact);
+ }
+ }
+
+ return types;
+}
+
static void
add_individual_to_store (GtkTreeStore *self,
GtkTreeIter *iter,
GtkTreeIter *parent,
- FolksIndividual *individual,
- EmpathyIndividualManagerFlags flags)
+ FolksIndividual *individual)
{
+ gboolean can_audio_call, can_video_call;
+ const gchar * const *types;
+
+ individual_can_audio_video_call (individual, &can_audio_call,
+ &can_video_call);
+
+ types = individual_get_client_types (individual);
+
gtk_tree_store_insert_with_values (self, iter, parent, 0,
EMPATHY_INDIVIDUAL_STORE_COL_NAME,
- folks_individual_get_alias (individual),
+ folks_aliasable_get_alias (FOLKS_ALIASABLE (individual)),
EMPATHY_INDIVIDUAL_STORE_COL_INDIVIDUAL, individual,
EMPATHY_INDIVIDUAL_STORE_COL_IS_GROUP, FALSE,
EMPATHY_INDIVIDUAL_STORE_COL_IS_SEPARATOR, FALSE,
- EMPATHY_INDIVIDUAL_STORE_COL_CAN_AUDIO_CALL,
- folks_individual_get_capabilities (individual) &
- FOLKS_CAPABILITIES_FLAGS_AUDIO,
- EMPATHY_INDIVIDUAL_STORE_COL_CAN_VIDEO_CALL,
- folks_individual_get_capabilities (individual) &
- FOLKS_CAPABILITIES_FLAGS_VIDEO,
- EMPATHY_INDIVIDUAL_STORE_COL_FLAGS, flags,
+ EMPATHY_INDIVIDUAL_STORE_COL_CAN_AUDIO_CALL, can_audio_call,
+ EMPATHY_INDIVIDUAL_STORE_COL_CAN_VIDEO_CALL, can_video_call,
+ EMPATHY_INDIVIDUAL_STORE_COL_CLIENT_TYPES, types,
-1);
}
/* Groups are only at the top level. */
if (gtk_tree_path_get_depth (path) != 1)
- {
- return FALSE;
- }
+ return FALSE;
gtk_tree_model_get (model, iter,
EMPATHY_INDIVIDUAL_STORE_COL_NAME, &str,
if (!fg.found)
{
if (created)
- {
- *created = TRUE;
- }
+ *created = TRUE;
gtk_tree_store_insert_with_values (GTK_TREE_STORE (self), &iter_group,
NULL, 0,
-1);
if (iter_group_to_set)
- {
- *iter_group_to_set = iter_group;
- }
+ *iter_group_to_set = iter_group;
gtk_tree_store_insert_with_values (GTK_TREE_STORE (self), &iter_separator,
&iter_group, 0,
-1);
if (iter_separator_to_set)
- {
- *iter_separator_to_set = iter_separator;
- }
+ *iter_separator_to_set = iter_separator;
}
else
{
if (created)
- {
- *created = FALSE;
- }
+ *created = FALSE;
if (iter_group_to_set)
- {
- *iter_group_to_set = fg.iter;
- }
+ *iter_group_to_set = fg.iter;
iter_separator = fg.iter;
EMPATHY_INDIVIDUAL_STORE_COL_IS_SEPARATOR, &is_separator, -1);
if (is_separator && iter_separator_to_set)
- {
- *iter_separator_to_set = iter_separator;
- }
+ *iter_separator_to_set = iter_separator;
}
}
}
(GtkTreeModelForeachFunc) individual_store_find_contact_foreach, &fc);
if (fc.found)
- {
- l = fc.iters;
- }
+ l = fc.iters;
return l;
}
+static void
+free_iters (GList *iters)
+{
+ g_list_foreach (iters, (GFunc) gtk_tree_iter_free, NULL);
+ g_list_free (iters);
+}
+
static void
individual_store_remove_individual (EmpathyIndividualStore *self,
FolksIndividual *individual)
iters = individual_store_find_contact (self, individual);
if (iters == NULL)
- {
- return;
- }
+ return;
/* Clean up model */
model = GTK_TREE_MODEL (self);
}
}
- g_list_foreach (iters, (GFunc) gtk_tree_iter_free, NULL);
- g_list_free (iters);
+ free_iters (iters);
}
static void
GtkTreeIter iter;
GHashTable *group_set = NULL;
GList *groups = NULL, *l;
- EmpathyIndividualManager *manager;
EmpathyContact *contact;
TpConnection *connection;
- EmpathyIndividualManagerFlags flags = 0;
+ gchar *protocol_name;
priv = GET_PRIV (self);
- if (EMP_STR_EMPTY (folks_individual_get_alias (individual)) ||
- (!priv->show_offline && !folks_individual_is_online (individual)))
- {
- return;
- }
+ if (EMP_STR_EMPTY (folks_aliasable_get_alias (FOLKS_ALIASABLE (individual))))
+ return;
if (priv->show_groups)
{
- group_set = folks_individual_get_groups (individual);
+ group_set = folks_groupable_get_groups (FOLKS_GROUPABLE (individual));
groups = g_hash_table_get_keys (group_set);
}
- manager = empathy_individual_manager_dup_singleton ();
contact = empathy_contact_dup_from_folks_individual (individual);
connection = empathy_contact_get_connection (contact);
- flags = empathy_individual_manager_get_flags_for_connection (manager,
- connection);
+
+ tp_connection_parse_object_path (connection, &protocol_name, NULL);
if (groups == NULL)
{
parent = &iter_group;
- /* TODO: implement */
- DEBUG ("forcing the People Nearby group even when 'show "
- "groups' is off is unimplemented");
-
if (!priv->show_groups)
+ parent = NULL;
+ else if (!tp_strdiff (protocol_name, "local-xmpp"))
{
- parent = NULL;
+ /* these are People Nearby */
+ individual_store_get_group (self,
+ EMPATHY_INDIVIDUAL_STORE_PEOPLE_NEARBY, &iter_group, NULL, NULL,
+ TRUE);
}
else
{
}
add_individual_to_store (GTK_TREE_STORE (self), &iter, parent,
- individual, flags);
+ individual);
}
+ g_free (protocol_name);
+
/* Else add to each group. */
for (l = groups; l; l = l->next)
{
FALSE);
add_individual_to_store (GTK_TREE_STORE (self), &iter, &iter_group,
- individual, flags);
+ individual);
}
g_list_free (groups);
- if (group_set != NULL)
- g_hash_table_unref (group_set);
if (priv->show_groups &&
folks_favourite_get_is_favourite (FOLKS_FAVOURITE (individual)))
&iter_group, NULL, NULL, TRUE);
add_individual_to_store (GTK_TREE_STORE (self), &iter, &iter_group,
- individual, flags);
+ individual);
}
individual_store_contact_update (self, individual);
}
}
- g_list_foreach (iters, (GFunc) gtk_tree_iter_free, NULL);
- g_list_free (iters);
+ free_iters (iters);
+}
+static void individual_store_contact_active_free (ShowActiveData *data);
+
+static void
+individual_store_contact_active_invalidated (ShowActiveData *data,
+ GObject *old_object)
+{
+ /* Remove the timeout and free the struct, since the individual or individual
+ * store has disappeared. */
+ g_source_remove (data->timeout);
+
+ if (old_object == (GObject *) data->self)
+ data->self = NULL;
+ else if (old_object == (GObject *) data->individual)
+ data->individual = NULL;
+ else
+ g_assert_not_reached ();
+
+ individual_store_contact_active_free (data);
}
static ShowActiveData *
ShowActiveData *data;
DEBUG ("Individual'%s' now active, and %s be removed",
- folks_individual_get_alias (individual), remove_ ? "WILL" : "WILL NOT");
+ folks_aliasable_get_alias (FOLKS_ALIASABLE (individual)),
+ remove_ ? "WILL" : "WILL NOT");
data = g_slice_new0 (ShowActiveData);
- data->self = g_object_ref (self);
- data->individual = g_object_ref (individual);
+ /* We don't actually want to force either the IndividualStore or the
+ * Individual to stay alive, since the user could quit Empathy or disable
+ * the account before the contact_active timeout is fired. */
+ g_object_weak_ref (G_OBJECT (self),
+ (GWeakNotify) individual_store_contact_active_invalidated, data);
+ g_object_weak_ref (G_OBJECT (individual),
+ (GWeakNotify) individual_store_contact_active_invalidated, data);
+
+ data->self = self;
+ data->individual = individual;
data->remove = remove_;
+ data->timeout = 0;
return data;
}
static void
individual_store_contact_active_free (ShowActiveData *data)
{
- g_object_unref (data->individual);
- g_object_unref (data->self);
+ if (data->self != NULL)
+ {
+ g_object_weak_unref (G_OBJECT (data->self),
+ (GWeakNotify) individual_store_contact_active_invalidated, data);
+ }
+
+ if (data->individual != NULL)
+ {
+ g_object_weak_unref (G_OBJECT (data->individual),
+ (GWeakNotify) individual_store_contact_active_invalidated, data);
+ }
g_slice_free (ShowActiveData, data);
}
static gboolean
individual_store_contact_active_cb (ShowActiveData *data)
{
- EmpathyIndividualStorePriv *priv;
-
- priv = GET_PRIV (data->self);
-
- if (data->remove &&
- !priv->show_offline && !folks_individual_is_online (data->individual))
+ if (data->remove)
{
DEBUG ("Individual'%s' active timeout, removing item",
- folks_individual_get_alias (data->individual));
+ folks_aliasable_get_alias (FOLKS_ALIASABLE (data->individual)));
individual_store_remove_individual (data->self, data->individual);
}
DEBUG ("Individual'%s' no longer active",
- folks_individual_get_alias (data->individual));
+ folks_aliasable_get_alias (FOLKS_ALIASABLE (data->individual)));
individual_store_contact_set_active (data->self,
data->individual, FALSE, TRUE);
return FALSE;
}
+typedef struct {
+ EmpathyIndividualStore *store; /* weak */
+ GCancellable *cancellable; /* owned */
+} LoadAvatarData;
+
static void
-individual_avatar_pixbuf_received_cb (GObject *object,
+individual_avatar_pixbuf_received_cb (FolksIndividual *individual,
GAsyncResult *result,
- gpointer user_data)
+ LoadAvatarData *data)
{
- FolksIndividual *individual = FOLKS_INDIVIDUAL (object);
- EmpathyIndividualStore *self = user_data;
GError *error = NULL;
GdkPixbuf *pixbuf;
if (error != NULL)
{
DEBUG ("failed to retrieve pixbuf for individual %s: %s",
- folks_individual_get_alias (individual),
+ folks_aliasable_get_alias (FOLKS_ALIASABLE (individual)),
error->message);
g_clear_error (&error);
}
- else
+ else if (data->store != NULL)
{
GList *iters, *l;
- iters = individual_store_find_contact (self, individual);
+ iters = individual_store_find_contact (data->store, individual);
for (l = iters; l; l = l->next)
{
- gtk_tree_store_set (GTK_TREE_STORE (self), l->data,
+ gtk_tree_store_set (GTK_TREE_STORE (data->store), l->data,
EMPATHY_INDIVIDUAL_STORE_COL_PIXBUF_AVATAR, pixbuf,
-1);
}
+
+ free_iters (iters);
}
+
+ /* Free things */
+ if (data->store != NULL)
+ {
+ EmpathyIndividualStorePriv *priv = GET_PRIV (data->store);
+
+ g_object_remove_weak_pointer (G_OBJECT (data->store),
+ (gpointer *) &data->store);
+ priv->avatar_cancellables = g_list_remove (priv->avatar_cancellables,
+ data->cancellable);
+ }
+
+ tp_clear_object (&pixbuf);
+ g_object_unref (data->cancellable);
+ g_slice_free (LoadAvatarData, data);
}
static void
GtkTreeModel *model;
GList *iters, *l;
gboolean in_list;
- gboolean should_be_in_list;
gboolean was_online = TRUE;
gboolean now_online = FALSE;
gboolean set_model = FALSE;
gboolean do_set_refresh = FALSE;
gboolean show_avatar = FALSE;
GdkPixbuf *pixbuf_status;
+ LoadAvatarData *load_avatar_data;
priv = GET_PRIV (self);
}
/* Get online state now. */
- now_online = folks_individual_is_online (individual);
-
- if (priv->show_offline || now_online)
- {
- should_be_in_list = TRUE;
- }
- else
- {
- should_be_in_list = FALSE;
- }
-
- if (!in_list && !should_be_in_list)
- {
- /* Nothing to do. */
- DEBUG ("Individual:'%s' in list:NO, should be:NO",
- folks_individual_get_alias (individual));
-
- g_list_foreach (iters, (GFunc) gtk_tree_iter_free, NULL);
- g_list_free (iters);
- return;
- }
- else if (in_list && !should_be_in_list)
- {
- DEBUG ("Individual:'%s' in list:YES, should be:NO",
- folks_individual_get_alias (individual));
-
- if (priv->show_active)
- {
- do_remove = TRUE;
- do_set_active = TRUE;
- do_set_refresh = TRUE;
+ now_online = folks_presence_is_online (FOLKS_PRESENCE (individual));
- set_model = TRUE;
- DEBUG ("Remove item (after timeout)");
- }
- else
- {
- DEBUG ("Remove item (now)!");
- individual_store_remove_individual (self, individual);
- }
- }
- else if (!in_list && should_be_in_list)
+ if (!in_list)
{
DEBUG ("Individual'%s' in list:NO, should be:YES",
- folks_individual_get_alias (individual));
+ folks_aliasable_get_alias (FOLKS_ALIASABLE (individual)));
individual_store_add_individual (self, individual);
else
{
DEBUG ("Individual'%s' in list:YES, should be:YES",
- folks_individual_get_alias (individual));
+ folks_aliasable_get_alias (FOLKS_ALIASABLE (individual)));
/* Get online state before. */
if (iters && g_list_length (iters) > 0)
show_avatar = TRUE;
}
- empathy_pixbuf_avatar_from_individual_scaled_async (individual,
- individual_avatar_pixbuf_received_cb, 32, 32, self);
+ /* Load the avatar asynchronously */
+ load_avatar_data = g_slice_new (LoadAvatarData);
+ load_avatar_data->store = self;
+ g_object_add_weak_pointer (G_OBJECT (self),
+ (gpointer *) &load_avatar_data->store);
+ load_avatar_data->cancellable = g_cancellable_new ();
+
+ priv->avatar_cancellables = g_list_prepend (priv->avatar_cancellables,
+ load_avatar_data->cancellable);
+ empathy_pixbuf_avatar_from_individual_scaled_async (individual, 32, 32,
+ load_avatar_data->cancellable,
+ (GAsyncReadyCallback) individual_avatar_pixbuf_received_cb,
+ load_avatar_data);
pixbuf_status =
empathy_individual_store_get_individual_status_icon (self, individual);
for (l = iters; l && set_model; l = l->next)
{
+ gboolean can_audio_call, can_video_call;
+ const gchar * const *types;
+
+ individual_can_audio_video_call (individual, &can_audio_call,
+ &can_video_call);
+
+ types = individual_get_client_types (individual);
+
gtk_tree_store_set (GTK_TREE_STORE (self), l->data,
EMPATHY_INDIVIDUAL_STORE_COL_ICON_STATUS, pixbuf_status,
EMPATHY_INDIVIDUAL_STORE_COL_PIXBUF_AVATAR_VISIBLE, show_avatar,
EMPATHY_INDIVIDUAL_STORE_COL_NAME,
- folks_individual_get_alias (individual),
+ folks_aliasable_get_alias (FOLKS_ALIASABLE (individual)),
EMPATHY_INDIVIDUAL_STORE_COL_PRESENCE_TYPE,
- folks_individual_get_presence_type (individual),
+ folks_presence_get_presence_type (FOLKS_PRESENCE (individual)),
EMPATHY_INDIVIDUAL_STORE_COL_STATUS,
- folks_individual_get_presence_message (individual),
- EMPATHY_INDIVIDUAL_STORE_COL_CAN_AUDIO_CALL,
- folks_individual_get_capabilities (individual) &
- FOLKS_CAPABILITIES_FLAGS_AUDIO,
- EMPATHY_INDIVIDUAL_STORE_COL_CAN_VIDEO_CALL,
- folks_individual_get_capabilities (individual) &
- FOLKS_CAPABILITIES_FLAGS_VIDEO,
+ folks_presence_get_presence_message (FOLKS_PRESENCE (individual)),
EMPATHY_INDIVIDUAL_STORE_COL_COMPACT, priv->is_compact,
EMPATHY_INDIVIDUAL_STORE_COL_IS_GROUP, FALSE,
EMPATHY_INDIVIDUAL_STORE_COL_IS_ONLINE, now_online,
EMPATHY_INDIVIDUAL_STORE_COL_IS_SEPARATOR, FALSE,
+ EMPATHY_INDIVIDUAL_STORE_COL_CAN_AUDIO_CALL, can_audio_call,
+ EMPATHY_INDIVIDUAL_STORE_COL_CAN_VIDEO_CALL, can_video_call,
+ EMPATHY_INDIVIDUAL_STORE_COL_CLIENT_TYPES, types,
-1);
}
data =
individual_store_contact_active_new (self, individual,
do_remove);
- g_timeout_add_seconds (ACTIVE_USER_SHOW_TIME,
+ data->timeout = g_timeout_add_seconds (ACTIVE_USER_SHOW_TIME,
(GSourceFunc) individual_store_contact_active_cb, data);
}
}
* timeout removes the user from the contact list, really we
* should remove the first timeout.
*/
- g_list_foreach (iters, (GFunc) gtk_tree_iter_free, NULL);
- g_list_free (iters);
+ free_iters (iters);
}
static void
-individual_store_contact_updated_cb (FolksIndividual *individual,
+individual_store_individual_updated_cb (FolksIndividual *individual,
GParamSpec *param,
EmpathyIndividualStore *self)
{
DEBUG ("Individual'%s' updated, checking roster is in sync...",
- folks_individual_get_alias (individual));
+ folks_aliasable_get_alias (FOLKS_ALIASABLE (individual)));
+
+ individual_store_contact_update (self, individual);
+}
+
+static void
+individual_store_contact_updated_cb (EmpathyContact *contact,
+ GParamSpec *pspec,
+ EmpathyIndividualStore *self)
+{
+ FolksIndividual *individual;
+
+ DEBUG ("Contact '%s' updated, checking roster is in sync...",
+ empathy_contact_get_alias (contact));
+
+ individual = g_object_get_data (G_OBJECT (contact), "individual");
+ if (individual == NULL)
+ return;
individual_store_contact_update (self, individual);
}
+static void
+individual_personas_changed_cb (FolksIndividual *individual,
+ GList *added,
+ GList *removed,
+ EmpathyIndividualStore *self)
+{
+ GList *l;
+
+ DEBUG ("Individual '%s' personas-changed.",
+ folks_individual_get_id (individual));
+
+ /* FIXME: libfolks hasn't grown capabilities support yet, so we have to go
+ * through the EmpathyContacts for them. */
+ for (l = removed; l != NULL; l = l->next)
+ {
+ TpContact *tp_contact;
+ EmpathyContact *contact;
+
+ if (!TPF_IS_PERSONA (l->data))
+ continue;
+
+ tp_contact = tpf_persona_get_contact (TPF_PERSONA (l->data));
+ contact = empathy_contact_dup_from_tp_contact (tp_contact);
+ empathy_contact_set_persona (contact, FOLKS_PERSONA (l->data));
+
+ g_object_set_data (G_OBJECT (contact), "individual", NULL);
+ g_signal_handlers_disconnect_by_func (contact,
+ (GCallback) individual_store_contact_updated_cb, self);
+
+ g_object_unref (contact);
+ }
+
+ for (l = added; l != NULL; l = l->next)
+ {
+ TpContact *tp_contact;
+ EmpathyContact *contact;
+
+ if (!TPF_IS_PERSONA (l->data))
+ continue;
+
+ tp_contact = tpf_persona_get_contact (TPF_PERSONA (l->data));
+ contact = empathy_contact_dup_from_tp_contact (tp_contact);
+ empathy_contact_set_persona (contact, FOLKS_PERSONA (l->data));
+
+ g_object_set_data (G_OBJECT (contact), "individual", individual);
+ g_signal_connect (contact, "notify::capabilities",
+ (GCallback) individual_store_contact_updated_cb, self);
+ g_signal_connect (contact, "notify::client-types",
+ (GCallback) individual_store_contact_updated_cb, self);
+
+ g_object_unref (contact);
+ }
+}
+
static void
individual_store_add_individual_and_connect (EmpathyIndividualStore *self,
FolksIndividual *individual)
{
+ individual_store_add_individual (self, individual);
+
g_signal_connect (individual, "notify::avatar",
- G_CALLBACK (individual_store_contact_updated_cb), self);
+ (GCallback) individual_store_individual_updated_cb, self);
g_signal_connect (individual, "notify::presence-type",
- G_CALLBACK (individual_store_contact_updated_cb), self);
+ (GCallback) individual_store_individual_updated_cb, self);
g_signal_connect (individual, "notify::presence-message",
- G_CALLBACK (individual_store_contact_updated_cb), self);
+ (GCallback) individual_store_individual_updated_cb, self);
g_signal_connect (individual, "notify::alias",
- G_CALLBACK (individual_store_contact_updated_cb), self);
- g_signal_connect (individual, "notify::capabilities",
- G_CALLBACK (individual_store_contact_updated_cb), self);
+ (GCallback) individual_store_individual_updated_cb, self);
+ g_signal_connect (individual, "personas-changed",
+ (GCallback) individual_personas_changed_cb, self);
- individual_store_add_individual (self, individual);
+ individual_personas_changed_cb (individual,
+ folks_individual_get_personas (individual), NULL, self);
}
static void
-individual_store_remove_individual_and_disconnect (
- EmpathyIndividualStore *self,
+individual_store_disconnect_individual (EmpathyIndividualStore *self,
FolksIndividual *individual)
{
+ individual_personas_changed_cb (individual, NULL,
+ folks_individual_get_personas (individual), self);
+
g_signal_handlers_disconnect_by_func (individual,
- G_CALLBACK (individual_store_contact_updated_cb), self);
+ (GCallback) individual_store_individual_updated_cb, self);
+ g_signal_handlers_disconnect_by_func (individual,
+ (GCallback) individual_personas_changed_cb, self);
+}
+static void
+individual_store_remove_individual_and_disconnect (
+ EmpathyIndividualStore *self,
+ FolksIndividual *individual)
+{
+ individual_store_disconnect_individual (self, individual);
individual_store_remove_individual (self, individual);
}
static void
individual_store_members_changed_cb (EmpathyIndividualManager *manager,
- gchar *message,
+ const gchar *message,
GList *added,
GList *removed,
guint reason,
FolksIndividual *old_individual,
FolksIndividual *new_individual,
guint reason,
- gchar *message,
+ const gchar *message,
EmpathyIndividualStore *self)
{
EmpathyIndividualStorePriv *priv;
individual_store_dispose (GObject *object)
{
EmpathyIndividualStorePriv *priv = GET_PRIV (object);
- GList *contacts, *l;
+ GList *individuals, *l;
if (priv->dispose_has_run)
return;
priv->dispose_has_run = TRUE;
- contacts = empathy_individual_manager_get_members (priv->manager);
- for (l = contacts; l; l = l->next)
+ /* Cancel any pending avatar load operations */
+ for (l = priv->avatar_cancellables; l != NULL; l = l->next)
+ {
+ /* The cancellables are freed in individual_avatar_pixbuf_received_cb() */
+ g_cancellable_cancel (G_CANCELLABLE (l->data));
+ }
+ g_list_free (priv->avatar_cancellables);
+
+ individuals = empathy_individual_manager_get_members (priv->manager);
+ for (l = individuals; l; l = l->next)
{
- g_signal_handlers_disconnect_by_func (l->data,
- G_CALLBACK (individual_store_contact_updated_cb), object);
+ individual_store_disconnect_individual (EMPATHY_INDIVIDUAL_STORE (object),
+ FOLKS_INDIVIDUAL (l->data));
}
- g_list_free (contacts);
+ g_list_free (individuals);
g_signal_handlers_disconnect_by_func (priv->manager,
G_CALLBACK (individual_store_member_renamed_cb), object);
case PROP_INDIVIDUAL_MANAGER:
g_value_set_object (value, priv->manager);
break;
- case PROP_SHOW_OFFLINE:
- g_value_set_boolean (value, priv->show_offline);
- break;
case PROP_SHOW_AVATARS:
g_value_set_boolean (value, priv->show_avatars);
break;
individual_store_set_individual_manager (EMPATHY_INDIVIDUAL_STORE
(object), g_value_get_object (value));
break;
- case PROP_SHOW_OFFLINE:
- empathy_individual_store_set_show_offline (EMPATHY_INDIVIDUAL_STORE
- (object), g_value_get_boolean (value));
- break;
case PROP_SHOW_AVATARS:
empathy_individual_store_set_show_avatars (EMPATHY_INDIVIDUAL_STORE
(object), g_value_get_boolean (value));
"The individual manager",
EMPATHY_TYPE_INDIVIDUAL_MANAGER,
G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE));
- g_object_class_install_property (object_class,
- PROP_SHOW_OFFLINE,
- g_param_spec_boolean ("show-offline",
- "Show Offline",
- "Whether contact list should display "
- "offline contacts", FALSE, G_PARAM_READWRITE));
g_object_class_install_property (object_class,
PROP_SHOW_AVATARS,
g_param_spec_boolean ("show-avatars",
FolksIndividual *individual_b)
{
gint ret_val;
+ EmpathyContact *contact_a = NULL, *contact_b = NULL;
+ TpAccount *account_a, *account_b;
g_return_val_if_fail (individual_a != NULL || individual_b != NULL, 0);
/* alias */
- ret_val = g_utf8_collate (folks_individual_get_alias (individual_a),
- folks_individual_get_alias (individual_b));
+ ret_val = g_utf8_collate (
+ folks_aliasable_get_alias (FOLKS_ALIASABLE (individual_a)),
+ folks_aliasable_get_alias (FOLKS_ALIASABLE (individual_b)));
if (ret_val != 0)
goto out;
- /* identifier */
- ret_val = g_utf8_collate (folks_individual_get_id (individual_a),
- folks_individual_get_id (individual_b));
+ contact_a = empathy_contact_dup_from_folks_individual (individual_a);
+ contact_b = empathy_contact_dup_from_folks_individual (individual_b);
+ account_a = empathy_contact_get_account (contact_a);
+ account_b = empathy_contact_get_account (contact_b);
+
+ g_assert (account_a != NULL);
+ g_assert (account_b != NULL);
+
+ /* protocol */
+ ret_val = g_strcmp0 (tp_account_get_protocol (account_a),
+ tp_account_get_protocol (account_b));
+
+ if (ret_val != 0)
+ goto out;
+
+ /* account ID */
+ ret_val = g_strcmp0 (tp_proxy_get_object_path (account_a),
+ tp_proxy_get_object_path (account_b));
if (ret_val != 0)
goto out;
+ /* identifier */
+ ret_val = g_utf8_collate (folks_individual_get_id (individual_a),
+ folks_individual_get_id (individual_b));
+
out:
+ tp_clear_object (&contact_a);
+ tp_clear_object (&contact_b);
+
return ret_val;
}
/* If we managed to get this far, we can start looking at
* the presences.
*/
- folks_presence_type_a = folks_individual_get_presence_type (individual_a);
- folks_presence_type_b = folks_individual_get_presence_type (individual_b);
+ folks_presence_type_a =
+ folks_presence_get_presence_type (FOLKS_PRESENCE (individual_a));
+ folks_presence_type_b =
+ folks_presence_get_presence_type (FOLKS_PRESENCE (individual_b));
tp_presence_a = empathy_folks_presence_type_to_tp (folks_presence_type_a);
tp_presence_b = empathy_folks_presence_type_to_tp (folks_presence_type_b);
tp_clear_object (&individual_a);
tp_clear_object (&individual_b);
+ g_free (name_a);
+ g_free (name_b);
return ret_val;
}
G_TYPE_BOOLEAN, /* Is separator */
G_TYPE_BOOLEAN, /* Can make audio calls */
G_TYPE_BOOLEAN, /* Can make video calls */
- EMPATHY_TYPE_INDIVIDUAL_MANAGER_FLAGS, /* Flags */
G_TYPE_BOOLEAN, /* Is a fake group */
+ G_TYPE_STRV, /* Client types */
};
priv = GET_PRIV (self);
}
static gboolean
-individual_store_inibit_active_cb (EmpathyIndividualStore *self)
+individual_store_inhibit_active_cb (EmpathyIndividualStore *self)
{
EmpathyIndividualStorePriv *priv;
priv->show_protocols = FALSE;
priv->inhibit_active =
g_timeout_add_seconds (ACTIVE_USER_WAIT_TO_ENABLE_TIME,
- (GSourceFunc) individual_store_inibit_active_cb, self);
+ (GSourceFunc) individual_store_inhibit_active_cb, self);
priv->status_icons =
g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_object_unref);
individual_store_setup (self);
return priv->manager;
}
-gboolean
-empathy_individual_store_get_show_offline (EmpathyIndividualStore *self)
-{
- EmpathyIndividualStorePriv *priv;
-
- g_return_val_if_fail (EMPATHY_IS_INDIVIDUAL_STORE (self), FALSE);
-
- priv = GET_PRIV (self);
-
- return priv->show_offline;
-}
-
-void
-empathy_individual_store_set_show_offline (EmpathyIndividualStore *self,
- gboolean show_offline)
-{
- EmpathyIndividualStorePriv *priv;
- GList *contacts, *l;
- gboolean show_active;
-
- g_return_if_fail (EMPATHY_IS_INDIVIDUAL_STORE (self));
-
- priv = GET_PRIV (self);
-
- priv->show_offline = show_offline;
- show_active = priv->show_active;
-
- /* Disable temporarily. */
- priv->show_active = FALSE;
-
- contacts = empathy_individual_manager_get_members (priv->manager);
- for (l = contacts; l; l = l->next)
- {
- individual_store_contact_update (self, l->data);
- }
- g_list_free (contacts);
-
- /* Restore to original setting. */
- priv->show_active = show_active;
-
- g_object_notify (G_OBJECT (self), "show-offline");
-}
-
gboolean
empathy_individual_store_get_show_avatars (EmpathyIndividualStore *self)
{
gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (self),
EMPATHY_INDIVIDUAL_STORE_COL_NAME, GTK_SORT_ASCENDING);
break;
+
+ default:
+ g_assert_not_reached ();
}
g_object_notify (G_OBJECT (self), "sort-criterium");
GtkTreeIter parent_iter, iter;
gchar *name = NULL;
gboolean is_group;
- gboolean fake;
+ gboolean fake = FALSE;
g_return_val_if_fail (GTK_IS_TREE_MODEL (model), NULL);
break;
}
- show_protocols_here = priv->show_protocols && (contact_count == 1);
+ show_protocols_here = (priv->show_protocols && (contact_count == 1));
if (show_protocols_here)
{
contact = empathy_contact_dup_from_folks_individual (individual);
{
pixbuf_status =
empathy_pixbuf_contact_status_icon_with_icon_name (contact,
- status_icon_name, priv->show_protocols);
+ status_icon_name, show_protocols_here);
if (pixbuf_status != NULL)
{
g_hash_table_insert (priv->status_icons,