[nautilus] Bug 585591 – Starting/stopping drives



commit 66b53e82aa5d45cec89c99ab74e86caf2c49df00
Author: David Zeuthen <davidz redhat com>
Date:   Wed Jun 17 10:16:54 2009 -0400

    Bug 585591 â?? Starting/stopping drives
    
    This is the Nautilus user for the new GIO API for starting/stopping
    drives. See
    
    http://bugzilla.gnome.org/show_bug.cgi?id=585591
    
    for details.

 libnautilus-private/nautilus-file-private.h     |    3 +
 libnautilus-private/nautilus-file.c             |  147 ++++++++-
 libnautilus-private/nautilus-file.h             |   17 +
 libnautilus-private/nautilus-mime-actions.c     |   95 +++++-
 libnautilus-private/nautilus-vfs-file.c         |  116 ++++++
 src/file-manager/fm-actions.h                   |    6 +
 src/file-manager/fm-directory-view.c            |  446 +++++++++++++++++++++--
 src/file-manager/nautilus-directory-view-ui.xml |    8 +
 src/nautilus-places-sidebar.c                   |  205 ++++++++++-
 9 files changed, 1011 insertions(+), 32 deletions(-)
---
diff --git a/libnautilus-private/nautilus-file-private.h b/libnautilus-private/nautilus-file-private.h
index 010d7f6..a2fe8ab 100644
--- a/libnautilus-private/nautilus-file-private.h
+++ b/libnautilus-private/nautilus-file-private.h
@@ -214,6 +214,9 @@ struct NautilusFileDetails
 	eel_boolean_bit can_mount                     : 1;
 	eel_boolean_bit can_unmount                   : 1;
 	eel_boolean_bit can_eject                     : 1;
+	eel_boolean_bit can_start                     : 1;
+	eel_boolean_bit can_stop                      : 1;
+	eel_boolean_bit start_stop_type               : 3; /* GDriveStartStopType */
 
 	eel_boolean_bit filesystem_readonly           : 1;
 	eel_boolean_bit filesystem_use_preview        : 2; /* GFilesystemPreviewType */
diff --git a/libnautilus-private/nautilus-file.c b/libnautilus-private/nautilus-file.c
index 8f15448..0e0199b 100644
--- a/libnautilus-private/nautilus-file.c
+++ b/libnautilus-private/nautilus-file.c
@@ -312,6 +312,9 @@ nautilus_file_clear_info (NautilusFile *file)
 	file->details->can_mount = FALSE;
 	file->details->can_unmount = FALSE;
 	file->details->can_eject = FALSE;
+	file->details->can_start = FALSE;
+	file->details->can_stop = FALSE;
+	file->details->start_stop_type = G_DRIVE_START_STOP_TYPE_UNKNOWN;
 	file->details->has_permissions = FALSE;
 	file->details->permissions = 0;
 	file->details->size = -1;
@@ -879,6 +882,86 @@ nautilus_file_can_eject (NautilusFile *file)
 		 g_mount_can_eject (file->details->mount));
 }
 
+gboolean
+nautilus_file_can_start (NautilusFile *file)
+{
+	gboolean ret;
+	GDrive *drive;
+
+	g_return_val_if_fail (NAUTILUS_IS_FILE (file), FALSE);
+
+	ret = FALSE;
+
+	if (file->details->can_start) {
+		ret = TRUE;
+		goto out;
+	}
+
+	if (file->details->mount != NULL) {
+		drive = g_mount_get_drive (file->details->mount);
+		if (drive != NULL) {
+			ret = g_drive_can_start (drive);
+			g_object_unref (drive);
+		}
+	}
+
+ out:
+	return ret;
+}
+
+gboolean
+nautilus_file_can_stop (NautilusFile *file)
+{
+	gboolean ret;
+	GDrive *drive;
+
+	g_return_val_if_fail (NAUTILUS_IS_FILE (file), FALSE);
+
+	ret = FALSE;
+
+	if (file->details->can_stop) {
+		ret = TRUE;
+		goto out;
+	}
+
+	if (file->details->mount != NULL) {
+		drive = g_mount_get_drive (file->details->mount);
+		if (drive != NULL) {
+			ret = g_drive_can_stop (drive);
+			g_object_unref (drive);
+		}
+	}
+
+ out:
+	return ret;
+}
+
+GDriveStartStopType
+nautilus_file_get_start_stop_type (NautilusFile *file)
+{
+	GDriveStartStopType ret;
+	GDrive *drive;
+
+	g_return_val_if_fail (NAUTILUS_IS_FILE (file), FALSE);
+
+	ret = G_DRIVE_START_STOP_TYPE_UNKNOWN;
+
+	ret = file->details->start_stop_type;
+	if (ret != G_DRIVE_START_STOP_TYPE_UNKNOWN)
+		goto out;
+
+	if (file->details->mount != NULL) {
+		drive = g_mount_get_drive (file->details->mount);
+		if (drive != NULL) {
+			ret = g_drive_get_start_stop_type (drive);
+			g_object_unref (drive);
+		}
+	}
+
+ out:
+	return ret;
+}
+
 void
 nautilus_file_mount (NautilusFile                   *file,
 		     GMountOperation                *mount_op,
@@ -927,6 +1010,45 @@ nautilus_file_eject (NautilusFile *file)
 	}
 }
 
