[gnome-disk-utility] Catch up with udisks API changes and implement Expansion for Linux's MD RAID



commit 9b5be85d80d1ce18190e6f44ae3d86ee30160a97
Author: David Zeuthen <davidz redhat com>
Date:   Fri Feb 5 17:14:33 2010 -0500

    Catch up with udisks API changes and implement Expansion for Linux's MD RAID
    
    Screenshots here
    
     http://people.freedesktop.org/~david/gdu-mdraid-expansion/

 src/gdu-gtk/gdu-add-component-linux-md-dialog.c |  119 ++++++++++++------
 src/gdu-gtk/gdu-add-component-linux-md-dialog.h |   11 +-
 src/gdu-gtk/gdu-edit-linux-md-dialog.c          |   53 ++++++--
 src/gdu-gtk/gdu-edit-linux-md-dialog.h          |    4 +-
 src/gdu-gtk/gdu-gtk-enums.h                     |   14 ++
 src/gdu-gtk/gdu-gtk-enumtypes.h                 |    2 +
 src/gdu/gdu-callbacks.h                         |   10 +-
 src/gdu/gdu-device.c                            |   72 +++++++++---
 src/gdu/gdu-device.h                            |   15 ++-
 src/palimpsest/gdu-section-linux-md-drive.c     |  154 ++++++++++++++++++-----
 10 files changed, 350 insertions(+), 104 deletions(-)
---
diff --git a/src/gdu-gtk/gdu-add-component-linux-md-dialog.c b/src/gdu-gtk/gdu-add-component-linux-md-dialog.c
index 5988c7f..18dfbe0 100644
--- a/src/gdu-gtk/gdu-add-component-linux-md-dialog.c
+++ b/src/gdu-gtk/gdu-add-component-linux-md-dialog.c
@@ -35,12 +35,14 @@
 struct GduAddComponentLinuxMdDialogPrivate
 {
         GtkWidget *disk_selection_widget;
+        GduAddComponentLinuxMdFlags flags;
 };
 
 enum {
         PROP_0,
-        PROP_DRIVE,
-        PROP_SIZE
+        PROP_DRIVES,
+        PROP_SIZE,
+        PROP_FLAGS,
 };
 
 G_DEFINE_TYPE (GduAddComponentLinuxMdDialog, gdu_add_component_linux_md_dialog, GDU_TYPE_DIALOG)
@@ -55,6 +57,26 @@ gdu_add_component_linux_md_dialog_finalize (GObject *object)
 }
 
 static void
