summaryrefslogtreecommitdiff
path: root/monitor/gdu/ggdudrive.c
diff options
context:
space:
mode:
Diffstat (limited to 'monitor/gdu/ggdudrive.c')
-rw-r--r--monitor/gdu/ggdudrive.c676
1 files changed, 557 insertions, 119 deletions
diff --git a/monitor/gdu/ggdudrive.c b/monitor/gdu/ggdudrive.c
index d332e14b..c89928ca 100644
--- a/monitor/gdu/ggdudrive.c
+++ b/monitor/gdu/ggdudrive.c
@@ -51,6 +51,10 @@ struct _GGduDrive {
gboolean can_eject;
gboolean can_poll_for_media;
gboolean is_media_check_automatic;
+
+ GDriveStartStopType start_stop_type;
+ gboolean can_start;
+ gboolean can_stop;
};
static void g_gdu_drive_drive_iface_init (GDriveIface *iface);
@@ -126,6 +130,9 @@ update_drive (GGduDrive *drive)
gboolean old_is_media_removable;
gboolean old_has_media;
gboolean old_can_eject;
+ gboolean old_can_start;
+ gboolean old_can_stop;
+ gboolean old_start_stop_type;
gboolean old_is_media_check_automatic;
gboolean old_can_poll_for_media;
@@ -133,6 +140,9 @@ update_drive (GGduDrive *drive)
old_is_media_removable = drive->is_media_removable;
old_has_media = drive->has_media;
old_can_eject = drive->can_eject;
+ old_can_start = drive->can_start;
+ old_can_stop = drive->can_stop;
+ old_start_stop_type = drive->start_stop_type;
old_can_poll_for_media = drive->can_poll_for_media;
old_is_media_check_automatic = drive->is_media_check_automatic;
@@ -161,6 +171,7 @@ update_drive (GGduDrive *drive)
drive->is_media_removable = TRUE;
drive->has_media = TRUE;
drive->can_eject = FALSE;
+ drive->can_poll_for_media = FALSE;
}
else
{
@@ -171,12 +182,60 @@ update_drive (GGduDrive *drive)
/* All drives with removable media are ejectable
*
* See http://bugzilla.gnome.org/show_bug.cgi?id=576587 for why we want this.
+ *
+ * See also below where we e.g. set can_eject to TRUE for non-removable drives.
*/
- drive->can_eject = gdu_device_drive_get_is_media_ejectable (device) || gdu_device_drive_get_requires_eject (device) || gdu_device_is_removable (device) || gdu_device_drive_get_can_detach (device);
+ drive->can_eject = gdu_device_drive_get_is_media_ejectable (device) || gdu_device_drive_get_requires_eject (device) || gdu_device_is_removable (device);
drive->is_media_check_automatic = gdu_device_is_media_change_detected (device);
drive->can_poll_for_media = TRUE;
}
+ /* determine start/stop type */
+ drive->can_stop = FALSE;
+ drive->can_start = FALSE;
+ drive->start_stop_type = G_DRIVE_START_STOP_TYPE_UNKNOWN;
+ if (gdu_drive_is_activatable (GDU_DRIVE (drive->presentable)))
+ {
+ drive->can_stop = gdu_drive_can_deactivate (GDU_DRIVE (drive->presentable));
+ drive->can_start = gdu_drive_can_activate (GDU_DRIVE (drive->presentable), NULL);
+ drive->start_stop_type = G_DRIVE_START_STOP_TYPE_MULTIDISK;
+ }
+ else if (device != NULL && gdu_device_drive_get_can_detach (device))
+ {
+ /* If the device is not ejectable, just detach on Eject() and claim to be ejectable.
+ *
+ * This is so we get the UI to display "Eject" instead of "Shutdown" since it is
+ * more familiar and the common case. The way this works is that after the Eject()
+ * method returns we call Detach() - see eject_cb() below.
+ *
+ * (Note that it's not enough to just call Detach() since some devices, such as
+ * the Kindle, only works with Eject(). So we call them both in order)
+ */
+ if (!gdu_device_drive_get_is_media_ejectable (device))
+ {
+ drive->can_eject = TRUE;
+ /* we still set this since
+ *
+ * a) it helps when debugging things using gvfs-mount(1) output
+ * since the tool will print can_stop=0 but start_stop_type=shutdown
+ *
+ * b) we use it in eject_cb() to determine we need to call Detach()
+ * after Eject() successfully completes
+ */
+ drive->start_stop_type = G_DRIVE_START_STOP_TYPE_SHUTDOWN;
+ }
+ else
+ {
+ /* So here the device is ejectable and detachable - for example, a USB CD-ROM
+ * drive or a CD-ROM drive in an Ultrabay - for these, we want to offer both
+ * "Eject" and "Shutdown" options in the UI
+ */
+ drive->can_stop = TRUE;
+ drive->can_start = FALSE;
+ drive->start_stop_type = G_DRIVE_START_STOP_TYPE_SHUTDOWN;
+ }
+ }
+
if (device != NULL)
g_object_unref (device);
@@ -193,6 +252,9 @@ update_drive (GGduDrive *drive)
changed = !((old_is_media_removable == drive->is_media_removable) &&
(old_has_media == drive->has_media) &&
(old_can_eject == drive->can_eject) &&
+ (old_can_start == drive->can_start) &&
+ (old_can_stop == drive->can_stop) &&
+ (old_start_stop_type == drive->start_stop_type) &&
(old_is_media_check_automatic == drive->is_media_check_automatic) &&
(old_can_poll_for_media == drive->can_poll_for_media) &&
(g_strcmp0 (old_name, drive->name) == 0) &&
@@ -363,94 +425,34 @@ g_gdu_drive_can_poll_for_media (GDrive *_drive)
return drive->can_poll_for_media;
}
-static void
-detach_cb (GduDevice *device,
- GError *error,
- gpointer user_data)
+static gboolean
+g_gdu_drive_can_start (GDrive *_drive)
{
- GSimpleAsyncResult *simple = G_SIMPLE_ASYNC_RESULT (user_data);
-
- if (error != NULL)
- {
- g_simple_async_result_set_from_error (simple, error);
- g_error_free (error);
- }
-
- g_simple_async_result_complete (simple);
- g_object_unref (simple);
+ GGduDrive *drive = G_GDU_DRIVE (_drive);
+ return drive->can_start;
}
-static void
-eject_cb (GduDevice *device,
- GError *error,
- gpointer user_data)
+static gboolean
+g_gdu_drive_can_stop (GDrive *_drive)
{
- GSimpleAsyncResult *simple = G_SIMPLE_ASYNC_RESULT (user_data);
-
- if (error != NULL)
- {
- g_simple_async_result_set_from_error (simple, error);
- g_error_free (error);
- }
-
- g_simple_async_result_complete (simple);
- g_object_unref (simple);
+ GGduDrive *drive = G_GDU_DRIVE (_drive);
+ return drive->can_stop;
}
-
-static void
-g_gdu_drive_eject_do (GDrive *_drive,
- GCancellable *cancellable,
- GAsyncReadyCallback callback,
- gpointer user_data)
+static GDriveStartStopType
+g_gdu_drive_get_start_stop_type (GDrive *_drive)
{
GGduDrive *drive = G_GDU_DRIVE (_drive);
- GSimpleAsyncResult *simple;
- GduDevice *device;
+ return drive->start_stop_type;
+}
- device = gdu_presentable_get_device (drive->presentable);
- if (device == NULL)
- {
- simple = g_simple_async_result_new_error (G_OBJECT (drive),
- callback,
- user_data,
- G_IO_ERROR,
- G_IO_ERROR_FAILED,
- "Drive is activatable and not running");
- g_simple_async_result_complete_in_idle (simple);
- g_object_unref (simple);
- }
- else
- {
- simple = g_simple_async_result_new (G_OBJECT (drive),
- callback,
- user_data,
- NULL);
+/* ---------------------------------------------------------------------------------------------------- */
- /* Note that we also offer the Eject option for non-removable
- * devices (see update_drive() above) that are detachable so the
- * device may actually not be removable when we get here...
- *
- * However, keep in mind that a device may be both removable and
- * detachable (e.g. a usb optical drive)..
- *
- * Now, consider what would happen if we detached a USB optical
- * drive? The device would power down without actually ejecting
- * the media... and it would require a power-cycle or a replug
- * to use it for other media. Therefore, never detach devices
- * with removable media, only eject them.
- */
- if (gdu_device_drive_get_can_detach (device) && !gdu_device_is_removable (device))
- {
- gdu_device_op_drive_detach (device, detach_cb, simple);
- }
- else
- {
- gdu_device_op_drive_eject (device, eject_cb, simple);
- }
- g_object_unref (device);
- }
-}
+typedef void (*UnmountsMountsFunc) (GDrive *drive,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data,
+ gpointer on_all_unmounted_data);
typedef struct {
GDrive *drive;
@@ -460,6 +462,9 @@ typedef struct {
GMountUnmountFlags flags;
GList *pending_mounts;
+
+ UnmountsMountsFunc on_all_unmounted;
+ gpointer on_all_unmounted_data;
} UnmountMountsOp;
static void
@@ -475,12 +480,48 @@ free_unmount_mounts_op (UnmountMountsOp *data)
g_list_free (data->pending_mounts);
}
-static void _eject_unmount_mounts (UnmountMountsOp *data);
+static void
+unmount_mounts_cb (GObject *source_object,
+ GAsyncResult *res,
+ gpointer user_data);
static void
-_eject_unmount_mounts_cb (GObject *source_object,
- GAsyncResult *res,
- gpointer user_data)
+unmount_mounts_do (UnmountMountsOp *data)
+{
+ if (data->pending_mounts == NULL)
+ {
+
+ /*g_warning ("all pending mounts done");*/
+ data->on_all_unmounted (data->drive,
+ data->cancellable,
+ data->callback,
+ data->user_data,
+ data->on_all_unmounted_data);
+
+ g_object_unref (data->drive);
+ g_free (data);
+ }
+ else
+ {
+ GMount *mount;
+
+ mount = data->pending_mounts->data;
+ data->pending_mounts = g_list_remove (data->pending_mounts, mount);
+
+ /*g_warning ("unmounting %p", mount);*/
+
+ g_mount_unmount (mount,
+ data->flags,
+ data->cancellable,
+ unmount_mounts_cb,
+ data);
+ }
+}
+
+static void
+unmount_mounts_cb (GObject *source_object,
+ GAsyncResult *res,
+ gpointer user_data)
{
UnmountMountsOp *data = user_data;
GMount *mount = G_MOUNT (source_object);
@@ -514,86 +555,471 @@ _eject_unmount_mounts_cb (GObject *source_object,
/*g_warning ("successfully unmounted %p", mount);*/
/* move on to the next mount.. */
- _eject_unmount_mounts (data);
+ unmount_mounts_do (data);
}
g_object_unref (mount);
}
static void
-_eject_unmount_mounts (UnmountMountsOp *data)
+unmount_mounts (GGduDrive *drive,
+ GMountUnmountFlags flags,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data,
+ UnmountsMountsFunc on_all_unmounted,
+ gpointer on_all_unmounted_data)
{
GMount *mount;
+ UnmountMountsOp *data;
+ GList *l;
- if (data->pending_mounts == NULL)
+ data = g_new0 (UnmountMountsOp, 1);
+ data->drive = g_object_ref (drive);
+ data->cancellable = cancellable;
+ data->callback = callback;
+ data->user_data = user_data;
+ data->flags = flags;
+ data->on_all_unmounted = on_all_unmounted;
+ data->on_all_unmounted_data = on_all_unmounted_data;
+
+ for (l = drive->volumes; l != NULL; l = l->next)
{
+ GGduVolume *volume = l->data;
+ mount = g_volume_get_mount (G_VOLUME (volume));
+ if (mount != NULL && g_mount_can_unmount (mount))
+ data->pending_mounts = g_list_prepend (data->pending_mounts, g_object_ref (mount));
+ }
- /*g_warning ("all pending mounts done; ejecting drive");*/
+ unmount_mounts_do (data);
+}
- g_gdu_drive_eject_do (data->drive,
- data->cancellable,
- data->callback,
- data->user_data);
+/* ---------------------------------------------------------------------------------------------------- */
- g_object_unref (data->drive);
- g_free (data);
+static void
+detach_after_eject_cb (GduDevice *device,
+ GError *error,
+ gpointer user_data)
+{
+ GSimpleAsyncResult *simple = G_SIMPLE_ASYNC_RESULT (user_data);
+
+ /* Don't return an error here - this is because some devices, such as
+ * the Kindle, can do Eject() but not Detach() e.g. the STOP UNIT
+ * command or any other part of Detach() may fail.
+ */
+ if (error != NULL)
+ {
+ g_warning ("Detach() after Eject() failed with: %s", error->message);
+ g_error_free (error);
+ }
+
+ g_simple_async_result_complete (simple);
+ g_object_unref (simple);
+}
+
+static void
+eject_cb (GduDevice *device,
+ GError *error,
+ gpointer user_data)
+{
+ GSimpleAsyncResult *simple = G_SIMPLE_ASYNC_RESULT (user_data);
+ GGduDrive *drive;
+
+ if (error != NULL)
+ {
+ g_simple_async_result_set_from_error (simple, error);
+ g_simple_async_result_complete (simple);
+ g_object_unref (simple);
+ g_error_free (error);
+ goto out;
+ }
+
+ drive = G_GDU_DRIVE (g_async_result_get_source_object (G_ASYNC_RESULT (simple)));
+ if (drive->can_stop == FALSE && drive->start_stop_type == G_DRIVE_START_STOP_TYPE_SHUTDOWN)
+ {
+ /* If device is not ejectable but it is detachable and we don't support stop(),
+ * then also run Detach() after Eject() - see update_drive() for details for why...
+ */
+ gdu_device_op_drive_detach (device, detach_after_eject_cb, simple);
}
else
{
- mount = data->pending_mounts->data;
- data->pending_mounts = g_list_remove (data->pending_mounts, mount);
+ /* otherwise we are done */
+ g_simple_async_result_complete (simple);
+ g_object_unref (simple);
+ }
+ g_object_unref (drive);
- /*g_warning ("unmounting %p", mount);*/
+ out:
+ ;
+}
- g_mount_unmount (mount,
- data->flags,
- data->cancellable,
- _eject_unmount_mounts_cb,
- data);
+static void
+g_gdu_drive_eject_on_all_unmounted (GDrive *_drive,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data,
+ gpointer on_all_unmounted_data)
+{
+ GGduDrive *drive = G_GDU_DRIVE (_drive);
+ GSimpleAsyncResult *simple;
+ GduDevice *device;
+
+ device = gdu_presentable_get_device (drive->presentable);
+ if (device == NULL)
+ {
+ simple = g_simple_async_result_new_error (G_OBJECT (drive),
+ callback,
+ user_data,
+ G_IO_ERROR,
+ G_IO_ERROR_FAILED,
+ "Drive is activatable and not running");
+ g_simple_async_result_complete_in_idle (simple);
+ g_object_unref (simple);
+ }
+ else
+ {
+ simple = g_simple_async_result_new (G_OBJECT (drive),
+ callback,
+ user_data,
+ NULL);
+
+ gdu_device_op_drive_eject (device, eject_cb, simple);
}
}
static void
-g_gdu_drive_eject (GDrive *drive,
+g_gdu_drive_eject (GDrive *_drive,
GMountUnmountFlags flags,
GCancellable *cancellable,
GAsyncReadyCallback callback,
gpointer user_data)
{
- GGduDrive *gdu_drive = G_GDU_DRIVE (drive);
- UnmountMountsOp *data;
- GList *l;
+ GGduDrive *drive = G_GDU_DRIVE (_drive);
/* first we need to go through all the volumes and unmount their assoicated mounts (if any) */
+ unmount_mounts (drive,
+ flags,
+ cancellable,
+ callback,
+ user_data,
+ g_gdu_drive_eject_on_all_unmounted,
+ NULL);
+}
- data = g_new0 (UnmountMountsOp, 1);
- data->drive = g_object_ref (drive);
- data->cancellable = cancellable;
- data->callback = callback;
- data->user_data = user_data;
- data->flags = flags;
+static gboolean
+g_gdu_drive_eject_finish (GDrive *drive,
+ GAsyncResult *result,
+ GError **error)
+{
+ return !g_simple_async_result_propagate_error (G_SIMPLE_ASYNC_RESULT (result), error);
+}
+
+/* ---------------------------------------------------------------------------------------------------- */
- for (l = gdu_drive->volumes; l != NULL; l = l->next)
+static void
+stop_cb (GduDevice *device,
+ GError *error,
+ gpointer user_data)
+{
+ GSimpleAsyncResult *simple = G_SIMPLE_ASYNC_RESULT (user_data);
+
+ if (error != NULL)
{
- GGduVolume *volume = l->data;
- GMount *mount;
+ g_simple_async_result_set_from_error (simple, error);
+ g_error_free (error);
+ }
- mount = g_volume_get_mount (G_VOLUME (volume));
- if (mount != NULL && g_mount_can_unmount (mount))
- data->pending_mounts = g_list_prepend (data->pending_mounts, g_object_ref (mount));
+ g_simple_async_result_complete (simple);
+ g_object_unref (simple);
+}
+
+static void
+drive_deactivate_cb (GduDrive *drive,
+ GError *error,
+ gpointer user_data)
+{
+ GSimpleAsyncResult *simple = G_SIMPLE_ASYNC_RESULT (user_data);
+
+ if (error != NULL)
+ {
+ g_simple_async_result_set_from_error (simple, error);
+ g_error_free (error);
}
- _eject_unmount_mounts (data);
+ g_simple_async_result_complete (simple);
+ g_object_unref (simple);
+}
+
+static void
+g_gdu_drive_stop_on_all_unmounted (GDrive *_drive,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data,
+ gpointer on_all_unmounted_data)
+{
+ GGduDrive *drive = G_GDU_DRIVE (_drive);
+ GSimpleAsyncResult *simple;
+ GduDevice *device;
+
+ device = gdu_presentable_get_device (drive->presentable);
+ if (device == NULL)
+ {
+ simple = g_simple_async_result_new_error (G_OBJECT (drive),
+ callback,
+ user_data,
+ G_IO_ERROR,
+ G_IO_ERROR_FAILED,
+ "Drive is activatable and not running");
+ g_simple_async_result_complete_in_idle (simple);
+ g_object_unref (simple);
+ }
+ else
+ {
+ simple = g_simple_async_result_new (G_OBJECT (drive),
+ callback,
+ user_data,
+ NULL);
+
+ switch (drive->start_stop_type)
+ {
+ case G_DRIVE_START_STOP_TYPE_SHUTDOWN:
+ gdu_device_op_drive_detach (device, stop_cb, simple);
+ break;
+
+ case G_DRIVE_START_STOP_TYPE_MULTIDISK:
+ gdu_drive_deactivate (GDU_DRIVE (drive->presentable), drive_deactivate_cb, simple);
+ break;
+
+ default:
+ g_simple_async_result_set_error (simple,
+ G_IO_ERROR,
+ G_IO_ERROR_NOT_SUPPORTED,
+ "start_stop_type %d not supported",
+ drive->start_stop_type);
+ g_simple_async_result_complete_in_idle (simple);
+ g_object_unref (simple);
+ break;
+ }
+ }
+}
+
+static void
+g_gdu_drive_stop (GDrive *_drive,
+ GMountUnmountFlags flags,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
+{
+ GGduDrive *drive = G_GDU_DRIVE (_drive);
+
+ /* first we need to go through all the volumes and unmount their assoicated mounts (if any) */
+ unmount_mounts (drive,
+ flags,
+ cancellable,
+ callback,
+ user_data,
+ g_gdu_drive_stop_on_all_unmounted,
+ NULL);
}
static gboolean
-g_gdu_drive_eject_finish (GDrive *drive,
+g_gdu_drive_stop_finish (GDrive *drive,
+ GAsyncResult *result,
+ GError **error)
+{
+ return !g_simple_async_result_propagate_error (G_SIMPLE_ASYNC_RESULT (result), error);
+}
+
+/* ---------------------------------------------------------------------------------------------------- */
+
+static void
+start_cb (GduDrive *drive,
+ gchar *assembled_drive_object_path,
+ GError *error,
+ gpointer user_data)
+{
+ GSimpleAsyncResult *simple = G_SIMPLE_ASYNC_RESULT (user_data);
+
+ if (error != NULL)
+ {
+ g_simple_async_result_set_error (simple,
+ G_IO_ERROR,
+ G_IO_ERROR_FAILED,
+ "Failed activating drive: %s",
+ error->message);
+ g_error_free (error);
+ }
+ else
+ {
+ g_free (assembled_drive_object_path);
+ }
+ g_simple_async_result_complete (simple);
+}
+
+typedef struct
+{
+ GGduDrive *drive;
+ GSimpleAsyncResult *simple;
+
+ GMountOperation *start_operation;
+ gulong start_operation_reply_handler_id;
+} StartOpData;
+
+static void
+start_operation_reply (GMountOperation *op,
+ GMountOperationResult result,
+ gpointer user_data)
+{
+ StartOpData *data = user_data;
+ gint choice;
+
+ /* we got what we wanted; don't listen to any other signals from the start operation */
+ if (data->start_operation_reply_handler_id != 0)
+ {
+ g_signal_handler_disconnect (data->start_operation, data->start_operation_reply_handler_id);
+ data->start_operation_reply_handler_id = 0;
+ }
+
+ if (result != G_MOUNT_OPERATION_HANDLED)
+ {
+ if (result == G_MOUNT_OPERATION_ABORTED)
+ {
+ /* The user aborted the operation so consider it "handled" */
+ g_simple_async_result_set_error (data->simple,
+ G_IO_ERROR,
+ G_IO_ERROR_FAILED_HANDLED,
+ "Start operation dialog aborted (user should never see this error since "
+ "it is G_IO_ERROR_FAILED_HANDLED)");
+ }
+ else
+ {
+ g_simple_async_result_set_error (data->simple,
+ G_IO_ERROR,
+ G_IO_ERROR_FAILED,
+ "Expected G_MOUNT_OPERATION_HANDLED but got %d", result);
+ }
+ g_simple_async_result_complete (data->simple);
+ goto out;
+ }
+
+ /* handle the user pressing cancel */
+ choice = g_mount_operation_get_choice (data->start_operation);
+ if (choice == 1)
+ {
+ g_simple_async_result_set_error (data->simple,
+ G_IO_ERROR,
+ G_IO_ERROR_FAILED_HANDLED,
+ "User refused to start degraded array (user should never see this error since "
+ "it is G_IO_ERROR_FAILED_HANDLED)");
+ g_simple_async_result_complete (data->simple);
+ goto out;
+ }
+
+ gdu_drive_activate (GDU_DRIVE (data->drive->presentable), start_cb, data->simple);
+
+ out:
+ g_object_unref (data->drive);
+ g_object_unref (data->start_operation);
+ g_free (data);
+}
+
+static void
+g_gdu_drive_start (GDrive *_drive,
+ GDriveStartFlags flags,
+ GMountOperation *start_operation,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
+{
+ GGduDrive *drive = G_GDU_DRIVE (_drive);
+ GSimpleAsyncResult *simple;
+ gboolean degraded;
+
+ /* TODO: handle GCancellable */
+
+ if (!gdu_drive_can_activate (GDU_DRIVE (drive->presentable), &degraded))
+ goto not_supported;
+
+ if (start_operation == NULL && degraded)
+ goto refuse_degraded_without_confirmation;
+
+ simple = g_simple_async_result_new (G_OBJECT (drive),
+ callback,
+ user_data,
+ NULL);
+
+ if (degraded)
+ {
+ const gchar *message;
+ const gchar *choices[3];
+ StartOpData *data;
+
+ message = _("Start drive in degraded mode?\n"
+ "Starting a drive in degraded mode means that "
+ "the drive is no longer tolerant to failures. "
+ "Data on the drive may be irrevocably lost if a "
+ "component fails.");
+
+ choices[0] = _("Start Anyway");
+ choices[1] = _("Cancel");
+ choices[2] = NULL;
+
+ data = g_new0 (StartOpData, 1);
+ data->drive = g_object_ref (drive);
+ data->simple = simple;
+ data->start_operation = g_object_ref (start_operation);
+ data->start_operation_reply_handler_id = g_signal_connect (start_operation,
+ "reply",
+ G_CALLBACK (start_operation_reply),
+ data);
+
+ g_signal_emit_by_name (start_operation,
+ "ask-question",
+ message,
+ choices);
+ }
+ else
+ {
+ gdu_drive_activate (GDU_DRIVE (drive->presentable), start_cb, simple);
+ }
+
+ return;
+
+ not_supported:
+ simple = g_simple_async_result_new_error (G_OBJECT (drive),
+ callback,
+ user_data,
+ G_IO_ERROR,
+ G_IO_ERROR_NOT_SUPPORTED,
+ "Starting drive with start_stop_type %d is not supported",
+ drive->start_stop_type);
+ g_simple_async_result_complete_in_idle (simple);
+ g_object_unref (simple);
+ return;
+
+ refuse_degraded_without_confirmation:
+ simple = g_simple_async_result_new_error (G_OBJECT (drive),
+ callback,
+ user_data,
+ G_IO_ERROR,
+ G_IO_ERROR_FAILED,
+ "Refusing to start degraded multidisk drive without user confirmation");
+ g_simple_async_result_complete_in_idle (simple);
+ g_object_unref (simple);
+
+}
+
+static gboolean
+g_gdu_drive_start_finish (GDrive *drive,
GAsyncResult *result,
GError **error)
{
return !g_simple_async_result_propagate_error (G_SIMPLE_ASYNC_RESULT (result), error);
}
+/* ---------------------------------------------------------------------------------------------------- */
+
static void
poll_media_cb (GduDevice *device,
GError *error,
@@ -656,6 +1082,8 @@ g_gdu_drive_poll_for_media_finish (GDrive *drive,
return !g_simple_async_result_propagate_error (G_SIMPLE_ASYNC_RESULT (result), error);
}
+/* ---------------------------------------------------------------------------------------------------- */
+
static char *
g_gdu_drive_get_identifier (GDrive *_drive,
const char *kind)
@@ -688,6 +1116,8 @@ g_gdu_drive_enumerate_identifiers (GDrive *_drive)
return (gchar **) g_ptr_array_free (p, FALSE);
}
+/* ---------------------------------------------------------------------------------------------------- */
+
static void
g_gdu_drive_drive_iface_init (GDriveIface *iface)
{
@@ -706,6 +1136,14 @@ g_gdu_drive_drive_iface_init (GDriveIface *iface)
iface->poll_for_media_finish = g_gdu_drive_poll_for_media_finish;
iface->get_identifier = g_gdu_drive_get_identifier;
iface->enumerate_identifiers = g_gdu_drive_enumerate_identifiers;
+
+ iface->get_start_stop_type = g_gdu_drive_get_start_stop_type;
+ iface->can_start = g_gdu_drive_can_start;
+ iface->can_stop = g_gdu_drive_can_stop;
+ iface->start = g_gdu_drive_start;
+ iface->start_finish = g_gdu_drive_start_finish;
+ iface->stop = g_gdu_drive_stop;
+ iface->stop_finish = g_gdu_drive_stop_finish;
}
gboolean