Index: libnautilus-private/Makefile.am
===================================================================
RCS file: /cvs/gnome/nautilus/libnautilus-private/Makefile.am,v
retrieving revision 1.244
diff -u -p -r1.244 Makefile.am
--- libnautilus-private/Makefile.am	4 Apr 2005 19:30:23 -0000	1.244
+++ libnautilus-private/Makefile.am	18 Jul 2005 18:31:13 -0000
@@ -188,6 +188,8 @@ libnautilus_private_la_SOURCES = \
 	nautilus-view.h \
 	nautilus-window-info.c \
 	nautilus-window-info.h \
+	nautilus-xds-dnd.c \
+	nautilus-xds-dnd.h \
 	$(NULL)
 
 $(lib_LTLIBRARIES): $(dependency_static_libs)
Index: libnautilus-private/nautilus-dnd.c
===================================================================
RCS file: /cvs/gnome/nautilus/libnautilus-private/nautilus-dnd.c,v
retrieving revision 1.21
diff -u -p -r1.21 nautilus-dnd.c
--- libnautilus-private/nautilus-dnd.c	6 Jul 2005 12:18:27 -0000	1.21
+++ libnautilus-private/nautilus-dnd.c	18 Jul 2005 18:31:14 -0000
@@ -90,6 +90,7 @@ nautilus_drag_finalize (NautilusDragInfo
 {
 	gtk_target_list_unref (drag_info->target_list);
 	nautilus_drag_destroy_selection_list (drag_info->selection_list);
+	g_free (drag_info->xds_target_uri);
 
 	g_free (drag_info);
 }
@@ -871,4 +872,31 @@ nautilus_drag_selection_includes_special
 	}
 	
 	return FALSE;
+}
+
+NautilusDndTargetCapsMask
+nautilus_drag_target_get_caps_mask (NautilusIconDndTargetType target)
+{
+	switch (target) {
+		case NAUTILUS_ICON_DND_GNOME_ICON_LIST:
+		case NAUTILUS_ICON_DND_XDS:
+		case NAUTILUS_ICON_DND_OCTET_STREAM:
+			return NAUTILUS_ICON_DND_TARGET_CAPS_BACKGROUND_AND_FOLDERS;
+
+		case NAUTILUS_ICON_DND_URI_LIST:
+		case NAUTILUS_ICON_DND_URL:
+		case NAUTILUS_ICON_DND_TEXT:
+		case NAUTILUS_ICON_DND_RESET_BACKGROUND:
+		case NAUTILUS_ICON_DND_ROOTWINDOW_DROP:
+		case NAUTILUS_ICON_DND_COLOR:
+		case NAUTILUS_ICON_DND_BGIMAGE:
+			return NAUTILUS_ICON_DND_TARGET_CAPS_BACKGROUND;
+
+		case NAUTILUS_ICON_DND_KEYWORD:
+			return NAUTILUS_ICON_DND_TARGET_CAPS_FILES_AND_FOLDERS;
+
+		default:
+			g_assert_not_reached ();
+			return 0;
+	}
 }
Index: libnautilus-private/nautilus-dnd.h
===================================================================
RCS file: /cvs/gnome/nautilus/libnautilus-private/nautilus-dnd.h,v
retrieving revision 1.13
diff -u -p -r1.13 nautilus-dnd.h
--- libnautilus-private/nautilus-dnd.h	6 Jul 2005 12:18:27 -0000	1.13
+++ libnautilus-private/nautilus-dnd.h	18 Jul 2005 18:31:14 -0000
@@ -31,8 +31,10 @@
 
 /* Drag & Drop target names. */
 #define NAUTILUS_ICON_DND_GNOME_ICON_LIST_TYPE  "x-special/gnome-icon-list"
+#define NAUTILUS_ICON_DND_XDS_TYPE              "XdndDirectSave0"
 #define NAUTILUS_ICON_DND_URI_LIST_TYPE         "text/uri-list"
 #define NAUTILUS_ICON_DND_URL_TYPE	        "_NETSCAPE_URL"
+#define NAUTILUS_ICON_DND_OCTET_STREAM_TYPE     "application/octet-stream"
 #define NAUTILUS_ICON_DND_COLOR_TYPE            "application/x-color"
 #define NAUTILUS_ICON_DND_BGIMAGE_TYPE          "property/bgimage"
 #define NAUTILUS_ICON_DND_KEYWORD_TYPE          "property/keyword"