+gdu_add_component_linux_md_dialog_set_property (GObject          *object,
+                                                guint             property_id,
+                                                const GValue     *value,
+                                                GParamSpec       *pspec)
+{
+        GduAddComponentLinuxMdDialog *dialog = GDU_ADD_COMPONENT_LINUX_MD_DIALOG (object);
+
+        switch (property_id) {
+
+        case PROP_FLAGS:
+                dialog->priv->flags = g_value_get_flags (value);
+                break;
+
+        default:
+                G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+                break;
+        }
+}
+
+static void
 gdu_add_component_linux_md_dialog_get_property (GObject    *object,
                                                 guint       property_id,
                                                 GValue     *value,
@@ -63,14 +85,18 @@ gdu_add_component_linux_md_dialog_get_property (GObject    *object,
         GduAddComponentLinuxMdDialog *dialog = GDU_ADD_COMPONENT_LINUX_MD_DIALOG (object);
 
         switch (property_id) {
-        case PROP_DRIVE:
-                g_value_take_object (value, gdu_add_component_linux_md_dialog_get_drive (dialog));
+        case PROP_DRIVES:
+                g_value_take_boxed (value, gdu_add_component_linux_md_dialog_get_drives (dialog));
                 break;
 
         case PROP_SIZE:
                 g_value_set_uint64 (value, gdu_add_component_linux_md_dialog_get_size (dialog));
                 break;
 
+        case PROP_FLAGS:
+                g_value_set_flags (value, dialog->priv->flags);
+                break;
+
         default:
                 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
                 break;
@@ -151,6 +177,7 @@ gdu_add_component_linux_md_dialog_constructed (GObject *object)
         GtkWidget *image;
         GtkWidget *label;
         gchar *s;
+        gchar *s2;
         GIcon *icon;
         GduPresentable *p;
         GduDevice *d;
@@ -162,6 +189,7 @@ gdu_add_component_linux_md_dialog_constructed (GObject *object)
         gchar *component_size_str;
         gchar *array_name;
         gchar *array_name_vpd;
+        GduDiskSelectionWidgetFlags flags;
 
         slaves = gdu_linux_md_drive_get_slaves (GDU_LINUX_MD_DRIVE (gdu_dialog_get_presentable (GDU_DIALOG (dialog))));
         slave = GDU_DEVICE (slaves->data);
@@ -178,10 +206,6 @@ gdu_add_component_linux_md_dialog_constructed (GObject *object)
                                GTK_STOCK_CANCEL,
                                GTK_RESPONSE_CANCEL);
 
-        gtk_dialog_add_button (GTK_DIALOG (dialog),
-                               GTK_STOCK_ADD,
-                               GTK_RESPONSE_APPLY);
-
         content_area = gtk_dialog_get_content_area (GTK_DIALOG (dialog));
 
         icon = gdu_presentable_get_icon (gdu_dialog_get_presentable (GDU_DIALOG (dialog)));
@@ -200,7 +224,29 @@ gdu_add_component_linux_md_dialog_constructed (GObject *object)
         d = gdu_presentable_get_device (p);
         pool = gdu_presentable_get_pool (p);
 
-        s = g_strdup_printf (_("Add Component to %s"), array_name);
+        flags = GDU_DISK_SELECTION_WIDGET_FLAGS_NONE;
+        if (dialog->priv->flags & GDU_ADD_COMPONENT_LINUX_MD_FLAGS_SPARE) {
+                s = g_strdup_printf (_("Add spare to %s"), array_name);
+                s2 = g_strdup_printf (_("Select a device to create a %s spare on for the RAID Array \"%s\" (%s)"),
+                                     component_size_str,
+                                     array_name,
+                                     array_name_vpd);
+                gtk_dialog_add_button (GTK_DIALOG (dialog),
+                                       GTK_STOCK_ADD,
+                                       GTK_RESPONSE_APPLY);
+        } else if (dialog->priv->flags & GDU_ADD_COMPONENT_LINUX_MD_FLAGS_EXPANSION) {
+                s = g_strdup_printf (_("Expand %s"), array_name);
+                s2 = g_strdup_printf (_("Select one or more devices to use %s on for expanding the RAID Array \"%s\" (%s)"),
+                                     component_size_str,
+                                     array_name,
+                                     array_name_vpd);
+                flags |= GDU_DISK_SELECTION_WIDGET_FLAGS_ALLOW_MULTIPLE;
+                gtk_dialog_add_button (GTK_DIALOG (dialog),
+                                       _("_Expand"),
+                                       GTK_RESPONSE_APPLY);
+        } else {
+                g_assert_not_reached ();
+        }
         gtk_window_set_title (GTK_WINDOW (dialog), s);
         g_free (s);
 
@@ -210,21 +256,13 @@ gdu_add_component_linux_md_dialog_constructed (GObject *object)
         gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
         gtk_label_set_line_wrap (GTK_LABEL (label), TRUE);
         gtk_label_set_width_chars (GTK_LABEL (label), 70); /* TODO: hate */
-        /* Translators: The first %s is the size (e.g. "42 GB") and the two following %s are the
-         * name and vpd_name of the array (e.g. "Saturn" and "6 TB RAID-6")
-         */
-        s = g_strdup_printf (_("Select a disk to create a %s component on for the RAID Array \"%s\" (%s)"),
-                             component_size_str,
-                             array_name,
-                             array_name_vpd);
-        gtk_label_set_markup (GTK_LABEL (label), s);
-        g_free (s);
+        gtk_label_set_markup (GTK_LABEL (label), s2);
+        g_free (s2);
         gtk_box_pack_start (GTK_BOX (vbox), label, FALSE, FALSE, 0);
 
         /* --- */
 
-        disk_selection_widget = gdu_disk_selection_widget_new (pool,
-                                                               GDU_DISK_SELECTION_WIDGET_FLAGS_NONE);
+        disk_selection_widget = gdu_disk_selection_widget_new (pool, flags);
         g_signal_connect (disk_selection_widget,
                           "is-drive-ignored",
                           G_CALLBACK (on_is_drive_ignored),
@@ -269,17 +307,18 @@ gdu_add_component_linux_md_dialog_class_init (GduAddComponentLinuxMdDialogClass
 
         g_type_class_add_private (klass, sizeof (GduAddComponentLinuxMdDialogPrivate));
 
+        object_class->set_property = gdu_add_component_linux_md_dialog_set_property;
         object_class->get_property = gdu_add_component_linux_md_dialog_get_property;
         object_class->constructed  = gdu_add_component_linux_md_dialog_constructed;
         object_class->finalize     = gdu_add_component_linux_md_dialog_finalize;
 
         g_object_class_install_property (object_class,
-                                         PROP_DRIVE,
-                                         g_param_spec_object ("drive",
-                                                              NULL,
-                                                              NULL,
-                                                              GDU_TYPE_DRIVE,
-                                                              G_PARAM_READABLE));
+                                         PROP_DRIVES,
+                                         g_param_spec_boxed ("drives",
+                                                             NULL,
+                                                             NULL,
+                                                             G_TYPE_PTR_ARRAY,
+                                                             G_PARAM_READABLE));
 
         g_object_class_install_property (object_class,
                                          PROP_SIZE,
@@ -290,6 +329,17 @@ gdu_add_component_linux_md_dialog_class_init (GduAddComponentLinuxMdDialogClass
                                                               G_MAXUINT64,
                                                               0,
                                                               G_PARAM_READABLE));
+
+        g_object_class_install_property (object_class,
+                                         PROP_FLAGS,
+                                         g_param_spec_flags ("flags",
+                                                             NULL,
+                                                             NULL,
+                                                             GDU_TYPE_ADD_COMPONENT_LINUX_MD_FLAGS,
+                                                             GDU_ADD_COMPONENT_LINUX_MD_FLAGS_NONE,
+                                                             G_PARAM_READABLE|
+                                                             G_PARAM_WRITABLE|
+                                                             G_PARAM_CONSTRUCT_ONLY));
 }
 
 static void
@@ -301,31 +351,28 @@ gdu_add_component_linux_md_dialog_init (GduAddComponentLinuxMdDialog *dialog)
 }
 
 GtkWidget *
-gdu_add_component_linux_md_dialog_new (GtkWindow       *parent,
-                                       GduLinuxMdDrive *linux_md_drive)
+gdu_add_component_linux_md_dialog_new (GtkWindow                    *parent,
+                                       GduAddComponentLinuxMdFlags   flags,
+                                       GduLinuxMdDrive              *linux_md_drive)
 {
         g_return_val_if_fail (GDU_IS_LINUX_MD_DRIVE (linux_md_drive), NULL);
         return GTK_WIDGET (g_object_new (GDU_TYPE_ADD_COMPONENT_LINUX_MD_DIALOG,
                                          "transient-for", parent,
                                          "presentable", linux_md_drive,
+                                         "flags", flags,
                                          NULL));
 }
 
-GduDrive *
-gdu_add_component_linux_md_dialog_get_drive (GduAddComponentLinuxMdDialog *dialog)
+GPtrArray *
+gdu_add_component_linux_md_dialog_get_drives (GduAddComponentLinuxMdDialog *dialog)
 {
         GPtrArray *drives;
-        GduDrive *ret;
 
         g_return_val_if_fail (GDU_IS_ADD_COMPONENT_LINUX_MD_DIALOG (dialog), NULL);
 
-        ret = NULL;
         drives = gdu_disk_selection_widget_get_selected_drives (GDU_DISK_SELECTION_WIDGET (dialog->priv->disk_selection_widget));
-        if (drives->len > 0)
-                ret = g_object_ref (GDU_DRIVE (drives->pdata[0]));
-        g_ptr_array_unref (drives);
 
-        return ret;
+        return drives;
 }
 
 guint64
diff --git a/src/gdu-gtk/gdu-add-component-linux-md-dialog.h b/src/gdu-gtk/gdu-add-component-linux-md-dialog.h
index 24658e3..44ad189 100644
--- a/src/gdu-gtk/gdu-add-component-linux-md-dialog.h
+++ b/src/gdu-gtk/gdu-add-component-linux-md-dialog.h
@@ -52,11 +52,12 @@ struct GduAddComponentLinuxMdDialogClass
         GduDialogClass parent_class;
 };
 
