diff -rupN nautilus-2.20.0-orig/libnautilus-private/Makefile.am nautilus-2.20.0-undo/libnautilus-private/Makefile.am
--- nautilus-2.20.0-orig/libnautilus-private/Makefile.am	2007-08-21 11:37:54.000000000 +0200
+++ nautilus-2.20.0-undo/libnautilus-private/Makefile.am	2007-10-15 14:44:54.000000000 +0200
@@ -210,6 +210,8 @@ libnautilus_private_la_SOURCES = \
 	nautilus-view.h \
 	nautilus-window-info.c \
 	nautilus-window-info.h \
+	nautilus-undostack-manager.c \
+	nautilus-undostack-manager.h \
 	$(NULL)
 
 BEAGLE_SOURCES = \
diff -rupN nautilus-2.20.0-orig/libnautilus-private/Makefile.in nautilus-2.20.0-undo/libnautilus-private/Makefile.in
--- nautilus-2.20.0-orig/libnautilus-private/Makefile.in	2007-09-18 09:01:39.000000000 +0200
+++ nautilus-2.20.0-undo/libnautilus-private/Makefile.in	2007-10-15 14:45:05.000000000 +0200
@@ -145,7 +145,8 @@ am__libnautilus_private_la_SOURCES_DIST 
 	nautilus-window-info.h nautilus-search-engine-beagle.c \
 	nautilus-search-engine-beagle.h \
 	nautilus-search-engine-tracker.c \
-	nautilus-search-engine-tracker.h
+	nautilus-search-engine-tracker.h \
+	nautilus-undostack-manager.h nautilus-undostack-manager.c
 am__objects_1 =
 am__objects_2 = nautilus-metafile-server-stubs.lo \
 	nautilus-metafile-server-skels.lo \
