+typedef enum
+{
+ DND_DRAG_TYPE_INVALID = -1,
+ DND_DRAG_TYPE_URI_LIST,
+} DndDragType;
+
+#define DRAG_TYPE(T,I) \
+ { (gchar *) T, 0, I }
+
+static const GtkTargetEntry drag_types_dest[] = {
+ DRAG_TYPE ("text/path-list", DND_DRAG_TYPE_URI_LIST),
+ DRAG_TYPE ("text/uri-list", DND_DRAG_TYPE_URI_LIST),
+};
+
+static GdkAtom drag_atoms_dest[G_N_ELEMENTS (drag_types_dest)];
+
+static DndDragType
+get_drag_type (GtkWidget *widget,
+ GdkDragContext *context)
+{
+ GdkAtom target;
+ guint i;
+
+ target = gtk_drag_dest_find_target (widget, context, NULL);
+
+ for (i = 0; i < G_N_ELEMENTS (drag_atoms_dest); i++)
+ {
+ if (target == drag_atoms_dest[i])
+ return drag_types_dest[i].info;
+ }
+
+ return DND_DRAG_TYPE_INVALID;
+}
+
+static gboolean
+individual_supports_ft (FolksIndividual *individual)
+{
+ EmpathyContact *contact;
+ EmpathyCapabilities caps;
+ gboolean result;
+
+ contact = empathy_contact_dup_from_folks_individual (individual);
+ if (contact == NULL)
+ return FALSE;
+
+ caps = empathy_contact_get_capabilities (contact);
+ result = (caps & EMPATHY_CAPABILITIES_FT);
+
+ g_object_unref (contact);
+ return result;
+}
+
+static gboolean
+view_drag_motion_cb (GtkWidget *widget,
+ GdkDragContext *context,
+ gint x,
+ gint y,
+ guint time_,
+ EmpathyRosterWindow *self)
+{
+ DndDragType type;
+
+ type = get_drag_type (widget, context);
+
+ if (type == DND_DRAG_TYPE_URI_LIST)
+ {
+ /* Check if contact supports FT */
+ FolksIndividual *individual;
+ GtkListBoxRow *row;
+
+ individual = empathy_roster_view_get_individual_at_y (self->priv->view,
+ y, &row);
+ if (individual == NULL)
+ goto no_hl;
+
+ if (!individual_supports_ft (individual))
+ goto no_hl;
+
+ gtk_list_box_drag_highlight_row (GTK_LIST_BOX (widget), row);
+ return FALSE;
+ }
+
+no_hl:
+ gtk_list_box_drag_unhighlight_row (GTK_LIST_BOX (widget));
+ return FALSE;
+}
+
+static gboolean
+view_drag_drop_cb (GtkWidget *widget,
+ GdkDragContext *context,
+ gint x,
+ gint y,
+ guint time_,
+ EmpathyRosterWindow *self)
+{
+ DndDragType type;
+ FolksIndividual *individual;
+
+ type = get_drag_type (widget, context);
+ if (type == DND_DRAG_TYPE_INVALID)
+ return FALSE;
+
+ individual = empathy_roster_view_get_individual_at_y (self->priv->view, y,
+ NULL);
+ if (individual == NULL)
+ return FALSE;
+
+ if (!individual_supports_ft (individual))
+ return FALSE;
+
+ gtk_drag_get_data (widget, context,
+ gtk_drag_dest_find_target (widget, context, NULL), time_);
+
+ return TRUE;
+}
+
+static void
+view_drag_data_received_cb (GtkWidget *widget,
+ GdkDragContext *context,
+ gint x,
+ gint y,
+ GtkSelectionData *selection,
+ guint info,
+ guint time_,
+ EmpathyRosterWindow *self)
+{
+ gboolean success = FALSE;
+
+ if (selection == NULL)
+ goto out;
+
+ if (info == DND_DRAG_TYPE_URI_LIST)
+ {
+ const gchar *path;
+ FolksIndividual *individual;
+ EmpathyContact *contact;
+
+ individual = empathy_roster_view_get_individual_at_y (self->priv->view,
+ y, NULL);
+ g_return_if_fail (individual != NULL);
+
+ path = (const gchar *) gtk_selection_data_get_data (selection);
+
+ contact = empathy_contact_dup_from_folks_individual (individual);
+ empathy_send_file_from_uri_list (contact, path);
+
+ g_object_unref (contact);
+
+ success = TRUE;
+ }
+
+out:
+ gtk_drag_finish (context, success, FALSE, time_);
+}
+
+static void
+roster_window_most_available_presence_changed_cb (TpAccountManager *manager,
+ TpConnectionPresenceType presence,
+ const gchar *status,
+ const gchar *message,
+ EmpathyRosterWindow *self)
+{
+ set_notebook_page (self);
+}
+
+static void
+show_offline_changed_cb (GSettings *settings,
+ const gchar *key,
+ EmpathyRosterWindow *self)
+{
+ set_notebook_page (self);
+}
+