@@ -50,8 +52,10 @@ typedef struct {
 /* Standard Drag & Drop types. */
 typedef enum {
 	NAUTILUS_ICON_DND_GNOME_ICON_LIST,
+	NAUTILUS_ICON_DND_XDS,
 	NAUTILUS_ICON_DND_URI_LIST,
 	NAUTILUS_ICON_DND_URL,
+	NAUTILUS_ICON_DND_OCTET_STREAM,
 	NAUTILUS_ICON_DND_COLOR,
 	NAUTILUS_ICON_DND_BGIMAGE,
 	NAUTILUS_ICON_DND_KEYWORD,
@@ -67,6 +71,22 @@ typedef enum {
 	NAUTILUS_DND_ACTION_SET_AS_GLOBAL_BACKGROUND = NAUTILUS_DND_ACTION_FIRST << 2
 } NautilusDndAction;
 
+typedef enum {
+	NAUTILUS_ICON_DND_TARGET_CAPS_BACKGROUND = 1 << 1,
+	NAUTILUS_ICON_DND_TARGET_CAPS_FILES = 1 << 2,
+	NAUTILUS_ICON_DND_TARGET_CAPS_FOLDERS = 1 << 3
+} NautilusDndTargetCaps;
+
+typedef int NautilusDndTargetCapsMask;
+
+#define NAUTILUS_ICON_DND_TARGET_CAPS_BACKGROUND_AND_FOLDERS \
+	(NAUTILUS_ICON_DND_TARGET_CAPS_BACKGROUND | \
+	 NAUTILUS_ICON_DND_TARGET_CAPS_FOLDERS)
+
+#define NAUTILUS_ICON_DND_TARGET_CAPS_FILES_AND_FOLDERS \
+	(NAUTILUS_ICON_DND_TARGET_CAPS_FILES | \
+	 NAUTILUS_ICON_DND_TARGET_CAPS_FOLDERS)
+
 /* drag&drop-related information. */
 typedef struct {
 	GtkTargetList *target_list;
@@ -95,6 +115,7 @@ typedef struct {
 	gboolean waiting_to_autoscroll;
 	gint64 start_auto_scroll_in;
 
+	char *xds_target_uri;
 } NautilusDragInfo;
 
 typedef void 		(* NautilusDragEachSelectedItemDataGet)	(const char *url, 
@@ -147,5 +168,6 @@ void                        nautilus_dra
 void                        nautilus_drag_autoscroll_stop               (NautilusDragInfo                     *drag_info);
 
 gboolean                    nautilus_drag_selection_includes_special_link (GList                              *selection_list);
+NautilusDndTargetCapsMask   nautilus_drag_target_get_caps_mask            (NautilusIconDndTargetType           target);
 
 #endif
Index: libnautilus-private/nautilus-file-dnd.c
===================================================================
RCS file: /cvs/gnome/nautilus/libnautilus-private/nautilus-file-dnd.c,v
retrieving revision 1.6
diff -u -p -r1.6 nautilus-file-dnd.c
--- libnautilus-private/nautilus-file-dnd.c	29 Nov 2004 15:28:14 -0000	1.6
+++ libnautilus-private/nautilus-file-dnd.c	18 Jul 2005 18:31:14 -0000
@@ -32,14 +32,8 @@
 #include <eel/eel-string.h>
 
 gboolean
-nautilus_drag_can_accept_item (NautilusFile *drop_target_item,
-			       const char *item_uri)
+nautilus_drag_can_accept_uris (NautilusFile *drop_target_item)
 {
-	if (nautilus_file_matches_uri (drop_target_item, item_uri)) {
-		/* can't accept itself */
-		return FALSE;
-	}
-	
 	if (nautilus_file_is_directory (drop_target_item)) {
 		/* target is a directory, accept anything */
 		return TRUE;
@@ -60,6 +54,18 @@ nautilus_drag_can_accept_item (NautilusF
 	}
 	
 	return FALSE;
+}
+
+gboolean
+nautilus_drag_can_accept_item (NautilusFile *drop_target_item,
+			       const char *item_uri)
+{
+	if (nautilus_file_matches_uri (drop_target_item, item_uri)) {
+		/* can't accept itself */
+		return FALSE;
+	}
+
+	return nautilus_drag_can_accept_uris (drop_target_item);
 }
 					       
 gboolean
Index: libnautilus-private/nautilus-file-dnd.h
===================================================================
RCS file: /cvs/gnome/nautilus/libnautilus-private/nautilus-file-dnd.h,v
retrieving revision 1.5
diff -u -p -r1.5 nautilus-file-dnd.h
--- libnautilus-private/nautilus-file-dnd.h	22 Feb 2002 18:54:15 -0000	1.5
+++ libnautilus-private/nautilus-file-dnd.h	18 Jul 2005 18:31:14 -0000
@@ -29,6 +29,7 @@
 
 #define NAUTILUS_FILE_DND_ERASE_KEYWORD "erase"
 
+gboolean nautilus_drag_can_accept_uris              (NautilusFile *drop_target_item);
 gboolean nautilus_drag_can_accept_item              (NautilusFile *drop_target_item,
 						     const char   *item_uri);
 gboolean nautilus_drag_can_accept_items             (NautilusFile *drop_target_item,
Index: libnautilus-private/nautilus-icon-dnd.c
===================================================================
RCS file: /cvs/gnome/nautilus/libnautilus-private/nautilus-icon-dnd.c,v
retrieving revision 1.148
diff -u -p -r1.148 nautilus-icon-dnd.c
--- libnautilus-private/nautilus-icon-dnd.c	13 Jul 2005 08:17:29 -0000	1.148
+++ libnautilus-private/nautilus-icon-dnd.c	18 Jul 2005 18:31:15 -0000
@@ -32,9 +32,11 @@
 #include "nautilus-icon-dnd.h"
 
 #include "nautilus-file-dnd.h"
+#include "nautilus-file-operations.h"
 #include "nautilus-icon-private.h"
 #include "nautilus-link.h"
 #include "nautilus-metadata.h"
+#include "nautilus-xds-dnd.h"
 #include <eel/eel-background.h>
 #include <eel/eel-gdk-pixbuf-extensions.h>
 #include <eel/eel-glib-extensions.h>
@@ -50,6 +52,7 @@
 #include <gtk/gtkmain.h>
 #include <gtk/gtksignal.h>
 #include <gtk/gtkstock.h>
+#include <X11/Xatom.h>
 #include <libgnome/gnome-i18n.h>
 #include <eel/eel-canvas-rect-ellipse.h>
 #include <libgnomeui/gnome-stock-icons.h>
@@ -69,8 +72,10 @@ static const GtkTargetEntry drag_types [
 
 static const GtkTargetEntry drop_types [] = {
 	{ NAUTILUS_ICON_DND_GNOME_ICON_LIST_TYPE, 0, NAUTILUS_ICON_DND_GNOME_ICON_LIST },
+	{ NAUTILUS_ICON_DND_XDS_TYPE, 0, NAUTILUS_ICON_DND_XDS },
 	{ NAUTILUS_ICON_DND_URI_LIST_TYPE, 0, NAUTILUS_ICON_DND_URI_LIST },
 	{ NAUTILUS_ICON_DND_URL_TYPE, 0, NAUTILUS_ICON_DND_URL },
+	{ NAUTILUS_ICON_DND_OCTET_STREAM_TYPE, 0, NAUTILUS_ICON_DND_OCTET_STREAM },
 	{ NAUTILUS_ICON_DND_COLOR_TYPE, 0, NAUTILUS_ICON_DND_COLOR },
 	{ NAUTILUS_ICON_DND_BGIMAGE_TYPE, 0, NAUTILUS_ICON_DND_BGIMAGE },
 	{ NAUTILUS_ICON_DND_KEYWORD_TYPE, 0, NAUTILUS_ICON_DND_KEYWORD },
@@ -81,6 +86,15 @@ static const GtkTargetEntry drop_types [
 static void     stop_dnd_highlight         (GtkWidget      *widget);
 static void     dnd_highlight_queue_redraw (GtkWidget      *widget);
 
+static char *   get_container_uri          (NautilusIconContainer *container);
+
+static char * nautilus_icon_container_find_drop_target (NautilusIconContainer *container,
+							GdkDragContext        *context,
+							int                    x,
+							int                    y,
+							gboolean              *icon_hit);
+
+
 static GtkTargetList *drop_types_list = NULL;
 static GtkTargetList *drop_types_list_root = NULL;
 
@@ -369,7 +383,10 @@ nautilus_icon_container_dropped_icon_fee
 
 /* FIXME bugzilla.gnome.org 47445: Needs to become a shared function */
 static void
-get_data_on_first_target_we_support (GtkWidget *widget, GdkDragContext *context, guint32 time)
+get_data_on_first_target_we_support (GtkWidget *widget,
+				     GdkDragContext *context,
+				     int x, int y,
+				     guint32 time)
 {
 	GList *target;
 	GtkTargetList *list;
@@ -401,9 +418,41 @@ get_data_on_first_target_we_support (Gtk
 		if (gtk_target_list_find (list, 
 					  target_atom,
 					  &info)) {
-			/* Don't get_data for rootwindow drops unless it's the actual drop */
-			if (info == NAUTILUS_ICON_DND_ROOTWINDOW_DROP &&
-			    !drag_info->drop_occured) {
+			if (info == NAUTILUS_ICON_DND_XDS) {
+				if (drag_info->drop_occured) {
+					char *drop_target_uri;
+					NautilusFile *file;
+					gboolean success;
+
+					if (drag_info->xds_target_uri != NULL) {
+						/* XDS save failed. Try octet stream target. */
+						continue;
+					}
+
+					drop_target_uri = nautilus_icon_container_find_drop_target (
+						NAUTILUS_ICON_CONTAINER (widget), context, x, y, NULL);
+					file = nautilus_file_get (drop_target_uri);
+
+					drag_info->xds_target_uri = nautilus_xds_dnd_handle_drop_stage_1 (file, context);
+
+					success = (drag_info->xds_target_uri != NULL);
+					if (success) {
+						/* advance to stage 2 */
+						gtk_drag_get_data (widget, context, target_atom, time);
+					} else {
+						gtk_drag_finish (context, FALSE, FALSE, time);
+					}
+
+					nautilus_file_unref (file);
+					g_free (drop_target_uri);
+				} else {
+					drag_info->got_drop_data_type = TRUE;
+					drag_info->data_type = NAUTILUS_ICON_DND_XDS;
+				}
+			} else if (info == NAUTILUS_ICON_DND_ROOTWINDOW_DROP &&
+			           !drag_info->drop_occured) {
+				/* Don't get_data for rootwindow drops unless it's the actual drop */
+
 				/* We can't call get_data here, because that would
 				   make the source execute the rootwin action */
 				drag_info->got_drop_data_type = TRUE;
@@ -421,6 +470,7 @@ get_data_on_first_target_we_support (Gtk
 static void
 nautilus_icon_container_ensure_drag_data (NautilusIconContainer *container,
 					  GdkDragContext *context,
+					  int x, int y,
 					  guint32 time)
 {
 	NautilusIconDndInfo *dnd_info;
@@ -428,7 +478,7 @@ nautilus_icon_container_ensure_drag_data
 	dnd_info = container->details->dnd_info;
 
 	if (!dnd_info->drag_info.got_drop_data_type) {
-		get_data_on_first_target_we_support (GTK_WIDGET (container), context, time);
+		get_data_on_first_target_we_support (GTK_WIDGET (container), context, x, y, time);
 	}
 }
 
@@ -938,12 +988,10 @@ nautilus_icon_container_find_drop_target
 	NautilusIcon *drop_target_icon;
 	double world_x, world_y;
 	NautilusFile *file;
+	NautilusDndTargetCapsMask caps_mask;
 	char *icon_uri;
-
-	*icon_hit = FALSE;
-	if (container->details->dnd_info->drag_info.selection_list == NULL) {
-		return NULL;
-	}
+	char *ret;
+	gboolean acceptable;
 
 	canvas_widget_to_world (EEL_CANVAS (container), x, y, &world_x, &world_y);
 	
@@ -960,26 +1008,42 @@ nautilus_icon_container_find_drop_target
 		if (icon_uri != NULL) {
 			file = nautilus_file_get (icon_uri);
 
-			if (!nautilus_drag_can_accept_items (file, 
-					container->details->dnd_info->drag_info.selection_list)) {
+			caps_mask = nautilus_drag_target_get_caps_mask (container->details->dnd_info->drag_info.data_type);
+
+
+			if (container->details->dnd_info->drag_info.selection_list != NULL) {
+				acceptable = (caps_mask & NAUTILUS_ICON_DND_TARGET_CAPS_FOLDERS) != 0 &&
+					     nautilus_drag_can_accept_items (file,
+						    container->details->dnd_info->drag_info.selection_list);
+			} else if (nautilus_drag_can_accept_uris (file)) {
+				acceptable = (caps_mask & NAUTILUS_ICON_DND_TARGET_CAPS_FOLDERS) != 0;
+			} else {
+				acceptable = (caps_mask & NAUTILUS_ICON_DND_TARGET_CAPS_FILES) != 0;
+			}
+
+			if (!acceptable) {
 			 	/* the item we dropped our selection on cannot accept the items,
 			 	 * do the same thing as if we just dropped the items on the canvas
 				 */
 				drop_target_icon = NULL;
 			}
-			
+
 			g_free (icon_uri);
 			nautilus_file_unref (file);
 		}
 	}
 
-	if (drop_target_icon == NULL) {
-		*icon_hit = FALSE;
-		return get_container_uri (container);
+	if (drop_target_icon != NULL) {
+		ret = nautilus_icon_container_get_icon_drop_target_uri (container, drop_target_icon);
+	} else {	
+		ret = get_container_uri (container);
 	}
-	
-	*icon_hit = TRUE;
-	return nautilus_icon_container_get_icon_drop_target_uri (container, drop_target_icon);
+
+	if (icon_hit != NULL) {
+		*icon_hit = (drop_target_icon != NULL);
+	}
+
+	return ret;
 }
 
 static gboolean
@@ -1088,11 +1152,9 @@ nautilus_icon_container_get_drop_action 
 					 int *action)
 {
 	char *drop_target;
-	gboolean icon_hit;
 	NautilusIcon *icon;
 	double world_x, world_y;
 
-	icon_hit = FALSE;
 	if (!container->details->dnd_info->drag_info.got_drop_data_type) {
 		/* drag_data_received_callback didn't get called yet */
 		return;
@@ -1112,10 +1174,7 @@ nautilus_icon_container_get_drop_action 
 			return;
 		}
 		drop_target = nautilus_icon_container_find_drop_target (container,
-			context, x, y, &icon_hit);
-		if (!drop_target) {
-			return;
-		}
+			context, x, y, NULL);
 		nautilus_drag_default_drop_action_for_icons (context, drop_target, 
 			container->details->dnd_info->drag_info.selection_list, 
 			action);
@@ -1147,6 +1206,11 @@ nautilus_icon_container_get_drop_action 
 		*action = context->suggested_action;
 		break;
 
+	case NAUTILUS_ICON_DND_XDS:
+	case NAUTILUS_ICON_DND_OCTET_STREAM:
+		*action = GDK_ACTION_MOVE;
+		break;
+
 	case NAUTILUS_ICON_DND_TEXT:
 		*action = GDK_ACTION_COPY;
 		break;
@@ -1180,12 +1244,15 @@ nautilus_icon_dnd_update_drop_target (Na
 {
 	NautilusIcon *icon;
 	NautilusFile *file;
+	NautilusDndTargetCapsMask caps_mask;
 	double world_x, world_y;
 	char *uri;
+	gboolean acceptable;
 	
 	g_assert (NAUTILUS_IS_ICON_CONTAINER (container));
-	if ((container->details->dnd_info->drag_info.selection_list == NULL) 
-	   && (container->details->dnd_info->drag_info.data_type != NAUTILUS_ICON_DND_KEYWORD)) {
+
+	caps_mask = nautilus_drag_target_get_caps_mask (container->details->dnd_info->drag_info.data_type);
+	if ((caps_mask & NAUTILUS_ICON_DND_TARGET_CAPS_FILES_AND_FOLDERS) == 0) {
 		return;
 	}
 
@@ -1201,13 +1268,22 @@ nautilus_icon_dnd_update_drop_target (Na
 	 */
 
 	/* Find if target icon accepts our drop. */
-	if (icon != NULL && (container->details->dnd_info->drag_info.data_type != NAUTILUS_ICON_DND_KEYWORD)) {
+	if (icon != NULL) {
 		    uri = nautilus_icon_container_get_icon_uri (container, icon);
 		    file = nautilus_file_get (uri);
 		    g_free (uri);
-		
-		    if (!nautilus_drag_can_accept_items (file,
-							 container->details->dnd_info->drag_info.selection_list)) {
+
+		    if (container->details->dnd_info->drag_info.selection_list != NULL) {
+			    acceptable = (caps_mask & NAUTILUS_ICON_DND_TARGET_CAPS_FOLDERS) != 0 &&
+				    	 nautilus_drag_can_accept_items (file,
+						container->details->dnd_info->drag_info.selection_list);
+		    } else if (nautilus_drag_can_accept_uris (file)) {
+			    acceptable = ((caps_mask & NAUTILUS_ICON_DND_TARGET_CAPS_FOLDERS) != 0);
+		    } else {
+			    acceptable = ((caps_mask & NAUTILUS_ICON_DND_TARGET_CAPS_FILES) != 0);
+		    }
+
+		    if (!acceptable) {
 			    icon = NULL;
 		    }
 
@@ -1433,7 +1509,7 @@ drag_motion_callback (GtkWidget *widget,
 {
 	int action;
 	
-	nautilus_icon_container_ensure_drag_data (NAUTILUS_ICON_CONTAINER (widget), context, time);
+	nautilus_icon_container_ensure_drag_data (NAUTILUS_ICON_CONTAINER (widget), context, x, y, time);
 	nautilus_icon_container_position_shadow (NAUTILUS_ICON_CONTAINER (widget), x, y);
 	nautilus_icon_dnd_update_drop_target (NAUTILUS_ICON_CONTAINER (widget), context, x, y);
 	set_up_auto_scroll_if_needed (NAUTILUS_ICON_CONTAINER (widget));
@@ -1471,7 +1547,7 @@ drag_drop_callback (GtkWidget *widget,
 	*/
 	dnd_info->drag_info.drop_occured = TRUE;
 
-	get_data_on_first_target_we_support (widget, context, time);
+	get_data_on_first_target_we_support (widget, context, x, y, time);
 
 	return FALSE;
 }
@@ -1568,6 +1644,11 @@ nautilus_icon_dnd_uri_list_free_strings 
 */
 
 static void
+cb (gpointer foo)
+{
+}
+
+static void
 drag_data_received_callback (GtkWidget *widget,
 			     GdkDragContext *context,
 			     int x,
@@ -1580,7 +1661,7 @@ drag_data_received_callback (GtkWidget *
     	NautilusDragInfo *drag_info;
 	EelBackground *background;
 	char *tmp;
-	gboolean success;
+	gboolean finish, success;
 
 	drag_info = &(NAUTILUS_ICON_CONTAINER (widget)->details->dnd_info->drag_info);
 
@@ -1614,26 +1695,31 @@ drag_data_received_callback (GtkWidget *
 	case NAUTILUS_ICON_DND_ROOTWINDOW_DROP:
 		/* Do nothing, this won't even happen, since we don't want to call get_data twice */
 		break;
+	case NAUTILUS_ICON_DND_XDS:
+		break;
 	}
 
 	/* this is the second use case of this callback.
 	 * we have to do the actual work for the drop.
 	 */
 	if (drag_info->drop_occured) {
+		XDSDropStage2Result res;
 
+		finish = TRUE;
 		success = FALSE;
 		switch (info) {
 		case NAUTILUS_ICON_DND_GNOME_ICON_LIST:
 			nautilus_icon_container_receive_dropped_icons
 				(NAUTILUS_ICON_CONTAINER (widget),
 				 context, x, y);
+			finish = success = TRUE;
 			break;
 		case NAUTILUS_ICON_DND_COLOR:
 			receive_dropped_color (NAUTILUS_ICON_CONTAINER (widget),
 					       x, y,
 					       context->action,
 					       data);
-			success = TRUE;
+			finish = success = TRUE;
 			break;
 		case NAUTILUS_ICON_DND_BGIMAGE:
 			receive_dropped_tile_image
@@ -1650,22 +1736,57 @@ drag_data_received_callback (GtkWidget *
 			receive_dropped_url
 				(NAUTILUS_ICON_CONTAINER (widget),
 				 (char *) data->data, context->action, x, y);
-			success = TRUE;
+			finish = success = TRUE;
 			break;
 		case NAUTILUS_ICON_DND_URI_LIST:
 			receive_dropped_uri_list
 				(NAUTILUS_ICON_CONTAINER (widget),
 				 (char *) data->data, context->action, x, y);
-			success = TRUE;
+			finish = success = TRUE;
+			break;
+		case NAUTILUS_ICON_DND_XDS:
+			res = nautilus_xds_dnd_handle_drop_stage_2 (widget, context, data, time);
+			switch (res) {
+			case XDS_DROP_STAGE_2_RESULT_SUCCESS:
+				finish = success = TRUE;
+				break;
+
+			case XDS_DROP_STAGE_2_RESULT_FAILURE:
+			case XDS_DROP_STAGE_2_RESULT_ERROR:
+				finish = TRUE;
+				success = FALSE;
+				break;
+
+			case XDS_DROP_STAGE_2_RESULT_FAILURE_BUT_OCTET:
+				drag_info->got_drop_data_type = FALSE;
+				finish = FALSE;
+				break;
+
+			default:
+				g_assert_not_reached ();
+				break;
+			}
 			break;
 		case NAUTILUS_ICON_DND_TEXT:
 			tmp = gtk_selection_data_get_text (data);
 			receive_dropped_text
 				(NAUTILUS_ICON_CONTAINER (widget),
 				 (char *) tmp, context->action, x, y);
-			success = TRUE;
+			finish = success = TRUE;
 			g_free (tmp);
 			break;
+		case NAUTILUS_ICON_DND_OCTET_STREAM:
+			finish = TRUE;
+			success = (drag_info->xds_target_uri != NULL);
+			if (success) {
+				nautilus_file_operations_new_file (
+					widget, drag_info->xds_target_uri,
+					(char *) data->data,
+					(NautilusNewFileCallback) cb, NULL);
+			} else {
+				g_warning ("\"application/octet-stream\" used in non-XDS context. Ignoring.");
+			}
+			break;
 		case NAUTILUS_ICON_DND_RESET_BACKGROUND:
 			background = eel_get_widget_background (widget);
 			if (background != NULL) {
@@ -1677,14 +1798,16 @@ drag_data_received_callback (GtkWidget *
 			/* Do nothing, everything is done by the sender */
 			break;
 		}
-		gtk_drag_finish (context, success, FALSE, time);
-		
-		nautilus_icon_container_free_drag_data (NAUTILUS_ICON_CONTAINER (widget));
-		
-		set_drop_target (NAUTILUS_ICON_CONTAINER (widget), NULL);
+		if (finish) {
+			gtk_drag_finish (context, success, FALSE, time);
 
-		/* reinitialise it for the next dnd */
-		drag_info->drop_occured = FALSE;
+			nautilus_icon_container_free_drag_data (NAUTILUS_ICON_CONTAINER (widget));
+			
+			set_drop_target (NAUTILUS_ICON_CONTAINER (widget), NULL);
+
+			/* reinitialise it for the next dnd */
+			drag_info->drop_occured = FALSE;
+		}
 	}
 
 }
Index: libnautilus-private/nautilus-tree-view-drag-dest.c
===================================================================
RCS file: /cvs/gnome/nautilus/libnautilus-private/nautilus-tree-view-drag-dest.c,v
retrieving revision 1.11
diff -u -p -r1.11 nautilus-tree-view-drag-dest.c
--- libnautilus-private/nautilus-tree-view-drag-dest.c	6 Jul 2005 12:18:27 -0000	1.11
+++ libnautilus-private/nautilus-tree-view-drag-dest.c	18 Jul 2005 18:31:15 -0000
@@ -36,14 +36,18 @@
 #include <libgnome/gnome-macros.h>
 #include <libgnomevfs/gnome-vfs-utils.h>
 #include "nautilus-file-dnd.h"
+#include "nautilus-file-operations.h"
 #include "nautilus-icon-dnd.h"
 #include "nautilus-link.h"
 #include "nautilus-marshal.h"
+#include "nautilus-xds-dnd.h"
 
 #define AUTO_SCROLL_MARGIN 20
 
 #define HOVER_EXPAND_TIMEOUT 1000
 
+#define XDS_ATOM gdk_atom_intern ("XdndDirectSave0", FALSE)
+
 struct _NautilusTreeViewDragDestDetails {
 	GtkTreeView *tree_view;
 
@@ -53,6 +57,7 @@ struct _NautilusTreeViewDragDestDetails 
 	guint drag_type;
 	GtkSelectionData *drag_data;
 	GList *drag_list;
+	char *xds_target_uri;
 
 	guint highlight_id;
 	guint scroll_id;
@@ -80,8 +85,10 @@ GNOME_CLASS_BOILERPLATE (NautilusTreeVie
 
 static const GtkTargetEntry drag_types [] = {
 	{ NAUTILUS_ICON_DND_GNOME_ICON_LIST_TYPE, 0, NAUTILUS_ICON_DND_GNOME_ICON_LIST },
+	{ NAUTILUS_ICON_DND_XDS_TYPE, 0, NAUTILUS_ICON_DND_XDS },
 	{ NAUTILUS_ICON_DND_URI_LIST_TYPE, 0, NAUTILUS_ICON_DND_URI_LIST },
 	{ NAUTILUS_ICON_DND_URL_TYPE, 0, NAUTILUS_ICON_DND_URL },
+	{ NAUTILUS_ICON_DND_OCTET_STREAM_TYPE, 0, NAUTILUS_ICON_DND_OCTET_STREAM }
 	/* FIXME: Should handle emblems once the list view supports them */
 };
 
@@ -239,7 +246,8 @@ clear_drag_dest_row (NautilusTreeViewDra
 static void
 get_drag_data (NautilusTreeViewDragDest *dest,
 	       GdkDragContext *context, 
-	       guint32 time)
+	       guint32 time,
+	       gboolean is_drag_motion)
 {
 	GdkAtom target;
 	
@@ -247,8 +255,12 @@ get_drag_data (NautilusTreeViewDragDest 
 					    context, 
 					    NULL);
 
-	gtk_drag_get_data (GTK_WIDGET (dest->details->tree_view),
-			   context, target, time);
+	if (is_drag_motion && target == XDS_ATOM) {
+		/* XDS drag data will be received on drop only */
+		dest->details->drag_type = NAUTILUS_ICON_DND_XDS;
+	} else { gtk_drag_get_data (GTK_WIDGET (dest->details->tree_view),
+				   context, target, time);
+	}
 }
 
 static void
@@ -265,6 +277,9 @@ free_drag_data (NautilusTreeViewDragDest
 		nautilus_drag_destroy_selection_list (dest->details->drag_list);
 		dest->details->drag_list = NULL;
 	}
+
+	g_free (dest->details->xds_target_uri);
+	dest->details->xds_target_uri = NULL;
 }
 
 static char *
@@ -305,6 +320,7 @@ get_drop_path (NautilusTreeViewDragDest 
 {
 	NautilusFile *file;
 	GtkTreePath *ret;
+	gboolean acceptable;
 	
 	if (!path) {
 		return NULL;
@@ -314,15 +330,21 @@ get_drop_path (NautilusTreeViewDragDest 
 	
 	ret = NULL;
 
-	if (!file || !nautilus_drag_can_accept_items (file, dest->details->drag_list)){
-		if (gtk_tree_path_get_depth (path) == 1) {
-			ret = NULL;
-		} else {
-			ret = gtk_tree_path_copy (path);
-			gtk_tree_path_up (ret);
-		}
+	if (file && dest->details->drag_list) {
+		acceptable = nautilus_drag_can_accept_items (file, dest->details->drag_list);
+	} else if (file) {
+		acceptable = nautilus_drag_can_accept_uris (file);
+	} else {
+		acceptable = FALSE;
+	}
+
+	if (acceptable) {
+		ret = gtk_tree_path_copy (path);
+	} else if (gtk_tree_path_get_depth (path) == 1) {
+		ret = NULL;
 	} else {
 		ret = gtk_tree_path_copy (path);
+		gtk_tree_path_up (ret);
 	}
 
 	nautilus_file_unref (file);
@@ -356,7 +378,8 @@ get_drop_action (NautilusTreeViewDragDes
 	char *drop_target;
 	guint action;
 	
-	if (!dest->details->have_drag_data ||
+	if ((!dest->details->have_drag_data &&
+	     dest->details->drag_type != NAUTILUS_ICON_DND_XDS) ||
 	    (dest->details->drag_type == NAUTILUS_ICON_DND_GNOME_ICON_LIST &&
 	     dest->details->drag_list == NULL)) {
 		return 0;
@@ -379,11 +402,15 @@ get_drop_action (NautilusTreeViewDragDes
 		g_free (drop_target);
 		
 		return action;
-		
+
+	case NAUTILUS_ICON_DND_XDS:
+	case NAUTILUS_ICON_DND_OCTET_STREAM:
+		return GDK_ACTION_MOVE;
+
 	case NAUTILUS_ICON_DND_URL:
 		return nautilus_drag_default_drop_action_for_url (context);
-		
-	case NAUTILUS_ICON_DND_URI_LIST :
+
+	case NAUTILUS_ICON_DND_URI_LIST:
 		return context->suggested_action;
 
 	case NAUTILUS_ICON_DND_TEXT:
@@ -424,7 +451,7 @@ drag_motion_callback (GtkWidget *widget,
 	
 
 	if (!dest->details->have_drag_data) {
-		get_drag_data (dest, context, time);
+		get_drag_data (dest, context, time, TRUE);
 	}
 	drop_path = get_drop_path (dest, path);
 	
@@ -495,25 +522,43 @@ drag_leave_callback (GtkWidget *widget,
 	remove_expand_timeout (dest);
 }
 
-static void
-receive_uris (NautilusTreeViewDragDest *dest,
-	      GdkDragContext *context,
-	      GList *source_uris,
-	      int x, int y)
+static char *
+get_drop_target_at_pos (NautilusTreeViewDragDest *dest,
+			int x, int y)
 {
-	char *drop_target;
 	GtkTreePath *path;
 	GtkTreePath *drop_path;
-	GtkTreeViewDropPosition pos;
-	GdkDragAction action;
+	char *drop_target;
 
 	gtk_tree_view_get_dest_row_at_pos (dest->details->tree_view, x, y, 
-					   &path, &pos);
+					   &path, NULL);
 
 	drop_path = get_drop_path (dest, path);
 
 	drop_target = get_drop_target (dest, drop_path);
 
+	if (path) {
+		gtk_tree_path_free (path);
+	}
+
+	if (drop_path) {
+		gtk_tree_path_free (drop_path);
+	}
+
+	return drop_target;
+}
+
+static void
+receive_uris (NautilusTreeViewDragDest *dest,
+	      GdkDragContext *context,
+	      GList *source_uris,
+	      int x, int y)
+{
+	char *drop_target;
+	GdkDragAction action;
+
+	drop_target = get_drop_target_at_pos (dest, x, y);
+
 	if (context->action == GDK_ACTION_ASK) {
 		if (nautilus_drag_selection_includes_special_link (dest->details->drag_list)) {
 			/* We only want to move the trash */
@@ -538,14 +583,6 @@ receive_uris (NautilusTreeViewDragDest *
 			       x, y);
 	}
 
-	if (path) {
-		gtk_tree_path_free (path);
-	}
-
-	if (drop_path) {
-		gtk_tree_path_free (drop_path);
-	}
-
 	g_free (drop_target);
 }
 
@@ -626,6 +663,11 @@ receive_dropped_url (NautilusTreeViewDra
 		       x, y);
 }
 
+static void
+cb (void) {
+	;
+}
+
 static gboolean
 drag_data_received_callback (GtkWidget *widget,
 			     GdkDragContext *context,
@@ -637,15 +679,20 @@ drag_data_received_callback (GtkWidget *
 			     gpointer data)
 {
 	NautilusTreeViewDragDest *dest;
-	gboolean success;
+	gboolean success, finish;
 	
 	dest = NAUTILUS_TREE_VIEW_DRAG_DEST (data);
 
 	if (!dest->details->have_drag_data) {
 		dest->details->have_drag_data = TRUE;
 		dest->details->drag_type = info;
-		dest->details->drag_data = 
-			gtk_selection_data_copy (selection_data);
+		if (info != NAUTILUS_ICON_DND_XDS) {
+			dest->details->drag_data = 
+				gtk_selection_data_copy (selection_data);
+		} else {
+			dest->details->drag_data = NULL;
+		}
+
 		if (info == NAUTILUS_ICON_DND_GNOME_ICON_LIST) {
 			dest->details->drag_list = 
 				nautilus_drag_build_selection_list (selection_data);
@@ -653,29 +700,90 @@ drag_data_received_callback (GtkWidget *
 	}
 
 	if (dest->details->drop_occurred) {
+		finish = TRUE;
 		success = FALSE;
 		switch (info) {
 		case NAUTILUS_ICON_DND_GNOME_ICON_LIST :
 			receive_dropped_icons (dest, context, x, y);
-			success = TRUE;
+			finish = success = TRUE;
+			break;
+		case NAUTILUS_ICON_DND_XDS:
+			if (dest->details->xds_target_uri == NULL) {
+				NautilusFile *file;
+				char *uri;
+
+				uri = get_drop_target_at_pos (dest, x, y);
+				file = nautilus_file_get (uri);
+				dest->details->xds_target_uri = nautilus_xds_dnd_handle_drop_stage_1 (file, context);
+
+				nautilus_file_unref (file);
+				g_free (uri);
+
+				finish = (dest->details->xds_target_uri == NULL);
+				if (finish) {
+					success = FALSE;
+				} else {
+					/* advance to stage 2 */
+					gtk_drag_get_data (widget, context, XDS_ATOM, time);
+				}
+				break;
+			} else {
+				XDSDropStage2Result res;
+
+				res = nautilus_xds_dnd_handle_drop_stage_2 (widget, context, selection_data, time);
+				switch (res) {
+				case XDS_DROP_STAGE_2_RESULT_SUCCESS:
+					finish = success = TRUE;
+					break;
+
+				case XDS_DROP_STAGE_2_RESULT_FAILURE:
+				case XDS_DROP_STAGE_2_RESULT_ERROR:
+					finish = TRUE;
+					success = FALSE;
+					break;
+
+				case XDS_DROP_STAGE_2_RESULT_FAILURE_BUT_OCTET:
+					dest->details->have_drag_data = FALSE;
+					finish = FALSE;
+					break;
+
+				default:
+					g_assert_not_reached ();
+					break;
+				}
+			}
 			break;
 		case NAUTILUS_ICON_DND_URL :
 			receive_dropped_url (dest, context, x, y);
-			success = TRUE;
+			finish = success = TRUE;
 			break;
 		case NAUTILUS_ICON_DND_URI_LIST :
 			receive_dropped_uri_list (dest, context, x, y);
-			success = TRUE;
+			finish = success = TRUE;
 			break;
 		case NAUTILUS_ICON_DND_TEXT:
 			receive_dropped_text (dest, context, x, y);
-			success = TRUE;
+			finish = success = TRUE;
+			break;
+		case NAUTILUS_ICON_DND_OCTET_STREAM:
+			finish = TRUE;
+			success = (dest->details->xds_target_uri != NULL);
+			if (success) {
+				nautilus_file_operations_new_file (
+					widget, dest->details->xds_target_uri,
+					(char *) selection_data->data,
+					(NautilusNewFileCallback) cb, NULL);
+			} else {
+				g_warning ("\"application/octet-stream\" used in non-XDS context. Ignoring.");
+			}
 			break;
 		}
 
-		dest->details->drop_occurred = FALSE;
-		free_drag_data (dest);
-		gtk_drag_finish (context, success, FALSE, time);
+		if (finish) {
+			dest->details->drop_occurred = FALSE;
+			free_drag_data (dest);
+			gtk_drag_finish (context, success, FALSE, time);
+		}
 	}
 
 	/* appease GtkTreeView by preventing its drag_data_receive
@@ -700,7 +808,7 @@ drag_drop_callback (GtkWidget *widget,
 
 	dest->details->drop_occurred = TRUE;
 
-	get_drag_data (dest, context, time);
+	get_drag_data (dest, context, time, FALSE);
 	remove_scroll_timeout (dest);
 	remove_expand_timeout (dest);
 	clear_drag_dest_row (dest);