@@ -195,6 +196,7 @@ am_libnautilus_private_la_OBJECTS = $(am
 	nautilus-undo.lo nautilus-users-groups-cache.lo \
 	nautilus-vfs-directory.lo nautilus-vfs-file.lo \
 	nautilus-view-factory.lo nautilus-view.lo \
+	nautilus-undostack-manager.lo \
 	nautilus-window-info.lo $(am__objects_1) $(am__objects_4) \
 	$(am__objects_6)
 libnautilus_private_la_OBJECTS = $(am_libnautilus_private_la_OBJECTS)
@@ -563,6 +565,7 @@ libnautilus_private_la_SOURCES =  \
 	nautilus-vfs-file.c nautilus-vfs-file.h \
 	nautilus-view-factory.c nautilus-view-factory.h \
 	nautilus-view.c nautilus-view.h nautilus-window-info.c \
+	nautilus-undostack-manager.h nautilus-undostack-manager.c \
 	nautilus-window-info.h $(NULL) $(am__append_1) $(am__append_2)
 BEAGLE_SOURCES = \
 	nautilus-search-engine-beagle.c \
diff -rupN nautilus-2.20.0-orig/libnautilus-private/nautilus-file.c nautilus-2.20.0-undo/libnautilus-private/nautilus-file.c
--- nautilus-2.20.0-orig/libnautilus-private/nautilus-file.c	2007-09-10 09:03:46.000000000 +0200
+++ nautilus-2.20.0-undo/libnautilus-private/nautilus-file.c	2007-10-23 14:57:11.000000000 +0200
@@ -48,6 +48,7 @@
 #include "nautilus-users-groups-cache.h"
 #include "nautilus-vfs-file.h"
 #include "nautilus-saved-search-file.h"
+#include "nautilus-undostack-manager.h"
 #include <eel/eel-debug.h>
 #include <eel/eel-glib-extensions.h>
 #include <eel/eel-gtk-extensions.h>
@@ -113,6 +114,7 @@ typedef struct {
 	gpointer callback_data;
 	gboolean is_rename;
 	gboolean use_slow_mime;
+	gboolean is_undoredo;
 } Operation;
 
 typedef void (* ModifyListFunction) (GList **list, NautilusFile *file);
@@ -1080,9 +1082,20 @@ rename_callback (GnomeVFSAsyncHandle *ha
 
 		new_uri = nautilus_file_get_uri (op->file);
 		nautilus_directory_moved (old_uri, new_uri);
-		g_free (new_uri);
-		g_free (old_uri);
-
+		
+		/* Undo: Construct undo object */
+		if (!op->is_undoredo) {
+			GHashTable* affected_uri = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free);
+			g_hash_table_insert (affected_uri, new_uri, old_uri);
+			NautilusUndoStackManager* manager = nautilus_undostack_manager_instance ();
+			NautilusUndoStackAction* action = nautilus_undostack_manager_new_action (NAUTILUS_UNDOSTACK_RENAME);
+			nautilus_undostack_manager_set_affected_uris (action, affected_uri);
+			nautilus_undostack_manager_add_action (manager, action);
+		} else {
+		/* Done */
+			g_free (new_uri);
+			g_free (old_uri);
+		}
 
 		/* the rename could have affected the display name if e.g.
 		 * we're in a vfolder where the name comes from a desktop file
@@ -1227,6 +1240,7 @@ rename_guts (NautilusFile *file,
 	op = operation_new (file, callback, callback_data);
 	op->is_rename = TRUE;
 	op->use_slow_mime = file->details->got_slow_mime_type;
+	op->is_undoredo = FALSE;
 
 	options = NAUTILUS_FILE_DEFAULT_FILE_INFO_OPTIONS;
 	if (op->use_slow_mime) {
@@ -6391,3 +6405,54 @@ nautilus_self_check_file (void)
 }
 
 #endif /* !NAUTILUS_OMIT_SELF_CHECK */
+
+static void
+undo_rename_guts (NautilusFile *file,
+	     const char *new_name,
+	     NautilusFileOperationCallback callback,
+	     gpointer callback_data)
+{
+	Operation *op;
+	GnomeVFSFileInfo *partial_file_info;
+	GnomeVFSURI *vfs_uri;
+	GnomeVFSFileInfoOptions options;
+	
+	g_return_if_fail (NAUTILUS_IS_FILE (file));
+	g_return_if_fail (new_name != NULL);
+	g_return_if_fail (callback != NULL);
+
+	/* Set up a renaming operation. */
+	op = operation_new (file, callback, callback_data);
+	op->is_rename = TRUE;
+	op->use_slow_mime = file->details->got_slow_mime_type;
+	op->is_undoredo = TRUE;
+
+	options = NAUTILUS_FILE_DEFAULT_FILE_INFO_OPTIONS;
+	if (op->use_slow_mime) {
+		options |= GNOME_VFS_FILE_INFO_FORCE_SLOW_MIME_TYPE;
+	}
+
+	/* Do the renaming. */
+	partial_file_info = gnome_vfs_file_info_new ();
+	partial_file_info->name = g_strdup (new_name);
+	vfs_uri = nautilus_file_get_gnome_vfs_uri (file);
+	gnome_vfs_async_set_file_info (&op->handle,
+				       vfs_uri, partial_file_info, 
+				       GNOME_VFS_SET_FILE_INFO_NAME,
+				       options,
+				       GNOME_VFS_PRIORITY_DEFAULT,
+				       rename_callback, op);
+	gnome_vfs_file_info_unref (partial_file_info);
+	gnome_vfs_uri_unref (vfs_uri);
+}
+
+void
+nautilus_file_undo_rename (NautilusFile *file,
+		      const char *new_name,
+		      NautilusFileOperationCallback callback,
+		      gpointer callback_data)
+{
+	undo_rename_guts (file, new_name, callback, callback_data);
+	return;
+}
+
diff -rupN nautilus-2.20.0-orig/libnautilus-private/nautilus-file.h nautilus-2.20.0-undo/libnautilus-private/nautilus-file.h
--- nautilus-2.20.0-orig/libnautilus-private/nautilus-file.h	2007-04-03 12:08:46.000000000 +0200
+++ nautilus-2.20.0-undo/libnautilus-private/nautilus-file.h	2007-10-22 17:18:14.000000000 +0200
@@ -358,6 +358,12 @@ void                    nautilus_file_li
 /* Debugging */
 void                    nautilus_file_dump                              (NautilusFile                   *file);
 
+/* Undo */
+void 		nautilus_file_undo_rename (NautilusFile *file,
+		      							const char *new_name,
+		      							NautilusFileOperationCallback callback,
+		      							gpointer callback_data);
+
 typedef struct NautilusFileDetails NautilusFileDetails;
 
 struct NautilusFile {
diff -rupN nautilus-2.20.0-orig/libnautilus-private/nautilus-file-operations.c nautilus-2.20.0-undo/libnautilus-private/nautilus-file-operations.c
--- nautilus-2.20.0-orig/libnautilus-private/nautilus-file-operations.c	2007-04-03 12:08:46.000000000 +0200
+++ nautilus-2.20.0-undo/libnautilus-private/nautilus-file-operations.c	2007-10-24 17:24:47.000000000 +0200
@@ -93,10 +93,15 @@ struct TransferInfo {
 	void (* done_callback) (GHashTable *debuting_uris, gpointer data);
 	gpointer done_callback_data;
 	GHashTable *debuting_uris;
+	/* Undo stuff */
+	GHashTable *affected_uris;
+	gboolean is_undoredo;
+	/* End undo stuff */
 	gboolean cancelled;	
 	IconPositionIterator *iterator;
 };
 
+
 static TransferInfo *
 transfer_info_new (GtkWidget *parent_view)
 {
@@ -520,6 +525,7 @@ handle_transfer_ok (const GnomeVFSXferPr
 			GList *delete_me;
 
 			delete_me = g_list_prepend (NULL, progress_info->target_name);
+			g_hash_table_remove (transfer_info->affected_uris, progress_info->target_name);
 			nautilus_file_operations_delete (delete_me, transfer_info->parent_view, NULL, NULL);
 			g_list_free (delete_me);
 		}
@@ -605,8 +611,36 @@ handle_transfer_ok (const GnomeVFSXferPr
 	case GNOME_VFS_XFER_PHASE_COMPLETED:
 		nautilus_file_changes_consume_changes (TRUE);
 		if (transfer_info->done_callback != NULL) {
+									       
+			/* Undo: Construct undo object */
+			if ((g_hash_table_size (transfer_info->affected_uris) != 0) && !transfer_info->is_undoredo) {		
+				NautilusUndoStackAction* undo_action = NULL;
+				NautilusUndoStackManager* manager = nautilus_undostack_manager_instance ();
+				
+				switch (transfer_info->kind) {
+					case TRANSFER_MOVE:
+						undo_action = nautilus_undostack_manager_new_action (NAUTILUS_UNDOSTACK_MOVE);
+						break;
+					case TRANSFER_COPY:
+						undo_action = nautilus_undostack_manager_new_action (NAUTILUS_UNDOSTACK_COPY);
+						break;
+					case TRANSFER_MOVE_TO_TRASH:
+						undo_action = nautilus_undostack_manager_new_action (NAUTILUS_UNDOSTACK_MOVETOTRASH);
+						break;
+					case TRANSFER_LINK:
+						undo_action = nautilus_undostack_manager_new_action (NAUTILUS_UNDOSTACK_CREATELINK);
+						break;						
+					default:
+						break; /* We shouldn't reach this */						
+				}	
+				nautilus_undostack_manager_set_affected_uris (undo_action, transfer_info->affected_uris);
+				nautilus_undostack_manager_add_action (manager, undo_action);
+			}
+			/* Done */
+			
 			transfer_info->done_callback (transfer_info->debuting_uris,
-						      transfer_info->done_callback_data);
+				  transfer_info->done_callback_data);
+						      
 			/* done_callback now owns (will free) debuting_uris */
 			transfer_info->debuting_uris = NULL;
 		}
@@ -1731,6 +1765,7 @@ apply_one_position (IconPositionIterator
 
 typedef struct {
 	GHashTable		*debuting_uris;
+	GHashTable		*affected_uris;
 	IconPositionIterator	*iterator;
 } SyncTransferInfo;
 
@@ -1741,14 +1776,17 @@ static int
 sync_transfer_callback (GnomeVFSXferProgressInfo *progress_info, gpointer data)
 {
 	GHashTable	     *debuting_uris;
+	GHashTable		 *affected_uris;
 	IconPositionIterator *position_iterator;
 	gboolean              really_moved;
 
 	if (data != NULL) {
 		debuting_uris	  = ((SyncTransferInfo *) data)->debuting_uris;
+		affected_uris	  = ((SyncTransferInfo *) data)->affected_uris;
 		position_iterator = ((SyncTransferInfo *) data)->iterator;
 	} else {
 		debuting_uris     = NULL;
+		affected_uris	  = NULL;
 		position_iterator = NULL;
 	}
 
@@ -1778,6 +1816,12 @@ sync_transfer_callback (GnomeVFSXferProg
 							      g_strdup (progress_info->target_name),
 							      GINT_TO_POINTER (TRUE));
 				}
+				
+				if (affected_uris != NULL) {
+					g_hash_table_replace (affected_uris,
+							      g_strdup (progress_info->target_name),
+							      g_strdup (progress_info->source_name));
+				}
 			}
 			nautilus_file_changes_queue_file_added (progress_info->target_name);
 			break;
@@ -1816,6 +1860,12 @@ sync_transfer_callback (GnomeVFSXferProg
 				nautilus_file_changes_queue_file_moved (progress_info->source_name,
 									progress_info->target_name);
 			}
+			
+			if (really_moved && (affected_uris != NULL)) {
+				g_hash_table_replace (affected_uris,
+							      g_strdup (progress_info->target_name),
+							      g_strdup (progress_info->source_name));
+			}
 			break;
 			
 		case GNOME_VFS_XFER_PHASE_DELETESOURCE:
@@ -2259,10 +2309,13 @@ nautilus_file_operations_copy_move (cons
 	transfer_info->done_callback = done_callback;
 	transfer_info->done_callback_data = done_callback_data;
 	transfer_info->debuting_uris = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
+	transfer_info->affected_uris = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free);
+	transfer_info->is_undoredo = FALSE;
 
 	sync_transfer_info = g_new (SyncTransferInfo, 1);
 	sync_transfer_info->iterator = icon_position_iterator;
 	sync_transfer_info->debuting_uris = transfer_info->debuting_uris;
+	sync_transfer_info->affected_uris = transfer_info->affected_uris;
 
 	transfer_info->iterator = sync_transfer_info->iterator;
 
@@ -2281,7 +2334,7 @@ nautilus_file_operations_copy_move (cons
 		gnome_vfs_uri_unref (trash_dir_uri);
 	}
 	gnome_vfs_uri_unref (target_dir_uri);
-}
+}	
 
 typedef struct {
 	GnomeVFSAsyncHandle *handle;
@@ -2289,6 +2342,7 @@ typedef struct {
 	gpointer data;
 	GtkWidget *parent_view;
 	IconPositionIterator *iterator;
+	gboolean is_undoredo;
 } NewFolderTransferState;
 
 static int
@@ -2342,6 +2396,17 @@ new_folder_transfer_callback (GnomeVFSAs
 			new_uri = NULL;
 			if (progress_info->vfs_status == GNOME_VFS_OK) {
 				new_uri = progress_info->target_name;
+				/* Undo: Construct undo object */
+				if (!state->is_undoredo) {
+					GHashTable* affected_uri = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free);
+					gchar* folder_uri = g_strdup (new_uri);
+					g_hash_table_insert (affected_uri, folder_uri, folder_uri);
+					NautilusUndoStackManager* manager = nautilus_undostack_manager_instance ();
+					NautilusUndoStackAction* action = nautilus_undostack_manager_new_action (NAUTILUS_UNDOSTACK_CREATEFOLDER);
+					nautilus_undostack_manager_set_affected_uris (action, affected_uri);
+					nautilus_undostack_manager_add_action (manager, action);
+				}
+				/* Done */
 			}
 			(* state->done_callback) (new_uri,
 						  state->data);
@@ -2432,6 +2497,7 @@ nautilus_file_operations_new_folder (Gtk
 		 gdk_screen_get_number (gtk_widget_get_screen (parent_view)),
 		 FALSE);
 	sync_transfer_info->debuting_uris = NULL;
+	sync_transfer_info->affected_uris = NULL;
 
 	g_free (text_uri);
 
@@ -2440,6 +2506,7 @@ nautilus_file_operations_new_folder (Gtk
 	state->data = data;
 	state->parent_view = parent_view;
 	state->iterator = sync_transfer_info->iterator;
+	state->is_undoredo = FALSE;
 	eel_add_weak_pointer (&state->parent_view);
 
 	gnome_vfs_async_xfer (&state->handle, NULL, target_uri_list,
@@ -2461,6 +2528,9 @@ typedef struct {
 	GtkWidget *parent_view;
 	GHashTable *debuting_uris;
 	IconPositionIterator *iterator;
+	gboolean is_undoredo;
+	gboolean is_new_empty_file;
+	gchar* template;
 } NewFileTransferState;
 
 
@@ -2525,6 +2595,25 @@ new_file_transfer_callback (GnomeVFSAsyn
 		g_hash_table_foreach (state->debuting_uris,
 				      get_new_file_uri, &uri);
 
+		/* Undo: Construct undo object */
+		if (!state->is_undoredo) {
+			GHashTable* affected_uri = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free);
+			gchar* new_uri = g_strdup (uri);
+			NautilusUndoStackAction* action = NULL;
+			NautilusUndoStackManager* manager = nautilus_undostack_manager_instance ();
+			if (state->is_new_empty_file) {
+				g_hash_table_insert (affected_uri, new_uri, new_uri);
+				action = nautilus_undostack_manager_new_action (NAUTILUS_UNDOSTACK_CREATEEMPTYFILE);
+				g_free (state->template);
+			} else {
+				g_hash_table_insert (affected_uri, new_uri, state->template);
+				action = nautilus_undostack_manager_new_action (NAUTILUS_UNDOSTACK_CREATEFILEFROMTEMPLATE);
+			}
+			nautilus_undostack_manager_set_affected_uris (action, affected_uri);
+			nautilus_undostack_manager_add_action (manager, action);
+		}
+		/* Done */
+		
 		(* state->done_callback) (uri, state->data);
 		/* uri is owned by hashtable, don't free */
 		eel_remove_weak_pointer (&state->parent_view);
@@ -2585,14 +2674,16 @@ new_file_transfer_callback (GnomeVFSAsyn
 	}
 }
 
-void 
-nautilus_file_operations_new_file_from_template (GtkWidget *parent_view, 
+static void 
+internal_file_operation_new_file_from_template (GtkWidget *parent_view, 
 						 GdkPoint *target_point,
 						 const char *parent_dir,
 						 const char *target_filename,
 						 const char *template_uri,
 						 NautilusNewFileCallback done_callback,
-						 gpointer data)
+						 gpointer data,
+						 gboolean is_undoredo,
+						 gboolean is_new_empty_file)
 {
 	GList *target_uri_list;
 	GList *source_uri_list;
@@ -2646,6 +2737,7 @@ nautilus_file_operations_new_file_from_t
 		 gdk_screen_get_number (gtk_widget_get_screen (parent_view)),
 		 TRUE);
 	sync_transfer_info->debuting_uris = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
+	sync_transfer_info->affected_uris = NULL;
 
 	state = g_new (NewFileTransferState, 1);
 	state->done_callback = done_callback;
@@ -2653,6 +2745,9 @@ nautilus_file_operations_new_file_from_t
 	state->parent_view = parent_view;
 	state->iterator = sync_transfer_info->iterator;
 	state->debuting_uris = sync_transfer_info->debuting_uris;
+	state->is_undoredo = is_undoredo;
+	state->is_new_empty_file = is_new_empty_file;
+	state->template = g_strdup (template_uri);
 	eel_add_weak_pointer (&state->parent_view);
 
 	target_uri_list = g_list_prepend (NULL, target_uri);
@@ -2697,13 +2792,14 @@ new_file_from_temp_callback (const char 
 }
 
 
-void 
-nautilus_file_operations_new_file (GtkWidget *parent_view, 
+static void 
+internal_file_operation_new_file (GtkWidget *parent_view, 
 				   GdkPoint *target_point,
 				   const char *parent_dir,
 				   const char *initial_contents,
 				   NautilusNewFileCallback done_callback,
-				   gpointer data)
+				   gpointer data,
+				   gboolean is_undoredo)
 {
 	struct NewFileData *new_data;
 	char source_file_str[] = "/tmp/nautilus-sourceXXXXXX";
@@ -2740,13 +2836,15 @@ nautilus_file_operations_new_file (GtkWi
 	new_data->done_callback = done_callback;
 	new_data->callback_data = data;
 	
-	nautilus_file_operations_new_file_from_template (parent_view, 
+	internal_file_operation_new_file_from_template (parent_view, 
 							 target_point,
 							 parent_dir,
 							 target_filename,
 							 source_file_uri,
 							 new_file_from_temp_callback,
-							 new_data);
+							 new_data,
+							 is_undoredo,
+							 TRUE);
 
 	g_free (source_file_uri);
 	g_free (target_filename);
@@ -2817,6 +2915,8 @@ nautilus_file_operations_delete (const G
 	transfer_info->done_callback = done_callback;
 	transfer_info->done_callback_data = done_callback_data;
 	transfer_info->debuting_uris = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
+	transfer_info->affected_uris = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free);
+	transfer_info->is_undoredo = FALSE;
 
 	gnome_vfs_async_xfer (&transfer_info->handle, uri_list,  NULL,
 	      		      GNOME_VFS_XFER_DELETE_ITEMS | GNOME_VFS_XFER_RECURSIVE,
@@ -2840,6 +2940,7 @@ do_empty_trash (GtkWidget *parent_view)
 
 	trash_dir_list = nautilus_trash_monitor_get_trash_directories ();
 	if (trash_dir_list != NULL) {
+		
 		/* set up the move parameters */
 		transfer_info = transfer_info_new (parent_view);
 
@@ -2861,7 +2962,7 @@ do_empty_trash (GtkWidget *parent_view)
 		      		      GNOME_VFS_XFER_OVERWRITE_MODE_REPLACE,
 				      GNOME_VFS_PRIORITY_DEFAULT,
 		      		      update_transfer_callback, transfer_info,
-		      		      sync_transfer_callback, NULL);
+		      		      sync_transfer_callback, NULL);			      		      
 	}
 
 	gnome_vfs_uri_list_free (trash_dir_list);
@@ -3458,3 +3559,397 @@ nautilus_self_check_file_operations (voi
 }
 
 #endif
+
+void
+nautilus_file_operations_undo_copy_move (const GList *source_list,
+				    const GList *target_list,
+				    GdkDragAction copy_action,
+				    GtkWidget *parent_view,
+				    void (*done_callback) (GHashTable *debuting_uris, gpointer data),
+				    gpointer done_callback_data)
+{
+	GList *source_uri_list = NULL;
+	GList *target_uri_list = NULL;
+	const GList *s, *t;
+	GnomeVFSURI *source_uri, *source_dir_uri, *target_uri, *target_dir_uri;
+	GnomeVFSXferOptions move_options;
+	gchar* target_dir;
+	gboolean target_is_trash;
+	gboolean target_is_mapping;
+	gboolean have_nonlocal_source;
+	gboolean have_nonmapping_source;
+	gboolean duplicate;
+	GnomeVFSResult result;
+	TransferInfo *transfer_info;
+	SyncTransferInfo *sync_transfer_info;
+
+	result = GNOME_VFS_OK;
+
+	target_is_trash = FALSE;
+	target_is_mapping = FALSE;
+
+	g_assert (source_list != NULL);
+	
+	/* Check if target is the trash */
+	target_dir_uri = gnome_vfs_uri_new ((char *) g_list_first ((GList*) target_list));
+	target_dir = gnome_vfs_uri_extract_dirname (target_dir_uri);
+	
+	if (eel_uri_is_trash (target_dir)) {
+		target_is_trash = TRUE;
+	}
+	
+	g_free (target_dir);
+	gnome_vfs_uri_unref (target_dir_uri);	
+
+	target_dir_uri = NULL;
+	duplicate = copy_action != GDK_ACTION_MOVE;
+
+	for (s = source_list, t = target_list; s != NULL; s = s->next, t = t->next) {
+
+		source_uri = gnome_vfs_uri_new ((const char *) s->data);
+		target_uri = gnome_vfs_uri_new ((const char *) t->data);
+		
+		source_dir_uri = gnome_vfs_uri_get_parent (source_uri);
+		target_dir_uri = gnome_vfs_uri_get_parent (target_uri);
+
+		if (strcmp (source_uri->method_string, "file") != 0) {
+			have_nonlocal_source = TRUE;
+		}
+
+		if (strcmp (source_uri->method_string, "burn") != 0) {
+			have_nonmapping_source = TRUE;
+		}
+
+		if (strcmp (target_uri->method_string, "burn") == 0) {
+			target_is_mapping = TRUE;
+		}
+
+		if (source_uri == NULL) {
+			continue;
+		}
+		
+		target_uri_list = g_list_prepend (target_uri_list, target_uri);
+		source_uri_list = g_list_prepend (source_uri_list, source_uri);
+		
+		if (duplicate && source_dir_uri != NULL &&
+			    !gnome_vfs_uri_equal (source_dir_uri, target_dir_uri)) {
+				duplicate = FALSE;
+			}
+			
+		if (source_dir_uri != NULL) {
+			gnome_vfs_uri_unref (source_dir_uri);
+		}	
+		
+		if (target_dir_uri != NULL) {
+			gnome_vfs_uri_unref (target_dir_uri);
+		}			
+	}
+
+	move_options = GNOME_VFS_XFER_RECURSIVE;
+	
+	source_uri_list = g_list_reverse (source_uri_list);
+	target_uri_list = g_list_reverse (target_uri_list);
+
+	if (target_is_mapping && have_nonmapping_source && !have_nonlocal_source && (copy_action == GDK_ACTION_COPY || copy_action == GDK_ACTION_MOVE)) {
+		copy_action = GDK_ACTION_LINK;
+	}
+	if (copy_action == GDK_ACTION_MOVE && (!target_is_mapping || !have_nonmapping_source)) {
+		move_options |= GNOME_VFS_XFER_REMOVESOURCE;
+	} else if (copy_action == GDK_ACTION_LINK) {
+		move_options |= GNOME_VFS_XFER_LINK_ITEMS;
+	}
+	
+	/* set up the copy/move parameters */
+	transfer_info = transfer_info_new (parent_view);
+	
+	if (target_is_trash && (move_options & GNOME_VFS_XFER_REMOVESOURCE) != 0) {
+		/* when moving to trash, handle name conflicts automatically */
+		move_options |= GNOME_VFS_XFER_USE_UNIQUE_NAMES;
+		/* localizers: progress dialog title */
+		transfer_info->operation_title = _("Moving files to the Trash");
+		/* localizers: label prepended to the progress count */
+		transfer_info->action_label =_("Throwing out file:");
+		/* localizers: label prepended to the name of the current file moved */
+		transfer_info->progress_verb =_("Moving");
+		transfer_info->preparation_name =_("Preparing to Move to Trash...");
+
+		transfer_info->kind = TRANSFER_MOVE_TO_TRASH;
+
+	} else if ((move_options & GNOME_VFS_XFER_REMOVESOURCE) != 0) {
+		/* localizers: progress dialog title */
+		transfer_info->operation_title = _("Moving files");
+		/* localizers: label prepended to the progress count */
+		transfer_info->action_label =_("Moving file:");
+		/* localizers: label prepended to the name of the current file moved */
+		transfer_info->progress_verb =_("Moving");
+		transfer_info->preparation_name =_("Preparing To Move...");
+		transfer_info->cleanup_name = _("Finishing Move...");
+
+		transfer_info->kind = TRANSFER_MOVE;
+
+	} else if ((move_options & GNOME_VFS_XFER_LINK_ITEMS) != 0) {
+		/* when creating links, handle name conflicts automatically */
+		move_options |= GNOME_VFS_XFER_USE_UNIQUE_NAMES;
+		/* localizers: progress dialog title */
+		transfer_info->operation_title = _("Creating links to files");
+		/* localizers: label prepended to the progress count */
+		transfer_info->action_label =_("Linking file:");
+		/* localizers: label prepended to the name of the current file linked */
+		transfer_info->progress_verb =_("Linking");
+		transfer_info->preparation_name = _("Preparing to Create Links...");
+		transfer_info->cleanup_name = _("Finishing Creating Links...");
+
+		transfer_info->kind = TRANSFER_LINK;
+
+	} else {
+		/* localizers: progress dialog title */
+		transfer_info->operation_title = _("Copying files");
+		/* localizers: label prepended to the progress count */
+		transfer_info->action_label =_("Copying file:");
+		/* localizers: label prepended to the name of the current file copied */
+		transfer_info->progress_verb =_("Copying");
+		transfer_info->preparation_name =_("Preparing To Copy...");
+		transfer_info->cleanup_name = "";
+
+		transfer_info->kind = TRANSFER_COPY;
+	}
+
+	transfer_info->error_mode = GNOME_VFS_XFER_ERROR_MODE_QUERY;
+	transfer_info->overwrite_mode = GNOME_VFS_XFER_OVERWRITE_MODE_QUERY;
+	transfer_info->done_callback = done_callback;
+	transfer_info->done_callback_data = done_callback_data;
+	transfer_info->debuting_uris = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
+	transfer_info->affected_uris = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free);
+	transfer_info->is_undoredo = TRUE;
+
+	sync_transfer_info = g_new (SyncTransferInfo, 1);
+	sync_transfer_info->iterator = NULL;
+	sync_transfer_info->debuting_uris = transfer_info->debuting_uris;
+	sync_transfer_info->affected_uris = transfer_info->affected_uris;
+
+	transfer_info->iterator = sync_transfer_info->iterator;
+
+	if (result == GNOME_VFS_OK) {
+		gnome_vfs_async_xfer (&transfer_info->handle, source_uri_list, target_uri_list,
+		      		      move_options, GNOME_VFS_XFER_ERROR_MODE_QUERY, 
+		      		      GNOME_VFS_XFER_OVERWRITE_MODE_QUERY,
+				      GNOME_VFS_PRIORITY_DEFAULT,
+		      		      update_transfer_callback, transfer_info,
+		      		      sync_transfer_callback, sync_transfer_info);
+	}
+
+	gnome_vfs_uri_list_free (source_uri_list);
+	gnome_vfs_uri_list_free (target_uri_list);
+}
+
+void 
+nautilus_file_operations_undo_delete (const GList *item_uris, 
+				 GtkWidget *parent_view,
+				 NautilusDeleteCallback done_callback, 
+				 gpointer done_callback_data)
+{
+	GList *uri_list;
+	const GList *p;
+	const char *item_uri;
+	NautilusFile *file;
+	TransferInfo *transfer_info;
+
+	nautilus_debug_log_with_uri_list (FALSE, NAUTILUS_DEBUG_LOG_DOMAIN_USER, item_uris,
+					  "delete files:");
+
+	uri_list = NULL;
+	for (p = item_uris; p != NULL; p = p->next) {
+		item_uri = (const char *) p->data;
+
+		if (eel_uri_is_desktop (item_uri)) {
+			file = nautilus_file_get_existing (item_uri);
+			if (file != NULL) {
+				if (NAUTILUS_IS_DESKTOP_ICON_FILE (file)) {
+					NautilusDesktopLink *link;
+
+					link = nautilus_desktop_icon_file_get_link (NAUTILUS_DESKTOP_ICON_FILE (file));
+
+					if (link != NULL) {
+						nautilus_desktop_link_monitor_delete_link (nautilus_desktop_link_monitor_get (),
+											   link,
+											   parent_view);
+						g_object_unref (link);
+					}
+				}
+				nautilus_file_unref (file);
+			}
+		} else {
+			uri_list = g_list_prepend (uri_list, 
+						   gnome_vfs_uri_new (item_uri));
+		}
+	}
+	uri_list = g_list_reverse (uri_list);
+
+	if (uri_list == NULL) {
+		return;
+	}
+
+	transfer_info = transfer_info_new (parent_view);
+
+	/* localizers: progress dialog title */
+	transfer_info->operation_title = _("Deleting files");
+	/* localizers: label prepended to the progress count */
+	transfer_info->action_label =_("Files deleted:");
+	/* localizers: label prepended to the name of the current file deleted */
+	transfer_info->progress_verb =_("Deleting");
+	transfer_info->preparation_name =_("Preparing to Delete files...");
+	transfer_info->cleanup_name ="";
+
+	transfer_info->error_mode = GNOME_VFS_XFER_ERROR_MODE_QUERY;
+	transfer_info->overwrite_mode = GNOME_VFS_XFER_OVERWRITE_MODE_REPLACE;
+	transfer_info->kind = TRANSFER_DELETE;
+	transfer_info->is_undoredo = TRUE;
+	
+	transfer_info->done_callback = done_callback;
+	transfer_info->done_callback_data = done_callback_data;
+	transfer_info->debuting_uris = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
+	transfer_info->affected_uris = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free);
+
+	gnome_vfs_async_xfer (&transfer_info->handle, uri_list,  NULL,
+	      		      GNOME_VFS_XFER_DELETE_ITEMS | GNOME_VFS_XFER_RECURSIVE,
+	      		      GNOME_VFS_XFER_ERROR_MODE_QUERY, 
+	      		      GNOME_VFS_XFER_OVERWRITE_MODE_REPLACE,
+			      GNOME_VFS_PRIORITY_DEFAULT,
+	      		      update_transfer_callback, transfer_info,
+	      		      sync_transfer_callback, NULL);
+
+	gnome_vfs_uri_list_free (uri_list);
+}
+
+void 
+nautilus_file_operations_undo_new_folder (GtkWidget *parent_view, 
+				     GdkPoint *target_point,
+				     const char *folder_uri,
+				     NautilusNewFolderCallback done_callback,
+				     gpointer data)
+{
+	GList *target_uri_list;
+	GnomeVFSURI *uri;
+	char *text_uri;
+	NewFolderTransferState *state;
+	SyncTransferInfo *sync_transfer_info;
+
+	g_assert (folder_uri != NULL);
+
+	uri = gnome_vfs_uri_new (folder_uri);
+
+	target_uri_list = g_list_prepend (NULL, uri);
+
+	text_uri = gnome_vfs_uri_to_string (uri, GNOME_VFS_URI_HIDE_NONE);
+
+	sync_transfer_info = g_new (SyncTransferInfo, 1);
+	sync_transfer_info->iterator = icon_position_iterator_new_single
+		(target_point, text_uri,
+		 gdk_screen_get_number (gtk_widget_get_screen (parent_view)),
+		 FALSE);
+	sync_transfer_info->debuting_uris = NULL;
+	sync_transfer_info->affected_uris = NULL;
+
+	g_free (text_uri);
+
+	state = g_new (NewFolderTransferState, 1);
+	state->done_callback = done_callback;
+	state->data = data;
+	state->parent_view = parent_view;
+	state->iterator = sync_transfer_info->iterator;
+	state->is_undoredo = TRUE;
+	eel_add_weak_pointer (&state->parent_view);
+
+	gnome_vfs_async_xfer (&state->handle, NULL, target_uri_list,
+	      		      GNOME_VFS_XFER_NEW_UNIQUE_DIRECTORY,
+	      		      GNOME_VFS_XFER_ERROR_MODE_QUERY, 
+	      		      GNOME_VFS_XFER_OVERWRITE_MODE_QUERY,
+			      GNOME_VFS_PRIORITY_DEFAULT,
+	      		      new_folder_transfer_callback, state,
+	      		      sync_transfer_callback, sync_transfer_info);
+
+	gnome_vfs_uri_list_free (target_uri_list);
+}
+
+
+void 
+nautilus_file_operations_new_file_from_template (GtkWidget *parent_view, 
+						 GdkPoint *target_point,
+						 const char *parent_dir,
+						 const char *target_filename,
+						 const char *template_uri,
+						 NautilusNewFileCallback done_callback,
+						 gpointer data)
+{
+	/* This is part of an ugly hack... to distinguish between new empty file
+	 * and new file from template
+	 */
+	internal_file_operation_new_file_from_template (parent_view,
+							target_point,
+							parent_dir,
+							target_filename,
+							template_uri,
+							done_callback,
+							data,
+							FALSE,
+							FALSE);
+}
+
+void 
+nautilus_file_operations_undo_new_file_from_template (GtkWidget *parent_view, 
+						 GdkPoint *target_point,
+						 const char *parent_dir,
+						 const char *target_filename,
+						 const char *template_uri,
+						 NautilusNewFileCallback done_callback,
+						 gpointer data)
+{
+	internal_file_operation_new_file_from_template (parent_view,
+							target_point,
+							parent_dir,
+							target_filename,
+							template_uri,
+							done_callback,
+							data,
+							TRUE,
+							FALSE);
+}
+
+void 
+nautilus_file_operations_new_file (GtkWidget *parent_view, 
+				   GdkPoint *target_point,
+				   const char *parent_dir,
+				   const char *initial_contents,
+				   NautilusNewFileCallback done_callback,
+				   gpointer data)
+{
+	internal_file_operation_new_file (parent_view,
+							target_point,
+							parent_dir,
+							initial_contents,
+							done_callback,
+							data,
+							FALSE);
+}
+
+
+void 
+nautilus_file_operations_undo_new_file (GtkWidget *parent_view, 
+				   GdkPoint *target_point,
+				   const char *parent_dir,
+				   const char *initial_contents,
+				   NautilusNewFileCallback done_callback,
+				   gpointer data)
+{
+	internal_file_operation_new_file (parent_view,
+							target_point,
+							parent_dir,
+							initial_contents,
+							done_callback,
+							data,
+							TRUE);
+}
+
+						 
+
+
diff -rupN nautilus-2.20.0-orig/libnautilus-private/nautilus-file-operations.h nautilus-2.20.0-undo/libnautilus-private/nautilus-file-operations.h
--- nautilus-2.20.0-orig/libnautilus-private/nautilus-file-operations.h	2007-04-03 12:08:46.000000000 +0200
+++ nautilus-2.20.0-undo/libnautilus-private/nautilus-file-operations.h	2007-10-24 17:25:37.000000000 +0200
@@ -32,6 +32,7 @@
 #include <libgnomevfs/gnome-vfs-types.h>
 #include <libgnomevfs/gnome-vfs-utils.h>
 #include <libgnomevfs/gnome-vfs-volume-monitor.h>
+#include "nautilus-undostack-manager.h"
 
 typedef void (* NautilusCopyCallback)      (GHashTable *debuting_uris,
 					    gpointer    callback_data);
@@ -51,19 +52,23 @@ void nautilus_file_operations_copy_move 
 					   GdkDragAction              copy_action,
 					   GtkWidget                 *parent_view,
 					   NautilusCopyCallback       done_callback,
-					   gpointer                   done_callback_data);
+					   gpointer                   done_callback_data);				     					   		   
+
 void nautilus_file_operations_empty_trash (GtkWidget                 *parent_view);
