-/** @brief Callback to construct a row pixmap */
-static void ql_drag_make_row_pixmaps(GtkTreeModel attribute((unused)) *model,
- GtkTreePath *path,
- GtkTreeIter attribute((unused)) *iter,
- gpointer data) {
- struct ql_drag_begin_state *qdbs = data;
-
- qdbs->pixmaps[qdbs->index++]
- = gtk_tree_view_create_row_drag_icon(GTK_TREE_VIEW(qdbs->ql->view),
- path);
+/** @brief Identify the drop path
+ * @param w Destination tree view widget
+ * @param model Underlying tree model
+ * @param wx X coordinate
+ * @param wy Y coordinate
+ * @param posp Where to store relative position
+ * @return Target path or NULL
+ *
+ * This is used by ql_drag_motion() and ql_drag_data_received() to identify a
+ * drop would or does land. It's important that they use the same code since
+ * otherwise the visual feedback can be inconsistent with the actual effect!
+ *
+ * Remember to free the returned path.
+ */
+static GtkTreePath *ql_drop_path(GtkWidget *w,
+ GtkTreeModel *model,
+ int wx, int wy,
+ GtkTreeViewDropPosition *posp) {
+ GtkTreePath *path = NULL;
+ GtkTreeViewDropPosition pos;
+ GtkTreeIter iter[1], last[1];
+ int tx, ty;
+
+ gtk_tree_view_convert_widget_to_tree_coords(GTK_TREE_VIEW(w),
+ wx, wy, &tx, &ty);
+ if(gtk_tree_view_get_dest_row_at_pos(GTK_TREE_VIEW(w),
+ wx, wy,
+ &path,
+ &pos)) {
+ //fprintf(stderr, "gtk_tree_view_get_dest_row_at_pos() -> TRUE\n");
+ // Normalize drop position
+ switch(pos) {
+ case GTK_TREE_VIEW_DROP_INTO_OR_BEFORE:
+ pos = GTK_TREE_VIEW_DROP_BEFORE;
+ break;
+ case GTK_TREE_VIEW_DROP_INTO_OR_AFTER:
+ pos = GTK_TREE_VIEW_DROP_AFTER;
+ break;
+ default: break;
+ }
+ } else if(gtk_tree_model_get_iter_first(model, iter)) {
+ /* If the pointer isn't over any particular row then either it's below
+ * the last row, in which case we want the dropzone to be below that row;
+ * or it's above the first row (in the column headings) in which case we
+ * want the dropzone to be above that row. */
+ if(ty >= 0) {
+ /* Find the last row */
+ do {
+ *last = *iter;
+ } while(gtk_tree_model_iter_next(model, iter));
+ /* The drop target is just after it */
+ pos = GTK_TREE_VIEW_DROP_AFTER;
+ *iter = *last;
+ } else {
+ /* The drop target will be just before the first row */
+ pos = GTK_TREE_VIEW_DROP_BEFORE;
+ }
+ path = gtk_tree_model_get_path(model, iter);
+ }
+ *posp = pos;
+ return path;