/* Given a drop path retrieved by gtk_tree_view_get_dest_row_at_pos, this function * determines whether dropping a bookmark item at the specified path is allow. * If dropping is not allowed, this function tries to choose an alternative position * for the bookmark item and modified the tree path @tp passed into this function. */ static gboolean get_bookmark_drag_dest(FmPlacesView* view, GtkTreePath** tp, GtkTreeViewDropPosition* pos) { gboolean ret = TRUE; if(*tp) { /* if the drop site is below the separator (in the bookmark area) */ if(fm_places_model_path_is_bookmark(FM_PLACES_MODEL(model), *tp)) { /* we cannot drop into a item */ if(*pos == GTK_TREE_VIEW_DROP_INTO_OR_BEFORE || *pos == GTK_TREE_VIEW_DROP_INTO_OR_AFTER) ret = FALSE; else ret = TRUE; } else /* the drop site is above the separator (in the places area containing volumes) */ { const GtkTreePath* sep = fm_places_model_get_separator_path(FM_PLACES_MODEL(model)); /* set drop site at the first bookmark item */ gtk_tree_path_get_indices(*tp)[0] = gtk_tree_path_get_indices(sep)[0] + 1; *pos = GTK_TREE_VIEW_DROP_BEFORE; ret = TRUE; } } else { /* drop at end of the bookmarks list instead */ *tp = gtk_tree_path_new_from_indices(gtk_tree_model_iter_n_children(GTK_TREE_MODEL(model), NULL) - 1, -1); *pos = GTK_TREE_VIEW_DROP_AFTER; ret = TRUE; } g_debug("path: %s", gtk_tree_path_to_string(*tp)); return ret; }
static gboolean row_draggable(GtkTreeDragSource* drag_source, GtkTreePath* tp) { FmPlacesModel* model = FM_PLACES_MODEL(drag_source); return fm_places_model_path_is_bookmark(model, tp); }
static void on_drag_data_received ( GtkWidget *dest_widget, GdkDragContext *drag_context, gint x, gint y, GtkSelectionData *sel_data, guint info, guint time) { FmPlacesView* view = FM_PLACES_VIEW(dest_widget); GtkTreePath* dest_tp = NULL; GtkTreeViewDropPosition pos; gtk_tree_view_get_dest_row_at_pos(GTK_TREE_VIEW(view), x, y, &dest_tp, &pos); switch(info) { case FM_DND_DEST_TARGET_BOOOKMARK: if(get_bookmark_drag_dest(view, &dest_tp, &pos)) /* got the drop position */ { GtkTreePath* src_tp; /* get the source row */ gboolean ret = gtk_tree_get_row_drag_data(sel_data, NULL, &src_tp); if(ret) { /* don't do anything if source and dest are the same row */ if(G_UNLIKELY(gtk_tree_path_compare(src_tp, dest_tp) == 0)) ret = FALSE; else { /* don't do anything if this is not a bookmark item */ if(!fm_places_model_path_is_bookmark(FM_PLACES_MODEL(model), src_tp)) ret = FALSE; } if(ret) { GtkTreeIter src_it, dest_it; FmPlaceItem* item = NULL; ret = FALSE; /* get the source bookmark item */ if(gtk_tree_model_get_iter(GTK_TREE_MODEL(model), &src_it, src_tp)) gtk_tree_model_get(GTK_TREE_MODEL(model), &src_it, FM_PLACES_MODEL_COL_INFO, &item, -1); if(item) { /* move it to destination position */ if(gtk_tree_model_get_iter(GTK_TREE_MODEL(model), &dest_it, dest_tp)) { int new_pos, sep_pos; /* get index of the separator */ const GtkTreePath* sep_tp = fm_places_model_get_separator_path(FM_PLACES_MODEL(model)); sep_pos = gtk_tree_path_get_indices(sep_tp)[0]; if(pos == GTK_TREE_VIEW_DROP_BEFORE) gtk_list_store_move_before(model, &src_it, &dest_it); else gtk_list_store_move_after(model, &src_it, &dest_it); new_pos = gtk_tree_path_get_indices(dest_tp)[0] - sep_pos - 1; /* reorder the bookmark item */ fm_bookmarks_reorder(FM_PLACES_MODEL(model)->bookmarks, item->bm_item, new_pos); ret = TRUE; } } } gtk_tree_path_free(src_tp); } gtk_drag_finish(drag_context, ret, FALSE, time); } break; default: /* check if files are received. */ fm_dnd_dest_drag_data_received(view->dnd_dest, drag_context, x, y, sel_data, info, time); break; } if(dest_tp) gtk_tree_path_free(dest_tp); }
static gboolean on_drag_motion (GtkWidget *dest_widget, GdkDragContext *drag_context, gint x, gint y, guint time) { FmPlacesView* view = FM_PLACES_VIEW(dest_widget); /* fm_drag_context_has_target_name(drag_context, "GTK_TREE_MODEL_ROW"); */ GdkAtom target; GtkTreeViewDropPosition pos; GtkTreePath* tp, *sep; gboolean ret = FALSE; GdkDragAction action = 0; target = gtk_drag_dest_find_target(dest_widget, drag_context, NULL); if(target == GDK_NONE) return FALSE; gtk_tree_view_get_dest_row_at_pos((GtkTreeView*)view, x, y, &tp, &pos); /* handle reordering bookmark items first */ if(target == gdk_atom_intern_static_string("GTK_TREE_MODEL_ROW")) { /* bookmark item is being dragged */ ret = get_bookmark_drag_dest(view, &tp, &pos); action = ret ? GDK_ACTION_MOVE : 0; /* bookmark items can only be moved */ } /* try FmDndDest */ else if(fm_dnd_dest_is_target_supported(view->dnd_dest, target)) { /* the user is dragging files. get FmFileInfo of drop site. */ if(pos == GTK_TREE_VIEW_DROP_INTO_OR_BEFORE || pos == GTK_TREE_VIEW_DROP_INTO_OR_AFTER) /* drag into items */ { FmPlaceItem* item = NULL; GtkTreeIter it; /* FIXME: handle adding bookmarks with Dnd */ if(tp && gtk_tree_model_get_iter(GTK_TREE_MODEL(model), &it, tp)) gtk_tree_model_get(GTK_TREE_MODEL(model), &it, FM_PLACES_MODEL_COL_INFO, &item, -1); fm_dnd_dest_set_dest_file(view->dnd_dest, item && item->fi ? item->fi : NULL); action = fm_dnd_dest_get_default_action(view->dnd_dest, drag_context, target); ret = action != 0; } else /* drop between items, create bookmark items for dragged files */ { if( (!tp || fm_places_model_path_is_bookmark(FM_PLACES_MODEL(model), tp)) && get_bookmark_drag_dest(view, &tp, &pos)) /* tp is after separator */ { action = GDK_ACTION_LINK; ret = TRUE; } else { action = 0; ret = FALSE; } } } gdk_drag_status(drag_context, action, time); if(ret) gtk_tree_view_set_drag_dest_row(GTK_TREE_VIEW(view), tp, pos); else gtk_tree_view_set_drag_dest_row(GTK_TREE_VIEW(view), NULL, 0); if(tp) gtk_tree_path_free(tp); return ret; }