+void
+nautilus_file_start (NautilusFile                   *file,
+		     GMountOperation                *start_op,
+		     GCancellable                   *cancellable,
+		     NautilusFileOperationCallback   callback,
+		     gpointer                        callback_data)
+{
+	GError *error;
+
+	if (NAUTILUS_FILE_GET_CLASS (file)->start == NULL) {
+		if (callback) {
+			error = NULL;
+			g_set_error_literal (&error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED,
+                                             _("This file cannot be started"));
+			callback (file, NULL, error, callback_data);
+			g_error_free (error);
+		}
+	} else {
+		NAUTILUS_FILE_GET_CLASS (file)->start (file, start_op, cancellable, callback, callback_data);
+	}
+}
+
+void
+nautilus_file_stop (NautilusFile *file)
+{
+	if (file->details->can_stop) {
+		if (NAUTILUS_FILE_GET_CLASS (file)->stop != NULL) {
+			NAUTILUS_FILE_GET_CLASS (file)->stop (file);
+		}
+	} else if (file->details->mount != NULL) {
+		GDrive *drive;
+		drive = g_mount_get_drive (file->details->mount);
+		if (drive != NULL) {
+			g_drive_stop (drive, 0, NULL, NULL, NULL);
+			g_object_unref (drive);
+		}
+	}
+}
+
 /**
  * nautilus_file_is_desktop_directory:
  * 
@@ -1546,6 +1668,8 @@ update_info_internal (NautilusFile *file,
 	gboolean has_permissions;
 	guint32 permissions;
 	gboolean can_read, can_write, can_execute, can_delete, can_trash, can_rename, can_mount, can_unmount, can_eject;
+	gboolean can_start, can_stop;
+	GDriveStartStopType start_stop_type;
 	gboolean thumbnailing_failed;
 	int uid, gid;
 	goffset size;
@@ -1664,6 +1788,9 @@ update_info_internal (NautilusFile *file,
 	can_mount = FALSE;
 	can_unmount = FALSE;
 	can_eject = FALSE;
+	can_start = FALSE;
+	can_stop = FALSE;
+	start_stop_type = G_DRIVE_START_STOP_TYPE_UNKNOWN;
 	if (g_file_info_has_attribute (info, G_FILE_ATTRIBUTE_ACCESS_CAN_READ)) {
 		can_read = g_file_info_get_attribute_boolean (info,
 							      G_FILE_ATTRIBUTE_ACCESS_CAN_READ);
@@ -1700,6 +1827,18 @@ update_info_internal (NautilusFile *file,
 		can_eject = g_file_info_get_attribute_boolean (info,
 							       G_FILE_ATTRIBUTE_MOUNTABLE_CAN_EJECT);
 	}
+	if (g_file_info_has_attribute (info, G_FILE_ATTRIBUTE_MOUNTABLE_CAN_START)) {
+		can_start = g_file_info_get_attribute_boolean (info,
+							       G_FILE_ATTRIBUTE_MOUNTABLE_CAN_START);
+	}
+	if (g_file_info_has_attribute (info, G_FILE_ATTRIBUTE_MOUNTABLE_CAN_STOP)) {
+		can_stop = g_file_info_get_attribute_boolean (info,
+							      G_FILE_ATTRIBUTE_MOUNTABLE_CAN_STOP);
+	}
+	if (g_file_info_has_attribute (info, G_FILE_ATTRIBUTE_MOUNTABLE_START_STOP_TYPE)) {
+		start_stop_type = g_file_info_get_attribute_uint32 (info,
+								    G_FILE_ATTRIBUTE_MOUNTABLE_START_STOP_TYPE);
+	}
 	if (file->details->can_read != can_read ||
 	    file->details->can_write != can_write ||
 	    file->details->can_execute != can_execute ||
@@ -1708,7 +1847,10 @@ update_info_internal (NautilusFile *file,
 	    file->details->can_rename != can_rename ||
 	    file->details->can_mount != can_mount ||
 	    file->details->can_unmount != can_unmount ||
-	    file->details->can_eject != can_eject) {
+	    file->details->can_eject != can_eject ||
+	    file->details->can_start != can_start ||
+	    file->details->can_stop != can_stop ||
+	    file->details->start_stop_type != start_stop_type) {
 		changed = TRUE;
 	}
 	
@@ -1721,6 +1863,9 @@ update_info_internal (NautilusFile *file,
 	file->details->can_mount = can_mount;
 	file->details->can_unmount = can_unmount;
 	file->details->can_eject = can_eject;
+	file->details->can_start = can_start;
+	file->details->can_stop = can_stop;
+	file->details->start_stop_type = start_stop_type;
 
 	free_owner = FALSE;
 	owner = g_file_info_get_attribute_string (info, G_FILE_ATTRIBUTE_OWNER_USER);
diff --git a/libnautilus-private/nautilus-file.h b/libnautilus-private/nautilus-file.h
index a9e573d..0544308 100644
--- a/libnautilus-private/nautilus-file.h
+++ b/libnautilus-private/nautilus-file.h
@@ -255,6 +255,9 @@ gboolean                nautilus_file_can_trash                         (Nautilu
 gboolean                nautilus_file_can_mount                         (NautilusFile                   *file);
 gboolean                nautilus_file_can_unmount                       (NautilusFile                   *file);
 gboolean                nautilus_file_can_eject                         (NautilusFile                   *file);
+gboolean                nautilus_file_can_start                         (NautilusFile                   *file);
+gboolean                nautilus_file_can_stop                          (NautilusFile                   *file);
+GDriveStartStopType     nautilus_file_get_start_stop_type               (NautilusFile                   *file);
 
 void                    nautilus_file_mount                             (NautilusFile                   *file,
 									 GMountOperation                *mount_op,
@@ -264,6 +267,13 @@ void                    nautilus_file_mount                             (Nautilu
 void                    nautilus_file_unmount                           (NautilusFile                   *file);
 void                    nautilus_file_eject                             (NautilusFile                   *file);
 
+void                    nautilus_file_start                             (NautilusFile                   *file,
+									 GMountOperation                *start_op,
+									 GCancellable                   *cancellable,
+									 NautilusFileOperationCallback   callback,
+									 gpointer                        callback_data);
+void                    nautilus_file_stop                              (NautilusFile                   *file);
+
 /* Basic operations for file objects. */
 void                    nautilus_file_set_owner                         (NautilusFile                   *file,
 									 const char                     *user_name_or_id,
@@ -512,6 +522,13 @@ typedef struct {
 							  gpointer                        callback_data);
 	void                 (* unmount)                 (NautilusFile *file);
 	void                 (* eject)                   (NautilusFile *file);
+
+	void                  (* start)                  (NautilusFile                   *file,
+							  GMountOperation                *start_op,
+							  GCancellable                   *cancellable,
+							  NautilusFileOperationCallback   callback,
+							  gpointer                        callback_data);
+	void                 (* stop)                    (NautilusFile *file);
 } NautilusFileClass;
 
 #endif /* NAUTILUS_FILE_H */