+
 void nautilus_file_operations_new_folder  (GtkWidget                 *parent_view,
 					   GdkPoint                  *target_point,
 					   const char                *parent_dir_uri,
 					   NautilusNewFolderCallback  done_callback,
 					   gpointer                   done_callback_data);
+
 void nautilus_file_operations_new_file    (GtkWidget                 *parent_view,
 					   GdkPoint                  *target_point,
 					   const char                *parent_dir,
 					   const char                *initial_contents,
 					   NautilusNewFileCallback    done_callback,
 					   gpointer                   data);
+
 void nautilus_file_operations_new_file_from_template (GtkWidget               *parent_view,
 					   	      GdkPoint                *target_point,
 						      const char              *parent_dir,
@@ -75,8 +80,8 @@ void nautilus_file_operations_new_file_f
 void nautilus_file_operations_delete      (const GList               *item_uris,
 					   GtkWidget                 *parent_view,
 					   NautilusDeleteCallback done_callback,
-					   gpointer done_callback_data);
-
+					   gpointer done_callback_data);					   
+					   
 void nautilus_file_set_permissions_recursive (const char                     *directory,
 					      GnomeVFSFilePermissions         file_permissions,
 					      GnomeVFSFilePermissions         file_mask,
@@ -93,6 +98,44 @@ void nautilus_file_operations_unmount_vo
 void nautilus_file_operations_unmount_drive (GtkWidget 						 *parent_view,
 								GnomeVFSDrive *drive, 
 								GnomeVFSVolumeOpCallback callback,
-								gpointer user_data);								
+								gpointer user_data);
+								
+void nautilus_file_operations_undo_copy_move (const GList *source_list,
+				    const GList *target_list,
+				    GdkDragAction copy_action,
+				    GtkWidget *parent_view,
+				    void (*done_callback) (GHashTable *debuting_uris, gpointer data),
+				    gpointer done_callback_data);		
+				    
+void nautilus_file_operations_undo_delete (const GList *item_uris, 
+				 GtkWidget *parent_view,
+				 NautilusDeleteCallback done_callback, 
+				 gpointer done_callback_data);
+				 
+void 
+nautilus_file_operations_undo_new_folder (GtkWidget *parent_view, 
+				     GdkPoint *target_point,
+				     const char *folder_uri,
+				     NautilusNewFolderCallback done_callback,
+				     gpointer data);
+				     
+void 
+nautilus_file_operations_undo_new_file (GtkWidget *parent_view, 
+				   GdkPoint *target_point,
+				   const char *parent_dir,
+				   const char *initial_contents,
+				   NautilusNewFileCallback done_callback,
+				   gpointer data);
+				   
+void 
+nautilus_file_operations_undo_new_file_from_template (GtkWidget *parent_view, 
+						 GdkPoint *target_point,
+						 const char *parent_dir,
+						 const char *target_filename,
+						 const char *template_uri,
+						 NautilusNewFileCallback done_callback,
+						 gpointer data);				   
+				   
+				   				     
 
 #endif /* NAUTILUS_FILE_OPERATIONS_H */
