+
+/* Drag and drop stuff */
+static void
+drag_data_get_cb (GtkWidget *widget, GdkDragContext *context,
+ GtkSelectionData *selection_data,
+ guint info, guint time, gpointer data)
+{
+ GtkTreeModel *model;
+ GtkTreeIter iter;
+ GtkTreePath *source_row;
+
+ source_row = get_selected_row (GTK_TREE_VIEW(widget), &model);
+ if ((source_row == NULL) || (!gtk_tree_model_get_iter(model, &iter, source_row))) return;
+
+ switch (info) {
+ case MODEST_HEADER_ROW:
+ gtk_tree_set_row_drag_data (selection_data, model, source_row);
+ break;
+ case MODEST_MSG: {
+ TnyHeader *hdr;
+ gtk_tree_model_get (model, &iter,
+ TNY_GTK_HEADER_LIST_MODEL_INSTANCE_COLUMN, &hdr,
+ -1);
+ if (hdr) {
+ g_object_unref (G_OBJECT(hdr));
+ }
+ break;
+ }
+ default:
+ g_message ("default");
+ }
+
+ gtk_tree_path_free (source_row);
+}
+
+/* Header view drag types */
+const GtkTargetEntry header_view_drag_types[] = {
+ { "GTK_TREE_MODEL_ROW", GTK_TARGET_SAME_APP, MODEST_HEADER_ROW },
+ { "text/uri-list", 0, MODEST_MSG },
+
+};
+
+static void
+setup_drag_and_drop (GtkTreeView *self)
+{
+ gtk_drag_source_set (GTK_WIDGET (self),
+ GDK_BUTTON1_MASK,
+ header_view_drag_types,
+ G_N_ELEMENTS (header_view_drag_types),
+ GDK_ACTION_MOVE | GDK_ACTION_COPY);
+
+ g_signal_connect(G_OBJECT (self), "drag_data_get",
+ G_CALLBACK(drag_data_get_cb), NULL);
+}
+
+static GtkTreePath *
+get_selected_row (GtkTreeView *self, GtkTreeModel **model)
+{
+ GtkTreePath *path = NULL;
+ GtkTreeSelection *sel = NULL;
+ GList *rows = NULL;
+
+ sel = gtk_tree_view_get_selection(self);
+ rows = gtk_tree_selection_get_selected_rows (sel, model);
+
+ if ((rows == NULL) || (g_list_length(rows) != 1))
+ goto frees;
+
+ path = gtk_tree_path_copy(g_list_nth_data (rows, 0));
+
+
+ /* Free */
+ frees:
+ g_list_foreach(rows,(GFunc) gtk_tree_path_free, NULL);
+ g_list_free(rows);
+
+ return path;
+}
+
+/*
+ * This function moves the tree view scroll to the current selected
+ * row when the widget grabs the focus
+ */
+static gboolean
+on_focus_in (GtkWidget *self,
+ GdkEventFocus *event,
+ gpointer user_data)
+{
+ GtkTreeSelection *selection;
+ GtkTreeModel *model;
+ GList *selected = NULL;
+ GtkTreePath *selected_path = NULL;
+
+ model = gtk_tree_view_get_model (GTK_TREE_VIEW (self));
+ if (!model)
+ return FALSE;
+
+ selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (self));
+ /* If none selected yet, pick the first one */
+ if (gtk_tree_selection_count_selected_rows (selection) == 0) {
+ GtkTreeIter iter;
+ GtkTreePath *path;
+
+ /* Return if the model is empty */
+ if (!gtk_tree_model_get_iter_first (model, &iter))
+ return FALSE;
+
+ path = gtk_tree_model_get_path (model, &iter);
+ gtk_tree_selection_select_path (selection, path);
+ gtk_tree_path_free (path);
+ }
+
+ /* Need to get the all the rows because is selection multiple */
+ selected = gtk_tree_selection_get_selected_rows (selection, &model);
+ selected_path = (GtkTreePath *) selected->data;
+
+ /* Check if we need to scroll */
+ #if GTK_CHECK_VERSION(2, 8, 0) /* TODO: gtk_tree_view_get_visible_range() is only available in GTK+ 2.8 */
+ GtkTreePath *start_path = NULL;
+ GtkTreePath *end_path = NULL;
+ if (gtk_tree_view_get_visible_range (GTK_TREE_VIEW (self),
+ &start_path,
+ &end_path)) {
+
+ if ((gtk_tree_path_compare (start_path, selected_path) != -1) ||
+ (gtk_tree_path_compare (end_path, selected_path) != 1)) {
+
+ /* Scroll to first path */
+ gtk_tree_view_scroll_to_cell (GTK_TREE_VIEW (self),
+ selected_path,
+ NULL,
+ TRUE,
+ 0.5,
+ 0.0);
+ }
+ }
+ #endif /* GTK_CHECK_VERSION */
+
+ /* Frees */
+ g_list_foreach (selected, (GFunc) gtk_tree_path_free, NULL);
+ g_list_free (selected);
+
+ return FALSE;
+}