-GType         gdu_add_component_linux_md_dialog_get_type  (void) G_GNUC_CONST;
-GtkWidget    *gdu_add_component_linux_md_dialog_new       (GtkWindow                    *parent,
-                                                           GduLinuxMdDrive              *linux_md_drive);
-GduDrive     *gdu_add_component_linux_md_dialog_get_drive (GduAddComponentLinuxMdDialog *dialog);
-guint64       gdu_add_component_linux_md_dialog_get_size  (GduAddComponentLinuxMdDialog *dialog);
+GType         gdu_add_component_linux_md_dialog_get_type   (void) G_GNUC_CONST;
+GtkWidget    *gdu_add_component_linux_md_dialog_new        (GtkWindow                    *parent,
+                                                            GduAddComponentLinuxMdFlags   flags,
+                                                            GduLinuxMdDrive              *linux_md_drive);
+GPtrArray    *gdu_add_component_linux_md_dialog_get_drives (GduAddComponentLinuxMdDialog *dialog);
+guint64       gdu_add_component_linux_md_dialog_get_size   (GduAddComponentLinuxMdDialog *dialog);
 
 G_END_DECLS
 
diff --git a/src/gdu-gtk/gdu-edit-linux-md-dialog.c b/src/gdu-gtk/gdu-edit-linux-md-dialog.c
index c6664b9..8cae427 100644
--- a/src/gdu-gtk/gdu-edit-linux-md-dialog.c
+++ b/src/gdu-gtk/gdu-edit-linux-md-dialog.c
@@ -43,14 +43,16 @@ struct GduEditLinuxMdDialogPrivate
         GduDetailsElement *component_state_element;
         GduDetailsElement *component_device_element;
 