diff -rupN nautilus-2.20.0-orig/libnautilus-private/nautilus-undostack-manager.c nautilus-2.20.0-undo/libnautilus-private/nautilus-undostack-manager.c
--- nautilus-2.20.0-orig/libnautilus-private/nautilus-undostack-manager.c	1970-01-01 01:00:00.000000000 +0100
+++ nautilus-2.20.0-undo/libnautilus-private/nautilus-undostack-manager.c	2007-10-24 17:52:33.000000000 +0200
@@ -0,0 +1,1231 @@
+/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
+
+/* NautilusUndoStackManager - Manages undo of file operations (implementation)                  
+ *
+ * Copyright (C) 2007 Amos Brocco
+ *
+ * Author: Amos Brocco <amos.brocco@unifr.ch>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#include "nautilus-undostack-manager.h"
+#include "nautilus-file-operations.h"
+#include "nautilus-file.h"
+#include <glib/gprintf.h>
+#include <glib-object.h>
+#include <glib/gi18n.h>
+#include <locale.h>
+#include <gdk/gdk.h>
+#include <libgnomevfs/gnome-vfs.h>
+#include <libgnomevfs/gnome-vfs-utils.h>
+
+/* How the stack works:
+
+                  Index
+                    v
+	Head ----> |*|*|*|*|*|*|*|*|*|*|*|*|*|*|*|*|*|*|*|*|*|
+
+	Most Recent Action -----------------------------Oldest Action
+
+	Actions are structure that contain some information used by the manager and
+	an Hashtable that maps target-uris to source-uris.
+
+	The stack is implemented as a queue. New actions are pushed on the left.
+	The index variable indicates the action that will undoed when requested to.
+	At the beginning index is at position 0 (index = 0 also means that no-redo is possible).
+
+	When an action is undone, the index pointer is shifted one position to the right.
+	When an action is redone, the index pointer is shifted one position to the left.
+
+	When a new action is pushed on the stack, all the actions from the head of the stack
+	till the index position (i.e. actions that could have been redone) are cleared, and 
+	index is shifted back to 0. The new action is then added to the head (left) of the stack
+	(this behavior follows what I found in other apps, such as gedit: redo is cleared when
+	the user performs a new operation/edit)
+
+	The size of the stack is limited. When such limit is reached, the oldest action is 
+	removed from the history.
+
+	Example of the behavior (v indicates the index position):
+
+	-- Initial situation: 4 actions can be undone A, B, C, and D
+     v
+    |A|B|C|D|
+	-- Undo A:
+       v
+    |A|B|C|D|
+	-- Undo B:
+         v
+    |A|B|C|D|
+	-- Redo B:
+       v
+    |A|B|C|D|
+	-- Action X is added:
+	 v
+    |X|B|C|D|	
+	
+	The stack is protected using a mutex because actions can be added asynchronously, 
+	when (asynchronous) transfers are finished. In those situations, we must avoid that
+	actions	are added to the history while an user is requesting an undo/redo. 
+	 
+	Updates for the UI are pushed by mean of signals:
+	
+	"undo-label-changed" STRING : Sends the new label that should be shown as undo in the menu
+	
+	"undo-description-changed" STRING : Sends the new tooltip that should be shown for undo
+	
+	"redo-label-changed" STRING : Sends the new label that should be shown as redo in the menu
+	
+	"redo-description-changed" STRING : Sends the new tooltip that should be shown for redo
+	
+	"undo-availability-changed" BOOLEAN : Informs if the undo is available
+	
+	"redo-availability-changed" BOOLEAN : Informs if the redo is available
+	 
+	"status-update-finished" : Sent when menu updates are to be committed
+	 
+	The UI can force an update by sending a "request-menu-update" to the undostack manager.
+	
+*/
+	
+
+/* Private fields */
+
+struct _NautilusUndoStackAction {
+	NautilusUndoStackActionType	type;
+	GHashTable* affected_uris; /* Keys: target uris, Values: source uris */
+	gboolean locked; /* True if the action is being undone/redone */
+	gboolean freed; /* True if the action must be freed after undo/redo */
+	guint count; /* Size of affected uris (count of items) */
+	NautilusFile* file; /* Pointer used by rename */
+};
+
+struct _NautilusUndoStackManagerPrivate {
+	/* Private fields */
+	GQueue*		stack;
+	guint		undo_levels;
+	guint		index;
+	GMutex*		mutex; 		/* Used to protect access to stack (because of async file ops) */
+	gboolean 	dispose_has_run;
+};
+
+#define NAUTILUS_UNDOSTACK_MANAGER_GET_PRIVATE(o)  \
+   (G_TYPE_INSTANCE_GET_PRIVATE ((o), TYPE_NAUTILUS_UNDOSTACK_MANAGER, NautilusUndoStackManagerPrivate))
+   
+/* Properties */
+
+enum { PROP_UNDOSTACK_MANAGER_0, PROP_UNDO_LEVELS };
+
+static void nautilus_undostack_manager_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec);
+
+static void nautilus_undostack_manager_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec); 
+   
+/* UndoStack Manager destructors prototypes */
+
+static void nautilus_undostack_manager_finalize (GObject* object);
+
+static void nautilus_undostack_manager_dispose (GObject* object);
+
+/* Other prototypes */
+
+static void stack_clear_n_oldest (GQueue* stack, guint n);
+
+static void stack_fix_size (NautilusUndoStackManagerPrivate* priv);
+
+static gboolean can_undo (NautilusUndoStackManagerPrivate* priv);
+
+static gboolean can_redo (NautilusUndoStackManagerPrivate* priv);
+
+static void stack_push_action (NautilusUndoStackManagerPrivate* priv, NautilusUndoStackAction* action);
+
+static NautilusUndoStackAction* stack_scroll_left (NautilusUndoStackManagerPrivate* priv);
+
+static NautilusUndoStackAction* stack_scroll_right (NautilusUndoStackManagerPrivate* priv);
+
+static NautilusUndoStackAction* get_next_redo_action (NautilusUndoStackManagerPrivate* priv);
+
+static NautilusUndoStackAction* get_next_undo_action (NautilusUndoStackManagerPrivate* priv);
+
+static gchar* get_undo_label (NautilusUndoStackAction* action);
+
+static gchar* get_undo_description (NautilusUndoStackAction* action);
+
+static gchar* get_redo_label (NautilusUndoStackAction* action);
+
+static gchar* get_redo_description (NautilusUndoStackAction* action);
+
+static void notify_undo_status (NautilusUndoStackManager* manager, NautilusUndoStackAction* action);
+
+static void notify_redo_status (NautilusUndoStackManager* manager, NautilusUndoStackAction* action);
+
+static void free_undostack_action (gpointer data, gpointer user_data);
+
+static void undostack_dispose_all (GQueue *queue);
+
+static void undo_redo_done_transfer_callback (GHashTable *debuting_uris, gpointer data);
+
+static void undo_rename_callback (NautilusFile *file, GnomeVFSResult result, gpointer data);
+
+static void nautilus_undostack_manager_request_menu_update (NautilusUndoStackManager* manager);
+
+static void notify_status_update_finished (NautilusUndoStackManager* manager);
+
+static void clear_redo_actions (NautilusUndoStackManagerPrivate* priv);
+
+static void undo_new_folder_callback (const char *new_folder_uri, gpointer callback_data);
+
+/* Type definition */
+
+G_DEFINE_TYPE (NautilusUndoStackManager, nautilus_undostack_manager, G_TYPE_OBJECT);
+
+/* Base functions */
+
+static void
+nautilus_undostack_manager_class_init (NautilusUndoStackManagerClass* klass)
+{
+	GParamSpec	*undo_levels;
+	GObjectClass	*g_object_class;
+	
+	/* Add private structure */
+	g_type_class_add_private (klass, sizeof (NautilusUndoStackManagerPrivate));
+	
+	/* Create properties */
+	undo_levels = g_param_spec_uint ("undo-levels",
+					"undo levels",
+					"Number of undo levels to be stored",
+					1,
+					UINT_MAX,
+					30,
+					G_PARAM_READWRITE|G_PARAM_CONSTRUCT);
+		
+	/* Set properties get/set methods */					
+	g_object_class = G_OBJECT_CLASS(klass);					
+					
+	g_object_class->set_property = nautilus_undostack_manager_set_property;
+	g_object_class->get_property = nautilus_undostack_manager_get_property;
+	
+	/* Install properties */
+	g_object_class_install_property (g_object_class,
+					PROP_UNDO_LEVELS,
+					undo_levels);	
+					
+	/* Declare signals that can be emitted.... use separate signals for description 
+	 * and label... didn't want to add more code just for a custom marshaller */
+	
+	klass->request_menu_update = nautilus_undostack_manager_request_menu_update;
+	
+	klass->undo_label_changed_id = g_signal_new ("undo-label-changed",
+                 G_TYPE_FROM_CLASS (klass),
+                 G_SIGNAL_RUN_LAST | G_SIGNAL_NO_RECURSE | G_SIGNAL_NO_HOOKS,
+                 0,
+                 NULL,
+                 NULL,
+                 g_cclosure_marshal_VOID__STRING,
+                 G_TYPE_NONE,
+                 1,
+                 G_TYPE_STRING);
+                 
+	klass->undo_description_changed_id = g_signal_new ("undo-description-changed",
+                 G_TYPE_FROM_CLASS (klass),
+                 G_SIGNAL_RUN_LAST | G_SIGNAL_NO_RECURSE | G_SIGNAL_NO_HOOKS,
+                 0,
+                 NULL,
+                 NULL,
+                 g_cclosure_marshal_VOID__STRING,
+                 G_TYPE_NONE,
+                 1,
+                 G_TYPE_STRING);                 
+                 
+	klass->undo_availability_changed_id = g_signal_new ("undo-availability-changed",
+                 G_TYPE_FROM_CLASS (klass),
+                 G_SIGNAL_RUN_LAST | G_SIGNAL_NO_RECURSE | G_SIGNAL_NO_HOOKS,
+                 0,
+                 NULL,
+                 NULL,
+                 g_cclosure_marshal_VOID__BOOLEAN,
+                 G_TYPE_NONE ,
+                 1,
+                 G_TYPE_BOOLEAN);                 
+                 
+	klass->redo_label_changed_id = g_signal_new ("redo-label-changed",
+                 G_TYPE_FROM_CLASS (klass),
+                 G_SIGNAL_RUN_LAST | G_SIGNAL_NO_RECURSE | G_SIGNAL_NO_HOOKS,
+                 0,
+                 NULL,
+                 NULL,
+                 g_cclosure_marshal_VOID__STRING,
+                 G_TYPE_NONE,
+                 1,
+                 G_TYPE_STRING);
+                 
+	klass->redo_description_changed_id = g_signal_new ("redo-description-changed",
+                 G_TYPE_FROM_CLASS (klass),
+                 G_SIGNAL_RUN_LAST | G_SIGNAL_NO_RECURSE | G_SIGNAL_NO_HOOKS,
+                 0,
+                 NULL,
+                 NULL,
+                 g_cclosure_marshal_VOID__STRING,
+                 G_TYPE_NONE,
+                 1,
+                 G_TYPE_STRING);                  
+                 
+	klass->redo_availability_changed_id = g_signal_new ("redo-availability-changed",
+                 G_TYPE_FROM_CLASS (klass),
+                 G_SIGNAL_RUN_LAST | G_SIGNAL_NO_RECURSE | G_SIGNAL_NO_HOOKS,
+                 0,
+                 NULL,
+                 NULL,
+                 g_cclosure_marshal_VOID__BOOLEAN,
+                 G_TYPE_NONE,
+                 1,
+                 G_TYPE_BOOLEAN);
+
+	/* Emitted to ask the listener to update the menu */
+	klass->status_update_finished_id = g_signal_new ("status-update-finished",
+                 G_TYPE_FROM_CLASS (klass),
+                 G_SIGNAL_RUN_LAST | G_SIGNAL_NO_RECURSE | G_SIGNAL_NO_HOOKS,
+                 0,
+                 NULL,
+                 NULL,
+                 g_cclosure_marshal_VOID__VOID,
+                 G_TYPE_NONE,
+                 0);                 
+       
+    /* This can be both emitted and received */
+    klass->request_menu_update_id = g_signal_new ("request-menu-update",
+                 G_TYPE_FROM_CLASS (klass),
+                 G_SIGNAL_RUN_LAST | G_SIGNAL_NO_RECURSE | G_SIGNAL_NO_HOOKS,
+                 G_STRUCT_OFFSET (NautilusUndoStackManagerClass, request_menu_update),
+                 NULL,
+                 NULL,
+                 g_cclosure_marshal_VOID__VOID,
+                 G_TYPE_NONE,
+                 0);              
+	
+	/* Hook deconstructors */		
+	g_object_class->dispose = nautilus_undostack_manager_dispose;
+	g_object_class->finalize = nautilus_undostack_manager_finalize;				
+}
+
+static void
+nautilus_undostack_manager_init (NautilusUndoStackManager* self)
+{
+	NautilusUndoStackManagerPrivate* 	priv;
+
+	priv = NAUTILUS_UNDOSTACK_MANAGER_GET_PRIVATE (self);
+	
+	self->priv = priv;
+  
+	/* Initialize private fields */
+	priv->stack = g_queue_new() ;
+	priv->mutex = g_mutex_new ();
+	priv->index = 0;
+	priv->dispose_has_run = FALSE;
+}
+
+
+static void
+nautilus_undostack_manager_dispose (GObject* object)
+{
+	NautilusUndoStackManager *self = NAUTILUS_UNDOSTACK_MANAGER (object);
+	NautilusUndoStackManagerPrivate* priv = self->priv;
+		
+	if (priv->dispose_has_run)
+		return;
+
+	g_mutex_lock (priv->mutex);
+
+	/* Free each undoable action in the stack and the stack itself */
+	undostack_dispose_all (priv->stack);
+	g_queue_free (priv->stack);
+	g_mutex_unlock (priv->mutex);
+	
+	g_mutex_free (priv->mutex);
+
+	priv->dispose_has_run = TRUE;
+
+	G_OBJECT_CLASS (nautilus_undostack_manager_parent_class)->dispose (object);
+}
+
+static void
+nautilus_undostack_manager_finalize (GObject* object)
+{
+	G_OBJECT_CLASS (nautilus_undostack_manager_parent_class)->finalize (object);
+}
+
+/* Property management */
+
+static void 
+nautilus_undostack_manager_set_property(GObject *object,
+			       guint prop_id,
+			       const GValue *value,
+			       GParamSpec *pspec)
+{
+	g_return_if_fail (IS_NAUTILUS_UNDOSTACK_MANAGER (object));
+	
+	NautilusUndoStackManager*		manager = NAUTILUS_UNDOSTACK_MANAGER (object);
+	NautilusUndoStackManagerPrivate* 	priv = manager->priv;
+	guint				new_undo_levels;
+
+	switch(prop_id) {
+		case PROP_UNDO_LEVELS:
+			new_undo_levels = g_value_get_uint (value);
+			if (new_undo_levels > 0 && (priv->undo_levels != new_undo_levels)) {
+					priv->undo_levels = new_undo_levels;
+					g_mutex_lock (priv->mutex);
+						stack_fix_size (priv);
+						notify_undo_status (manager, get_next_undo_action (priv));
+						notify_redo_status (manager, get_next_redo_action (priv));
+						notify_status_update_finished (manager);
+					g_mutex_unlock (priv->mutex);
+			}
+			break;
+
+		default:
+			G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+			break;
+	}
+}
+
+static void 
+nautilus_undostack_manager_get_property(GObject *object,
+			       guint prop_id,
+			       GValue *value,
+			       GParamSpec *pspec)
+{
+	g_return_if_fail (IS_NAUTILUS_UNDOSTACK_MANAGER (object));
+	
+	NautilusUndoStackManager*		manager = NAUTILUS_UNDOSTACK_MANAGER (object);
+	NautilusUndoStackManagerPrivate* 	priv = manager->priv;
+  
+  	switch(prop_id) {
+     		case PROP_UNDO_LEVELS:
+        		g_value_set_uint (value, priv->undo_levels);
+        		break;
+ 
+     		default:
+	        	G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+       			break;
+  	}
+}
+
+/* Public methods implementation */
+
+NautilusUndoStackManager*
+nautilus_undostack_manager_instance (void)
+{	
+	static NautilusUndoStackManager* manager = NULL;
+	
+	if (manager == NULL) {
+		manager = g_object_new (TYPE_NAUTILUS_UNDOSTACK_MANAGER, "undo-levels", 32, NULL);
+	}
+	
+	return manager;
+}
+
+void
+nautilus_undostack_manager_redo (NautilusUndoStackManager* manager, GtkWidget *parent_view, NautilusUndostackFinishCallback cb)
+{
+	g_return_if_fail (IS_NAUTILUS_UNDOSTACK_MANAGER (manager));
+	
+	NautilusUndoStackManagerPrivate* 	priv = manager->priv;
+	gchar* new_uri;
+	gchar* new_name;
+	gchar* old_uri;
+	GList* first_new_uris;
+	GList* first_old_uris;
+	GList* new_folder_list;
+	gchar* new_folder_uri;
+	gchar* parent_folder;
+	gchar* template_uri;
+	GnomeVFSURI* new_vfs_uri;
+	
+	g_mutex_lock (priv->mutex);
+
+		NautilusUndoStackAction* action = stack_scroll_left (priv);
+		
+		/* Action will be NULL if redo is not possible */
+		if (action != NULL) {
+			action->locked = TRUE;
+			/* As we locket this action, an immediate undo is not possible */
+			notify_undo_status (manager, NULL);
+			/* ... but another redo may be available */
+			notify_redo_status (manager, get_next_redo_action (priv));
+			notify_status_update_finished (manager);
+		} else {
+			notify_undo_status (manager, get_next_undo_action (priv));
+			/* If this redo failed, there is no next redo */
+			notify_redo_status (manager, NULL);
+			notify_status_update_finished (manager);
+		}
+
+	g_mutex_unlock (priv->mutex);
+	
+	if (action != NULL) {
+		action->locked = TRUE; /* Remember to unlock when redo is finished */
+		switch (action->type) {
+			case NAUTILUS_UNDOSTACK_COPY:
+				nautilus_file_operations_undo_copy_move (g_hash_table_get_values (action->affected_uris),
+					g_hash_table_get_keys (action->affected_uris),
+				    GDK_ACTION_COPY,
+				    parent_view,
+				    undo_redo_done_transfer_callback,
+				    action);
+				break;
+			case NAUTILUS_UNDOSTACK_MOVE:
+				nautilus_file_operations_undo_copy_move (g_hash_table_get_values (action->affected_uris),
+					g_hash_table_get_keys (action->affected_uris),
+				    GDK_ACTION_MOVE,
+				    parent_view,
+				    undo_redo_done_transfer_callback,
+				    action);
+				break;
+			case NAUTILUS_UNDOSTACK_RENAME:
+				first_new_uris = g_list_first (g_hash_table_get_keys (action->affected_uris));
+				first_old_uris = g_list_first (g_hash_table_get_values (action->affected_uris));
+				new_uri = (gchar*) first_new_uris->data;
+				old_uri = (gchar*) first_old_uris->data;
+				action->file = nautilus_file_get (old_uri);
+				new_vfs_uri = gnome_vfs_uri_new (new_uri);
+				new_name = gnome_vfs_uri_extract_short_name (new_vfs_uri);
+				gnome_vfs_uri_unref (new_vfs_uri);
+				nautilus_file_undo_rename (action->file, new_name, undo_rename_callback, action);
+				g_free (new_name);
+				break;
+			case NAUTILUS_UNDOSTACK_CREATEFILEFROMTEMPLATE:
+				first_new_uris = g_list_first (g_hash_table_get_keys (action->affected_uris));
+				first_old_uris = g_list_first (g_hash_table_get_values (action->affected_uris));
+				new_uri = (gchar*) first_new_uris->data;
+				template_uri = (gchar*) first_old_uris->data;
+				new_vfs_uri = gnome_vfs_uri_new (new_uri);
+				parent_folder = gnome_vfs_uri_extract_dirname (new_vfs_uri);
+				new_name = gnome_vfs_uri_extract_short_name (new_vfs_uri);
+				gnome_vfs_uri_unref (new_vfs_uri);
+				nautilus_file_operations_undo_new_file_from_template (parent_view,
+					NULL,
+					parent_folder,
+					new_name,
+					template_uri,
+					undo_new_folder_callback,
+					action);
+				g_free (parent_folder);
+				g_free (new_name);
+				break;
+			case NAUTILUS_UNDOSTACK_CREATEEMPTYFILE:
+				first_new_uris = g_list_first (g_hash_table_get_keys (action->affected_uris));
+				new_uri = (gchar*) first_new_uris->data;
+				new_vfs_uri = gnome_vfs_uri_new (new_uri);
+				parent_folder = gnome_vfs_uri_extract_dirname (new_vfs_uri);
+				gnome_vfs_uri_unref (new_vfs_uri);
+				nautilus_file_operations_undo_new_file (parent_view,
+					NULL,
+					parent_folder,
+					NULL,
+					undo_new_folder_callback,
+					action);
+				g_free (parent_folder);
+				break;
+			case NAUTILUS_UNDOSTACK_CREATEFOLDER:
+				new_folder_list = g_list_first (g_hash_table_get_keys (action->affected_uris));
+				new_folder_uri = (gchar*) new_folder_list->data;
+				nautilus_file_operations_undo_new_folder (parent_view, 
+				     NULL,
+				     new_folder_uri,
+				     undo_new_folder_callback,
+				     action);			     
+				break;
+			case NAUTILUS_UNDOSTACK_MOVETOTRASH:
+				nautilus_file_operations_undo_copy_move (g_hash_table_get_values (action->affected_uris),
+					g_hash_table_get_keys (action->affected_uris),
+				    GDK_ACTION_MOVE,
+				    parent_view,
+				    undo_redo_done_transfer_callback,
+				    action);
+				break;
+			case NAUTILUS_UNDOSTACK_CREATELINK:
+				nautilus_file_operations_undo_copy_move (g_hash_table_get_values (action->affected_uris),
+					g_hash_table_get_keys (action->affected_uris),
+				    GDK_ACTION_LINK,
+				    parent_view,
+				    undo_redo_done_transfer_callback,
+				    action);
+				break;			
+			case NAUTILUS_UNDOSTACK_DELETE:				
+			default:
+				break; /* We shouldn't be here */					
+			}
+	}
+	
+	(*cb) ((gpointer) parent_view);
+}
+
+void
+nautilus_undostack_manager_undo (NautilusUndoStackManager* manager, GtkWidget *parent_view, NautilusUndostackFinishCallback cb)
+{
+	g_return_if_fail (IS_NAUTILUS_UNDOSTACK_MANAGER (manager));
+	
+	NautilusUndoStackManagerPrivate* 	priv = manager->priv;
+	gchar* new_uri;
+	gchar* old_uri;
+	gchar* new_name;
+	GList* first_new_uris;
+	GList* first_old_uris;
+		
+	g_mutex_lock (priv->mutex);
+
+		NautilusUndoStackAction* action = stack_scroll_right (priv);
+	
+		if (action != NULL) {
+			action->locked = TRUE;
+			/* If we can undo, then there may exist a next undo action */
+			notify_undo_status (manager, get_next_undo_action (priv));
+			/* ...but the redo action will be locked (WE locked it!) */
+			notify_redo_status (manager, NULL);
+			notify_status_update_finished (manager);
+		} else {
+			/* If we cannot undo, then there will be no next undo */
+			notify_undo_status (manager, NULL);
+			/* But there could be the old redo */
+			notify_redo_status (manager, get_next_redo_action (priv));
+			notify_status_update_finished (manager);	
+		}
+
+	g_mutex_unlock (priv->mutex);
+	
+	if (action != NULL) {
+		switch (action->type) {
+			case NAUTILUS_UNDOSTACK_COPY:
+				nautilus_file_operations_undo_delete (g_hash_table_get_keys (action->affected_uris), 
+					parent_view, 
+					undo_redo_done_transfer_callback, 
+					action);
+				break;
+			case NAUTILUS_UNDOSTACK_MOVE:
+				nautilus_file_operations_undo_copy_move (g_hash_table_get_keys (action->affected_uris),
+					g_hash_table_get_values (action->affected_uris),
+				    GDK_ACTION_MOVE,
+				    parent_view,
+				    undo_redo_done_transfer_callback,
+				    action);
+				break;
+			case NAUTILUS_UNDOSTACK_RENAME:
+				first_new_uris = g_list_first (g_hash_table_get_keys (action->affected_uris));
+				first_old_uris = g_list_first (g_hash_table_get_values (action->affected_uris));
+				new_uri = (gchar*) first_new_uris->data;
+				old_uri = (gchar*) first_old_uris->data;
+				action->file = nautilus_file_get (new_uri);
+				GnomeVFSURI* new_vfs_uri = gnome_vfs_uri_new (old_uri);
+				new_name = gnome_vfs_uri_extract_short_name (new_vfs_uri);
+				gnome_vfs_uri_unref (new_vfs_uri);
+				nautilus_file_undo_rename (action->file, new_name, undo_rename_callback, action);
+				g_free (new_name);
+				break;
+			case NAUTILUS_UNDOSTACK_CREATEEMPTYFILE:
+			case NAUTILUS_UNDOSTACK_CREATEFILEFROMTEMPLATE:
+				nautilus_file_operations_undo_delete (g_hash_table_get_keys (action->affected_uris), 
+					parent_view, 
+					undo_redo_done_transfer_callback, 
+					action);
+				break;
+			case NAUTILUS_UNDOSTACK_CREATEFOLDER:
+				nautilus_file_operations_undo_delete (g_hash_table_get_keys (action->affected_uris), 
+					parent_view, 
+					undo_redo_done_transfer_callback, 
+					action);
+				break;
+			case NAUTILUS_UNDOSTACK_MOVETOTRASH:
+				nautilus_file_operations_undo_copy_move (g_hash_table_get_keys (action->affected_uris),
+					g_hash_table_get_values (action->affected_uris),
+				    GDK_ACTION_MOVE,
+				    parent_view,
+				    undo_redo_done_transfer_callback,
+				    action);
+				break;
+			case NAUTILUS_UNDOSTACK_CREATELINK:
+				nautilus_file_operations_undo_delete (g_hash_table_get_keys (action->affected_uris), 
+					parent_view, 
+					undo_redo_done_transfer_callback, 
+					action);
+				break;					
+			case NAUTILUS_UNDOSTACK_DELETE:
+			default:
+				break; /* We shouldn't be here */					
+			}
+	}
+	
+	(*cb) ((gpointer) parent_view);
+}
+
+NautilusUndoStackAction*
+nautilus_undostack_manager_new_action (NautilusUndoStackActionType type)
+{
+	NautilusUndoStackAction* action;
+
+	action = (NautilusUndoStackAction*) g_malloc (sizeof(NautilusUndoStackAction));
+	
+	action->locked = FALSE;
+	
+	action->freed = FALSE;
+	
+	action->type = type;
+	
+	action->affected_uris = NULL;
+	
+	action->count = 0;
+	
+	action->file = NULL;
+	
+	return action;
+}
+
+void
+nautilus_undostack_manager_add_action (NautilusUndoStackManager* manager, NautilusUndoStackAction* action)
+{
+	g_return_if_fail (IS_NAUTILUS_UNDOSTACK_MANAGER (manager));
+	
+	NautilusUndoStackManagerPrivate* 	priv = manager->priv;
+	
+	g_mutex_lock (priv->mutex);
+	
+		stack_push_action (priv, action);
+	
+		/* Here we don't use get_next_* because we are sure
+		 * that action will be the next and that all redo has
+		 * been erased */
+		notify_undo_status (manager, action);
+		notify_redo_status (manager, NULL);
+		notify_status_update_finished (manager);
+	
+	g_mutex_unlock (priv->mutex);
+}
+
+void
+nautilus_undostack_manager_trash_has_emptied (NautilusUndoStackManager* manager)
+{
+	g_return_if_fail (IS_NAUTILUS_UNDOSTACK_MANAGER (manager));
+	
+	NautilusUndoStackManagerPrivate* 	priv = manager->priv;
+	
+	/* Clear actions from the oldest to the newest move to trash */
+	
+	g_mutex_lock (priv->mutex);
+	
+		clear_redo_actions (priv);
+	
+		/* Search newest move to trash */
+		guint i;
+		guint length = g_queue_get_length (priv->stack);
+		guint newest_move_to_trash_position = -1;
+		NautilusUndoStackAction*  action = NULL;
+		
+		for (i=0; i < length; i++) {
+			action = (NautilusUndoStackAction*) g_queue_peek_nth (priv->stack, i);
+			if (action->type == NAUTILUS_UNDOSTACK_MOVETOTRASH) {
+				newest_move_to_trash_position  = i;
+				break;
+			}
+		}
+		
+		if (newest_move_to_trash_position >= 0) {
+			guint to_clear = length - newest_move_to_trash_position;
+			stack_clear_n_oldest (priv->stack, to_clear);
+		}
+
+	g_mutex_unlock (priv->mutex);		
+}
+
+void 
+nautilus_undostack_manager_set_affected_uris (NautilusUndoStackAction* action, GHashTable* uris)
+{
+	action->affected_uris = uris;
+	action->count = g_hash_table_size (uris);
+}
+
+/* Static (Private) methods implementation */
+
+static NautilusUndoStackAction*
+stack_scroll_right (NautilusUndoStackManagerPrivate* priv)
+{
+	gpointer data = NULL;
+	
+	if (!can_undo (priv))
+		return NULL;
+
+	data = g_queue_peek_nth (priv->stack, priv->index);
+	if (priv->index < g_queue_get_length (priv->stack)) {
+		priv->index++;
+	}
+
+	return data;
+}
+
+static NautilusUndoStackAction*
+stack_scroll_left (NautilusUndoStackManagerPrivate* priv)
+{
+	gpointer data = NULL;
+	
+	if (!can_redo (priv))
+		return NULL;
+
+	priv->index--;
+	data = g_queue_peek_nth (priv->stack, priv->index);
+
+	return data;
+}
+
+static void
+stack_clear_n_oldest (GQueue* stack, guint n)
+{
+	g_print ("Clearing %d oldest\n", n);
+	
+	NautilusUndoStackAction* action;
+	guint i;
+	
+	for (i=0; i<n; i++) {
+		action = (NautilusUndoStackAction*) g_queue_pop_tail (stack);
+		if (action->locked) {
+			action->freed = TRUE;
+		} else {
+			free_undostack_action (action, NULL);
+		}			
+	}	
+}
+
+static void
+stack_fix_size (NautilusUndoStackManagerPrivate* priv)
+{
+	guint length = g_queue_get_length (priv->stack);
+	
+	if (length > priv->undo_levels) {
+		if (priv->index > (priv->undo_levels + 1)) {
+			/* If the index will fall off the stack
+			 * move it back to the maximum position */
+			priv->index = priv->undo_levels + 1; 
+		}
+		stack_clear_n_oldest (priv->stack, length-(priv->undo_levels));
+	}
+}
+
+static void
+clear_redo_actions (NautilusUndoStackManagerPrivate* priv)
+{
+	while (priv->index > 0) {
+		NautilusUndoStackAction* head = (NautilusUndoStackAction*) g_queue_pop_head (priv->stack); 
+		free_undostack_action (head, NULL);
+		priv->index--;
+	}
+}
+
+static void
+stack_push_action (NautilusUndoStackManagerPrivate* priv, NautilusUndoStackAction* action)
+{
+	guint length;
+
+	clear_redo_actions (priv);
+
+	g_queue_push_head (priv->stack,(gpointer) action);
+	length = g_queue_get_length (priv->stack);
+
+	if (length > priv->undo_levels) {
+		stack_fix_size (priv);
+		}
+}
+
+static gchar*
+get_undo_description	(NautilusUndoStackAction* action)
+{
+	gchar* description = NULL;
+	guint count;
+	
+	if (action != NULL) {
+		count = action->count;
+		switch (action->type) {
+			case NAUTILUS_UNDOSTACK_COPY:
+				description = g_strdup_printf (ngettext("Delete %d copied item",
+					   "Delete %d copied items", count), count);
+				break;
+			case NAUTILUS_UNDOSTACK_MOVE:
+				description = g_strdup_printf (ngettext("Move %d item back to its original location",
+					   "Move %d items back to their original location", count), count);
+				break;
+			case NAUTILUS_UNDOSTACK_RENAME:
+				description = g_strdup_printf (ngettext("Restore original name of %d item",
+					   "Restore original name of %d items", count), count);
+				break;
+			case NAUTILUS_UNDOSTACK_CREATEEMPTYFILE:
+				description = g_strdup_printf (ngettext("Delete %d new empty file",
+					   "Delete %d new empty files", count), count);
+				break;
+			case NAUTILUS_UNDOSTACK_CREATEFILEFROMTEMPLATE:
+				description = g_strdup_printf (ngettext("Delete %d new file",
+					   "Delete %d new files", count), count);
+				break;								
+			case NAUTILUS_UNDOSTACK_CREATEFOLDER:
+				description = g_strdup_printf (ngettext("Delete %d new folder",
+					   "Delete %d new folders", count), count);
+				break;
+			case NAUTILUS_UNDOSTACK_MOVETOTRASH:
+				description = g_strdup_printf (ngettext("Restore %d item from trash",
+					   "Restore %d items from trash", count), count);
+				break;
+			case NAUTILUS_UNDOSTACK_CREATELINK:
+				description = g_strdup_printf (ngettext("Restore link to %d item",
+					   "Restore links to %d items", count), count);
+				break;					
+			case NAUTILUS_UNDOSTACK_DELETE:
+				description = g_strdup_printf (ngettext("Undelete %d item",
+					   "Undelete %d items", count), count);
+				break;
+			default:
+				break;
+			}
+	}
+
+	return description;	
+}	
+
+static gchar*
+get_redo_description	(NautilusUndoStackAction* action)
+{
+	gchar* description = NULL;
+	guint count;
+	
+	if (action != NULL) {
+		count = action->count;
+		switch (action->type) {
+			case NAUTILUS_UNDOSTACK_COPY:
+				description = g_strdup_printf (ngettext("Redo copy of %d item",
+					   "Redo copy of %d items", count), count);
+				break;
+			case NAUTILUS_UNDOSTACK_MOVE:
+				description = g_strdup_printf (ngettext("Redo move of %d item",
+					   "Redo move of %d items", count), count);
+				break;
+			case NAUTILUS_UNDOSTACK_RENAME:
+				description = g_strdup_printf (ngettext("Redo rename of %d item",
+					   "Redo rename of %d items", count), count);
+				break;
+			case NAUTILUS_UNDOSTACK_CREATEEMPTYFILE:
+				description = g_strdup_printf (ngettext("Redo creation of %d empty file",
+					   "Redo creation of %d empty files", count), count);
+				break;
+			case NAUTILUS_UNDOSTACK_CREATEFILEFROMTEMPLATE:
+				description = g_strdup_printf (ngettext("Redo creation of %d file",
+					   "Redo creation of %d files", count), count);
+				break;				
+			case NAUTILUS_UNDOSTACK_CREATEFOLDER:
+				description = g_strdup_printf (ngettext("Redo creation of %d folder",
+					   "Redo creation of %d folders", count), count);
+				break;
+			case NAUTILUS_UNDOSTACK_MOVETOTRASH:
+				description = g_strdup_printf (ngettext("Redo move to trash of %d item",
+					   "Redo move to trash of %d items", count), count);
+				break;
+			case NAUTILUS_UNDOSTACK_CREATELINK:
+				description = g_strdup_printf (ngettext("Redo create link to %d item",
+					   "Redo create links to %d items", count), count);
+				break;				
+			case NAUTILUS_UNDOSTACK_DELETE:
+				description = g_strdup_printf (ngettext("Redo delete of %d item",
+					   "Redo delete of %d items", count), count);
+				break;
+			default:
+				break;
+			}
+	}
+
+	return description;	
+}	
+
+static gchar*
+get_undo_label	(NautilusUndoStackAction* action)
+{
+	gchar* label = NULL;
+	guint count;	
+	
+	if (action != NULL) {
+		count = action->count;
+		switch (action->type) {
+			case NAUTILUS_UNDOSTACK_COPY:
+				label = g_strdup_printf (ngettext("_Undo copy of %d item",
+					   "_Undo copy of %d items", count), count);
+				break;
+			case NAUTILUS_UNDOSTACK_MOVE:
+				label = g_strdup_printf (ngettext("_Undo move of %d item",
+					   "_Undo move of %d items", count), count);
+				break;
+			case NAUTILUS_UNDOSTACK_RENAME:
+				label = g_strdup_printf (ngettext("_Undo rename of %d item",
+					   "_Undo rename of %d items", count), count);
+				break;			
+			case NAUTILUS_UNDOSTACK_CREATEEMPTYFILE:
+				label = g_strdup_printf (ngettext("_Undo creation of %d empty file",
+					   "_Undo creation of %d empty files", count), count);
+				break;
+			case NAUTILUS_UNDOSTACK_CREATEFILEFROMTEMPLATE:
+				label = g_strdup_printf (ngettext("_Undo creation of %d file",
+					   "_Undo creation of %d files", count), count);
+				break;					
+			case NAUTILUS_UNDOSTACK_CREATEFOLDER:
+				label = g_strdup_printf (ngettext("_Undo creation of %d folder",
+					   "_Undo creation of %d folders", count), count);
+				break;
+			case NAUTILUS_UNDOSTACK_MOVETOTRASH:
+				label = g_strdup_printf (ngettext("_Undo move to trash of %d item",
+					   "_Undo move to trash of %d items", count), count);
+				break;
+			case NAUTILUS_UNDOSTACK_CREATELINK:
+				label = g_strdup_printf (ngettext("_Undo create link to %d item",
+					   "_Undo create link to %d items", count), count);
+				break;							
+			case NAUTILUS_UNDOSTACK_DELETE:
+				label = g_strdup_printf (ngettext("_Undo delete of %d item",
+					   "_Undo delete of %d items", count), count);
+				break;
+			default:
+				break;
+			}
+	}
+
+	return label;
+}
+
+static gchar*
+get_redo_label	(NautilusUndoStackAction* action)
+{
+	gchar* label = NULL;
+	guint count;	
+
+	if (action != NULL) {
+		count = action->count;
+		switch (action->type) {
+			case NAUTILUS_UNDOSTACK_COPY:
+				label = g_strdup_printf (ngettext("_Redo copy of %d item",
+					   "_Redo copy of %d items", count), count);
+				break;
+			case NAUTILUS_UNDOSTACK_MOVE:
+				label = g_strdup_printf (ngettext("_Redo move of %d item",
+					   "_Redo move of %d items", count), count);
+				break;
+			case NAUTILUS_UNDOSTACK_RENAME:
+				label = g_strdup_printf (ngettext("_Redo rename of %d item",
+					   "_Redo rename of %d items", count), count);
+				break;
+			case NAUTILUS_UNDOSTACK_CREATEEMPTYFILE:
+				label = g_strdup_printf (ngettext("_Redo creation of %d empty file",
+					   "_Redo creation of %d empty files", count), count);
+				break;
+			case NAUTILUS_UNDOSTACK_CREATEFILEFROMTEMPLATE:
+				label = g_strdup_printf (ngettext("_Redo creation of %d file",
+					   "_Redo creation of %d files", count), count);
+				break;				
+			case NAUTILUS_UNDOSTACK_CREATEFOLDER:
+				label = g_strdup_printf (ngettext("_Redo creation of %d folder",
+					   "_Redo creation of %d folders", count), count);
+				break;
+			case NAUTILUS_UNDOSTACK_MOVETOTRASH:
+				label = g_strdup_printf (ngettext("_Redo move to trash of %d item",
+					   "_Redo move to trash of %d items", count), count);
+				break;
+			case NAUTILUS_UNDOSTACK_CREATELINK:
+				label = g_strdup_printf (ngettext("_Redo create link to %d item",
+					   "_Redo create link to %d items", count), count);
+				break;								
+			case NAUTILUS_UNDOSTACK_DELETE:
+				label = g_strdup_printf (ngettext("_Redo delete of %d item",
+					   "_Redo delete of %d items", count), count);
+				break;
+			default:
+				break;				
+			}
+	}
+
+	return label;
+}
+
+static void
+undo_new_folder_callback (const char *new_folder_uri, gpointer data)
+{		
+	undo_redo_done_transfer_callback (NULL, data);
+}
+
+static void
+undo_redo_done_transfer_callback (GHashTable *debuting_uris, gpointer data)
+{
+	NautilusUndoStackAction* action;
+
+	action = (NautilusUndoStackAction *) data;
+	
+	/* If the action needed to be freed but was locked, free now */
+	if (action->freed) {
+		free_undostack_action (action, NULL);
+	} else {
+		action->locked = FALSE;
+	}
+	
+	/* Update menus */
+	g_signal_emit_by_name (nautilus_undostack_manager_instance (), "request-menu-update");
+}
+
+static void
+undo_rename_callback (NautilusFile *file, GnomeVFSResult result, gpointer data)
+{
+	NautilusUndoStackAction *action = (NautilusUndoStackAction*) data;
+	if (action->file) {
+		nautilus_file_unref (action->file);
+		action->file = NULL;
+	}		
+	undo_redo_done_transfer_callback (NULL, data);
+}
+
+static void
+free_undostack_action (gpointer data, gpointer user_data)
+{
+	NautilusUndoStackAction *action = (NautilusUndoStackAction*) data;
+	if (action->affected_uris)
+		g_hash_table_destroy (action->affected_uris);
+}
+
+static void
+undostack_dispose_all (GQueue *queue)
+{
+	g_queue_foreach (queue, free_undostack_action, NULL);
+}
+
+static gboolean
+can_undo (NautilusUndoStackManagerPrivate* priv)
+{
+	return (get_next_undo_action (priv) != NULL);
+}
+
+static gboolean
+can_redo (NautilusUndoStackManagerPrivate* priv)
+{	
+	return (get_next_redo_action (priv) != NULL);
+}
+
+static NautilusUndoStackAction*
+get_next_redo_action (NautilusUndoStackManagerPrivate* priv)
+{	
+	if (g_queue_is_empty (priv->stack)) {
+		return NULL;
+	}
+	
+	if (priv->index == 0) {
+		/* ... no redo actions */
+		return NULL;
+	}
+	
+	NautilusUndoStackAction* action = g_queue_peek_nth (priv->stack, priv->index - 1);
+	
+	if (action->locked) {
+		return NULL;
+	} else {
+		return action;
+	}
+}
+
+static NautilusUndoStackAction*
+get_next_undo_action (NautilusUndoStackManagerPrivate* priv)
+{
+	if (g_queue_is_empty (priv->stack)) {
+		return NULL;
+	}
+
+	guint stack_size = g_queue_get_length (priv->stack);
+	
+	if (priv->index == stack_size) {
+		return NULL;
+	}
+	
+	NautilusUndoStackAction* action = g_queue_peek_nth (priv->stack, priv->index);
+	
+	if (action->locked) {
+		return NULL;
+	} else {
+		return action;
+	}		
+}
+
+static void
+notify_undo_status (NautilusUndoStackManager* manager, 
+				NautilusUndoStackAction* action)
+{
+	gchar* label;
+	gchar* description;
+	
+	label = get_undo_label (action);
+	description = get_undo_description (action);
+	
+	g_signal_emit_by_name (manager, "undo-label-changed", label);
+	g_signal_emit_by_name (manager, "undo-description-changed", description);
+	g_signal_emit_by_name (manager, "undo-availability-changed", !(action==NULL));
+	
+	if (label != NULL) {
+		g_free (label);
+	}
+	
+	if (description != NULL) {
+		g_free (description);
+	}
+}
+
+static void
+notify_redo_status (NautilusUndoStackManager* manager, 
+				NautilusUndoStackAction* action)
+{
+	gchar* label;
+	gchar* description;
+	
+	label = get_redo_label (action);
+	description = get_redo_description (action);
+	
+	g_signal_emit_by_name (manager, "redo-label-changed", label);
+	g_signal_emit_by_name (manager, "redo-description-changed", description);
+	g_signal_emit_by_name (manager, "redo-availability-changed", !(action==NULL));
+	
+	if (label != NULL) {
+		g_free (label);
+	}
+	
+	if (description != NULL) {
+		g_free (description);
+	}
+}
+
+static void
+notify_status_update_finished (NautilusUndoStackManager* manager)
+{
+	g_signal_emit_by_name (manager, "status-update-finished");
+}
+
+static void
+nautilus_undostack_manager_request_menu_update (NautilusUndoStackManager* manager)
+{
+	g_return_if_fail (IS_NAUTILUS_UNDOSTACK_MANAGER (manager));
+	
+	NautilusUndoStackManagerPrivate* priv = manager->priv;
+	
+	g_mutex_lock (priv->mutex);
+	
+		/* Emit notify for undo and redo */
+		notify_undo_status (manager, get_next_undo_action (priv));
+		notify_redo_status (manager, get_next_redo_action (priv));
+		notify_status_update_finished (manager);
+		
+	g_mutex_unlock (priv->mutex);	
+}
diff -rupN nautilus-2.20.0-orig/libnautilus-private/nautilus-undostack-manager.h nautilus-2.20.0-undo/libnautilus-private/nautilus-undostack-manager.h
--- nautilus-2.20.0-orig/libnautilus-private/nautilus-undostack-manager.h	1970-01-01 01:00:00.000000000 +0100
+++ nautilus-2.20.0-undo/libnautilus-private/nautilus-undostack-manager.h	2007-10-24 17:52:48.000000000 +0200
@@ -0,0 +1,124 @@
+/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
+
+/* NautilusUndoStackManager - Manages undo of file operations (header)                   
+ *
+ * Copyright (C) 2007 Amos Brocco
+ *
+ * Author: Amos Brocco <amos.brocco@unifr.ch>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifndef NAUTILUS_UNDOSTACK_MANAGER_H
+#define NAUTILUS_UNDOSTACK_MANAGER_H
+
+#include <glib.h>
+#include <glib-object.h>
+#include <gtk/gtkwidget.h>
+
+/* Begin action structures */
+
+typedef enum {
+	NAUTILUS_UNDOSTACK_COPY,
+	NAUTILUS_UNDOSTACK_MOVE,
+	NAUTILUS_UNDOSTACK_RENAME,
+	NAUTILUS_UNDOSTACK_CREATEEMPTYFILE,
+	NAUTILUS_UNDOSTACK_CREATEFILEFROMTEMPLATE,
+	NAUTILUS_UNDOSTACK_CREATEFOLDER,
+	NAUTILUS_UNDOSTACK_MOVETOTRASH,
+	NAUTILUS_UNDOSTACK_CREATELINK,
+	NAUTILUS_UNDOSTACK_LINKINBURN,
+	NAUTILUS_UNDOSTACK_DELETE  /* Really ?  :) */
+} NautilusUndoStackActionType;
+
+typedef struct _NautilusUndoStackAction NautilusUndoStackAction;
+
+/* End action structures */
+
+typedef void (*NautilusUndostackFinishCallback)(gpointer data);
+
+typedef struct _NautilusUndoStackManagerPrivate NautilusUndoStackManagerPrivate;
+
+typedef struct _NautilusUndoStackManager
+{
+	GObject 			parent_instance;
+	
+	NautilusUndoStackManagerPrivate* priv;
+	
+} NautilusUndoStackManager;
+
+typedef struct _NautilusUndoStackManagerClass
+{
+	GObjectClass 			parent_class;
+	
+	/* Signals */
+	guint					undo_label_changed_id;
+	guint					undo_description_changed_id;
+	guint					undo_availability_changed_id;
+	guint					redo_label_changed_id;
+	guint					redo_description_changed_id;
+	guint					redo_availability_changed_id;
+	guint					request_menu_update_id;
+	guint					status_update_finished_id;
+	
+	/* Signal handler */
+    void (*request_menu_update) (NautilusUndoStackManager *manager);
+
+} NautilusUndoStackManagerClass;
+
+
+#define TYPE_NAUTILUS_UNDOSTACK_MANAGER (nautilus_undostack_manager_get_type())
+
+#define NAUTILUS_UNDOSTACK_MANAGER(object) \
+ (G_TYPE_CHECK_INSTANCE_CAST((object), TYPE_NAUTILUS_UNDOSTACK_MANAGER, NautilusUndoStackManager))
+
+#define NAUTILUS_UNDOSTACK_MANAGER_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_CAST((klass), TYPE_NAUTILUS_UNDOSTACK_MANAGER, NautilusUndoStackManagerClass))
+
+#define IS_NAUTILUS_UNDOSTACK_MANAGER(object) \
+ (G_TYPE_CHECK_INSTANCE_TYPE((object), TYPE_NAUTILUS_UNDOSTACK_MANAGER))
+
+#define IS_NAUTILUS_UNDOSTACK_MANAGER_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_TYPE((klass), TYPE_NAUTILUS_UNDOSTACK_MANAGER))
+
+#define NAUTILUS_UNDOSTACK_MANAGER_GET_CLASS(object) \
+ (G_TYPE_INSTANCE_GET_CLASS((object), TYPE_NAUTILUS_UNDOSTACK_MANAGER, NautilusUndoStackManagerClass))
+
+
+/* Prototypes for public methods */
+
+/* Adds a new action to the stack */
+void 			nautilus_undostack_manager_add_action	 	(NautilusUndoStackManager* manager, NautilusUndoStackAction* action);
+
+/* Undo the last action added to the stack */
+void			nautilus_undostack_manager_undo				(NautilusUndoStackManager* manager, GtkWidget *parent_view, NautilusUndostackFinishCallback cb);
+
+/* Redo the last undone action */
+void			nautilus_undostack_manager_redo				(NautilusUndoStackManager* manager, GtkWidget *parent_view, NautilusUndostackFinishCallback cb);
+
+/* Creates a new action of the specified type */
+NautilusUndoStackAction*	nautilus_undostack_manager_new_action		(NautilusUndoStackActionType type);
+
+/* Sets the hashtable with source_uri->target_uri pairs */
+void 			nautilus_undostack_manager_set_affected_uris (NautilusUndoStackAction* action, GHashTable* uris);
+
+/* Notifies the manager that the trash has been emptied (erases all actions from the oldest to the last move to trash) */
+void			nautilus_undostack_manager_trash_has_emptied (NautilusUndoStackManager* manager);
+
+/* Returns the undo manager */
+NautilusUndoStackManager* nautilus_undostack_manager_instance (void);
+					
+#endif /* NAUTILUS_UNDOSTACK_MANAGER_H */
diff -rupN nautilus-2.20.0-orig/src/file-manager/fm-actions.h nautilus-2.20.0-undo/src/file-manager/fm-actions.h
--- nautilus-2.20.0-orig/src/file-manager/fm-actions.h	2007-04-03 12:08:04.000000000 +0200
+++ nautilus-2.20.0-undo/src/file-manager/fm-actions.h	2007-10-16 09:20:40.000000000 +0200
@@ -77,5 +77,7 @@
 #define FM_ACTION_STRETCH "Stretch"
 #define FM_ACTION_UNSTRETCH "Unstretch"
 #define FM_ACTION_ZOOM_ITEMS "Zoom Items"