diff --git a/libnautilus-private/nautilus-mime-actions.c b/libnautilus-private/nautilus-mime-actions.c
index 770ff46..bee21a5 100644
--- a/libnautilus-private/nautilus-mime-actions.c
+++ b/libnautilus-private/nautilus-mime-actions.c
@@ -72,6 +72,7 @@ typedef struct {
 	GCancellable *cancellable;
 	GList *locations;
 	GList *mountables;
+	GList *start_mountables;
 	GList *not_mounted;
 	NautilusWindowOpenMode mode;
 	NautilusWindowOpenFlags flags;
@@ -104,6 +105,7 @@ static void cancel_activate_callback                (gpointer            callbac
 static void activate_activation_uris_ready_callback (GList              *files,
 						     gpointer            callback_data);
 static void activation_mount_mountables             (ActivateParameters *parameters);
+static void activation_start_mountables             (ActivateParameters *parameters);
 static void activate_callback                       (GList              *files,
 						     gpointer            callback_data);
 static void activation_mount_not_mounted            (ActivateParameters *parameters);
@@ -1025,6 +1027,7 @@ activation_parameters_free (ActivateParameters *parameters)
 	g_object_unref (parameters->cancellable);
 	launch_location_list_free (parameters->locations);
 	nautilus_file_list_free (parameters->mountables);
+	nautilus_file_list_free (parameters->start_mountables);
 	nautilus_file_list_free (parameters->not_mounted);
 	g_free (parameters->activation_directory);
 	g_free (parameters->timed_wait_prompt);
@@ -2133,7 +2136,85 @@ activation_mount_mountables (ActivateParameters *parameters)
 		return;
 	}
 
-	activation_get_activation_uris (parameters);
+	if (parameters->mountables == NULL && parameters->start_mountables == NULL)
+		activation_get_activation_uris (parameters);
+}
+
+
+static void
+activation_mountable_started (NautilusFile  *file,
+			      GFile         *gfile_of_file,
+			      GError        *error,
+			      gpointer       callback_data)
+{
+	ActivateParameters *parameters = callback_data;
+	LaunchLocation *location;
+
+	/* Remove from list of files that have to be mounted */
+	parameters->start_mountables = g_list_remove (parameters->start_mountables, file);
+	nautilus_file_unref (file);
+
+	if (error == NULL) {
+		/* Remove file */
+		location = find_launch_location_for_file (parameters->locations, file);
+		if (location != NULL) {
+			parameters->locations = g_list_remove (parameters->locations, location);
+			launch_location_free (location);
+		}
+
+	} else {
+		/* Remove failed file */
+		if (error->domain != G_IO_ERROR ||
+		    (error->code != G_IO_ERROR_FAILED_HANDLED)) {
+			location = find_launch_location_for_file (parameters->locations,
+								  file);
+			if (location) {
+				parameters->locations =
+					g_list_remove (parameters->locations,
+						       location);
+				launch_location_free (location);
+			}
+		}
+
+		if (error->domain != G_IO_ERROR ||
+		    (error->code != G_IO_ERROR_CANCELLED &&
+		     error->code != G_IO_ERROR_FAILED_HANDLED)) {
+			eel_show_error_dialog (_("Unable to start location"),
+					       error->message, NULL);
+		}
+
+		if (error->code == G_IO_ERROR_CANCELLED) {
+			activation_parameters_free (parameters);
+			return;
+		}
+	}
+
+	/* Start more mountables */
+	activation_start_mountables (parameters);
+}
+
+static void
+activation_start_mountables (ActivateParameters *parameters)
+{
+	NautilusFile *file;
+	GMountOperation *start_op;
+
+	if (parameters->start_mountables != NULL) {
+		file = parameters->start_mountables->data;
+		start_op = gtk_mount_operation_new (parameters->parent_window);
+		g_signal_connect (start_op, "notify::is-showing",
+				  G_CALLBACK (activate_mount_op_active), parameters);
+		nautilus_file_start (file,
+				     start_op,
+				     parameters->cancellable,
+				     activation_mountable_started,
+				     parameters);
+		g_object_unref (start_op);
+		return;
+	}
+
+	if (parameters->mountables == NULL && parameters->start_mountables == NULL)
+		activation_get_activation_uris (parameters);
 }
 
 /**
@@ -2205,10 +2286,20 @@ nautilus_mime_activate_files (GtkWindow *parent_window,
 			parameters->mountables = g_list_prepend (parameters->mountables,
 								 nautilus_file_ref (file));
 		}
+
+		if (nautilus_file_can_start (file)) {
+			parameters->start_mountables = g_list_prepend (parameters->start_mountables,
+								       nautilus_file_ref (file));
+		}
 	}
 	
 	activation_start_timed_cancel (parameters);
-	activation_mount_mountables (parameters);
+	if (parameters->mountables != NULL)
+		activation_mount_mountables (parameters);
+	if (parameters->start_mountables != NULL)
+		activation_start_mountables (parameters);
+	if (parameters->mountables == NULL && parameters->start_mountables == NULL)
+		activation_get_activation_uris (parameters);
 }
 
 /**
diff --git a/libnautilus-private/nautilus-vfs-file.c b/libnautilus-private/nautilus-vfs-file.c
index 11c5846..8714575 100644
--- a/libnautilus-private/nautilus-vfs-file.c
+++ b/libnautilus-private/nautilus-vfs-file.c
@@ -377,6 +377,120 @@ vfs_file_eject (NautilusFile *file)
 }
 
 static void
+vfs_file_start_callback (GObject *source_object,
+			 GAsyncResult *res,
+			 gpointer callback_data)
+{
+	NautilusFileOperation *op;
+	gboolean started;
+	GError *error;
+
+	op = callback_data;
+
+	error = NULL;
+	started = g_file_start_mountable_finish (G_FILE (source_object),
+						 res, &error);
+
+	if (!started &&
+	    error->domain == G_IO_ERROR &&
+	    (error->code == G_IO_ERROR_FAILED_HANDLED ||
+	     error->code == G_IO_ERROR_CANCELLED)) {
+		g_error_free (error);
+		error = NULL;
+	}
+
+	nautilus_file_operation_complete (op, G_FILE (source_object), error);
+	if (error) {
+		g_error_free (error);
+	}
+}
+
+
+static void
+vfs_file_start (NautilusFile                   *file,
+		GMountOperation                *start_op,
+		GCancellable                   *cancellable,
+		NautilusFileOperationCallback   callback,
+		gpointer                        callback_data)
+{
+	NautilusFileOperation *op;
+	GError *error;
+	GFile *location;
+
+	if (file->details->type != G_FILE_TYPE_MOUNTABLE) {
+		if (callback) {
+			error = NULL;
+			g_set_error_literal (&error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED,
+                                             _("This file cannot be started"));
+			callback (file, NULL, error, callback_data);
+			g_error_free (error);
+		}
+		return;
+	}
+
+	op = nautilus_file_operation_new (file, callback, callback_data);
+	if (cancellable) {
+		g_object_unref (op->cancellable);
+		op->cancellable = g_object_ref (cancellable);
+	}
+
+	location = nautilus_file_get_location (file);
+	g_file_start_mountable (location,
+				0,
+				start_op,
+				op->cancellable,
+				vfs_file_start_callback,
+				op);
+	g_object_unref (location);
+}
+
+static void
+vfs_file_stop_callback (GObject *source_object,
+			GAsyncResult *res,
+			gpointer callback_data)
+{
+	NautilusFileOperation *op;
+	gboolean stopped;
+	GError *error;
+
+	op = callback_data;
+
+	error = NULL;
+	stopped = g_file_stop_mountable_finish (G_FILE (source_object),
+						res, &error);
+
+	if (!stopped &&
+	    error->domain == G_IO_ERROR &&
+	    (error->code == G_IO_ERROR_FAILED_HANDLED ||
+	     error->code == G_IO_ERROR_CANCELLED)) {
+		g_error_free (error);
+		error = NULL;
+	}
+
+	nautilus_file_operation_complete (op, G_FILE (source_object), error);
+	if (error) {
+		g_error_free (error);
+	}
+}
+
+static void
+vfs_file_stop (NautilusFile *file)
+{
+	NautilusFileOperation *op;
+	GFile *location;
+
+	op = nautilus_file_operation_new (file, NULL, NULL);
+
+	location = nautilus_file_get_location (file);
+	g_file_stop_mountable (location,
+			       G_MOUNT_UNMOUNT_NONE,
+			       op->cancellable,
+			       vfs_file_stop_callback,
+			       op);
+	g_object_unref (location);
+}
+
+static void
 nautilus_vfs_file_init (gpointer object, gpointer klass)
 {
 	NautilusVFSFile *file;
@@ -404,4 +518,6 @@ nautilus_vfs_file_class_init (gpointer klass)
 	file_class->mount = vfs_file_mount;
 	file_class->unmount = vfs_file_unmount;
 	file_class->eject = vfs_file_eject;
+	file_class->start = vfs_file_start;
+	file_class->stop = vfs_file_stop;
 }
diff --git a/src/file-manager/fm-actions.h b/src/file-manager/fm-actions.h
index 57bc10c..77dc94f 100644
--- a/src/file-manager/fm-actions.h
+++ b/src/file-manager/fm-actions.h
@@ -69,14 +69,20 @@
 #define FM_ACTION_UNMOUNT_VOLUME "Unmount Volume"
 #define FM_ACTION_EJECT_VOLUME "Eject Volume"
 #define FM_ACTION_FORMAT_VOLUME "Format Volume"
+#define FM_ACTION_START_VOLUME "Start Volume"
+#define FM_ACTION_STOP_VOLUME "Stop Volume"
 #define FM_ACTION_SELF_MOUNT_VOLUME "Self Mount Volume"
 #define FM_ACTION_SELF_UNMOUNT_VOLUME "Self Unmount Volume"
 #define FM_ACTION_SELF_EJECT_VOLUME "Self Eject Volume"
 #define FM_ACTION_SELF_FORMAT_VOLUME "Self Format Volume"
+#define FM_ACTION_SELF_START_VOLUME "Self Start Volume"
+#define FM_ACTION_SELF_STOP_VOLUME "Self Stop Volume"
 #define FM_ACTION_LOCATION_MOUNT_VOLUME "Location Mount Volume"
 #define FM_ACTION_LOCATION_UNMOUNT_VOLUME "Location Unmount Volume"
 #define FM_ACTION_LOCATION_EJECT_VOLUME "Location Eject Volume"
 #define FM_ACTION_LOCATION_FORMAT_VOLUME "Location Format Volume"
+#define FM_ACTION_LOCATION_START_VOLUME "Location Start Volume"
+#define FM_ACTION_LOCATION_STOP_VOLUME "Location Stop Volume"
 #define FM_ACTION_SCRIPTS "Scripts"
 #define FM_ACTION_NEW_DOCUMENTS "New Documents"
 #define FM_ACTION_NEW_EMPTY_FILE "New Empty File"
diff --git a/src/file-manager/fm-directory-view.c b/src/file-manager/fm-directory-view.c
index e33a38f..aaf8af9 100644
--- a/src/file-manager/fm-directory-view.c
+++ b/src/file-manager/fm-directory-view.c
@@ -353,6 +353,10 @@ static void action_unmount_volume_callback         (GtkAction *action,
 						    gpointer   data);
 static void action_format_volume_callback          (GtkAction *action,
 						    gpointer   data);
+static void action_start_volume_callback           (GtkAction *action,
+						    gpointer   data);
+static void action_stop_volume_callback            (GtkAction *action,
+						    gpointer   data);
 
 /* location popup-related actions */
 
@@ -6030,6 +6034,68 @@ action_eject_volume_callback (GtkAction *action,
 }
 
 static void
