--- libnautilus-private/nautilus-tree-view-drag-dest.c 2007-04-03 12:08:46.000000000 +0200 +++ libnautilus-private/nautilus-tree-view-drag-dest.c 2007-09-14 13:25:16.000000000 +0200 @@ -21,6 +21,7 @@ * Boston, MA 02111-1307, USA. * * Author: Dave Camp + * XDS support: Benedikt Meurer (adapted by Amos Brocco ) */ /* nautilus-tree-view-drag-dest.c: Handles drag and drop for treeviews which @@ -39,6 +40,9 @@ #include "nautilus-icon-dnd.h" #include "nautilus-link.h" #include "nautilus-marshal.h" +#include "nautilus-debug-log.h" +#include +#include #define AUTO_SCROLL_MARGIN 20 @@ -57,6 +61,8 @@ struct _NautilusTreeViewDragDestDetails guint highlight_id; guint scroll_id; guint expand_id; + + gchar *drop_path; }; enum { @@ -83,7 +89,8 @@ static const GtkTargetEntry drag_types [ /* prefer "_NETSCAPE_URL" over "text/uri-list" to satisfy web browsers. */ { NAUTILUS_ICON_DND_NETSCAPE_URL_TYPE, 0, NAUTILUS_ICON_DND_NETSCAPE_URL }, { NAUTILUS_ICON_DND_URI_LIST_TYPE, 0, NAUTILUS_ICON_DND_URI_LIST }, - { NAUTILUS_ICON_DND_KEYWORD_TYPE, 0, NAUTILUS_ICON_DND_KEYWORD } + { NAUTILUS_ICON_DND_KEYWORD_TYPE, 0, NAUTILUS_ICON_DND_KEYWORD }, + { NAUTILUS_ICON_DND_XDNDDIRECTSAVE_TYPE, 0, NAUTILUS_ICON_DND_XDNDDIRECTSAVE }, /* XDS Protocol Type */ }; @@ -409,6 +416,7 @@ get_drop_action (NautilusTreeViewDragDes return context->suggested_action; case NAUTILUS_ICON_DND_TEXT: + case NAUTILUS_ICON_DND_XDNDDIRECTSAVE: return GDK_ACTION_COPY; case NAUTILUS_ICON_DND_KEYWORD: @@ -439,6 +447,7 @@ drag_motion_callback (GtkWidget *widget, GtkTreeViewDropPosition pos; GdkWindow *bin_window; guint action; + gchar *uri_path; dest = NAUTILUS_TREE_VIEW_DRAG_DEST (data); @@ -465,13 +474,42 @@ drag_motion_callback (GtkWidget *widget, gtk_tree_view_get_drag_dest_row (GTK_TREE_VIEW (widget), &old_drop_path, NULL); + if (action) { + + /* XDS support: I need to save the drop path here, because I didn't + * succeeded to get it from the drag_drop_callback (x and y coordinates + * passed to it do not match drop position, so I cannot get the target later) */ + + uri_path = get_drop_target_uri_for_path (dest, drop_path); + + if (uri_path != NULL) { + if (dest->details->drop_path != NULL) { + /* A path is already in, free and replace */ + if (strcmp (uri_path, dest->details->drop_path) != 0) { + g_free (dest->details->drop_path); + dest->details->drop_path = g_strdup (uri_path); + } + } else { + /* No previous path is there */ + dest->details->drop_path = g_strdup (uri_path); + } + + g_free (uri_path); + + } + + /* End XDS support */ + set_drag_dest_row (dest, drop_path); + model = gtk_tree_view_get_model (GTK_TREE_VIEW (widget)); if (drop_path == NULL || (old_drop_path != NULL && gtk_tree_path_compare (old_drop_path, drop_path) != 0)) { remove_expand_timeout (dest); } + + if (dest->details->expand_id == 0 && drop_path != NULL) { gtk_tree_model_get_iter (model, &drop_iter, drop_path); if (gtk_tree_model_iter_has_child (model, &drop_iter)) { @@ -766,6 +804,22 @@ drag_data_received_callback (GtkWidget * receive_dropped_keyword (dest, context, x, y); success = TRUE; break; + case NAUTILUS_ICON_DND_XDNDDIRECTSAVE: + /* Indicate that we don't provide "F" fallback */ + if (G_UNLIKELY (dest->details->drag_data->format == 8 + && dest->details->drag_data->length == 1 + && dest->details->drag_data->data[0] == 'F')) { + gdk_property_change (GDK_DRAWABLE (context->source_window), + gdk_atom_intern (NAUTILUS_ICON_DND_XDNDDIRECTSAVE_TYPE, FALSE), + gdk_atom_intern ("text/plain", FALSE), 8, + GDK_PROP_MODE_REPLACE, (const guchar *) "", 0); + } else if (G_LIKELY (dest->details->drag_data->format == 8 + && dest->details->drag_data->length == 1 + && dest->details->drag_data->data[0] == 'S')) { + /* FIXME: XDS Successful... Do we need to tell the treeview to update itself? */ + } + success = TRUE; + break; } dest->details->drop_occurred = FALSE; @@ -790,8 +844,70 @@ drag_drop_callback (GtkWidget *widget, gpointer data) { NautilusTreeViewDragDest *dest; + guint info; + guchar *prop_text; + gint prop_len; + GnomeVFSURI *base; + gchar *uri = NULL; + GdkAtom target; dest = NAUTILUS_TREE_VIEW_DRAG_DEST (data); + + target = gtk_drag_dest_find_target (GTK_WIDGET (dest->details->tree_view), + context, + NULL); + + info = dest->details->drag_type; + + if (G_UNLIKELY (target == GDK_NONE)) { + return FALSE; + } else if (target != GDK_NONE) { + if (info == NAUTILUS_ICON_DND_XDNDDIRECTSAVE) { + if (gdk_property_get (context->source_window, gdk_atom_intern (NAUTILUS_ICON_DND_XDNDDIRECTSAVE_TYPE, FALSE), + gdk_atom_intern ("text/plain", FALSE), 0, 1024, FALSE, NULL, NULL, + &prop_len, &prop_text) && prop_text != NULL) { + /* Zero-terminate the string */ + prop_text = g_realloc (prop_text, prop_len + 1); + prop_text[prop_len] = '\0'; + + /* Verify that the file name provided by the source is valid */ + if (G_LIKELY (*prop_text != '\0' && strchr ((const gchar *) prop_text, G_DIR_SEPARATOR) == NULL)) { + + /* Retrieve drop target path */ + if (dest->details->drop_path != NULL) { + /* Resolve relative path */ + base = gnome_vfs_uri_new (dest->details->drop_path); + base = gnome_vfs_uri_append_file_name (base, (const gchar *) prop_text); + uri = gnome_vfs_uri_to_string (base, GNOME_VFS_URI_HIDE_NONE); + /* Change the property */ + gdk_property_change (GDK_DRAWABLE (context->source_window), + gdk_atom_intern (NAUTILUS_ICON_DND_XDNDDIRECTSAVE_TYPE, FALSE), + gdk_atom_intern ("text/plain", FALSE), 8, + GDK_PROP_MODE_REPLACE, (const guchar *) uri, + strlen (uri)); + + /* Free memory */ + g_free (dest->details->drop_path); + dest->details->drop_path = NULL; + gnome_vfs_uri_unref (base); + g_free (uri); + } else { + nautilus_debug_log (FALSE, NAUTILUS_DEBUG_LOG_DOMAIN_USER, + "Could not retrieve XDS drag site "); + } + } else { + /* tell the user that the file name provided by the X Direct Save source is invalid */ + nautilus_debug_log (FALSE, NAUTILUS_DEBUG_LOG_DOMAIN_USER, + "Invalid filename provided by XDS drag site"); + } + /* cleanup */ + g_free (prop_text); + } + /* if uri == NULL, we didn't set the property */ + if (G_UNLIKELY (uri == NULL)) + return FALSE; + } + } dest->details->drop_occurred = TRUE; @@ -844,6 +960,9 @@ nautilus_tree_view_drag_dest_finalize (G dest = NAUTILUS_TREE_VIEW_DRAG_DEST (object); free_drag_data (dest); + + if (dest->details->drop_path) + g_free (dest->details->drop_path); g_free (dest->details);