aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--libempathy-gtk/empathy-individual-linker.c87
-rw-r--r--libempathy-gtk/empathy-individual-view.c376
-rw-r--r--libempathy-gtk/empathy-individual-view.h26
-rw-r--r--libempathy-gtk/empathy-persona-view.c268
-rw-r--r--libempathy-gtk/empathy-persona-view.h15
-rw-r--r--libempathy/empathy-individual-manager.c13
-rw-r--r--src/empathy-main-window.c5
7 files changed, 634 insertions, 156 deletions
diff --git a/libempathy-gtk/empathy-individual-linker.c b/libempathy-gtk/empathy-individual-linker.c
index 9ebb4718b..b4226a71c 100644
--- a/libempathy-gtk/empathy-individual-linker.c
+++ b/libempathy-gtk/empathy-individual-linker.c
@@ -216,6 +216,78 @@ row_toggled_cb (GtkCellRendererToggle *cell_renderer,
gtk_tree_path_free (tree_path);
}
+static gboolean
+individual_view_drag_motion_cb (GtkWidget *widget,
+ GdkDragContext *context,
+ gint x,
+ gint y,
+ guint time_)
+{
+ EmpathyIndividualView *view = EMPATHY_INDIVIDUAL_VIEW (widget);
+ GdkAtom target;
+
+ target = gtk_drag_dest_find_target (GTK_WIDGET (view), context, NULL);
+
+ if (target == gdk_atom_intern_static_string ("text/persona-id"))
+ {
+ GtkTreePath *path;
+
+ /* FIXME: It doesn't make sense for us to highlight a specific row or
+ * position to drop a Persona in, so just highlight the entire widget.
+ * Since I can't find a way to do this, just highlight the first possible
+ * position in the tree. */
+ gdk_drag_status (context, gdk_drag_context_get_suggested_action (context),
+ time_);
+
+ path = gtk_tree_path_new_first ();
+ gtk_tree_view_set_drag_dest_row (GTK_TREE_VIEW (view), path,
+ GTK_TREE_VIEW_DROP_BEFORE);
+ gtk_tree_path_free (path);
+
+ return TRUE;
+ }
+
+ /* Unknown or unhandled drag target */
+ gdk_drag_status (context, GDK_ACTION_DEFAULT, time_);
+ gtk_tree_view_set_drag_dest_row (GTK_TREE_VIEW (view), NULL, 0);
+
+ return FALSE;
+}
+
+static gboolean
+individual_view_drag_persona_received_cb (EmpathyIndividualView *view,
+ GdkDragAction action,
+ FolksPersona *persona,
+ FolksIndividual *individual,
+ EmpathyIndividualLinker *self)
+{
+ EmpathyIndividualLinkerPriv *priv = GET_PRIV (self);
+
+ /* A Persona has been dragged onto the EmpathyIndividualView (from the
+ * EmpathyPersonaView), so we try to remove the Individual which contains
+ * the Persona from the link. */
+ if (individual != priv->start_individual)
+ {
+ unlink_individual (self, individual);
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+static gboolean
+persona_view_drag_individual_received_cb (EmpathyPersonaView *view,
+ GdkDragAction action,
+ FolksIndividual *individual,
+ EmpathyIndividualLinker *self)
+{
+ /* An Individual has been dragged onto the EmpathyPersonaView (from the
+ * EmpathyIndividualView), so we try to add the Individual to the link. */
+ link_individual (self, individual);
+
+ return TRUE;
+}
+
static void
set_up (EmpathyIndividualLinker *self)
{
@@ -258,11 +330,18 @@ set_up (EmpathyIndividualLinker *self)
empathy_individual_store_set_show_protocols (priv->individual_store, FALSE);
priv->individual_view = empathy_individual_view_new (priv->individual_store,
- EMPATHY_INDIVIDUAL_VIEW_FEATURE_NONE, EMPATHY_INDIVIDUAL_FEATURE_NONE);
+ EMPATHY_INDIVIDUAL_VIEW_FEATURE_INDIVIDUAL_DRAG |
+ EMPATHY_INDIVIDUAL_VIEW_FEATURE_INDIVIDUAL_DROP |
+ EMPATHY_INDIVIDUAL_VIEW_FEATURE_PERSONA_DROP,
+ EMPATHY_INDIVIDUAL_FEATURE_NONE);
empathy_individual_view_set_show_offline (priv->individual_view, TRUE);
g_signal_connect (priv->individual_view, "row-activated",
(GCallback) row_activated_cb, self);
+ g_signal_connect (priv->individual_view, "drag-motion",
+ (GCallback) individual_view_drag_motion_cb, self);
+ g_signal_connect (priv->individual_view, "drag-persona-received",
+ (GCallback) individual_view_drag_persona_received_cb, self);
/* Add a checkbox column to the selector */
cell_renderer = gtk_cell_renderer_toggle_new ();
@@ -322,9 +401,13 @@ set_up (EmpathyIndividualLinker *self)
priv->persona_store = empathy_persona_store_new (priv->new_individual);
empathy_persona_store_set_show_protocols (priv->persona_store, TRUE);
- persona_view = empathy_persona_view_new (priv->persona_store);
+ persona_view = empathy_persona_view_new (priv->persona_store,
+ EMPATHY_PERSONA_VIEW_FEATURE_ALL);
empathy_persona_view_set_show_offline (persona_view, TRUE);
+ g_signal_connect (persona_view, "drag-individual-received",
+ (GCallback) persona_view_drag_individual_received_cb, self);
+
gtk_container_add (GTK_CONTAINER (scrolled_window),
GTK_WIDGET (persona_view));
gtk_widget_show (GTK_WIDGET (persona_view));
diff --git a/libempathy-gtk/empathy-individual-view.c b/libempathy-gtk/empathy-individual-view.c
index 6767c3bfd..b8365d175 100644
--- a/libempathy-gtk/empathy-individual-view.c
+++ b/libempathy-gtk/empathy-individual-view.c
@@ -68,9 +68,8 @@ typedef struct
EmpathyIndividualStore *store;
GtkTreeRowReference *drag_row;
EmpathyIndividualViewFeatureFlags view_features;
- EmpathyContactFeatureFlags individual_features;
+ EmpathyIndividualFeatureFlags individual_features;
GtkWidget *tooltip_widget;
- GtkTargetList *file_targets;
gboolean show_offline;
@@ -110,6 +109,7 @@ enum
enum DndDragType
{
DND_DRAG_TYPE_INDIVIDUAL_ID,
+ DND_DRAG_TYPE_PERSONA_ID,
DND_DRAG_TYPE_URI_LIST,
DND_DRAG_TYPE_STRING,
};
@@ -118,20 +118,16 @@ enum DndDragType
{ (gchar *) T, 0, I }
static const GtkTargetEntry drag_types_dest[] = {
+ DRAG_TYPE ("text/individual-id", DND_DRAG_TYPE_INDIVIDUAL_ID),
+ DRAG_TYPE ("text/persona-id", DND_DRAG_TYPE_PERSONA_ID),
DRAG_TYPE ("text/path-list", DND_DRAG_TYPE_URI_LIST),
DRAG_TYPE ("text/uri-list", DND_DRAG_TYPE_URI_LIST),
- DRAG_TYPE ("text/contact-id", DND_DRAG_TYPE_INDIVIDUAL_ID),
DRAG_TYPE ("text/plain", DND_DRAG_TYPE_STRING),
DRAG_TYPE ("STRING", DND_DRAG_TYPE_STRING),
};
-static const GtkTargetEntry drag_types_dest_file[] = {
- DRAG_TYPE ("text/path-list", DND_DRAG_TYPE_URI_LIST),
- DRAG_TYPE ("text/uri-list", DND_DRAG_TYPE_URI_LIST),
-};
-
static const GtkTargetEntry drag_types_source[] = {
- DRAG_TYPE ("text/contact-id", DND_DRAG_TYPE_INDIVIDUAL_ID),
+ DRAG_TYPE ("text/individual-id", DND_DRAG_TYPE_INDIVIDUAL_ID),
};
#undef DRAG_TYPE
@@ -141,7 +137,8 @@ static GdkAtom drag_atoms_source[G_N_ELEMENTS (drag_types_source)];
enum
{
- DRAG_CONTACT_RECEIVED,
+ DRAG_INDIVIDUAL_RECEIVED,
+ DRAG_PERSONA_RECEIVED,
LAST_SIGNAL
};
@@ -247,44 +244,6 @@ groups_change_group_cb (GObject *source,
}
}
-static void
-individual_view_handle_drag (EmpathyIndividualView *self,
- FolksIndividual *individual,
- const gchar *old_group,
- const gchar *new_group,
- GdkDragAction action)
-{
- g_return_if_fail (EMPATHY_IS_INDIVIDUAL_VIEW (self));
- g_return_if_fail (FOLKS_IS_INDIVIDUAL (individual));
-
- DEBUG ("individual %s dragged from '%s' to '%s'",
- folks_individual_get_id (individual), old_group, new_group);
-
- if (!tp_strdiff (new_group, EMPATHY_INDIVIDUAL_STORE_FAVORITE))
- {
- /* Mark contact as favourite */
- folks_favourite_set_is_favourite (FOLKS_FAVOURITE (individual), TRUE);
- return;
- }
-
- if (!tp_strdiff (old_group, EMPATHY_INDIVIDUAL_STORE_FAVORITE))
- {
- /* Remove contact as favourite */
- folks_favourite_set_is_favourite (FOLKS_FAVOURITE (individual), FALSE);
-
- /* Don't try to remove it */
- old_group = NULL;
- }
-
- if (new_group != NULL)
- folks_groups_change_group (FOLKS_GROUPS (individual), new_group, TRUE,
- groups_change_group_cb, NULL);
-
- if (old_group != NULL && action == GDK_ACTION_MOVE)
- folks_groups_change_group (FOLKS_GROUPS (individual), old_group, FALSE,
- groups_change_group_cb, NULL);
-}
-
static gboolean
group_can_be_modified (const gchar *name,
gboolean is_fake_group,
@@ -307,20 +266,20 @@ group_can_be_modified (const gchar *name,
}
static gboolean
-individual_view_contact_drag_received (GtkWidget *self,
+individual_view_individual_drag_received (GtkWidget *self,
GdkDragContext *context,
GtkTreeModel *model,
GtkTreePath *path,
GtkSelectionData *selection)
{
EmpathyIndividualViewPriv *priv;
- EmpathyIndividualManager *manager;
+ EmpathyIndividualManager *manager = NULL;
FolksIndividual *individual;
GtkTreePath *source_path;
const gchar *sel_data;
gchar *new_group = NULL;
gchar *old_group = NULL;
- gboolean new_group_is_fake, old_group_is_fake = TRUE;
+ gboolean new_group_is_fake, old_group_is_fake = TRUE, retval = FALSE;
priv = GET_PRIV (self);
@@ -329,10 +288,16 @@ individual_view_contact_drag_received (GtkWidget *self,
NULL, &new_group_is_fake);
if (!group_can_be_modified (new_group, new_group_is_fake, TRUE))
- return FALSE;
-
- /* Get source group information. */
- if (priv->drag_row)
+ goto finished;
+
+ /* Get source group information iff the view has the FEATURE_GROUPS_CHANGE
+ * feature. Otherwise, we just add the dropped contact to whichever group
+ * they were dropped in, and don't remove them from their old group. This
+ * allows for Individual views which shouldn't allow Individuals to have
+ * their groups changed, and also for dragging Individuals between Individual
+ * views. */
+ if ((priv->view_features & EMPATHY_INDIVIDUAL_VIEW_FEATURE_GROUPS_CHANGE) &&
+ priv->drag_row != NULL)
{
source_path = gtk_tree_row_reference_get_path (priv->drag_row);
if (source_path)
@@ -342,16 +307,19 @@ individual_view_contact_drag_received (GtkWidget *self,
NULL, &old_group_is_fake);
gtk_tree_path_free (source_path);
}
- }
- if (!group_can_be_modified (old_group, old_group_is_fake, FALSE))
- return FALSE;
+ if (!group_can_be_modified (old_group, old_group_is_fake, FALSE))
+ goto finished;
- if (!tp_strdiff (old_group, new_group))
+ if (!tp_strdiff (old_group, new_group))
+ goto finished;
+ }
+ else if (priv->drag_row != NULL)
{
- g_free (new_group);
- g_free (old_group);
- return FALSE;
+ /* We don't allow changing Individuals' groups, and this Individual was
+ * dragged from another group in *this* Individual view, so we disallow
+ * the drop. */
+ goto finished;
}
/* XXX: for contacts, we used to ensure the account, create the contact
@@ -364,23 +332,130 @@ individual_view_contact_drag_received (GtkWidget *self,
if (individual == NULL)
{
DEBUG ("failed to find drag event individual with ID '%s'", sel_data);
-
- g_object_unref (manager);
-
- return FALSE;
+ goto finished;
}
/* FIXME: We should probably wait for the cb before calling
* gtk_drag_finish */
- individual_view_handle_drag (EMPATHY_INDIVIDUAL_VIEW (self), individual,
- old_group, new_group, gdk_drag_context_get_selected_action (context));
+ /* Emit a signal notifying of the drag. We change the Individual's groups in
+ * the default signal handler. */
+ g_signal_emit (self, signals[DRAG_INDIVIDUAL_RECEIVED], 0,
+ gdk_drag_context_get_selected_action (context), individual, new_group,
+ old_group);
+
+ retval = TRUE;
- g_object_unref (G_OBJECT (manager));
+finished:
+ tp_clear_object (&manager);
g_free (old_group);
g_free (new_group);
- return TRUE;
+ return retval;
+}
+
+static void
+real_drag_individual_received_cb (EmpathyIndividualView *self,
+ GdkDragAction action,
+ FolksIndividual *individual,
+ const gchar *new_group,
+ const gchar *old_group)
+{
+ DEBUG ("individual %s dragged from '%s' to '%s'",
+ folks_individual_get_id (individual), old_group, new_group);
+
+ if (!tp_strdiff (new_group, EMPATHY_INDIVIDUAL_STORE_FAVORITE))
+ {
+ /* Mark contact as favourite */
+ folks_favourite_set_is_favourite (FOLKS_FAVOURITE (individual), TRUE);
+ return;
+ }
+
+ if (!tp_strdiff (old_group, EMPATHY_INDIVIDUAL_STORE_FAVORITE))
+ {
+ /* Remove contact as favourite */
+ folks_favourite_set_is_favourite (FOLKS_FAVOURITE (individual), FALSE);
+
+ /* Don't try to remove it */
+ old_group = NULL;
+ }
+
+ if (new_group != NULL)
+ {
+ folks_groups_change_group (FOLKS_GROUPS (individual), new_group, TRUE,
+ groups_change_group_cb, NULL);
+ }
+
+ if (old_group != NULL && action == GDK_ACTION_MOVE)
+ {
+ folks_groups_change_group (FOLKS_GROUPS (individual), old_group,
+ FALSE, groups_change_group_cb, NULL);
+ }
+}
+
+static gboolean
+individual_view_persona_drag_received (GtkWidget *self,
+ GdkDragContext *context,
+ GtkTreeModel *model,
+ GtkTreePath *path,
+ GtkSelectionData *selection)
+{
+ EmpathyIndividualViewPriv *priv;
+ EmpathyIndividualManager *manager = NULL;
+ FolksIndividual *individual = NULL;
+ FolksPersona *persona = NULL;
+ const gchar *persona_uid;
+ GList *individuals, *l;
+ gboolean retval = FALSE;
+
+ priv = GET_PRIV (self);
+
+ persona_uid = (const gchar *) gtk_selection_data_get_data (selection);
+
+ /* FIXME: This is slow, but the only way to find the Persona we're having
+ * dropped on us. */
+ manager = empathy_individual_manager_dup_singleton ();
+ individuals = empathy_individual_manager_get_members (manager);
+
+ for (l = individuals; l != NULL; l = l->next)
+ {
+ GList *personas, *p;
+
+ personas = folks_individual_get_personas (FOLKS_INDIVIDUAL (l->data));
+
+ for (p = personas; p != NULL; p = p->next)
+ {
+ if (!tp_strdiff (folks_persona_get_uid (FOLKS_PERSONA (p->data)),
+ persona_uid))
+ {
+ persona = g_object_ref (p->data);
+ individual = g_object_ref (l->data);
+ goto got_persona;
+ }
+ }
+ }
+
+got_persona:
+ g_list_free (individuals);
+
+ if (persona == NULL || individual == NULL)
+ {
+ DEBUG ("Failed to find drag event persona with UID '%s'", persona_uid);
+ }
+ else
+ {
+ /* Emit a signal notifying of the drag. We change the Individual's groups in
+ * the default signal handler. */
+ g_signal_emit (self, signals[DRAG_PERSONA_RECEIVED], 0,
+ gdk_drag_context_get_selected_action (context), persona, individual,
+ &retval);
+ }
+
+ tp_clear_object (&manager);
+ tp_clear_object (&persona);
+ tp_clear_object (&individual);
+
+ return retval;
}
static gboolean
@@ -436,13 +511,17 @@ individual_view_drag_data_received (GtkWidget *view,
{
success = FALSE;
}
- else if (info == DND_DRAG_TYPE_INDIVIDUAL_ID
- || info == DND_DRAG_TYPE_STRING)
+ else if (info == DND_DRAG_TYPE_INDIVIDUAL_ID)
{
- success = individual_view_contact_drag_received (view,
+ success = individual_view_individual_drag_received (view,
context, model, path, selection);
}
- else if (info == DND_DRAG_TYPE_URI_LIST)
+ else if (info == DND_DRAG_TYPE_PERSONA_ID)
+ {
+ success = individual_view_persona_drag_received (view, context, model,
+ path, selection);
+ }
+ else if (info == DND_DRAG_TYPE_URI_LIST || info == DND_DRAG_TYPE_STRING)
{
success = individual_view_file_drag_received (view,
context, model, path, selection);
@@ -511,17 +590,73 @@ individual_view_drag_motion (GtkWidget *widget,
gtk_tree_view_set_drag_dest_row (GTK_TREE_VIEW (widget), NULL, 0);
return FALSE;
}
- target = gtk_drag_dest_find_target (widget, context, priv->file_targets);
+ target = gtk_drag_dest_find_target (widget, context, NULL);
gtk_tree_model_get_iter (model, &iter, path);
- if (target == GDK_NONE)
+ if (target == drag_atoms_dest[DND_DRAG_TYPE_URI_LIST] ||
+ target == drag_atoms_dest[DND_DRAG_TYPE_STRING])
+ {
+ /* This is a file drag, and it can only be dropped on contacts,
+ * not groups.
+ * If we don't have FEATURE_FILE_DROP, disallow the drop completely,
+ * even if we have a valid target. */
+ FolksIndividual *individual = NULL;
+ EmpathyCapabilities caps = EMPATHY_CAPABILITIES_NONE;
+
+ if (priv->view_features & EMPATHY_INDIVIDUAL_VIEW_FEATURE_FILE_DROP)
+ {
+ gtk_tree_model_get (model, &iter,
+ EMPATHY_INDIVIDUAL_STORE_COL_INDIVIDUAL, &individual,
+ -1);
+ }
+
+ if (individual != NULL)
+ {
+ EmpathyContact *contact = NULL;
+
+ contact = empathy_contact_dup_from_folks_individual (individual);
+ caps = empathy_contact_get_capabilities (contact);
+
+ tp_clear_object (&contact);
+ }
+
+ if (individual != NULL &&
+ folks_individual_is_online (individual) &&
+ (caps & EMPATHY_CAPABILITIES_FT))
+ {
+ gdk_drag_status (context, GDK_ACTION_COPY, time_);
+ gtk_tree_view_set_drag_dest_row (GTK_TREE_VIEW (widget),
+ path, GTK_TREE_VIEW_DROP_INTO_OR_BEFORE);
+ }
+ else
+ {
+ gdk_drag_status (context, 0, time_);
+ gtk_tree_view_set_drag_dest_row (GTK_TREE_VIEW (widget), NULL, 0);
+ retval = FALSE;
+ }
+
+ if (individual != NULL)
+ g_object_unref (individual);
+ }
+ else if ((target == drag_atoms_dest[DND_DRAG_TYPE_INDIVIDUAL_ID] &&
+ (priv->view_features & EMPATHY_INDIVIDUAL_VIEW_FEATURE_GROUPS_CHANGE ||
+ priv->drag_row == NULL)) ||
+ (target == drag_atoms_dest[DND_DRAG_TYPE_PERSONA_ID] &&
+ priv->view_features & EMPATHY_INDIVIDUAL_VIEW_FEATURE_PERSONA_DROP))
{
- /* If target == GDK_NONE, then we don't have a target that can be
- dropped on a contact. This means a contact drag. If we're
- pointing to a group, highlight it. Otherwise, if the contact
- we're pointing to is in a group, highlight that. Otherwise,
+ /* If target != GDK_NONE, then we have a contact (individual or persona)
+ drag. If we're pointing to a group, highlight it. Otherwise, if the
+ contact we're pointing to is in a group, highlight that. Otherwise,
set the drag position to before the first row for a drag into
the "non-group" at the top.
+ If it's an Individual:
+ We only highlight things if the contact is from a different
+ Individual view, or if this Individual view has
+ FEATURE_GROUPS_CHANGE. This prevents highlighting in Individual views
+ which don't have FEATURE_GROUPS_CHANGE, but do have
+ FEATURE_INDIVIDUAL_DRAG and FEATURE_INDIVIDUAL_DROP.
+ If it's a Persona:
+ We only highlight things if we have FEATURE_PERSONA_DROP.
*/
GtkTreeIter group_iter;
gboolean is_group;
@@ -554,44 +689,6 @@ individual_view_drag_motion (GtkWidget *widget,
group_path, GTK_TREE_VIEW_DROP_BEFORE);
}
}
- else
- {
- /* This is a file drag, and it can only be dropped on contacts,
- not groups.
- */
- FolksIndividual *individual;
- EmpathyCapabilities caps = EMPATHY_CAPABILITIES_NONE;
-
- gtk_tree_model_get (model, &iter,
- EMPATHY_INDIVIDUAL_STORE_COL_INDIVIDUAL, &individual, -1);
- if (individual != NULL)
- {
- EmpathyContact *contact = NULL;
-
- contact = empathy_contact_dup_from_folks_individual (individual);
- caps = empathy_contact_get_capabilities (contact);
-
- tp_clear_object (&contact);
- }
-
- if (individual != NULL &&
- folks_individual_is_online (individual) &&
- (caps & EMPATHY_CAPABILITIES_FT))
- {
- gdk_drag_status (context, GDK_ACTION_COPY, time_);
- gtk_tree_view_set_drag_dest_row (GTK_TREE_VIEW (widget),
- path, GTK_TREE_VIEW_DROP_INTO_OR_BEFORE);
- }
- else
- {
- gdk_drag_status (context, 0, time_);
- gtk_tree_view_set_drag_dest_row (GTK_TREE_VIEW (widget), NULL, 0);
- retval = FALSE;
- }
-
- if (individual != NULL)
- g_object_unref (individual);
- }
if (!is_different && !cleanup)
return retval;
@@ -807,7 +904,7 @@ individual_view_row_activated (GtkTreeView *view,
GtkTreeModel *model;
GtkTreeIter iter;
- if (!(priv->individual_features & EMPATHY_CONTACT_FEATURE_CHAT))
+ if (!(priv->individual_features & EMPATHY_INDIVIDUAL_FEATURE_CHAT))
return;
model = gtk_tree_view_get_model (GTK_TREE_VIEW (view));
@@ -1731,10 +1828,10 @@ individual_view_set_view_features (EmpathyIndividualView *view,
is enabled).
*/
gtk_tree_view_set_reorderable (GTK_TREE_VIEW (view),
- (features & EMPATHY_INDIVIDUAL_VIEW_FEATURE_CONTACT_DRAG));
+ (features & EMPATHY_INDIVIDUAL_VIEW_FEATURE_INDIVIDUAL_DRAG));
/* Update DnD source/dest */
- if (features & EMPATHY_INDIVIDUAL_VIEW_FEATURE_CONTACT_DRAG)
+ if (features & EMPATHY_INDIVIDUAL_VIEW_FEATURE_INDIVIDUAL_DRAG)
{
gtk_drag_source_set (GTK_WIDGET (view),
GDK_BUTTON1_MASK,
@@ -1748,7 +1845,7 @@ individual_view_set_view_features (EmpathyIndividualView *view,
}
- if (features & EMPATHY_INDIVIDUAL_VIEW_FEATURE_CONTACT_DROP)
+ if (features & EMPATHY_INDIVIDUAL_VIEW_FEATURE_INDIVIDUAL_DROP)
{
gtk_drag_dest_set (GTK_WIDGET (view),
GTK_DEST_DEFAULT_ALL,
@@ -1763,7 +1860,7 @@ individual_view_set_view_features (EmpathyIndividualView *view,
/* Update has-tooltip */
has_tooltip =
- (features & EMPATHY_INDIVIDUAL_VIEW_FEATURE_CONTACT_TOOLTIP) != 0;
+ (features & EMPATHY_INDIVIDUAL_VIEW_FEATURE_INDIVIDUAL_TOOLTIP) != 0;
gtk_widget_set_has_tooltip (GTK_WIDGET (view), has_tooltip);
}
@@ -1776,7 +1873,6 @@ individual_view_dispose (GObject *object)
tp_clear_object (&priv->store);
tp_clear_object (&priv->filter);
tp_clear_pointer (&priv->tooltip_widget, gtk_widget_destroy);
- tp_clear_pointer (&priv->file_targets, gtk_target_list_unref);
empathy_individual_view_set_live_search (view, NULL);
@@ -1878,14 +1974,26 @@ empathy_individual_view_class_init (EmpathyIndividualViewClass *klass)
* won't be called. */
tree_view_class->row_activated = individual_view_row_activated;
- signals[DRAG_CONTACT_RECEIVED] =
- g_signal_new ("drag-contact-received",
+ klass->drag_individual_received = real_drag_individual_received_cb;
+
+ signals[DRAG_INDIVIDUAL_RECEIVED] =
+ g_signal_new ("drag-individual-received",
G_OBJECT_CLASS_TYPE (klass),
G_SIGNAL_RUN_LAST,
- 0,
+ G_STRUCT_OFFSET (EmpathyIndividualViewClass, drag_individual_received),
NULL, NULL,
- _empathy_gtk_marshal_VOID__OBJECT_STRING_STRING,
- G_TYPE_NONE, 3, EMPATHY_TYPE_CONTACT, G_TYPE_STRING, G_TYPE_STRING);
+ _empathy_gtk_marshal_VOID__UINT_OBJECT_STRING_STRING,
+ G_TYPE_NONE, 4, G_TYPE_UINT, FOLKS_TYPE_INDIVIDUAL,
+ G_TYPE_STRING, G_TYPE_STRING);
+
+ signals[DRAG_PERSONA_RECEIVED] =
+ g_signal_new ("drag-persona-received",
+ G_OBJECT_CLASS_TYPE (klass),
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (EmpathyIndividualViewClass, drag_persona_received),
+ NULL, NULL,
+ _empathy_gtk_marshal_BOOLEAN__UINT_OBJECT_OBJECT,
+ G_TYPE_BOOLEAN, 3, G_TYPE_UINT, FOLKS_TYPE_PERSONA, FOLKS_TYPE_INDIVIDUAL);
g_object_class_install_property (object_class,
PROP_STORE,
@@ -1904,10 +2012,10 @@ empathy_individual_view_class_init (EmpathyIndividualViewClass *klass)
g_object_class_install_property (object_class,
PROP_INDIVIDUAL_FEATURES,
g_param_spec_flags ("individual-features",
- "Features of the contact menu",
+ "Features of the individual menu",
"Flags for all enabled features for the menu",
EMPATHY_TYPE_INDIVIDUAL_FEATURE_FLAGS,
- EMPATHY_CONTACT_FEATURE_NONE, G_PARAM_READWRITE));
+ EMPATHY_INDIVIDUAL_FEATURE_NONE, G_PARAM_READWRITE));
g_object_class_install_property (object_class,
PROP_SHOW_OFFLINE,
g_param_spec_boolean ("show-offline",
@@ -1934,10 +2042,6 @@ empathy_individual_view_init (EmpathyIndividualView *view)
gtk_tree_view_set_row_separator_func (GTK_TREE_VIEW (view),
empathy_individual_store_row_separator_func, NULL, NULL);
- /* Set up drag target lists. */
- priv->file_targets = gtk_target_list_new (drag_types_dest_file,
- G_N_ELEMENTS (drag_types_dest_file));
-
/* Connect to tree view signals rather than override. */
g_signal_connect (view, "button-press-event",
G_CALLBACK (individual_view_button_press_event_cb), NULL);
@@ -2213,7 +2317,7 @@ empathy_individual_view_get_individual_menu (EmpathyIndividualView *view)
/* Remove contact */
if (priv->view_features &
- EMPATHY_INDIVIDUAL_VIEW_FEATURE_CONTACT_REMOVE &&
+ EMPATHY_INDIVIDUAL_VIEW_FEATURE_INDIVIDUAL_REMOVE &&
flags & EMPATHY_INDIVIDUAL_MANAGER_CAN_REMOVE)
{
diff --git a/libempathy-gtk/empathy-individual-view.h b/libempathy-gtk/empathy-individual-view.h
index 003ff2ab3..8a250bf20 100644
--- a/libempathy-gtk/empathy-individual-view.h
+++ b/libempathy-gtk/empathy-individual-view.h
@@ -53,11 +53,16 @@ typedef enum
EMPATHY_INDIVIDUAL_VIEW_FEATURE_GROUPS_SAVE = 1 << 0,
EMPATHY_INDIVIDUAL_VIEW_FEATURE_GROUPS_RENAME = 1 << 1,
EMPATHY_INDIVIDUAL_VIEW_FEATURE_GROUPS_REMOVE = 1 << 2,
- EMPATHY_INDIVIDUAL_VIEW_FEATURE_CONTACT_REMOVE = 1 << 3,
- EMPATHY_INDIVIDUAL_VIEW_FEATURE_CONTACT_DROP = 1 << 4,
- EMPATHY_INDIVIDUAL_VIEW_FEATURE_CONTACT_DRAG = 1 << 5,
- EMPATHY_INDIVIDUAL_VIEW_FEATURE_CONTACT_TOOLTIP = 1 << 6,
- EMPATHY_INDIVIDUAL_VIEW_FEATURE_ALL = (1 << 7) - 1,
+ /* NOTE: For this to behave as expected, FEATURE_INDIVIDUAL_DRAG and
+ * FEATURE_INDIVIDUAL_DROP should also be specified. */
+ EMPATHY_INDIVIDUAL_VIEW_FEATURE_GROUPS_CHANGE = 1 << 3,
+ EMPATHY_INDIVIDUAL_VIEW_FEATURE_INDIVIDUAL_REMOVE = 1 << 4,
+ EMPATHY_INDIVIDUAL_VIEW_FEATURE_INDIVIDUAL_DROP = 1 << 5,
+ EMPATHY_INDIVIDUAL_VIEW_FEATURE_INDIVIDUAL_DRAG = 1 << 6,
+ EMPATHY_INDIVIDUAL_VIEW_FEATURE_INDIVIDUAL_TOOLTIP = 1 << 7,
+ EMPATHY_INDIVIDUAL_VIEW_FEATURE_PERSONA_DROP = 1 << 8,
+ EMPATHY_INDIVIDUAL_VIEW_FEATURE_FILE_DROP = 1 << 9,
+ EMPATHY_INDIVIDUAL_VIEW_FEATURE_ALL = (1 << 10) - 1,
} EmpathyIndividualViewFeatureFlags;
struct _EmpathyIndividualView
@@ -69,6 +74,17 @@ struct _EmpathyIndividualView
struct _EmpathyIndividualViewClass
{
GtkTreeViewClass parent_class;
+
+ void (* drag_individual_received) (EmpathyIndividualView *self,
+ GdkDragAction action,
+ FolksIndividual *individual,
+ const gchar *new_group,
+ const gchar *old_group);
+
+ void (* drag_persona_received) (EmpathyIndividualView *self,
+ GdkDragAction action,
+ FolksPersona *persona,
+ FolksIndividual *individual);
};
GType empathy_individual_view_get_type (void) G_GNUC_CONST;
diff --git a/libempathy-gtk/empathy-persona-view.c b/libempathy-gtk/empathy-persona-view.c
index 04777b1b6..adfe6be5c 100644
--- a/libempathy-gtk/empathy-persona-view.c
+++ b/libempathy-gtk/empathy-persona-view.c
@@ -37,6 +37,7 @@
#include <folks/folks.h>
#include <folks/folks-telepathy.h>
+#include <libempathy/empathy-individual-manager.h>
#include <libempathy/empathy-utils.h>
#include "empathy-persona-view.h"
@@ -44,6 +45,8 @@
#include "empathy-images.h"
#include "empathy-cell-renderer-text.h"
#include "empathy-cell-renderer-activatable.h"
+#include "empathy-gtk-enum-types.h"
+#include "empathy-gtk-marshal.h"
#define DEBUG_FLAG EMPATHY_DEBUG_CONTACT
#include <libempathy/empathy-debug.h>
@@ -69,6 +72,7 @@ typedef struct
GtkTreeModelFilter *filter;
GtkWidget *tooltip_widget;
gboolean show_offline;
+ EmpathyPersonaViewFeatureFlags features;
} EmpathyPersonaViewPriv;
enum
@@ -76,8 +80,42 @@ enum
PROP_0,
PROP_MODEL,
PROP_SHOW_OFFLINE,
+ PROP_FEATURES,
};
+enum DndDragType
+{
+ DND_DRAG_TYPE_INDIVIDUAL_ID,
+ DND_DRAG_TYPE_PERSONA_ID,
+ DND_DRAG_TYPE_STRING,
+};
+
+#define DRAG_TYPE(T,I) \
+ { (gchar *) T, 0, I }
+
+static const GtkTargetEntry drag_types_dest[] = {
+ DRAG_TYPE ("text/individual-id", DND_DRAG_TYPE_INDIVIDUAL_ID),
+ DRAG_TYPE ("text/plain", DND_DRAG_TYPE_STRING),
+ DRAG_TYPE ("STRING", DND_DRAG_TYPE_STRING),
+};
+
+static const GtkTargetEntry drag_types_source[] = {
+ DRAG_TYPE ("text/persona-id", DND_DRAG_TYPE_PERSONA_ID),
+};
+
+#undef DRAG_TYPE
+
+static GdkAtom drag_atoms_dest[G_N_ELEMENTS (drag_types_dest)];
+static GdkAtom drag_atoms_source[G_N_ELEMENTS (drag_types_source)];
+
+enum
+{
+ DRAG_INDIVIDUAL_RECEIVED,
+ LAST_SIGNAL
+};
+
+static guint signals[LAST_SIGNAL];
+
G_DEFINE_TYPE (EmpathyPersonaView, empathy_persona_view, GTK_TYPE_TREE_VIEW);
static gboolean
@@ -311,6 +349,184 @@ text_cell_data_func (GtkTreeViewColumn *tree_column,
cell_set_background (self, cell, is_active);
}
+static gboolean
+individual_drag_received (EmpathyPersonaView *self,
+ GdkDragContext *context,
+ GtkSelectionData *selection)
+{
+ EmpathyPersonaViewPriv *priv;
+ EmpathyIndividualManager *manager = NULL;
+ FolksIndividual *individual;
+ const gchar *individual_id;
+ gboolean success = FALSE;
+
+ priv = GET_PRIV (self);
+
+ individual_id = (const gchar *) gtk_selection_data_get_data (selection);
+ manager = empathy_individual_manager_dup_singleton ();
+ individual = empathy_individual_manager_lookup_member (manager,
+ individual_id);
+
+ if (individual == NULL)
+ {
+ DEBUG ("Failed to find drag event individual with ID '%s'",
+ individual_id);
+ g_object_unref (manager);
+ return FALSE;
+ }
+
+ /* Emit a signal notifying of the drag. */
+ g_signal_emit (self, signals[DRAG_INDIVIDUAL_RECEIVED], 0,
+ gdk_drag_context_get_selected_action (context), individual, &success);
+
+ g_object_unref (manager);
+
+ return success;
+}
+
+static void
+drag_data_received (GtkWidget *widget,
+ GdkDragContext *context,
+ gint x,
+ gint y,
+ GtkSelectionData *selection,
+ guint info,
+ guint time_)
+{
+ EmpathyPersonaView *self = EMPATHY_PERSONA_VIEW (widget);
+ gboolean success = TRUE;
+
+ if (info == DND_DRAG_TYPE_INDIVIDUAL_ID || info == DND_DRAG_TYPE_STRING)
+ success = individual_drag_received (self, context, selection);
+
+ gtk_drag_finish (context, success, FALSE, GDK_CURRENT_TIME);
+}
+
+static gboolean
+drag_motion (GtkWidget *widget,
+ GdkDragContext *context,
+ gint x,
+ gint y,
+ guint time_)
+{
+ EmpathyPersonaView *self = EMPATHY_PERSONA_VIEW (widget);
+ EmpathyPersonaViewPriv *priv;
+ GdkAtom target;
+
+ priv = GET_PRIV (self);
+
+ target = gtk_drag_dest_find_target (GTK_WIDGET (self), context, NULL);
+
+ if (target == drag_atoms_dest[DND_DRAG_TYPE_INDIVIDUAL_ID])
+ {
+ GtkTreePath *path;
+
+ /* FIXME: It doesn't make sense for us to highlight a specific row or
+ * position to drop an Individual in, so just highlight the entire
+ * widget.
+ * Since I can't find a way to do this, just highlight the first possible
+ * position in the tree. */
+ gdk_drag_status (context, gdk_drag_context_get_suggested_action (context),
+ time_);
+
+ path = gtk_tree_path_new_first ();
+ gtk_tree_view_set_drag_dest_row (GTK_TREE_VIEW (self), path,
+ GTK_TREE_VIEW_DROP_BEFORE);
+ gtk_tree_path_free (path);
+
+ return TRUE;
+ }
+
+ /* Unknown or unhandled drag target */
+ gdk_drag_status (context, GDK_ACTION_DEFAULT, time_);
+ gtk_tree_view_set_drag_dest_row (GTK_TREE_VIEW (self), NULL, 0);
+
+ return FALSE;
+}
+
+static void
+drag_data_get (GtkWidget *widget,
+ GdkDragContext *context,
+ GtkSelectionData *selection,
+ guint info,
+ guint time_)
+{
+ EmpathyPersonaView *self = EMPATHY_PERSONA_VIEW (widget);
+ EmpathyPersonaViewPriv *priv;
+ FolksPersona *persona;
+ const gchar *persona_uid;
+
+ if (info != DND_DRAG_TYPE_PERSONA_ID)
+ return;
+
+ priv = GET_PRIV (self);
+
+ persona = empathy_persona_view_dup_selected (self);
+ if (persona == NULL)
+ return;
+
+ persona_uid = folks_persona_get_uid (persona);
+ gtk_selection_data_set (selection, drag_atoms_source[info], 8,
+ (guchar *) persona_uid, strlen (persona_uid) + 1);
+
+ g_object_unref (persona);
+}
+
+static gboolean
+drag_drop (GtkWidget *widget,
+ GdkDragContext *drag_context,
+ gint x,
+ gint y,
+ guint time_)
+{
+ return FALSE;
+}
+
+static void
+set_features (EmpathyPersonaView *self,
+ EmpathyPersonaViewFeatureFlags features)
+{
+ EmpathyPersonaViewPriv *priv = GET_PRIV (self);
+
+ priv->features = features;
+
+ /* Setting reorderable is a hack that gets us row previews as drag icons
+ for free. We override all the drag handlers. It's tricky to get the
+ position of the drag icon right in drag_begin. GtkTreeView has special
+ voodoo for it, so we let it do the voodoo that he do (but only if dragging
+ is enabled). */
+ gtk_tree_view_set_reorderable (GTK_TREE_VIEW (self),
+ (features & EMPATHY_PERSONA_VIEW_FEATURE_PERSONA_DRAG));
+
+ /* Update DnD source/dest */
+ if (features & EMPATHY_PERSONA_VIEW_FEATURE_PERSONA_DRAG)
+ {
+ gtk_drag_source_set (GTK_WIDGET (self),
+ GDK_BUTTON1_MASK,
+ drag_types_source,
+ G_N_ELEMENTS (drag_types_source),
+ GDK_ACTION_MOVE | GDK_ACTION_COPY);
+ }
+ else
+ {
+ gtk_drag_source_unset (GTK_WIDGET (self));
+ }
+
+ if (features & EMPATHY_PERSONA_VIEW_FEATURE_PERSONA_DROP)
+ {
+ gtk_drag_dest_set (GTK_WIDGET (self),
+ GTK_DEST_DEFAULT_ALL,
+ drag_types_dest,
+ G_N_ELEMENTS (drag_types_dest), GDK_ACTION_MOVE | GDK_ACTION_COPY);
+ }
+ else
+ {
+ gtk_drag_dest_unset (GTK_WIDGET (self));
+ }
+
+ g_object_notify (G_OBJECT (self), "features");
+}
+
static void
empathy_persona_view_init (EmpathyPersonaView *self)
{
@@ -329,6 +545,7 @@ constructed (GObject *object)
EmpathyPersonaView *self = EMPATHY_PERSONA_VIEW (object);
GtkCellRenderer *cell;
GtkTreeViewColumn *col;
+ guint i;
/* Set up view */
g_object_set (self,
@@ -393,6 +610,13 @@ constructed (GObject *object)
/* Actually add the column now we have added all cell renderers */
gtk_tree_view_append_column (GTK_TREE_VIEW (self), col);
+
+ /* Drag & Drop. */
+ for (i = 0; i < G_N_ELEMENTS (drag_types_dest); ++i)
+ drag_atoms_dest[i] = gdk_atom_intern (drag_types_dest[i].target, FALSE);
+
+ for (i = 0; i < G_N_ELEMENTS (drag_types_source); ++i)
+ drag_atoms_source[i] = gdk_atom_intern (drag_types_source[i].target, FALSE);
}
static void
@@ -411,6 +635,9 @@ get_property (GObject *object,
case PROP_SHOW_OFFLINE:
g_value_set_boolean (value, priv->show_offline);
break;
+ case PROP_FEATURES:
+ g_value_set_flags (value, priv->features);
+ break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
break;
@@ -434,6 +661,9 @@ set_property (GObject *object,
empathy_persona_view_set_show_offline (self,
g_value_get_boolean (value));
break;
+ case PROP_FEATURES:
+ set_features (self, g_value_get_flags (value));
+ break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
break;
@@ -459,12 +689,27 @@ static void
empathy_persona_view_class_init (EmpathyPersonaViewClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS (klass);
+ GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
object_class->constructed = constructed;
object_class->dispose = dispose;
object_class->get_property = get_property;
object_class->set_property = set_property;
+ widget_class->drag_data_received = drag_data_received;
+ widget_class->drag_drop = drag_drop;
+ widget_class->drag_data_get = drag_data_get;
+ widget_class->drag_motion = drag_motion;
+
+ signals[DRAG_INDIVIDUAL_RECEIVED] =
+ g_signal_new ("drag-individual-received",
+ G_OBJECT_CLASS_TYPE (klass),
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (EmpathyPersonaViewClass, drag_individual_received),
+ NULL, NULL,
+ _empathy_gtk_marshal_BOOLEAN__UINT_OBJECT,
+ G_TYPE_BOOLEAN, 2, G_TYPE_UINT, FOLKS_TYPE_INDIVIDUAL);
+
/* We override the "model" property so that we can wrap it in a
* GtkTreeModelFilter for showing/hiding offline personas. */
g_object_class_override_property (object_class, PROP_MODEL, "model");
@@ -481,12 +726,27 @@ empathy_persona_view_class_init (EmpathyPersonaViewClass *klass)
FALSE,
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+ /**
+ * EmpathyPersonaStore:features:
+ *
+ * Features of the view, such as whether drag and drop is enabled.
+ */
+ g_object_class_install_property (object_class, PROP_FEATURES,
+ g_param_spec_flags ("features",
+ "Features",
+ "Flags for all enabled features.",
+ EMPATHY_TYPE_PERSONA_VIEW_FEATURE_FLAGS,
+ EMPATHY_PERSONA_VIEW_FEATURE_NONE,
+ G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
g_type_class_add_private (object_class, sizeof (EmpathyPersonaViewPriv));
}
/**
* empathy_persona_view_new:
* @store: an #EmpathyPersonaStore
+ * @features: a set of flags specifying the view's functionality, or
+ * %EMPATHY_PERSONA_VIEW_FEATURE_NONE
*
* Create a new #EmpathyPersonaView displaying the personas in
* #EmpathyPersonaStore.
@@ -494,11 +754,15 @@ empathy_persona_view_class_init (EmpathyPersonaViewClass *klass)
* Return value: a new #EmpathyPersonaView
*/
EmpathyPersonaView *
-empathy_persona_view_new (EmpathyPersonaStore *store)
+empathy_persona_view_new (EmpathyPersonaStore *store,
+ EmpathyPersonaViewFeatureFlags features)
{
g_return_val_if_fail (EMPATHY_IS_PERSONA_STORE (store), NULL);
- return g_object_new (EMPATHY_TYPE_PERSONA_VIEW, "model", store, NULL);
+ return g_object_new (EMPATHY_TYPE_PERSONA_VIEW,
+ "model", store,
+ "features", features,
+ NULL);
}
/**
diff --git a/libempathy-gtk/empathy-persona-view.h b/libempathy-gtk/empathy-persona-view.h
index 11fe039eb..0a6317c6b 100644
--- a/libempathy-gtk/empathy-persona-view.h
+++ b/libempathy-gtk/empathy-persona-view.h
@@ -36,6 +36,14 @@
G_BEGIN_DECLS
+typedef enum
+{
+ EMPATHY_PERSONA_VIEW_FEATURE_NONE = 0,
+ EMPATHY_PERSONA_VIEW_FEATURE_PERSONA_DRAG = 1 << 0,
+ EMPATHY_PERSONA_VIEW_FEATURE_PERSONA_DROP = 1 << 1,
+ EMPATHY_PERSONA_VIEW_FEATURE_ALL = (1 << 2) - 1,
+} EmpathyPersonaViewFeatureFlags;
+
#define EMPATHY_TYPE_PERSONA_VIEW (empathy_persona_view_get_type ())
#define EMPATHY_PERSONA_VIEW(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), \
EMPATHY_TYPE_PERSONA_VIEW, EmpathyPersonaView))
@@ -57,11 +65,16 @@ typedef struct
typedef struct
{
GtkTreeViewClass parent_class;
+
+ void (* drag_individual_received) (EmpathyPersonaView *self,
+ GdkDragAction action,
+ FolksIndividual *individual);
} EmpathyPersonaViewClass;
GType empathy_persona_view_get_type (void) G_GNUC_CONST;
-EmpathyPersonaView *empathy_persona_view_new (EmpathyPersonaStore *store);
+EmpathyPersonaView *empathy_persona_view_new (EmpathyPersonaStore *store,
+ EmpathyPersonaViewFeatureFlags features);
FolksPersona *empathy_persona_view_dup_selected (EmpathyPersonaView *self);
diff --git a/libempathy/empathy-individual-manager.c b/libempathy/empathy-individual-manager.c
index 4d3eabb22..1e76cbf83 100644
--- a/libempathy/empathy-individual-manager.c
+++ b/libempathy/empathy-individual-manager.c
@@ -171,7 +171,7 @@ aggregator_individuals_changed_cb (FolksIndividualAggregator *aggregator,
EmpathyIndividualManager *self)
{
EmpathyIndividualManagerPriv *priv = GET_PRIV (self);
- GList *l, *added_filtered = NULL, *removed_filtered = NULL;
+ GList *l, *added_filtered = NULL;
/* Filter the individuals for ones which contain EmpathyContacts */
for (l = added; l; l = l->next)
@@ -197,26 +197,21 @@ aggregator_individuals_changed_cb (FolksIndividualAggregator *aggregator,
if (g_hash_table_lookup (priv->individuals,
folks_individual_get_id (ind)) != NULL)
- {
- removed_filtered = g_list_prepend (removed_filtered, ind);
- remove_individual (self, ind);
- }
+ remove_individual (self, ind);
}
/* Bail if we have no individuals left */
- if (added_filtered == NULL && removed_filtered == NULL)
+ if (added_filtered == NULL && removed == NULL)
return;
added_filtered = g_list_reverse (added_filtered);
- removed_filtered = g_list_reverse (removed_filtered);
g_signal_emit (self, signals[MEMBERS_CHANGED], 0, message,
- added_filtered, removed_filtered,
+ added_filtered, removed,
tp_chanel_group_change_reason_from_folks_groups_change_reason (reason),
TRUE);
g_list_free (added_filtered);
- g_list_free (removed_filtered);
}
static void
diff --git a/src/empathy-main-window.c b/src/empathy-main-window.c
index 5f9767639..fa6f15310 100644
--- a/src/empathy-main-window.c
+++ b/src/empathy-main-window.c
@@ -1680,9 +1680,12 @@ empathy_main_window_init (EmpathyMainWindow *window)
individual_manager);
g_object_unref (individual_manager);
+ /* For the moment, we disallow Persona drops onto the main contact list (e.g. from things such as
+ * the EmpathyPersonaView in the linking dialogue). No code is hooked up to do anything on a Persona
+ * drop, so allowing them would achieve nothing except confusion. */
priv->individual_view = empathy_individual_view_new (
priv->individual_store,
- EMPATHY_INDIVIDUAL_VIEW_FEATURE_ALL,
+ EMPATHY_INDIVIDUAL_VIEW_FEATURE_ALL ^ EMPATHY_INDIVIDUAL_VIEW_FEATURE_PERSONA_DROP,
EMPATHY_INDIVIDUAL_FEATURE_ALL);
priv->butterfly_log_migration_members_changed_id = g_signal_connect (