+file_start_callback (NautilusFile  *file,
+		     GFile         *result_location,
+		     GError        *error,
+		     gpointer       callback_data)
+{
+	if (error != NULL &&
+	    (error->domain != G_IO_ERROR ||
+	     (error->code != G_IO_ERROR_CANCELLED &&
+	      error->code != G_IO_ERROR_FAILED_HANDLED &&
+	      error->code != G_IO_ERROR_ALREADY_MOUNTED))) {
+		eel_show_error_dialog (_("Unable to start location"),
+				       error->message, NULL);
+	}
+}
+
+static void
+action_start_volume_callback (GtkAction *action,
+			      gpointer   data)
+{
+	NautilusFile *file;
+	GList *selection, *l;
+	FMDirectoryView *view;
+	GMountOperation *mount_op;
+
+        view = FM_DIRECTORY_VIEW (data);
+
+	selection = fm_directory_view_get_selection (view);
+	for (l = selection; l != NULL; l = l->next) {
+		file = NAUTILUS_FILE (l->data);
+
+		if (nautilus_file_can_start (file)) {
+			mount_op = gtk_mount_operation_new (fm_directory_view_get_containing_window (view));
+			nautilus_file_start (file, mount_op, NULL,
+					     file_start_callback, NULL);
+			g_object_unref (mount_op);
+		}
+	}
+	nautilus_file_list_free (selection);
+}
+
+static void
+action_stop_volume_callback (GtkAction *action,
+			     gpointer   data)
+{
+	NautilusFile *file;
+	GList *selection, *l;
+	FMDirectoryView *view;
+
+        view = FM_DIRECTORY_VIEW (data);
+
+	selection = fm_directory_view_get_selection (view);
+	for (l = selection; l != NULL; l = l->next) {
+		file = NAUTILUS_FILE (l->data);
+
+		if (nautilus_file_can_stop (file)) {
+			nautilus_file_stop (file);
+		}
+	}
+	nautilus_file_list_free (selection);
+}
+
+static void
 action_self_mount_volume_callback (GtkAction *action,
 				   gpointer data)
 {
@@ -6105,6 +6171,43 @@ action_self_format_volume_callback (GtkAction *action,
 }
 
 static void
+action_self_start_volume_callback (GtkAction *action,
+				   gpointer   data)
+{
+	NautilusFile *file;
+	FMDirectoryView *view;
+	GMountOperation *start_op;
+
+	view = FM_DIRECTORY_VIEW (data);
+
+	file = fm_directory_view_get_directory_as_file (view);
+	if (file == NULL) {
+		return;
+	}
+
+	start_op = gtk_mount_operation_new (fm_directory_view_get_containing_window (view));
+	nautilus_file_start (file, start_op, NULL, file_start_callback, NULL);
+	g_object_unref (start_op);
+}
+
+static void
+action_self_stop_volume_callback (GtkAction *action,
+				  gpointer   data)
+{
+	NautilusFile *file;
+	FMDirectoryView *view;
+
+	view = FM_DIRECTORY_VIEW (data);
+
+	file = fm_directory_view_get_directory_as_file (view);
+	if (file == NULL) {
+		return;
+	}
+
+	nautilus_file_stop (file);
+}
+
+static void
 action_location_mount_volume_callback (GtkAction *action,
 				       gpointer data)
 {
@@ -6180,6 +6283,43 @@ action_location_format_volume_callback (GtkAction *action,
 }
 
 static void
+action_location_start_volume_callback (GtkAction *action,
+				       gpointer   data)
+{
+	NautilusFile *file;
+	FMDirectoryView *view;
+	GMountOperation *start_op;
+
+	view = FM_DIRECTORY_VIEW (data);
+
+	file = view->details->location_popup_directory_as_file;
+	if (file == NULL) {
+		return;
+	}
+
+	start_op = gtk_mount_operation_new (fm_directory_view_get_containing_window (view));
+	nautilus_file_start (file, start_op, NULL, file_start_callback, NULL);
+	g_object_unref (start_op);
+}
+
+static void
+action_location_stop_volume_callback (GtkAction *action,
+				      gpointer   data)
+{
+	NautilusFile *file;
+	FMDirectoryView *view;
+
+	view = FM_DIRECTORY_VIEW (data);
+
+	file = view->details->location_popup_directory_as_file;
+	if (file == NULL) {
+		return;
+	}
+
+	nautilus_file_stop (file);
+}
+
+static void
 connect_to_server_response_callback (GtkDialog *dialog,
 				     int response_id,
 				     gpointer data)
@@ -6722,37 +6862,53 @@ static const GtkActionEntry directory_view_entries[] = {
   /* tooltip */                  N_("Make a permanent connection to this server"),
                                  G_CALLBACK (action_connect_to_server_link_callback) },
   /* name, stock id */         { "Mount Volume", NULL,
-  /* label, accelerator */       N_("_Mount Volume"), NULL,
+  /* label, accelerator */       N_("_Mount"), NULL,
   /* tooltip */                  N_("Mount the selected volume"),
                                  G_CALLBACK (action_mount_volume_callback) },
   /* name, stock id */         { "Unmount Volume", NULL,
-  /* label, accelerator */       N_("_Unmount Volume"), NULL,
+  /* label, accelerator */       N_("_Unmount"), NULL,
   /* tooltip */                  N_("Unmount the selected volume"),
                                  G_CALLBACK (action_unmount_volume_callback) },
   /* name, stock id */         { "Eject Volume", NULL,
-  /* label, accelerator */       N_("_Eject Volume"), NULL,
+  /* label, accelerator */       N_("_Eject"), NULL,
   /* tooltip */                  N_("Eject the selected volume"),
                                  G_CALLBACK (action_eject_volume_callback) },
   /* name, stock id */         { "Format Volume", NULL,
   /* label, accelerator */       N_("_Format"), NULL,
   /* tooltip */                  N_("Format the selected volume"),
                                  G_CALLBACK (action_format_volume_callback) },
+  /* name, stock id */         { "Start Volume", NULL,
+  /* label, accelerator */       N_("_Start"), NULL,
+  /* tooltip */                  N_("Start the selected volume"),
+                                 G_CALLBACK (action_start_volume_callback) },
+  /* name, stock id */         { "Stop Volume", NULL,
+  /* label, accelerator */       N_("_Stop"), NULL,
+  /* tooltip */                  N_("Stop the selected volume"),
+                                 G_CALLBACK (action_stop_volume_callback) },
   /* name, stock id */         { "Self Mount Volume", NULL,
-  /* label, accelerator */       N_("_Mount Volume"), NULL,
+  /* label, accelerator */       N_("_Mount"), NULL,
   /* tooltip */                  N_("Mount the volume associated with the open folder"),
                                  G_CALLBACK (action_self_mount_volume_callback) },
   /* name, stock id */         { "Self Unmount Volume", NULL,
-  /* label, accelerator */       N_("_Unmount Volume"), NULL,
+  /* label, accelerator */       N_("_Unmount"), NULL,
   /* tooltip */                  N_("Unmount the volume associated with the open folder"),
                                  G_CALLBACK (action_self_unmount_volume_callback) },
   /* name, stock id */         { "Self Eject Volume", NULL,
-  /* label, accelerator */       N_("_Eject Volume"), NULL,
+  /* label, accelerator */       N_("_Eject"), NULL,
   /* tooltip */                  N_("Eject the volume associated with the open folder"),
                                  G_CALLBACK (action_self_eject_volume_callback) },
   /* name, stock id */         { "Self Format Volume", NULL,
   /* label, accelerator */       N_("_Format"), NULL,
   /* tooltip */                  N_("Format the volume associated with the open folder"),
                                  G_CALLBACK (action_self_format_volume_callback) },
+  /* name, stock id */         { "Self Start Volume", NULL,
+  /* label, accelerator */       N_("_Start"), NULL,
+  /* tooltip */                  N_("Start the volume associated with the open folder"),
+                                 G_CALLBACK (action_self_start_volume_callback) },
+  /* name, stock id */         { "Self Stop Volume", NULL,
+  /* label, accelerator */       N_("_Stop"), NULL,
+  /* tooltip */                  N_("Stop the volume associated with the open folder"),
+                                 G_CALLBACK (action_self_stop_volume_callback) },
   /* name, stock id */         { "OpenCloseParent", NULL,
   /* label, accelerator */       N_("Open File and Close window"), "<alt><shift>Down",
   /* tooltip */                  NULL,
@@ -6807,21 +6963,29 @@ static const GtkActionEntry directory_view_entries[] = {
                                  G_CALLBACK (action_location_restore_from_trash_callback) },
 
   /* name, stock id */         { "Location Mount Volume", NULL,
-  /* label, accelerator */       N_("_Mount Volume"), NULL,
+  /* label, accelerator */       N_("_Mount"), NULL,
   /* tooltip */                  N_("Mount the volume associated with this folder"),
                                  G_CALLBACK (action_location_mount_volume_callback) },
   /* name, stock id */         { "Location Unmount Volume", NULL,
-  /* label, accelerator */       N_("_Unmount Volume"), NULL,
+  /* label, accelerator */       N_("_Unmount"), NULL,
   /* tooltip */                  N_("Unmount the volume associated with this folder"),
                                  G_CALLBACK (action_location_unmount_volume_callback) },
   /* name, stock id */         { "Location Eject Volume", NULL,
-  /* label, accelerator */       N_("_Eject Volume"), NULL,
+  /* label, accelerator */       N_("_Eject"), NULL,
   /* tooltip */                  N_("Eject the volume associated with this folder"),
                                  G_CALLBACK (action_location_eject_volume_callback) },
   /* name, stock id */         { "Location Format Volume", NULL,
   /* label, accelerator */       N_("_Format"), NULL,
   /* tooltip */                  N_("Format the volume associated with this folder"),
                                  G_CALLBACK (action_location_format_volume_callback) },
+  /* name, stock id */         { "Location Start Volume", NULL,
+  /* label, accelerator */       N_("_Start"), NULL,
+  /* tooltip */                  N_("Start the volume associated with this folder"),
+                                 G_CALLBACK (action_location_start_volume_callback) },
+  /* name, stock id */         { "Location Stop Volume", NULL,
+  /* label, accelerator */       N_("_Stop"), NULL,
+  /* tooltip */                  N_("Stop the volume associated with this folder"),
+                                 G_CALLBACK (action_location_stop_volume_callback) },
 
   /* name, stock id */         { "LocationProperties", GTK_STOCK_PROPERTIES,
   /* label, accelerator */       N_("_Properties"), NULL,
@@ -7102,12 +7266,15 @@ file_list_all_are_folders (GList *file_list)
 }
 
 static void
-file_should_show_foreach (NautilusFile *file,
-			  gboolean     *show_mount,
-			  gboolean     *show_unmount,
-			  gboolean     *show_eject,
-			  gboolean     *show_connect,
-			  gboolean     *show_format)
+file_should_show_foreach (NautilusFile        *file,
+			  gboolean            *show_mount,
+			  gboolean            *show_unmount,
+			  gboolean            *show_eject,
+			  gboolean            *show_connect,
+			  gboolean            *show_format,
+			  gboolean            *show_start,
+			  gboolean            *show_stop,
+			  GDriveStartStopType *start_stop_type)
 {
 	char *uri;
 
@@ -7116,6 +7283,8 @@ file_should_show_foreach (NautilusFile *file,
 	*show_eject = FALSE;
 	*show_connect = FALSE;
 	*show_format = FALSE;
+	*show_start = FALSE;
+	*show_stop = FALSE;
 
 	if (nautilus_file_can_eject (file)) {
 		*show_eject = TRUE;
@@ -7136,6 +7305,16 @@ file_should_show_foreach (NautilusFile *file,
 #endif
 	}
 
+	if (nautilus_file_can_start (file)) {
+		*show_start = TRUE;
+	}
+
+	if (nautilus_file_can_stop (file)) {
+		*show_stop = TRUE;
+	}
+
+	*start_stop_type = nautilus_file_get_start_stop_type (file);
+
 	if (nautilus_file_is_nautilus_link (file)) {
 		uri = nautilus_file_get_activation_uri (file);
 		if (uri != NULL &&
@@ -7151,16 +7330,21 @@ file_should_show_foreach (NautilusFile *file,
 }
 
 static void
-file_should_show_self (NautilusFile *file,
-		       gboolean     *show_mount,
-		       gboolean     *show_unmount,
-		       gboolean     *show_eject,
-		       gboolean     *show_format)
+file_should_show_self (NautilusFile        *file,
+		       gboolean            *show_mount,
+		       gboolean            *show_unmount,
+		       gboolean            *show_eject,
+		       gboolean            *show_format,
+		       gboolean            *show_start,
+		       gboolean            *show_stop,
+		       GDriveStartStopType *start_stop_type)
 {
 	*show_mount = FALSE;
 	*show_unmount = FALSE;
 	*show_eject = FALSE;
 	*show_format = FALSE;
+	*show_start = FALSE;
+	*show_stop = FALSE;
 
 	if (file == NULL) {
 		return;
@@ -7183,6 +7367,17 @@ file_should_show_self (NautilusFile *file,
 		*show_format = TRUE;
 	}
 #endif
+
+	if (nautilus_file_can_start (file)) {
+		*show_start = TRUE;
+	}
+
+	if (nautilus_file_can_stop (file)) {
+		*show_stop = TRUE;
+	}
+
+	*start_stop_type = nautilus_file_get_start_stop_type (file);
+
 }
 
 static GHashTable *
@@ -7385,10 +7580,16 @@ real_update_menus_volumes (FMDirectoryView *view,
 	gboolean show_eject;
 	gboolean show_connect;
 	gboolean show_format;
+	gboolean show_start;
+	gboolean show_stop;
+	GDriveStartStopType start_stop_type;
 	gboolean show_self_mount;
 	gboolean show_self_unmount;
 	gboolean show_self_eject;
 	gboolean show_self_format;
+	gboolean show_self_start;
+	gboolean show_self_stop;
+	GDriveStartStopType self_start_stop_type;
 	GtkAction *action;
 
 	show_mount = (selection != NULL);
@@ -7396,16 +7597,22 @@ real_update_menus_volumes (FMDirectoryView *view,
 	show_eject = (selection != NULL);
 	show_connect = (selection != NULL && selection_count == 1);
 	show_format = (selection != NULL && selection_count == 1);
+	show_start = (selection != NULL && selection_count == 1);
+	show_stop = (selection != NULL && selection_count == 1);
+	start_stop_type = G_DRIVE_START_STOP_TYPE_UNKNOWN;
 
 	for (l = selection; l != NULL && (show_mount || show_unmount
 					  || show_eject || show_connect
-                                          || show_format);
+                                          || show_format || show_start
+					  || show_stop);
 	     l = l->next) {
 		gboolean show_mount_one;
 		gboolean show_unmount_one;
 		gboolean show_eject_one;
 		gboolean show_connect_one;
 		gboolean show_format_one;
+		gboolean show_start_one;
+		gboolean show_stop_one;
 
 		file = NAUTILUS_FILE (l->data);
 		file_should_show_foreach (file,
@@ -7413,13 +7620,18 @@ real_update_menus_volumes (FMDirectoryView *view,
 					  &show_unmount_one,
 					  &show_eject_one,
 					  &show_connect_one,
-                                          &show_format_one);
+                                          &show_format_one,
+                                          &show_start_one,
+                                          &show_stop_one,
+					  &start_stop_type);
 
 		show_mount &= show_mount_one;
 		show_unmount &= show_unmount_one;
 		show_eject &= show_eject_one;
 		show_connect &= show_connect_one;
 		show_format &= show_format_one;
+		show_start &= show_start_one;
+		show_stop &= show_stop_one;
 	}
 
 	action = gtk_action_group_get_action (view->details->dir_action_group,
@@ -7442,14 +7654,76 @@ real_update_menus_volumes (FMDirectoryView *view,
 					      FM_ACTION_FORMAT_VOLUME);
 	gtk_action_set_visible (action, show_format);
 
-	show_self_mount = show_self_unmount = show_self_eject = show_self_format = FALSE;
+	action = gtk_action_group_get_action (view->details->dir_action_group,
+					      FM_ACTION_START_VOLUME);
+	gtk_action_set_visible (action, show_start);
+	if (show_start) {
+		switch (start_stop_type) {
+		default:
+		case G_DRIVE_START_STOP_TYPE_UNKNOWN:
+			gtk_action_set_label (action, _("_Start"));
+			gtk_action_set_tooltip (action, _("Start the select drive"));
+			break;
+		case G_DRIVE_START_STOP_TYPE_SHUTDOWN:
+			gtk_action_set_label (action, _("_Start"));
+			gtk_action_set_tooltip (action, _("Start the select drive"));
+			break;
+		case G_DRIVE_START_STOP_TYPE_NETWORK:
+			gtk_action_set_label (action, _("_Connect"));
+			gtk_action_set_tooltip (action, _("Connect to the selected drive"));
+			break;
+		case G_DRIVE_START_STOP_TYPE_MULTIDISK:
+			gtk_action_set_label (action, _("_Start Multi-disk Drive"));
+			gtk_action_set_tooltip (action, _("Start the selected multi-disk drive"));
+			break;
+		case G_DRIVE_START_STOP_TYPE_PASSWORD:
+			gtk_action_set_label (action, _("U_nlock Drive"));
+			gtk_action_set_tooltip (action, _("Unlock the selected drive"));
+			break;
+		}
+	}
+
+	action = gtk_action_group_get_action (view->details->dir_action_group,
+					      FM_ACTION_STOP_VOLUME);
+	gtk_action_set_visible (action, show_stop);
+	if (show_stop) {
+		switch (start_stop_type) {
+		default:
+		case G_DRIVE_START_STOP_TYPE_UNKNOWN:
+			gtk_action_set_label (action, _("_Stop"));
+			gtk_action_set_tooltip (action, _("Stop the selected drive"));
+			break;
+		case G_DRIVE_START_STOP_TYPE_SHUTDOWN:
+			gtk_action_set_label (action, _("_Safely Remove Drive"));
+			gtk_action_set_tooltip (action, _("Safely remove the selected drive"));
+			break;
+		case G_DRIVE_START_STOP_TYPE_NETWORK:
+			gtk_action_set_label (action, _("_Disconnect"));
+			gtk_action_set_tooltip (action, _("Disconnect the selected drive"));
+			break;
+		case G_DRIVE_START_STOP_TYPE_MULTIDISK:
+			gtk_action_set_label (action, _("_Stop Multi-disk Drive"));
+			gtk_action_set_tooltip (action, _("Stop the selected multi-disk drive"));
+			break;
+		case G_DRIVE_START_STOP_TYPE_PASSWORD:
+			gtk_action_set_label (action, _("_Lock Drive"));
+			gtk_action_set_tooltip (action, _("Lock the selected drive"));
+			break;
+		}
+	}
+
+	show_self_mount = show_self_unmount = show_self_eject =
+		show_self_format = show_self_start = show_self_stop = FALSE;
 
 	file = fm_directory_view_get_directory_as_file (view);
 	file_should_show_self (file,
 			       &show_self_mount,
 			       &show_self_unmount,
 			       &show_self_eject,
-			       &show_self_format);
+			       &show_self_format,
+			       &show_self_start,
+			       &show_self_stop,
+			       &self_start_stop_type);
 
 	action = gtk_action_group_get_action (view->details->dir_action_group,
 					      FM_ACTION_SELF_MOUNT_VOLUME);
@@ -7466,6 +7740,64 @@ real_update_menus_volumes (FMDirectoryView *view,
 	action = gtk_action_group_get_action (view->details->dir_action_group,
 					      FM_ACTION_SELF_FORMAT_VOLUME);
 	gtk_action_set_visible (action, show_self_format);
+
+	action = gtk_action_group_get_action (view->details->dir_action_group,
+					      FM_ACTION_SELF_START_VOLUME);
+	gtk_action_set_visible (action, show_self_start);
+	if (show_self_start) {
+		switch (self_start_stop_type) {
+		default:
+		case G_DRIVE_START_STOP_TYPE_UNKNOWN:
+			gtk_action_set_label (action, _("_Start"));
+			gtk_action_set_tooltip (action, _("Start the drive associated with the open folder"));
+			break;
+		case G_DRIVE_START_STOP_TYPE_SHUTDOWN:
+			gtk_action_set_label (action, _("_Start"));
+			gtk_action_set_tooltip (action, _("Start the drive associated with the open folder"));
+			break;
+		case G_DRIVE_START_STOP_TYPE_NETWORK:
+			gtk_action_set_label (action, _("_Connect"));
+			gtk_action_set_tooltip (action, _("Connect to the drive associated with the open folder"));
+			break;
+		case G_DRIVE_START_STOP_TYPE_MULTIDISK:
+			gtk_action_set_label (action, _("_Start Multi-disk Drive"));
+			gtk_action_set_tooltip (action, _("Start the multi-disk drive associated with the open folder"));
+			break;
+		case G_DRIVE_START_STOP_TYPE_PASSWORD:
+			gtk_action_set_label (action, _("_Unlock Drive"));
+			gtk_action_set_tooltip (action, _("Unlock the drive associated with the open folder"));
+			break;
+		}
+	}
+
+	action = gtk_action_group_get_action (view->details->dir_action_group,
+					      FM_ACTION_SELF_STOP_VOLUME);
+	gtk_action_set_visible (action, show_self_stop);
+	if (show_self_stop) {
+		switch (self_start_stop_type) {
+		default:
+		case G_DRIVE_START_STOP_TYPE_UNKNOWN:
+			gtk_action_set_label (action, _("_Stop"));
+			gtk_action_set_tooltip (action, _("_Stop the drive associated with the open folder"));
+			break;
+		case G_DRIVE_START_STOP_TYPE_SHUTDOWN:
+			gtk_action_set_label (action, _("_Safely Remove Drive"));
+			gtk_action_set_tooltip (action, _("Safely remove the drive associated with the open folder"));
+			break;
+		case G_DRIVE_START_STOP_TYPE_NETWORK:
+			gtk_action_set_label (action, _("_Disconnect"));
+			gtk_action_set_tooltip (action, _("Disconnect the drive associated with the open folder"));
+			break;
+		case G_DRIVE_START_STOP_TYPE_MULTIDISK:
+			gtk_action_set_label (action, _("_Stop Multi-disk Drive"));
+			gtk_action_set_tooltip (action, _("Stop the multi-disk drive associated with the open folder"));
+			break;
+		case G_DRIVE_START_STOP_TYPE_PASSWORD:
+			gtk_action_set_label (action, _("_Lock Drive"));
+			gtk_action_set_tooltip (action, _("Lock the drive associated with the open folder"));
+			break;
+		}
+	}
 }
 
 static void
@@ -7478,6 +7810,9 @@ real_update_location_menu_volumes (FMDirectoryView *view)
 	gboolean show_eject;
 	gboolean show_connect;
 	gboolean show_format;
+	gboolean show_start;
+	gboolean show_stop;
+	GDriveStartStopType start_stop_type;
 
 	g_assert (FM_IS_DIRECTORY_VIEW (view));
 	g_assert (NAUTILUS_IS_FILE (view->details->location_popup_directory_as_file));
@@ -7488,7 +7823,10 @@ real_update_location_menu_volumes (FMDirectoryView *view)
 				  &show_unmount,
 				  &show_eject,
 				  &show_connect,
-				  &show_format);
+				  &show_format,
+				  &show_start,
+				  &show_stop,
+				  &start_stop_type);
 
 	action = gtk_action_group_get_action (view->details->dir_action_group,
 					      FM_ACTION_LOCATION_MOUNT_VOLUME);
@@ -7505,6 +7843,64 @@ real_update_location_menu_volumes (FMDirectoryView *view)
 	action = gtk_action_group_get_action (view->details->dir_action_group,
 					      FM_ACTION_LOCATION_FORMAT_VOLUME);
 	gtk_action_set_visible (action, show_format);
+
+	action = gtk_action_group_get_action (view->details->dir_action_group,
+					      FM_ACTION_LOCATION_START_VOLUME);
+	gtk_action_set_visible (action, show_start);
+	if (show_start) {
+		switch (start_stop_type) {
+		default:
+		case G_DRIVE_START_STOP_TYPE_UNKNOWN:
+			gtk_action_set_label (action, _("_Start"));
+			gtk_action_set_tooltip (action, _("Start the selected drive"));
+			break;
+		case G_DRIVE_START_STOP_TYPE_SHUTDOWN:
+			gtk_action_set_label (action, _("_Start"));
+			gtk_action_set_tooltip (action, _("Start the selected drive"));
+			break;
+		case G_DRIVE_START_STOP_TYPE_NETWORK:
+			gtk_action_set_label (action, _("_Connect"));
+			gtk_action_set_tooltip (action, _("Connect to the selected drive"));
+			break;
+		case G_DRIVE_START_STOP_TYPE_MULTIDISK:
+			gtk_action_set_label (action, _("_Start Multi-disk Drive"));
+			gtk_action_set_tooltip (action, _("Start the selected multi-disk drive"));
+			break;
+		case G_DRIVE_START_STOP_TYPE_PASSWORD:
+			gtk_action_set_label (action, _("_Unlock Drive"));
+			gtk_action_set_tooltip (action, _("Unlock the selected drive"));
+			break;
+		}
+	}
+
+	action = gtk_action_group_get_action (view->details->dir_action_group,
+					      FM_ACTION_LOCATION_STOP_VOLUME);
+	gtk_action_set_visible (action, show_stop);
+	if (show_stop) {
+		switch (start_stop_type) {
+		default:
+		case G_DRIVE_START_STOP_TYPE_UNKNOWN:
+			gtk_action_set_label (action, _("_Stop"));
+			gtk_action_set_tooltip (action, _("Stop the selected volume"));
+			break;
+		case G_DRIVE_START_STOP_TYPE_SHUTDOWN:
+			gtk_action_set_label (action, _("_Safely Remove Drive"));
+			gtk_action_set_tooltip (action, _("Safely remove the selected drive"));
+			break;
+		case G_DRIVE_START_STOP_TYPE_NETWORK:
+			gtk_action_set_label (action, _("_Disconnect"));
+			gtk_action_set_tooltip (action, _("Disconnect the selected drive"));
+			break;
+		case G_DRIVE_START_STOP_TYPE_MULTIDISK:
+			gtk_action_set_label (action, _("_Stop Multi-disk Drive"));
+			gtk_action_set_tooltip (action, _("Stop the selected multi-disk drive"));
+			break;
+		case G_DRIVE_START_STOP_TYPE_PASSWORD:
+			gtk_action_set_label (action, _("_Lock Drive"));
+			gtk_action_set_tooltip (action, _("Lock the selected drive"));
+			break;
+		}
+	}
 }
 
 /* TODO: we should split out this routine into two functions:
diff --git a/src/file-manager/nautilus-directory-view-ui.xml b/src/file-manager/nautilus-directory-view-ui.xml
index dce7d2d..09252f0 100644
--- a/src/file-manager/nautilus-directory-view-ui.xml
+++ b/src/file-manager/nautilus-directory-view-ui.xml
@@ -40,6 +40,8 @@
 			<menuitem name="Self Unmount Volume" action="Self Unmount Volume"/>
 			<menuitem name="Self Eject Volume" action="Self Eject Volume"/>
 			<menuitem name="Self Format Volume" action="Self Format Volume"/>
+			<menuitem name="Self Start Volume" action="Self Start Volume"/>
+			<menuitem name="Self Stop Volume" action="Self Stop Volume"/>
 			<separator name="Properties Separator"/>
 			<menuitem name="Properties" action="Properties"/>
 		</placeholder>
@@ -110,6 +112,8 @@
 		<menuitem name="Self Unmount Volume" action="Self Unmount Volume"/>
 		<menuitem name="Self Eject Volume" action="Self Eject Volume"/>
 		<menuitem name="Self Format Volume" action="Self Format Volume"/>
+		<menuitem name="Self Start Volume" action="Self Start Volume"/>
+		<menuitem name="Self Stop Volume" action="Self Stop Volume"/>
 		<separator name="Properties separator"/>
 		<menuitem name="SelfProperties" action="SelfProperties"/>
 	</placeholder>
@@ -165,6 +169,8 @@
 		 <menuitem name="Unmount Volume" action="Unmount Volume"/>
 		 <menuitem name="Eject Volume" action="Eject Volume"/>
 		 <menuitem name="Format Volume" action="Format Volume"/>
+		 <menuitem name="Start Volume" action="Start Volume"/>
+		 <menuitem name="Stop Volume" action="Stop Volume"/>
         </placeholder>
         <menuitem name="Connect To Server Link" action="Connect To Server Link"/>
         <separator name="Properties Separator"/>
@@ -193,6 +199,8 @@
 	<menuitem name="Location Unmount Volume" action="Location Unmount Volume"/>
 	<menuitem name="Location Eject Volume" action="Location Eject Volume"/>
 	<menuitem name="Location Format Volume" action="Location Format Volume"/>
+	<menuitem name="Location Start Volume" action="Location Start Volume"/>
+	<menuitem name="Location Stop Volume" action="Location Stop Volume"/>
 	<separator name="Properties Separator"/>
 	<menuitem name="LocationProperties" action="LocationProperties"/>
 </popup>
diff --git a/src/nautilus-places-sidebar.c b/src/nautilus-places-sidebar.c
index 88b1b3c..24677d2 100644
--- a/src/nautilus-places-sidebar.c
+++ b/src/nautilus-places-sidebar.c
@@ -83,6 +83,8 @@ typedef struct {
 	GtkWidget *popup_menu_rescan_item;
 	GtkWidget *popup_menu_format_item;
 	GtkWidget *popup_menu_empty_trash_item;
+	GtkWidget *popup_menu_start_item;
+	GtkWidget *popup_menu_stop_item;
 
 	/* volume mounting - delayed open process */
 	gboolean mounting;
@@ -1268,6 +1270,8 @@ bookmarks_popup_menu_detach_cb (GtkWidget *attach_widget,
 	sidebar->popup_menu_eject_item = NULL;
 	sidebar->popup_menu_rescan_item = NULL;
 	sidebar->popup_menu_format_item = NULL;
+	sidebar->popup_menu_start_item = NULL;
+	sidebar->popup_menu_stop_item = NULL;
 	sidebar->popup_menu_empty_trash_item = NULL;
 }
 
@@ -1302,11 +1306,15 @@ check_visibility (GMount           *mount,
 		  gboolean         *show_unmount,
 		  gboolean         *show_eject,
 		  gboolean         *show_rescan,
-		  gboolean         *show_format)
+		  gboolean         *show_format,
+		  gboolean         *show_start,
+		  gboolean         *show_stop)
 {
 	*show_mount = FALSE;
 	*show_format = FALSE;
 	*show_rescan = FALSE;
+	*show_start = FALSE;
+	*show_stop = FALSE;
 
 	check_unmount_and_eject (mount, volume, drive, show_unmount, show_eject);
 
@@ -1315,6 +1323,9 @@ check_visibility (GMount           *mount,
 		    !g_drive_is_media_check_automatic (drive) && 
 		    g_drive_can_poll_for_media (drive))
 			*show_rescan = TRUE;
+
+		*show_start = g_drive_can_start (drive);
+		*show_stop  = g_drive_can_stop (drive);
 	}
 
 	if (volume != NULL) {
@@ -1343,6 +1354,8 @@ bookmarks_check_popup_sensitivity (NautilusPlacesSidebar *sidebar)
 	gboolean show_eject;
 	gboolean show_rescan;
 	gboolean show_format;
+	gboolean show_start;
+	gboolean show_stop;
 	gboolean show_empty_trash;
 	char *uri = NULL;
 	
@@ -1373,7 +1386,7 @@ bookmarks_check_popup_sensitivity (NautilusPlacesSidebar *sidebar)
 	gtk_widget_set_sensitive (sidebar->popup_menu_empty_trash_item, !nautilus_trash_monitor_is_empty ());
 
  	check_visibility (mount, volume, drive,
- 			  &show_mount, &show_unmount, &show_eject, &show_rescan, &show_format);
+ 			  &show_mount, &show_unmount, &show_eject, &show_rescan, &show_format, &show_start, &show_stop);
 
 	/* We actually want both eject and unmount since eject will unmount all volumes. 
 	 * TODO: hide unmount if the drive only has a single mountable volume 
@@ -1389,8 +1402,42 @@ bookmarks_check_popup_sensitivity (NautilusPlacesSidebar *sidebar)
 	eel_gtk_widget_set_shown (sidebar->popup_menu_eject_item, show_eject);
 	eel_gtk_widget_set_shown (sidebar->popup_menu_rescan_item, show_rescan);
 	eel_gtk_widget_set_shown (sidebar->popup_menu_format_item, show_format);
+	eel_gtk_widget_set_shown (sidebar->popup_menu_start_item, show_start);
+	eel_gtk_widget_set_shown (sidebar->popup_menu_stop_item, show_stop);
 	eel_gtk_widget_set_shown (sidebar->popup_menu_empty_trash_item, show_empty_trash);
 
+	/* Adjust start/stop items to reflect the type of the drive */
+	gtk_menu_item_set_label (GTK_MENU_ITEM (sidebar->popup_menu_start_item), _("_Start"));
+	gtk_menu_item_set_label (GTK_MENU_ITEM (sidebar->popup_menu_stop_item), _("_Stop"));
+	if ((show_start || show_stop) && drive != NULL) {
+		switch (g_drive_get_start_stop_type (drive)) {
+		case G_DRIVE_START_STOP_TYPE_SHUTDOWN:
+			/* start() for type G_DRIVE_START_STOP_TYPE_SHUTDOWN is normally not used */
+			gtk_menu_item_set_label (GTK_MENU_ITEM (sidebar->popup_menu_start_item), _("_Power On"));
+			gtk_menu_item_set_label (GTK_MENU_ITEM (sidebar->popup_menu_stop_item), _("_Safely Remove Drive"));
+			break;
+		case G_DRIVE_START_STOP_TYPE_NETWORK:
+			gtk_menu_item_set_label (GTK_MENU_ITEM (sidebar->popup_menu_start_item), _("_Connect Drive"));
+			gtk_menu_item_set_label (GTK_MENU_ITEM (sidebar->popup_menu_stop_item), _("_Disconnect Drive"));
+			break;
+		case G_DRIVE_START_STOP_TYPE_MULTIDISK:
+			gtk_menu_item_set_label (GTK_MENU_ITEM (sidebar->popup_menu_start_item), _("_Start Multi-disk Device"));
+			gtk_menu_item_set_label (GTK_MENU_ITEM (sidebar->popup_menu_stop_item), _("_Stop Multi-disk Device"));
+			break;
+		case G_DRIVE_START_STOP_TYPE_PASSWORD:
+			/* stop() for type G_DRIVE_START_STOP_TYPE_PASSWORD is normally not used */
+			gtk_menu_item_set_label (GTK_MENU_ITEM (sidebar->popup_menu_start_item), _("_Unlock Drive"));
+			gtk_menu_item_set_label (GTK_MENU_ITEM (sidebar->popup_menu_stop_item), _("_Lock Drive"));
+			break;
+
+		default:
+		case G_DRIVE_START_STOP_TYPE_UNKNOWN:
+			/* uses defaults set above */
+			break;
+		}
+	}
+
+
 	g_free (uri);
 }
 
@@ -1443,6 +1490,30 @@ volume_mounted_cb (GVolume *volume,
 }
 
 static void
+drive_start_from_bookmark_cb (GObject      *source_object,
+			      GAsyncResult *res,
+			      gpointer      user_data)
+{
+	GError *error;
+	char *primary;
+	char *name;
+
+	error = NULL;
+	if (!g_drive_poll_for_media_finish (G_DRIVE (source_object), res, &error)) {
+		if (error->code != G_IO_ERROR_FAILED_HANDLED) {
+			name = g_drive_get_name (G_DRIVE (source_object));
+			primary = g_strdup_printf (_("Unable to start %s"), name);
+			g_free (name);
+			eel_show_error_dialog (primary,
+					       error->message,
+					       NULL);
+			g_free (primary);
+		}
+		g_error_free (error);
+	}
+}
+
+static void
 open_selected_bookmark (NautilusPlacesSidebar *sidebar,
 			GtkTreeModel	      *model,
 			GtkTreePath	      *path,
@@ -1493,9 +1564,15 @@ open_selected_bookmark (NautilusPlacesSidebar *sidebar,
 		g_free (uri);
 
 	} else {
+		GDrive *drive;
 		GVolume *volume;
 		NautilusWindowSlot *slot;
-		gtk_tree_model_get (model, &iter, PLACES_SIDEBAR_COLUMN_VOLUME, &volume, -1);
+
+		gtk_tree_model_get (model, &iter,
+				    PLACES_SIDEBAR_COLUMN_DRIVE, &drive,
+				    PLACES_SIDEBAR_COLUMN_VOLUME, &volume,
+				    -1);
+
 		if (volume != NULL && !sidebar->mounting) {
 			sidebar->mounting = TRUE;
 
@@ -1510,8 +1587,18 @@ open_selected_bookmark (NautilusPlacesSidebar *sidebar,
 			nautilus_file_operations_mount_volume_full (NULL, volume, FALSE,
 								    volume_mounted_cb,
 								    G_OBJECT (sidebar));
-			g_object_unref (volume);
+		} else if (volume == NULL && drive != NULL && g_drive_can_start (drive)) {
+			GMountOperation *start_op;
+
+			start_op = gtk_mount_operation_new (NULL);
+			g_drive_start (drive, G_DRIVE_START_NONE, start_op, NULL, drive_start_from_bookmark_cb, NULL);
+			g_object_unref (start_op);
 		}
+
+		if (drive != NULL)
+			g_object_unref (drive);
+		if (volume != NULL)
+			g_object_unref (volume);
 	}
 }
 
@@ -1903,6 +1990,102 @@ format_shortcut_cb (GtkMenuItem           *item,
 }
 
 static void
+drive_start_cb (GObject      *source_object,
+		GAsyncResult *res,
+		gpointer      user_data)
+{
+	GError *error;
+	char *primary;
+	char *name;
+
+	error = NULL;
+	if (!g_drive_poll_for_media_finish (G_DRIVE (source_object), res, &error)) {
+		if (error->code != G_IO_ERROR_FAILED_HANDLED) {
+			name = g_drive_get_name (G_DRIVE (source_object));
+			primary = g_strdup_printf (_("Unable to start %s"), name);
+			g_free (name);
+			eel_show_error_dialog (primary,
+					       error->message,
+					       NULL);
+			g_free (primary);
+		}
+		g_error_free (error);
+	}
+}
+
+static void
+start_shortcut_cb (GtkMenuItem           *item,
+		   NautilusPlacesSidebar *sidebar)
+{
+	GtkTreeIter iter;
+	GDrive  *drive;
+
+	if (!get_selected_iter (sidebar, &iter)) {
+		return;
+	}
+
+	gtk_tree_model_get (GTK_TREE_MODEL (sidebar->store), &iter,
+			    PLACES_SIDEBAR_COLUMN_DRIVE, &drive,
+			    -1);
+
+	if (drive != NULL) {
+		GMountOperation *start_op;
+
+		start_op = gtk_mount_operation_new (NULL);
+
+		g_drive_start (drive, G_DRIVE_START_NONE, start_op, NULL, drive_start_cb, NULL);
+
+		g_object_unref (start_op);
+	}
+	g_object_unref (drive);
+}
+
+static void
+drive_stop_cb (GObject *source_object,
+	       GAsyncResult *res,
+	       gpointer user_data)
+{
+	GError *error;
+	char *primary;
+	char *name;
+
+	error = NULL;
+	if (!g_drive_poll_for_media_finish (G_DRIVE (source_object), res, &error)) {
+		if (error->code != G_IO_ERROR_FAILED_HANDLED) {
+			name = g_drive_get_name (G_DRIVE (source_object));
+			primary = g_strdup_printf (_("Unable to stop %s"), name);
+			g_free (name);
+			eel_show_error_dialog (primary,
+					       error->message,
+					       NULL);
+			g_free (primary);
+		}
+		g_error_free (error);
+	}
+}
+
+static void
+stop_shortcut_cb (GtkMenuItem           *item,
+		  NautilusPlacesSidebar *sidebar)
+{
+	GtkTreeIter iter;
+	GDrive  *drive;
+
+	if (!get_selected_iter (sidebar, &iter)) {
+		return;
+	}
+
+	gtk_tree_model_get (GTK_TREE_MODEL (sidebar->store), &iter,
+			    PLACES_SIDEBAR_COLUMN_DRIVE, &drive,
+			    -1);
+
+	if (drive != NULL) {
+		g_drive_stop (drive, G_MOUNT_UNMOUNT_NONE, NULL, drive_stop_cb, NULL);
+	}
+	g_object_unref (drive);
+}
+
+static void
 empty_trash_cb (GtkMenuItem           *item,
 		NautilusPlacesSidebar *sidebar)
 {
@@ -2035,6 +2218,20 @@ bookmarks_build_popup_menu (NautilusPlacesSidebar *sidebar)
 	gtk_widget_show (item);
 	gtk_menu_shell_append (GTK_MENU_SHELL (sidebar->popup_menu), item);
 
+	item = gtk_menu_item_new_with_mnemonic (_("_Start"));
+	sidebar->popup_menu_start_item = item;
+	g_signal_connect (item, "activate",
+			  G_CALLBACK (start_shortcut_cb), sidebar);
+	gtk_widget_show (item);
+	gtk_menu_shell_append (GTK_MENU_SHELL (sidebar->popup_menu), item);
+
+	item = gtk_menu_item_new_with_mnemonic (_("_Stop"));
+	sidebar->popup_menu_stop_item = item;
+	g_signal_connect (item, "activate",
+			  G_CALLBACK (stop_shortcut_cb), sidebar);
+	gtk_widget_show (item);
+	gtk_menu_shell_append (GTK_MENU_SHELL (sidebar->popup_menu), item);
+
 	/* Empty Trash menu item */
 
 	item = gtk_menu_item_new_with_mnemonic (_("Empty _Trash"));



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]