+#define FM_ACTION_UNDO "Undo"
+#define FM_ACTION_REDO "Redo"
 
 #endif /* FM_ACTIONS_H */
diff -rupN nautilus-2.20.0-orig/src/file-manager/fm-directory-view.c nautilus-2.20.0-undo/src/file-manager/fm-directory-view.c
--- nautilus-2.20.0-orig/src/file-manager/fm-directory-view.c	2007-08-27 10:03:57.000000000 +0200
+++ nautilus-2.20.0-undo/src/file-manager/fm-directory-view.c	2007-10-23 14:55:45.000000000 +0200
@@ -105,6 +105,7 @@
 #include <libnautilus-private/nautilus-trash-monitor.h>
 #include <libnautilus-private/nautilus-ui-utilities.h>
 #include <libnautilus-private/nautilus-signaller.h>
+#include <libnautilus-private/nautilus-undostack-manager.h>
 #include <unistd.h>
 
 /* Number of seconds until cancel dialog shows up */
@@ -281,6 +282,13 @@ struct FMDirectoryViewDetails
 	gboolean allow_moves;
 
 	GdkPoint context_menu_position;
+	
+	gboolean undo_active;
+	gboolean redo_active;
+	gchar* undo_action_description;
+	gchar* undo_action_label;
+	gchar* redo_action_description;
+	gchar* redo_action_label;
 };
 
 typedef enum {
@@ -432,6 +440,29 @@ static void action_location_trash_callba
 						     gpointer   callback_data);
 static void action_location_delete_callback         (GtkAction *action,
 						     gpointer   callback_data);