-        GduButtonElement *component_new_button;
+        GduButtonElement *add_spare_button;
+        GduButtonElement *expand_button;
         GduButtonElement *component_attach_button;
         GduButtonElement *component_remove_button;
 
 };
 
 enum {
-        NEW_BUTTON_CLICKED_SIGNAL,
+        ADD_SPARE_BUTTON_CLICKED_SIGNAL,
+        EXPAND_BUTTON_CLICKED_SIGNAL,
         ATTACH_BUTTON_CLICKED_SIGNAL,
         REMOVE_BUTTON_CLICKED_SIGNAL,
         LAST_SIGNAL
@@ -106,11 +108,22 @@ gdu_edit_linux_md_dialog_class_init (GduEditLinuxMdDialogClass *klass)
         object_class->constructed  = gdu_edit_linux_md_dialog_constructed;
         object_class->finalize     = gdu_edit_linux_md_dialog_finalize;
 
-        signals[NEW_BUTTON_CLICKED_SIGNAL] =
-                g_signal_new ("new-button-clicked",
+        signals[ADD_SPARE_BUTTON_CLICKED_SIGNAL] =
+                g_signal_new ("add-spare-button-clicked",
                               G_TYPE_FROM_CLASS (klass),
                               G_SIGNAL_RUN_LAST,
-                              G_STRUCT_OFFSET (GduEditLinuxMdDialogClass, new_button_clicked),
+                              G_STRUCT_OFFSET (GduEditLinuxMdDialogClass, add_spare_button_clicked),
+                              NULL,
+                              NULL,
+                              g_cclosure_marshal_VOID__VOID,
+                              G_TYPE_NONE,
+                              0);
+
+        signals[EXPAND_BUTTON_CLICKED_SIGNAL] =
+                g_signal_new ("expand-button-clicked",
+                              G_TYPE_FROM_CLASS (klass),
+                              G_SIGNAL_RUN_LAST,
+                              G_STRUCT_OFFSET (GduEditLinuxMdDialogClass, expand_button_clicked),
                               NULL,
                               NULL,
                               g_cclosure_marshal_VOID__VOID,
@@ -164,11 +177,19 @@ gdu_edit_linux_md_dialog_new (GtkWindow        *parent,
 /* ---------------------------------------------------------------------------------------------------- */
 
 static void
-on_component_new_button_clicked (GduButtonElement *button_element,
+on_add_spare_button_clicked (GduButtonElement *button_element,
                                  gpointer          user_data)
 {
         GduEditLinuxMdDialog *dialog = GDU_EDIT_LINUX_MD_DIALOG (user_data);
-        g_signal_emit (dialog, signals[NEW_BUTTON_CLICKED_SIGNAL], 0);
+        g_signal_emit (dialog, signals[ADD_SPARE_BUTTON_CLICKED_SIGNAL], 0);
+}
+
+static void
+on_expand_button_clicked (GduButtonElement *button_element,
+                          gpointer          user_data)
+{
+        GduEditLinuxMdDialog *dialog = GDU_EDIT_LINUX_MD_DIALOG (user_data);
+        g_signal_emit (dialog, signals[EXPAND_BUTTON_CLICKED_SIGNAL], 0);
 }
 
 static void
@@ -466,14 +487,24 @@ gdu_edit_linux_md_dialog_constructed (GObject *object)
         elements = g_ptr_array_new_with_free_func (g_object_unref);
 
         button_element = gdu_button_element_new (GTK_STOCK_NEW,
-                                                 _("_New Component"),
-                                                 _("Add a new component to the array"));
+                                                 _("Add _Spare"),
+                                                 _("Add a spare to the array"));
         g_signal_connect (button_element,
                           "clicked",
-                          G_CALLBACK (on_component_new_button_clicked),
+                          G_CALLBACK (on_add_spare_button_clicked),
                           dialog);
         g_ptr_array_add (elements, button_element);
-        dialog->priv->component_attach_button = button_element;
+        dialog->priv->add_spare_button = button_element;
+
+        button_element = gdu_button_element_new (GTK_STOCK_NEW,
+                                                 _("_Expand Array"),
+                                                 _("Increase the capacity of the array"));
+        g_signal_connect (button_element,
+                          "clicked",
+                          G_CALLBACK (on_expand_button_clicked),
+                          dialog);
+        g_ptr_array_add (elements, button_element);
+        dialog->priv->expand_button = button_element;
 
         button_element = gdu_button_element_new (GTK_STOCK_ADD,
                                                  _("_Attach Component"),
diff --git a/src/gdu-gtk/gdu-edit-linux-md-dialog.h b/src/gdu-gtk/gdu-edit-linux-md-dialog.h
index 11bb72f..408ce71 100644
--- a/src/gdu-gtk/gdu-edit-linux-md-dialog.h
+++ b/src/gdu-gtk/gdu-edit-linux-md-dialog.h
@@ -49,7 +49,9 @@ struct GduEditLinuxMdDialogClass
 {
         GduDialogClass parent_class;
 
-        void (*new_button_clicked)    (GduEditLinuxMdDialog *dialog);
+        void (*add_spare_button_clicked) (GduEditLinuxMdDialog *dialog);
+        void (*expand_button_clicked)    (GduEditLinuxMdDialog *dialog);
+
         void (*attach_button_clicked) (GduEditLinuxMdDialog *dialog,
                                        GduDevice            *slave);
         void (*remove_button_clicked) (GduEditLinuxMdDialog *dialog,
diff --git a/src/gdu-gtk/gdu-gtk-enums.h b/src/gdu-gtk/gdu-gtk-enums.h
index 4232571..26b4927 100644
--- a/src/gdu-gtk/gdu-gtk-enums.h
+++ b/src/gdu-gtk/gdu-gtk-enums.h
@@ -105,4 +105,18 @@ typedef enum {
         GDU_DISK_SELECTION_WIDGET_FLAGS_ALLOW_DISKS_WITH_INSUFFICIENT_SPACE = (1<<1)
 } GduDiskSelectionWidgetFlags;
 
+/**
+ * GduAddComponentLinuxMdFlags:
+ * @GDU_ADD_COMPONENT_LINUX_MD_FLAGS_NONE: No flags set.
+ * @GDU_ADD_COMPONENT_LINUX_MD_FLAGS_SPARE: The dialog is for selecting a spare.
+ * @GDU_ADD_COMPONENT_LINUX_MD_FLAGS_EXPANSION: The dialog is for selecting a device used for expansion.
+ *
+ * Flags used when creating a #GduAddComponentLinuxMdDialog.
+ */
+typedef enum {
+        GDU_ADD_COMPONENT_LINUX_MD_FLAGS_NONE = 0,
+        GDU_ADD_COMPONENT_LINUX_MD_FLAGS_SPARE = (1<<0),
+        GDU_ADD_COMPONENT_LINUX_MD_FLAGS_EXPANSION = (1<<1)
+} GduAddComponentLinuxMdFlags;
+
 #endif /* GDU_GTK_ENUMS_H */
diff --git a/src/gdu-gtk/gdu-gtk-enumtypes.h b/src/gdu-gtk/gdu-gtk-enumtypes.h
index 0e299a8..14638ff 100644
--- a/src/gdu-gtk/gdu-gtk-enumtypes.h
+++ b/src/gdu-gtk/gdu-gtk-enumtypes.h
@@ -19,6 +19,8 @@ GType gdu_format_dialog_flags_get_type (void) G_GNUC_CONST;
 #define GDU_TYPE_FORMAT_DIALOG_FLAGS (gdu_format_dialog_flags_get_type ())
 GType gdu_disk_selection_widget_flags_get_type (void) G_GNUC_CONST;
 #define GDU_TYPE_DISK_SELECTION_WIDGET_FLAGS (gdu_disk_selection_widget_flags_get_type ())
+GType gdu_add_component_linux_md_flags_get_type (void) G_GNUC_CONST;
+#define GDU_TYPE_ADD_COMPONENT_LINUX_MD_FLAGS (gdu_add_component_linux_md_flags_get_type ())
 G_END_DECLS
 
 #endif /* __GDU_GTK_ENUM_TYPES_H__ */
diff --git a/src/gdu/gdu-callbacks.h b/src/gdu/gdu-callbacks.h
index 5d20ced..dc6e661 100644
--- a/src/gdu/gdu-callbacks.h
+++ b/src/gdu/gdu-callbacks.h
@@ -101,9 +101,13 @@ typedef void (*GduDeviceLinuxMdCheckCompletedFunc) (GduDevice    *device,
                                                     GError       *error,
                                                     gpointer      user_data);
 
-typedef void (*GduDeviceLinuxMdAddComponentCompletedFunc) (GduDevice    *device,
-                                                           GError       *error,
-                                                           gpointer      user_data);
+typedef void (*GduDeviceLinuxMdAddSpareCompletedFunc) (GduDevice    *device,
+                                                       GError       *error,
+                                                       gpointer      user_data);
+
+typedef void (*GduDeviceLinuxMdExpandCompletedFunc) (GduDevice    *device,
+                                                     GError       *error,
+                                                     gpointer      user_data);
 
 typedef void (*GduDeviceLinuxMdRemoveComponentCompletedFunc) (GduDevice    *device,
                                                               GError       *error,
diff --git a/src/gdu/gdu-device.c b/src/gdu/gdu-device.c
index 10eaca6..6d31ab7 100644
--- a/src/gdu/gdu-device.c
+++ b/src/gdu/gdu-device.c
@@ -2430,14 +2430,14 @@ gdu_device_op_linux_md_check (GduDevice                           *device,
 
 typedef struct {
         GduDevice *device;
-        GduDeviceLinuxMdAddComponentCompletedFunc callback;
+        GduDeviceLinuxMdAddSpareCompletedFunc callback;
         gpointer user_data;
-} LinuxMdAddComponentData;
+} LinuxMdAddSpareData;
 
 static void
-op_add_component_to_linux_md_array_cb (DBusGProxy *proxy, GError *error, gpointer user_data)
+op_add_spare_to_linux_md_array_cb (DBusGProxy *proxy, GError *error, gpointer user_data)
 {
-        LinuxMdAddComponentData *data = user_data;
+        LinuxMdAddSpareData *data = user_data;
         _gdu_error_fixup (error);
         if (data->callback != NULL)
                 data->callback (data->device, error, data->user_data);
@@ -2446,26 +2446,68 @@ op_add_component_to_linux_md_array_cb (DBusGProxy *proxy, GError *error, gpointe
 }
 
 void
-gdu_device_op_linux_md_add_component (GduDevice                                 *device,
-                                      const char                                *component_objpath,
-                                      GduDeviceLinuxMdAddComponentCompletedFunc  callback,
-                                      gpointer                                   user_data)
+gdu_device_op_linux_md_add_spare (GduDevice                                 *device,
+                                  const char                                *component_objpath,
+                                  GduDeviceLinuxMdAddSpareCompletedFunc  callback,
+                                  gpointer                                   user_data)
 {
         char *options[16];
-        LinuxMdAddComponentData *data;
+        LinuxMdAddSpareData *data;
 
-        data = g_new0 (LinuxMdAddComponentData, 1);
+        data = g_new0 (LinuxMdAddSpareData, 1);
         data->device = g_object_ref (device);
         data->callback = callback;
         data->user_data = user_data;
 
         options[0] = NULL;
 
-        org_freedesktop_UDisks_Device_linux_md_add_component_async (device->priv->proxy,
-                                                                    component_objpath,
-                                                                    (const char **) options,
-                                                                    op_add_component_to_linux_md_array_cb,
-                                                                    data);
+        org_freedesktop_UDisks_Device_linux_md_add_spare_async (device->priv->proxy,
+                                                                component_objpath,
+                                                                (const char **) options,
+                                                                op_add_spare_to_linux_md_array_cb,
+                                                                data);
+}
+
+/* -------------------------------------------------------------------------------- */
+
+typedef struct {
+        GduDevice *device;
+        GduDeviceLinuxMdExpandCompletedFunc callback;
+        gpointer user_data;
+} LinuxMdExpandData;
+
+static void
+op_expand_to_linux_md_array_cb (DBusGProxy *proxy, GError *error, gpointer user_data)
+{
+        LinuxMdExpandData *data = user_data;
+        _gdu_error_fixup (error);
+        if (data->callback != NULL)
+                data->callback (data->device, error, data->user_data);
+        g_object_unref (data->device);
+        g_free (data);
+}
+
+void
+gdu_device_op_linux_md_expand (GduDevice                            *device,
+                               GPtrArray                            *component_objpaths,
+                               GduDeviceLinuxMdExpandCompletedFunc   callback,
+                               gpointer                              user_data)
+{
+        char *options[16];
+        LinuxMdExpandData *data;
+
+        data = g_new0 (LinuxMdExpandData, 1);
+        data->device = g_object_ref (device);
+        data->callback = callback;
+        data->user_data = user_data;
+
+        options[0] = NULL;
+
+        org_freedesktop_UDisks_Device_linux_md_expand_async (device->priv->proxy,
+                                                             component_objpaths,
+                                                             (const char **) options,
+                                                             op_expand_to_linux_md_array_cb,
+                                                             data);
 }
 
 /* -------------------------------------------------------------------------------- */
diff --git a/src/gdu/gdu-device.h b/src/gdu/gdu-device.h
index 4b29d0b..01bfc01 100644
--- a/src/gdu/gdu-device.h
+++ b/src/gdu/gdu-device.h
@@ -306,10 +306,17 @@ void gdu_device_op_linux_md_check    (GduDevice                           *devic
 
 /* ---------------------------------------------------------------------------------------------------- */
 
-void gdu_device_op_linux_md_add_component (GduDevice                                 *device,
-                                           const char                                *component_objpath,
-                                           GduDeviceLinuxMdAddComponentCompletedFunc  callback,
-                                           gpointer                                   user_data);
+void gdu_device_op_linux_md_add_spare (GduDevice                             *device,
+                                       const char                            *component_objpath,
+                                       GduDeviceLinuxMdAddSpareCompletedFunc  callback,
+                                       gpointer                               user_data);
+
+/* ---------------------------------------------------------------------------------------------------- */
+
+void gdu_device_op_linux_md_expand (GduDevice                           *device,
+                                    GPtrArray                           *component_objpaths,
+                                    GduDeviceLinuxMdExpandCompletedFunc  callback,
+                                    gpointer                             user_data);
 
 /* ---------------------------------------------------------------------------------------------------- */
 
diff --git a/src/palimpsest/gdu-section-linux-md-drive.c b/src/palimpsest/gdu-section-linux-md-drive.c
index 48637af..e696c80 100644
--- a/src/palimpsest/gdu-section-linux-md-drive.c
+++ b/src/palimpsest/gdu-section-linux-md-drive.c
@@ -593,10 +593,10 @@ on_components_dialog_attach_button_clicked (GduEditLinuxMdDialog *_dialog,
 
         slave_flags = gdu_linux_md_drive_get_slave_flags (linux_md_drive, slave_device);
         if (slave_flags & GDU_LINUX_MD_DRIVE_SLAVE_FLAGS_NOT_ATTACHED) {
-                gdu_device_op_linux_md_add_component (device,
-                                                      gdu_device_get_object_path (slave_device),
-                                                      attach_component_op_callback,
-                                                      g_object_ref (gdu_section_get_shell (GDU_SECTION (section))));
+                gdu_device_op_linux_md_add_spare (device,
+                                                  gdu_device_get_object_path (slave_device),
+                                                  attach_component_op_callback,
+                                                  g_object_ref (gdu_section_get_shell (GDU_SECTION (section))));
         }
 
  out:
@@ -609,8 +609,13 @@ on_components_dialog_attach_button_clicked (GduEditLinuxMdDialog *_dialog,
 typedef struct {
         GduShell *shell;
         GduLinuxMdDrive *linux_md_drive;
-        GduDrive *drive_to_add_to;
+        GduDevice *linux_md_drive_device;
+        GPtrArray *drives_to_add_to;
+        GPtrArray *created_components_object_paths;
+        guint next_volume_number;
+        gboolean failed;
         guint64 size;
+        gboolean is_expansion;
 } AddComponentData;
 
 static void
@@ -620,11 +625,17 @@ add_component_data_free (AddComponentData *data)
                 g_object_unref (data->shell);
         if (data->linux_md_drive != NULL)
                 g_object_unref (data->linux_md_drive);
-        if (data->drive_to_add_to != NULL)
-                g_object_unref (data->drive_to_add_to);
+        if (data->linux_md_drive_device != NULL)
+                g_object_unref (data->linux_md_drive_device);
+        if (data->drives_to_add_to != NULL)
+                g_ptr_array_unref (data->drives_to_add_to);
+        if (data->created_components_object_paths != NULL)
+                g_ptr_array_unref (data->created_components_object_paths);
         g_free (data);
 }
 
+static void do_create_volumes (AddComponentData *data);
+
 static void
 add_component_cb (GduDevice  *device,
                   GError     *error,
@@ -643,9 +654,13 @@ add_component_cb (GduDevice  *device,
                 gtk_dialog_run (GTK_DIALOG (dialog));
                 gtk_widget_destroy (dialog);
                 g_error_free (error);
+                data->failed = TRUE;
+        } else {
+                /* Onwards to the next one */
+                data->next_volume_number++;
         }
 
-        add_component_data_free (data);
+        do_create_volumes (data);
 }
 
 static void
@@ -667,30 +682,89 @@ new_component_create_volume_cb (GduDrive     *drive,
                                        error,
                                        _("Error creating component for RAID array"));
                 g_error_free (error);
-                add_component_data_free (data);
+                data->failed = TRUE;
+                do_create_volumes (data);
         } else {
                 GduDevice *component_device;
-                GduDevice *array_device;
 
                 component_device = gdu_presentable_get_device (GDU_PRESENTABLE (volume));
-                array_device = gdu_presentable_get_device (GDU_PRESENTABLE (data->linux_md_drive));
 
-                gdu_device_op_linux_md_add_component (array_device,
-                                                      gdu_device_get_object_path (component_device),
-                                                      add_component_cb,
-                                                      data);
+                if (data->is_expansion) {
+                        /* If expanding, just queue up object paths ... */
+                        g_ptr_array_add (data->created_components_object_paths,
+                                         g_strdup (gdu_device_get_object_path (component_device)));
+                        /* ... and continue onwards to the next volume */
+                        data->next_volume_number++;
+                        do_create_volumes (data);
+                } else {
+                        gdu_device_op_linux_md_add_spare (data->linux_md_drive_device,
+                                                          gdu_device_get_object_path (component_device),
+                                                          add_component_cb,
+                                                          data);
+                }
 
-                g_object_unref (array_device);
                 g_object_unref (component_device);
                 g_object_unref (volume);
         }
 }
 
 static void
-on_components_dialog_new_button_clicked (GduEditLinuxMdDialog *_dialog,
-                                         gpointer              user_data)
+expand_md_cb (GduDevice  *device,
+              GError     *error,
+              gpointer    user_data)
+{
+        AddComponentData *data = user_data;
+
+        if (error != NULL) {
+                GtkWidget *dialog;
+                dialog = gdu_error_dialog_new_for_drive (GTK_WINDOW (gdu_shell_get_toplevel (data->shell)),
+                                                         device,
+                                                         _("Error expanding RAID Array"),
+                                                         error);
+                gtk_widget_show_all (dialog);
+                gtk_window_present (GTK_WINDOW (dialog));
+                gtk_dialog_run (GTK_DIALOG (dialog));
+                gtk_widget_destroy (dialog);
+                g_error_free (error);
+                data->failed = TRUE;
+        }
+
+        add_component_data_free (data);
+}
+
+static void
+do_create_volumes (AddComponentData *data)
+{
+        if (data->failed) {
+                /* Failed - already shown dialogs */
+                add_component_data_free (data);
+        } else if (data->next_volume_number == data->drives_to_add_to->len) {
+                /* Done! */
+
+                if (data->is_expansion) {
+                        gdu_device_op_linux_md_expand (data->linux_md_drive_device,
+                                                       data->created_components_object_paths,
+                                                       expand_md_cb,
+                                                       data);
+                } else {
+                        add_component_data_free (data);
+                }
+        } else {
+                GduDrive *drive;
+                drive = data->drives_to_add_to->pdata[data->next_volume_number];
+                gdu_drive_create_volume (drive,
+                                         data->size,
+                                         gdu_device_linux_md_get_name (data->linux_md_drive_device),
+                                         GDU_CREATE_VOLUME_FLAGS_LINUX_MD,
+                                         (GAsyncReadyCallback) new_component_create_volume_cb,
+                                         data);
+        }
+}
+
+static void
+generic_add_component (GduSectionLinuxMdDrive *section,
+                       gboolean is_expansion)
 {
-        GduSectionLinuxMdDrive *section = GDU_SECTION_LINUX_MD_DRIVE (user_data);
         GduLinuxMdDrive *linux_md_drive;
         GduDevice *device;
         GtkWidget *dialog;
@@ -708,7 +782,11 @@ on_components_dialog_new_button_clicked (GduEditLinuxMdDialog *_dialog,
         if (device == NULL)
                 goto out;
 
-        dialog = gdu_add_component_linux_md_dialog_new (toplevel, linux_md_drive);
+        dialog = gdu_add_component_linux_md_dialog_new (toplevel,
+                                                        is_expansion ?
+                                                          GDU_ADD_COMPONENT_LINUX_MD_FLAGS_EXPANSION :
+                                                          GDU_ADD_COMPONENT_LINUX_MD_FLAGS_SPARE,
+                                                        linux_md_drive);
         gtk_widget_show_all (dialog);
         response = gtk_dialog_run (GTK_DIALOG (dialog));
         gtk_widget_hide (dialog);
@@ -718,15 +796,13 @@ on_components_dialog_new_button_clicked (GduEditLinuxMdDialog *_dialog,
         data = g_new0 (AddComponentData, 1);
         data->shell = g_object_ref (gdu_section_get_shell (GDU_SECTION (section)));
         data->linux_md_drive = g_object_ref (linux_md_drive);
-        data->drive_to_add_to = gdu_add_component_linux_md_dialog_get_drive (GDU_ADD_COMPONENT_LINUX_MD_DIALOG (dialog));
+        data->linux_md_drive_device = g_object_ref (device);
+        data->drives_to_add_to = gdu_add_component_linux_md_dialog_get_drives (GDU_ADD_COMPONENT_LINUX_MD_DIALOG (dialog));
         data->size = gdu_add_component_linux_md_dialog_get_size (GDU_ADD_COMPONENT_LINUX_MD_DIALOG (dialog));
+        data->is_expansion = is_expansion;
+        data->created_components_object_paths = g_ptr_array_new_with_free_func (g_free);
 
-        gdu_drive_create_volume (data->drive_to_add_to,
-                                 data->size,
-                                 gdu_device_linux_md_get_name (device),
-                                 GDU_CREATE_VOLUME_FLAGS_LINUX_MD,
-                                 (GAsyncReadyCallback) new_component_create_volume_cb,
-                                 data);
+        do_create_volumes (data);
 
  out:
         if (dialog != NULL)
@@ -735,6 +811,22 @@ on_components_dialog_new_button_clicked (GduEditLinuxMdDialog *_dialog,
                 g_object_unref (device);
 }
 
+static void
+on_components_dialog_expand_button_clicked (GduEditLinuxMdDialog *dialog,
+                                            gpointer              user_data)
+{
+        GduSectionLinuxMdDrive *section = GDU_SECTION_LINUX_MD_DRIVE (user_data);
+        generic_add_component (section, TRUE);
+}
+
+static void
+on_components_dialog_add_spare_button_clicked (GduEditLinuxMdDialog *dialog,
+                                               gpointer              user_data)
+{
+        GduSectionLinuxMdDrive *section = GDU_SECTION_LINUX_MD_DRIVE (user_data);
+        generic_add_component (section, FALSE);
+}
+
 /* ---------------------------------------------------------------------------------------------------- */
 
 static void
@@ -752,8 +844,12 @@ on_edit_components_button_clicked (GduButtonElement *button_element,
         dialog = gdu_edit_linux_md_dialog_new (toplevel, GDU_LINUX_MD_DRIVE (p));
 
         g_signal_connect (dialog,
-                          "new-button-clicked",
-                          G_CALLBACK (on_components_dialog_new_button_clicked),
+                          "add-spare-button-clicked",
+                          G_CALLBACK (on_components_dialog_add_spare_button_clicked),
+                          section);
+        g_signal_connect (dialog,
+                          "expand-button-clicked",
+                          G_CALLBACK (on_components_dialog_expand_button_clicked),
                           section);
         g_signal_connect (dialog,
                           "attach-button-clicked",



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