+						     
+/* undo-related actions */
+
+static void undo_label_changed_callback (NautilusUndoStackManager* manager, gchar* new_label, gpointer data);
+
+static void undo_description_changed_callback (NautilusUndoStackManager* manager, gchar* new_label, gpointer data);
+
+static void redo_label_changed_callback (NautilusUndoStackManager* manager, gchar* new_label, gpointer data);
+
+static void redo_description_changed_callback (NautilusUndoStackManager* manager, gchar* new_label, gpointer data);
+
+static void undo_availability_changed_callback (NautilusUndoStackManager* manager, gboolean new_availability, gpointer data);
+
+static void redo_availability_changed_callback (NautilusUndoStackManager* manager, gboolean new_availability, gpointer data);
+
+static void undo_redo_schedule_menu_update_callback (NautilusUndoStackManager* manager, gpointer data);
+
+static void undo_update_menu (FMDirectoryView *view);
+
+static void action_undo_callback (GtkAction *action, gpointer callback_data);
+						     
+static void action_redo_callback (GtkAction *action, gpointer callback_data);					     
+						     
 
 EEL_CLASS_BOILERPLATE (FMDirectoryView, fm_directory_view, GTK_TYPE_SCROLLED_WINDOW)
 
@@ -1029,9 +1060,17 @@ confirm_delete_directly (FMDirectoryView
 }
 
 static void
+finish_undoredo_callback (gpointer data)
+{
+	FMDirectoryView *view;
+
+	view = FM_DIRECTORY_VIEW (data);
+}
+
+static void
 delete_selected_files (FMDirectoryView *view)
 {
-        GList *selection;
+    GList *selection;
 	GList *node;
 	GList *file_uris;
 
@@ -1982,6 +2021,39 @@ fm_directory_view_init (FMDirectoryView 
 					 filtering_changed_callback, view);
 	eel_preferences_add_callback (NAUTILUS_PREFERENCES_SHOW_BACKUP_FILES,
 					 filtering_changed_callback, view);
+					 
+	/* Update undo actions stuff and connect signals from the undostack manager */					 
+	view->details->undo_active = FALSE;
+	view->details->redo_active = FALSE;
+	view->details->undo_action_description = NULL;
+	view->details->undo_action_label = NULL;
+	view->details->redo_action_description = NULL;
+	view->details->redo_action_label = NULL;	
+	
+	NautilusUndoStackManager* manager = nautilus_undostack_manager_instance ();	
+		
+	g_signal_connect_object (G_OBJECT(manager), "undo-label-changed",
+		   G_CALLBACK(undo_label_changed_callback), view, 0);
+		 
+	g_signal_connect_object (G_OBJECT(manager), "undo-description-changed",
+		   G_CALLBACK(undo_description_changed_callback), view, 0);
+		   
+	g_signal_connect_object (G_OBJECT(manager), "redo-label-changed",
+		   G_CALLBACK(redo_label_changed_callback), view, 0);		   
+		   
+	g_signal_connect_object (G_OBJECT(manager), "redo-description-changed",
+		   G_CALLBACK(redo_description_changed_callback), view, 0);	
+		   
+	g_signal_connect_object (G_OBJECT(manager), "undo-availability-changed",
+		   G_CALLBACK(undo_availability_changed_callback), view, 0);
+		   
+	g_signal_connect_object (G_OBJECT(manager), "redo-availability-changed",
+		   G_CALLBACK(redo_availability_changed_callback), view, 0);
+		   
+	g_signal_connect_object (G_OBJECT(manager), "status-update-finished",
+		   G_CALLBACK(undo_redo_schedule_menu_update_callback), view, 0);
+		   
+	g_signal_emit_by_name (manager, "request-menu-update");					 
 }
 
 static void
@@ -2652,6 +2724,8 @@ copy_move_done_callback (GHashTable *deb
 					       (GClosureNotify) debuting_uri_data_free,
 					       G_CONNECT_AFTER);
 		}
+		/* Schedule menu update for undo items */
+		schedule_update_menus (directory_view);
 	}
 
 	copy_move_done_data_free (copy_move_done_data);
@@ -6295,6 +6369,32 @@ action_paste_files_into_callback (GtkAct
 }
 
 static void
+real_action_undo (FMDirectoryView *view)
+{	
+	NautilusUndoStackManager *manager = nautilus_undostack_manager_instance ();
+	
+	/* Disable menus because they are in an untrustworthy status */
+	view->details->undo_active = FALSE;
+	view->details->redo_active = FALSE;
+	fm_directory_view_update_menus (view);
+	
+	nautilus_undostack_manager_undo (manager, GTK_WIDGET (view), finish_undoredo_callback);				      
+}
+
+static void
+real_action_redo (FMDirectoryView *view)
+{
+	NautilusUndoStackManager *manager = nautilus_undostack_manager_instance ();
+	
+	/* Disable menus because they are in an untrustworthy status */
+	view->details->undo_active = FALSE;
+	view->details->redo_active = FALSE;
+	fm_directory_view_update_menus (view);
+	
+	nautilus_undostack_manager_redo (manager, GTK_WIDGET (view), finish_undoredo_callback);
+}
+
+static void
 real_action_rename (FMDirectoryView *view,
 		    gboolean select_all)
 {
@@ -6333,6 +6433,20 @@ action_rename_select_all_callback (GtkAc
 }
 
 static void
+action_undo_callback (GtkAction *action,
+			gpointer callback_data)
+{
+	real_action_undo (FM_DIRECTORY_VIEW (callback_data));
+}
+
+static void
+action_redo_callback (GtkAction *action,
+			gpointer callback_data)
+{
+	real_action_redo (FM_DIRECTORY_VIEW (callback_data));
+}
+
+static void
 drive_mounted_callback (gboolean succeeded,
 			char *error,
 			char *detailed_error,
@@ -7071,6 +7185,15 @@ static const GtkActionEntry directory_vi
     N_("_Delete"), "",                /* label, accelerator */
     N_("Delete this folder, without moving to the Trash"),                   /* tooltip */ 
     G_CALLBACK (action_location_delete_callback) },
+    
+  { FM_ACTION_UNDO, GTK_STOCK_UNDO,                  /* name, stock id */
+    N_("_Undo"), "<control>Z",                /* label, accelerator */
+    N_("Undo the last action"),                   /* tooltip */ 
+    G_CALLBACK (action_undo_callback) },
+  { FM_ACTION_REDO, GTK_STOCK_REDO,                  /* name, stock id */
+    N_("_Redo"), "<control>Y",                /* label, accelerator */
+    N_("Redo the last undone action"),                   /* tooltip */ 
+    G_CALLBACK (action_redo_callback) },    
 };
 
 static const GtkToggleActionEntry directory_view_toggle_entries[] = {
@@ -7694,6 +7817,114 @@ clipboard_changed_callback (NautilusClip
 }
 
 static void
+undo_label_changed_callback (NautilusUndoStackManager* manager, gchar* new_label, gpointer data)
+{
+	FMDirectoryView *view;
+	view = FM_DIRECTORY_VIEW (data);
+	
+	view->details->undo_action_label = g_strdup (new_label);	
+}
+
+static void
+undo_description_changed_callback (NautilusUndoStackManager* manager, gchar* new_desc, gpointer data)
+{
+	FMDirectoryView *view;
+	view = FM_DIRECTORY_VIEW (data);
+	
+	view->details->undo_action_description = g_strdup (new_desc);	
+}
+
+static void
+redo_label_changed_callback (NautilusUndoStackManager* manager, gchar* new_label, gpointer data)
+{
+	FMDirectoryView *view;
+	view = FM_DIRECTORY_VIEW (data);
+	
+	view->details->redo_action_label = g_strdup (new_label);	
+}
+
+static void
+redo_description_changed_callback (NautilusUndoStackManager* manager, gchar* new_desc, gpointer data)
+{
+	FMDirectoryView *view;
+	view = FM_DIRECTORY_VIEW (data);
+	
+	view->details->redo_action_description = g_strdup (new_desc);	
+}
+
+static void
+undo_availability_changed_callback (NautilusUndoStackManager* manager, gboolean new_availability, gpointer data)
+{
+	FMDirectoryView *view;
+	view = FM_DIRECTORY_VIEW (data);
+	
+	view->details->undo_active = new_availability;	
+}
+
+static void
+redo_availability_changed_callback (NautilusUndoStackManager* manager, gboolean new_availability, gpointer data)
+{
+	FMDirectoryView *view;
+	view = FM_DIRECTORY_VIEW (data);
+	
+	view->details->redo_active = new_availability;	
+}
+
+static void
+undo_redo_schedule_menu_update_callback (NautilusUndoStackManager* manager, gpointer data)
+{
+	FMDirectoryView *view;
+	view = FM_DIRECTORY_VIEW (data);
+	
+	schedule_update_menus (view);
+}
+
+static void
+undo_update_menu (FMDirectoryView *view)
+{
+	GtkAction *action;
+	gboolean available = FALSE;
+	gchar* label;
+	gchar* tooltip;
+
+	/* Update undo entry */
+	action = gtk_action_group_get_action (view->details->dir_action_group,
+					      FM_ACTION_UNDO);
+	available = view->details->undo_active;					      
+	if (available) {
+		label = view->details->undo_action_label;
+		tooltip = view->details->undo_action_description;
+	} else {
+		/* Reset to default info */
+		label = _("Undo");
+		tooltip = _("Undo the last action");
+	}		
+	g_object_set (action,
+		      "label", label,
+		      "tooltip", tooltip,
+		      NULL);
+	gtk_action_set_sensitive (action, available);		  
+			      
+    /* Update redo entry */
+    action = gtk_action_group_get_action (view->details->dir_action_group,
+					      FM_ACTION_REDO);
+	available = view->details->redo_active;					      
+	if (available) {
+		label = view->details->redo_action_label;
+		tooltip = view->details->redo_action_description;
+	} else {
+		/* Reset to default info */
+		label = _("Redo");
+		tooltip = _("Redo the last undone action");
+	}		
+	g_object_set (action,
+		      "label", label,
+		      "tooltip", tooltip,
+		      NULL);
+	gtk_action_set_sensitive (action, available);						      	      
+}
+
+static void
 real_update_menus (FMDirectoryView *view)
 {
 	GList *selection, *l;
@@ -7949,6 +8180,8 @@ real_update_menus (FMDirectoryView *view
 	gtk_action_set_sensitive (action, can_create_files);
 
 	real_update_menus_volumes (view, selection, selection_count);
+	
+	undo_update_menu (view);
 
 	nautilus_file_list_free (selection);
 
diff -rupN nautilus-2.20.0-orig/src/file-manager/nautilus-directory-view-ui.xml nautilus-2.20.0-undo/src/file-manager/nautilus-directory-view-ui.xml
--- nautilus-2.20.0-orig/src/file-manager/nautilus-directory-view-ui.xml	2007-04-03 12:08:04.000000000 +0200
+++ nautilus-2.20.0-undo/src/file-manager/nautilus-directory-view-ui.xml	2007-10-16 09:15:59.000000000 +0200
@@ -54,6 +54,10 @@
 			<menuitem name="Copy" action="Copy"/>
 			<menuitem name="Paste" action="Paste"/>
 		</placeholder>
+		<placeholder name="Undostack Actions">
+			<menuitem name="Undo" action="Undo"/>
+			<menuitem name="Redo" action="Redo"/>
+		</placeholder>
 		<placeholder name="Select Items">
 		<menuitem name="Select All" action="Select All"/>
 		<menuitem name="Select Pattern" action="Select Pattern"/>
diff -rupN nautilus-2.20.0-orig/src/nautilus-application.h nautilus-2.20.0-undo/src/nautilus-application.h
--- nautilus-2.20.0-orig/src/nautilus-application.h	2007-04-03 12:08:06.000000000 +0200
+++ nautilus-2.20.0-undo/src/nautilus-application.h	2007-10-18 13:37:45.000000000 +0200
@@ -102,4 +102,6 @@ void                 nautilus_applicatio
 void                 nautilus_application_close_desktop     (void);
 void                 nautilus_application_load_session      (NautilusApplication *application,
 							     const char *filename); 
+
+
 #endif /* NAUTILUS_APPLICATION_H */
diff -rupN nautilus-2.20.0-orig/src/nautilus-shell-ui.xml nautilus-2.20.0-undo/src/nautilus-shell-ui.xml
--- nautilus-2.20.0-orig/src/nautilus-shell-ui.xml	2007-04-03 12:08:06.000000000 +0200
+++ nautilus-2.20.0-undo/src/nautilus-shell-ui.xml	2007-10-16 09:42:04.000000000 +0200
@@ -21,6 +21,8 @@
 		<menuitem name="Close" action="Close"/>
 	</menu>
 	<menu action="Edit">
+		<placeholder name="Undostack Actions"/>
+		<separator/>
 		<placeholder name="Clipboard Actions">
                 </placeholder>
 		<separator/>
diff -rupN nautilus-2.20.0-orig/src/nautilus-window-menus.c nautilus-2.20.0-undo/src/nautilus-window-menus.c
--- nautilus-2.20.0-orig/src/nautilus-window-menus.c	2007-08-21 11:37:48.000000000 +0200
+++ nautilus-2.20.0-undo/src/nautilus-window-menus.c	2007-10-16 10:02:44.000000000 +0200
@@ -596,9 +596,11 @@ static const GtkActionEntry main_entries
     N_("Prefere_nces"),               
     NULL, N_("Edit Nautilus preferences"),
     G_CALLBACK (action_preferences_callback) },
+#ifdef TEXT_CHANGE_UNDO     
   { "Undo", NULL, N_("_Undo"),               /* name, stock id, label */
     "<control>Z", N_("Undo the last text change"),
     G_CALLBACK (action_undo_callback) },
+#endif    
   { "Up", GTK_STOCK_GO_UP, N_("Open _Parent"),               /* name, stock id, label */
     "<alt>Up", N_("Open the parent folder"),
     G_CALLBACK (action_up_callback) },
