[gnome-disk-utility] Make the "Connect to server..." menu item actually work



commit c4a4879321bb3dc413029c39abdb78f3e2a0f0ba
Author: David Zeuthen <davidz redhat com>
Date:   Wed Dec 9 15:28:40 2009 -0500

    Make the "Connect to server..." menu item actually work
    
    Still need some work but the basics work well now.
    
    Signed-off-by: David Zeuthen <davidz redhat com>

 src/gdu-gtk/gdu-connect-to-server-dialog.c |   33 ++++-
 src/gdu-gtk/gdu-connect-to-server-dialog.h |    7 +-
 src/gdu-gtk/gdu-create-linux-md-dialog.c   |    6 +-
 src/gdu-gtk/gdu-disk-selection-widget.c    |    6 +-
 src/gdu-gtk/gdu-error-dialog.c             |   71 +++++----
 src/gdu-gtk/gdu-pool-tree-model.c          |  162 +++++++++++++-------
 src/gdu-gtk/gdu-pool-tree-model.h          |    4 +-
 src/gdu/Makefile.am                        |    2 +
 src/gdu/gdu-linux-md-drive.c               |   43 +++++-
 src/gdu/gdu-machine.c                      |  225 ++++++++++++++++++++++++++++
 src/gdu/gdu-machine.h                      |   60 ++++++++
 src/gdu/gdu-pool.c                         |   56 ++++++-
 src/gdu/gdu-pool.h                         |    8 +-
 src/gdu/gdu-private.h                      |    6 +-
 src/gdu/gdu-ssh-bridge.c                   |    8 +-
 src/gdu/gdu-ssh-bridge.h                   |    1 +
 src/gdu/gdu-types.h                        |    2 +
 src/gdu/gdu.h                              |    1 +
 src/palimpsest/gdu-main.c                  |   44 +++---
 src/palimpsest/gdu-shell.c                 |  158 +++++++++++++++----
 src/palimpsest/gdu-shell.h                 |   26 ++--
 21 files changed, 750 insertions(+), 179 deletions(-)
---
diff --git a/src/gdu-gtk/gdu-connect-to-server-dialog.c b/src/gdu-gtk/gdu-connect-to-server-dialog.c
index 4ea0516..9ecf08c 100644
--- a/src/gdu-gtk/gdu-connect-to-server-dialog.c
+++ b/src/gdu-gtk/gdu-connect-to-server-dialog.c
@@ -30,8 +30,6 @@
 
 struct GduConnectToServerDialogPrivate
 {
-        gchar *address;
-
         GtkWidget *hostname_entry;
         GtkWidget *username_entry;
 };
@@ -39,6 +37,7 @@ struct GduConnectToServerDialogPrivate
 enum
 {
         PROP_0,
+        PROP_USER_NAME,
         PROP_ADDRESS,
 };
 
@@ -49,9 +48,7 @@ static void gdu_connect_to_server_dialog_constructed (GObject *object);
 static void
 gdu_connect_to_server_dialog_finalize (GObject *object)
 {
-        GduConnectToServerDialog *dialog = GDU_CONNECT_TO_SERVER_DIALOG (object);
-
-        g_free (dialog->priv->address);
+        //GduConnectToServerDialog *dialog = GDU_CONNECT_TO_SERVER_DIALOG (object);
 
         if (G_OBJECT_CLASS (gdu_connect_to_server_dialog_parent_class)->finalize != NULL)
                 G_OBJECT_CLASS (gdu_connect_to_server_dialog_parent_class)->finalize (object);
@@ -66,8 +63,12 @@ gdu_connect_to_server_dialog_get_property (GObject    *object,
         GduConnectToServerDialog *dialog = GDU_CONNECT_TO_SERVER_DIALOG (object);
 
         switch (property_id) {
+        case PROP_USER_NAME:
+                g_value_take_string (value, gdu_connect_to_server_dialog_get_user_name (dialog));
+                break;
+
         case PROP_ADDRESS:
-                g_value_set_string (value, dialog->priv->address);
+                g_value_take_string (value, gdu_connect_to_server_dialog_get_address (dialog));
                 break;
 
         default:
@@ -88,6 +89,17 @@ gdu_connect_to_server_dialog_class_init (GduConnectToServerDialogClass *klass)
         object_class->finalize     = gdu_connect_to_server_dialog_finalize;
 
         g_object_class_install_property (object_class,
+                                         PROP_USER_NAME,
+                                         g_param_spec_string ("user-name",
+                                                              _("User Name"),
+                                                              _("The chosen user name"),
+                                                              NULL,
+                                                              G_PARAM_READABLE |
+                                                              G_PARAM_STATIC_NAME |
+                                                              G_PARAM_STATIC_NICK |
+                                                              G_PARAM_STATIC_BLURB));
+
+        g_object_class_install_property (object_class,
                                          PROP_ADDRESS,
                                          g_param_spec_string ("address",
                                                               _("Address"),
@@ -116,10 +128,17 @@ gdu_connect_to_server_dialog_new (GtkWindow *parent)
 /* ---------------------------------------------------------------------------------------------------- */
 
 gchar *
+gdu_connect_to_server_dialog_get_user_name (GduConnectToServerDialog *dialog)
+{
+        g_return_val_if_fail (GDU_IS_CONNECT_TO_SERVER_DIALOG (dialog), NULL);
+        return g_strdup (gtk_entry_get_text (GTK_ENTRY (dialog->priv->username_entry)));
+}
+
+gchar *
 gdu_connect_to_server_dialog_get_address  (GduConnectToServerDialog *dialog)
 {
         g_return_val_if_fail (GDU_IS_CONNECT_TO_SERVER_DIALOG (dialog), NULL);
-        return g_strdup (dialog->priv->address);
+        return g_strdup (gtk_entry_get_text (GTK_ENTRY (dialog->priv->hostname_entry)));
 }
 
 /* ---------------------------------------------------------------------------------------------------- */
diff --git a/src/gdu-gtk/gdu-connect-to-server-dialog.h b/src/gdu-gtk/gdu-connect-to-server-dialog.h
index b115dcb..b32d4d4 100644
--- a/src/gdu-gtk/gdu-connect-to-server-dialog.h
+++ b/src/gdu-gtk/gdu-connect-to-server-dialog.h
@@ -50,9 +50,10 @@ struct GduConnectToServerDialogClass
         GtkDialogClass parent_class;
 };
 
-GType       gdu_connect_to_server_dialog_get_type    (void) G_GNUC_CONST;
-GtkWidget*  gdu_connect_to_server_dialog_new         (GtkWindow                 *parent);
-gchar      *gdu_connect_to_server_dialog_get_address (GduConnectToServerDialog  *dialog);
+GType       gdu_connect_to_server_dialog_get_type      (void) G_GNUC_CONST;
+GtkWidget*  gdu_connect_to_server_dialog_new           (GtkWindow                 *parent);
+gchar      *gdu_connect_to_server_dialog_get_user_name (GduConnectToServerDialog  *dialog);
+gchar      *gdu_connect_to_server_dialog_get_address   (GduConnectToServerDialog  *dialog);
 
 G_END_DECLS
 
diff --git a/src/gdu-gtk/gdu-create-linux-md-dialog.c b/src/gdu-gtk/gdu-create-linux-md-dialog.c
index 1552c19..06d45b0 100644
--- a/src/gdu-gtk/gdu-create-linux-md-dialog.c
+++ b/src/gdu-gtk/gdu-create-linux-md-dialog.c
@@ -1062,11 +1062,15 @@ gdu_create_linux_md_dialog_constructed (GObject *object)
         GtkWidget *scrolled_window;
         GtkCellRenderer *renderer;
         GtkTreeViewColumn *column;
+        GPtrArray *pools;
 
-        dialog->priv->model = gdu_pool_tree_model_new (dialog->priv->pool,
+        pools = g_ptr_array_new ();
+        g_ptr_array_add (pools, dialog->priv->pool);
+        dialog->priv->model = gdu_pool_tree_model_new (pools,
                                                        NULL,
                                                        GDU_POOL_TREE_MODEL_FLAGS_NO_VOLUMES |
                                                        GDU_POOL_TREE_MODEL_FLAGS_NO_UNALLOCATABLE_DRIVES);
+        g_ptr_array_unref (pools);
 
         tree_view = gtk_tree_view_new_with_model (GTK_TREE_MODEL (dialog->priv->model));
         gtk_tree_view_set_rules_hint (GTK_TREE_VIEW (tree_view), TRUE);
diff --git a/src/gdu-gtk/gdu-disk-selection-widget.c b/src/gdu-gtk/gdu-disk-selection-widget.c
index 1527402..559f232 100644
--- a/src/gdu-gtk/gdu-disk-selection-widget.c
+++ b/src/gdu-gtk/gdu-disk-selection-widget.c
@@ -797,11 +797,15 @@ gdu_disk_selection_widget_constructed (GObject *object)
         GtkCellRenderer *renderer;
         GtkTreeViewColumn *column;
         GtkTreeModel *model;
+        GPtrArray *pools;
 
-        model = GTK_TREE_MODEL (gdu_pool_tree_model_new (widget->priv->pool,
+        pools = g_ptr_array_new ();
+        g_ptr_array_add (pools, widget->priv->pool);
+        model = GTK_TREE_MODEL (gdu_pool_tree_model_new (pools,
                                                          NULL,
                                                          GDU_POOL_TREE_MODEL_FLAGS_NO_VOLUMES |
                                                          GDU_POOL_TREE_MODEL_FLAGS_NO_UNALLOCATABLE_DRIVES));
+        g_ptr_array_unref (pools);
 
         widget->priv->model = gtk_tree_model_filter_new (model, NULL);
         g_object_unref (model);
diff --git a/src/gdu-gtk/gdu-error-dialog.c b/src/gdu-gtk/gdu-error-dialog.c
index b538e24..f4549f6 100644
--- a/src/gdu-gtk/gdu-error-dialog.c
+++ b/src/gdu-gtk/gdu-error-dialog.c
@@ -154,20 +154,11 @@ gdu_error_dialog_constructed (GObject *object)
         GtkWidget *label;
         GtkWidget *expander;
         gchar *s;
-        GIcon *icon;
-        GEmblem *emblem;
-        GIcon *error_icon;
-        GIcon *emblemed_icon;
-        gchar *name;
-        gchar *vpd_name;
         const gchar *error_msg;
         GtkWidget *scrolled_window;
         GtkWidget *text_view;
         GtkTextBuffer *buffer;
-
-        icon = NULL;
-        name = NULL;
-        vpd_name = NULL;
+        GduPresentable *presentable;
 
         gtk_window_set_title (GTK_WINDOW (dialog), _(""));
         gtk_window_set_resizable (GTK_WINDOW (dialog), FALSE);
@@ -180,17 +171,31 @@ gdu_error_dialog_constructed (GObject *object)
 
         content_area = gtk_dialog_get_content_area (GTK_DIALOG (dialog));
 
-        icon = gdu_presentable_get_icon (gdu_dialog_get_presentable (GDU_DIALOG (dialog)));
-        error_icon = g_themed_icon_new (GTK_STOCK_DIALOG_ERROR);
-        emblem = g_emblem_new (icon);
-        emblemed_icon = g_emblemed_icon_new (error_icon,
-                                             emblem);
+        presentable = gdu_dialog_get_presentable (GDU_DIALOG (dialog));
+        if (presentable != NULL) {
+                GIcon *icon;
+                GEmblem *emblem;
+                GIcon *error_icon;
+                GIcon *emblemed_icon;
+
+                icon = gdu_presentable_get_icon (presentable);
+                error_icon = g_themed_icon_new (GTK_STOCK_DIALOG_ERROR);
+                emblem = g_emblem_new (icon);
+                emblemed_icon = g_emblemed_icon_new (error_icon,
+                                                     emblem);
+                image = gtk_image_new_from_gicon (emblemed_icon, GTK_ICON_SIZE_DIALOG);
+
+                g_object_unref (icon);
+                g_object_unref (emblem);
+                g_object_unref (error_icon);
+                g_object_unref (emblemed_icon);
+        } else {
+                image = gtk_image_new_from_stock (GTK_STOCK_DIALOG_ERROR, GTK_ICON_SIZE_DIALOG);
+        }
 
         hbox = gtk_hbox_new (FALSE, 12);
         gtk_box_pack_start (GTK_BOX (content_area), hbox, TRUE, TRUE, 0);
 
-        image = gtk_image_new_from_gicon (emblemed_icon,
-                                          GTK_ICON_SIZE_DIALOG);
         gtk_misc_set_alignment (GTK_MISC (image), 0.5, 0.0);
         gtk_box_pack_start (GTK_BOX (hbox), image, FALSE, FALSE, 0);
 
@@ -243,12 +248,22 @@ gdu_error_dialog_constructed (GObject *object)
         if (error_msg == NULL)
                 error_msg = _("Unknown error");
 
-        name = gdu_presentable_get_name (gdu_dialog_get_presentable (GDU_DIALOG (dialog)));
-        vpd_name = gdu_presentable_get_vpd_name (gdu_dialog_get_presentable (GDU_DIALOG (dialog)));
-        s = g_strdup_printf (_("An error occured while performing an operation on \"%s\" (%s): %s"),
-                             name,
-                             vpd_name,
-                             error_msg);
+        if (presentable != NULL) {
+                gchar *name;
+                gchar *vpd_name;
+
+                name = gdu_presentable_get_name (presentable);
+                vpd_name = gdu_presentable_get_vpd_name (presentable);
+                s = g_strdup_printf (_("An error occured while performing an operation on \"%s\" (%s): %s"),
+                                     name,
+                                     vpd_name,
+                                     error_msg);
+
+                g_free (name);
+                g_free (vpd_name);
+        } else {
+                s = g_strdup_printf (_("An error occured: %s"), error_msg);
+        }
 
         label = gtk_label_new (s);
         g_free (s);
@@ -278,14 +293,6 @@ gdu_error_dialog_constructed (GObject *object)
         gtk_container_add (GTK_CONTAINER (expander), scrolled_window);
         gtk_container_add (GTK_CONTAINER (scrolled_window), text_view);
 
-        g_object_unref (icon);
-        g_object_unref (emblem);
-        g_object_unref (error_icon);
-        g_object_unref (emblemed_icon);
-
-        g_free (name);
-        g_free (vpd_name);
-
         gtk_widget_grab_focus (button);
 
         if (G_OBJECT_CLASS (gdu_error_dialog_parent_class)->constructed != NULL)
@@ -337,7 +344,7 @@ gdu_error_dialog_new (GtkWindow      *parent,
                       const gchar    *message,
                       const GError   *error)
 {
-        g_return_val_if_fail (GDU_IS_PRESENTABLE (presentable), NULL);
+        g_return_val_if_fail (presentable == NULL || GDU_IS_PRESENTABLE (presentable), NULL);
         return GTK_WIDGET (g_object_new (GDU_TYPE_ERROR_DIALOG,
                                          "transient-for", parent,
                                          "presentable", presentable,
diff --git a/src/gdu-gtk/gdu-pool-tree-model.c b/src/gdu-gtk/gdu-pool-tree-model.c
index e00e0c9..ea6a628 100644
--- a/src/gdu-gtk/gdu-pool-tree-model.c
+++ b/src/gdu-gtk/gdu-pool-tree-model.c
@@ -30,9 +30,10 @@
 
 struct GduPoolTreeModelPrivate
 {
-        GduPool *pool;
+        GPtrArray *pools;
         GduPresentable *root;
         GduPoolTreeModelFlags flags;
+        gboolean constructed;
 };
 
 G_DEFINE_TYPE (GduPoolTreeModel, gdu_pool_tree_model, GTK_TYPE_TREE_STORE)
@@ -41,7 +42,7 @@ enum
 {
         PROP_0,
         PROP_ROOT,
-        PROP_POOL,
+        PROP_POOLS,
         PROP_FLAGS,
 };
 
@@ -63,6 +64,18 @@ static void add_presentable        (GduPoolTreeModel *model,
 /* ---------------------------------------------------------------------------------------------------- */
 
 static void
+disconnect_from_pool_cb (GduPool  *pool,
+                         gpointer  user_data)
+{
+        GduPoolTreeModel *model = GDU_POOL_TREE_MODEL (user_data);
+        g_signal_handlers_disconnect_by_func (pool, on_presentable_added, model);
+        g_signal_handlers_disconnect_by_func (pool, on_presentable_removed, model);
+        g_signal_handlers_disconnect_by_func (pool, on_presentable_changed, model);
+}
+
+/* ---------------------------------------------------------------------------------------------------- */
+
+static void
 gdu_pool_tree_model_set_property (GObject      *object,
                                   guint         prop_id,
                                   const GValue *value,
@@ -71,8 +84,8 @@ gdu_pool_tree_model_set_property (GObject      *object,
         GduPoolTreeModel *model = GDU_POOL_TREE_MODEL (object);
 
         switch (prop_id) {
-        case PROP_POOL:
-                model->priv->pool = g_value_dup_object (value);
+        case PROP_POOLS:
+                gdu_pool_tree_model_set_pools (model, g_value_get_boxed (value));
                 break;
 
         case PROP_ROOT:
@@ -92,15 +105,15 @@ gdu_pool_tree_model_set_property (GObject      *object,
 
 static void
 gdu_pool_tree_model_get_property (GObject     *object,
-                             guint        prop_id,
-                             GValue      *value,
-                             GParamSpec  *pspec)
+                                  guint        prop_id,
+                                  GValue      *value,
+                                  GParamSpec  *pspec)
 {
         GduPoolTreeModel *model = GDU_POOL_TREE_MODEL (object);
 
         switch (prop_id) {
-        case PROP_POOL:
-                g_value_set_object (value, model->priv->pool);
+        case PROP_POOLS:
+                g_value_set_boxed (value, model->priv->pools);
                 break;
 
         case PROP_ROOT:
@@ -122,11 +135,10 @@ gdu_pool_tree_model_finalize (GObject *object)
 {
         GduPoolTreeModel *model = GDU_POOL_TREE_MODEL (object);
 
-        g_signal_handlers_disconnect_by_func (model->priv->pool, on_presentable_added, model);
-        g_signal_handlers_disconnect_by_func (model->priv->pool, on_presentable_removed, model);
-        g_signal_handlers_disconnect_by_func (model->priv->pool, on_presentable_changed, model);
-
-        g_object_unref (model->priv->pool);
+        if (model->priv->pools != NULL) {
+                g_ptr_array_foreach (model->priv->pools, (GFunc) disconnect_from_pool_cb, model);
+                g_ptr_array_unref (model->priv->pools);
+        }
 
         if (G_OBJECT_CLASS (gdu_pool_tree_model_parent_class)->finalize != NULL)
                 G_OBJECT_CLASS (gdu_pool_tree_model_parent_class)->finalize (object);
@@ -161,12 +173,35 @@ presentable_sort_func (GtkTreeModel *model,
 }
 
 static void
+do_coldplug (GduPoolTreeModel *model)
+{
+        guint n;
+
+        /* remove all.. */
+        gtk_tree_store_clear (GTK_TREE_STORE (model));
+
+        /* then coldplug it back */
+        for (n = 0; n < model->priv->pools->len; n++) {
+                GduPool *pool = GDU_POOL (model->priv->pools->pdata[n]);
+                GList *presentables;
+                GList *l;
+
+                presentables = gdu_pool_get_presentables (pool);
+                for (l = presentables; l != NULL; l = l->next) {
+                        GduPresentable *presentable = GDU_PRESENTABLE (l->data);
+
+                        add_presentable (model, presentable, NULL);
+                        g_object_unref (presentable);
+                }
+                g_list_free (presentables);
+        }
+}
+
+static void
 gdu_pool_tree_model_constructed (GObject *object)
 {
         GduPoolTreeModel *model = GDU_POOL_TREE_MODEL (object);
         GType column_types[8];
-        GList *presentables;
-        GList *l;
 
         column_types[0] = G_TYPE_ICON;
         column_types[1] = G_TYPE_STRING;
@@ -177,48 +212,65 @@ gdu_pool_tree_model_constructed (GObject *object)
         column_types[6] = G_TYPE_BOOLEAN;
         column_types[7] = G_TYPE_BOOLEAN;
 
-        gtk_tree_store_set_column_types (GTK_TREE_STORE (object),
+        gtk_tree_store_set_column_types (GTK_TREE_STORE (model),
                                          G_N_ELEMENTS (column_types),
                                          column_types);
 
-        gtk_tree_sortable_set_sort_func (GTK_TREE_SORTABLE (object),
+        gtk_tree_sortable_set_sort_func (GTK_TREE_SORTABLE (model),
                                          GDU_POOL_TREE_MODEL_COLUMN_PRESENTABLE,
                                          presentable_sort_func,
                                          NULL,
                                          NULL);
 
-        gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (object),
+        gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (model),
                                               GDU_POOL_TREE_MODEL_COLUMN_PRESENTABLE,
                                               GTK_SORT_ASCENDING);
 
-        /* coldplug */
-        presentables = gdu_pool_get_presentables (model->priv->pool);
-        for (l = presentables; l != NULL; l = l->next) {
-                GduPresentable *presentable = GDU_PRESENTABLE (l->data);
+        model->priv->constructed = TRUE;
 
-                add_presentable (model, presentable, NULL);
-                g_object_unref (presentable);
-        }
-        g_list_free (presentables);
-
-        /* add/remove/change when the pool reports presentable add/remove/change */
-        g_signal_connect (model->priv->pool,
-                          "presentable-added",
-                          G_CALLBACK (on_presentable_added),
-                          model);
-        g_signal_connect (model->priv->pool,
-                          "presentable-removed",
-                          G_CALLBACK (on_presentable_removed),
-                          model);
-        g_signal_connect (model->priv->pool,
-                          "presentable-changed",
-                          G_CALLBACK (on_presentable_changed),
-                          model);
+        do_coldplug (model);
 
         if (G_OBJECT_CLASS (gdu_pool_tree_model_parent_class)->constructed != NULL)
                 G_OBJECT_CLASS (gdu_pool_tree_model_parent_class)->constructed (object);
 }
 
+void
+gdu_pool_tree_model_set_pools (GduPoolTreeModel      *model,
+                               GPtrArray             *pools)
+{
+        guint n;
+
+        /* Do a deep copy here */
+        if (model->priv->pools != NULL) {
+                g_ptr_array_foreach (model->priv->pools, (GFunc) disconnect_from_pool_cb, model);
+                g_ptr_array_unref (model->priv->pools);
+        }
+
+        model->priv->pools = g_ptr_array_new_with_free_func (g_object_unref);
+        for (n = 0; pools != NULL && n < pools->len; n++) {
+                GduPool *pool = GDU_POOL (pools->pdata[n]);
+
+                g_signal_connect (pool,
+                                  "presentable-added",
+                                  G_CALLBACK (on_presentable_added),
+                                  model);
+                g_signal_connect (pool,
+                                  "presentable-removed",
+                                  G_CALLBACK (on_presentable_removed),
+                                  model);
+                g_signal_connect (pool,
+                                  "presentable-changed",
+                                  G_CALLBACK (on_presentable_changed),
+                                  model);
+
+                g_ptr_array_add (model->priv->pools, g_object_ref (pool));
+        }
+
+        /* only do coldplug if we have been constructed as the result depends on the value of the flags */
+        if (model->priv->constructed)
+                do_coldplug (model);
+}
+
 static void
 gdu_pool_tree_model_class_init (GduPoolTreeModelClass *klass)
 {
@@ -232,19 +284,19 @@ gdu_pool_tree_model_class_init (GduPoolTreeModelClass *klass)
         g_type_class_add_private (klass, sizeof (GduPoolTreeModelPrivate));
 
         /**
-         * GduPoolTreeModel:pool:
+         * GduPoolTreeModel:pools:
          *
-         * The pool used.
+         * The pools displayed - this must be a #GPtrArray of #GduPool objects.
          */
         g_object_class_install_property (gobject_class,
-                                         PROP_POOL,
-                                         g_param_spec_object ("pool",
-                                                              NULL,
-                                                              NULL,
-                                                              GDU_TYPE_POOL,
-                                                              G_PARAM_WRITABLE |
-                                                              G_PARAM_READABLE |
-                                                              G_PARAM_CONSTRUCT_ONLY));
+                                         PROP_POOLS,
+                                         g_param_spec_boxed ("pools",
+                                                             NULL,
+                                                             NULL,
+                                                             G_TYPE_PTR_ARRAY,
+                                                             G_PARAM_WRITABLE |
+                                                             G_PARAM_READABLE |
+                                                             G_PARAM_CONSTRUCT));
 
         /**
          * GduPoolTreeModel:root:
@@ -282,16 +334,18 @@ gdu_pool_tree_model_class_init (GduPoolTreeModelClass *klass)
 static void
 gdu_pool_tree_model_init (GduPoolTreeModel *model)
 {
-        model->priv = G_TYPE_INSTANCE_GET_PRIVATE (model, GDU_TYPE_POOL_TREE_MODEL, GduPoolTreeModelPrivate);
+        model->priv = G_TYPE_INSTANCE_GET_PRIVATE (model,
+                                                   GDU_TYPE_POOL_TREE_MODEL,
+                                                   GduPoolTreeModelPrivate);
 }
 
 GduPoolTreeModel *
-gdu_pool_tree_model_new (GduPool               *pool,
+gdu_pool_tree_model_new (GPtrArray             *pools,
                          GduPresentable        *root,
                          GduPoolTreeModelFlags  flags)
 {
         return GDU_POOL_TREE_MODEL (g_object_new (GDU_TYPE_POOL_TREE_MODEL,
-                                                  "pool", pool,
+                                                  "pools", pools,
                                                   "root", root,
                                                   "flags", flags,
                                                   NULL));
diff --git a/src/gdu-gtk/gdu-pool-tree-model.h b/src/gdu-gtk/gdu-pool-tree-model.h
index 81a016c..6c73d42 100644
--- a/src/gdu-gtk/gdu-pool-tree-model.h
+++ b/src/gdu-gtk/gdu-pool-tree-model.h
@@ -54,9 +54,11 @@ struct GduPoolTreeModelClass
 
 
 GType             gdu_pool_tree_model_get_type                 (void) G_GNUC_CONST;
-GduPoolTreeModel *gdu_pool_tree_model_new                      (GduPool               *pool,
+GduPoolTreeModel *gdu_pool_tree_model_new                      (GPtrArray             *pools,
                                                                 GduPresentable        *root,
                                                                 GduPoolTreeModelFlags  flags);
+void              gdu_pool_tree_model_set_pools                (GduPoolTreeModel      *model,
+                                                                GPtrArray             *pools);
 gboolean          gdu_pool_tree_model_get_iter_for_presentable (GduPoolTreeModel      *model,
                                                                 GduPresentable        *presentable,
                                                                 GtkTreeIter           *out_iter);
diff --git a/src/gdu/Makefile.am b/src/gdu/Makefile.am
index 690b854..7c4f404 100644
--- a/src/gdu/Makefile.am
+++ b/src/gdu/Makefile.am
@@ -52,6 +52,7 @@ libgduinclude_HEADERS =              			\
 	gdu-volume.h					\
 	gdu-volume-hole.h				\
 	gdu-hub.h					\
+	gdu-machine.h					\
 	$(NULL)
 
 libgdu_la_SOURCES =                                					\
@@ -73,6 +74,7 @@ libgdu_la_SOURCES =                                					\
 	gdu-error.c				gdu-error.h				\
 	gdu-process.c				gdu-process.h				\
 	gdu-hub.c				gdu-hub.h				\
+	gdu-machine.c				gdu-machine.h				\
 						gdu-private.h				\
 	gdu-ssh-bridge.c			gdu-ssh-bridge.h			\
 	$(BUILT_SOURCES)								\
diff --git a/src/gdu/gdu-linux-md-drive.c b/src/gdu/gdu-linux-md-drive.c
index f7ffbad..05051a7 100644
--- a/src/gdu/gdu-linux-md-drive.c
+++ b/src/gdu/gdu-linux-md-drive.c
@@ -62,6 +62,8 @@ struct _GduLinuxMdDrivePrivate
         gchar *device_file;
 
         gchar *id;
+
+        GduPresentable *enclosing_presentable;
 };
 
 static GObjectClass *parent_class = NULL;
@@ -119,6 +121,9 @@ gdu_linux_md_drive_finalize (GObject *object)
         g_free (drive->priv->uuid);
         g_free (drive->priv->device_file);
 
+        if (drive->priv->enclosing_presentable != NULL)
+                g_object_unref (drive->priv->enclosing_presentable);
+
         if (G_OBJECT_CLASS (parent_class)->finalize)
                 (* G_OBJECT_CLASS (parent_class)->finalize) (G_OBJECT (drive));
 }
@@ -326,6 +331,7 @@ device_job_changed (GduPool *pool, GduDevice *device, gpointer user_data)
  * @pool: A #GduPool.
  * @uuid: The UUID for the array.
  * @device_file: The device file for the array.
+ * @enclosing_presentable: The enclosing presentable
  *
  * Creates a new #GduLinuxMdDrive. Note that only one of @uuid and
  * @device_file may be %NULL.
@@ -333,7 +339,8 @@ device_job_changed (GduPool *pool, GduDevice *device, gpointer user_data)
 GduLinuxMdDrive *
 _gdu_linux_md_drive_new (GduPool      *pool,
                          const gchar  *uuid,
-                         const gchar  *device_file)
+                         const gchar  *device_file,
+                         GduPresentable *enclosing_presentable)
 {
         GduLinuxMdDrive *drive;
 
@@ -354,6 +361,9 @@ _gdu_linux_md_drive_new (GduPool      *pool,
                 drive->priv->device = gdu_pool_get_by_device_file (pool, device_file);
         }
 
+        drive->priv->enclosing_presentable =
+                enclosing_presentable != NULL ? g_object_ref (enclosing_presentable) : NULL;
+
         return drive;
 }
 
@@ -471,6 +481,9 @@ gdu_linux_md_drive_get_device (GduPresentable *presentable)
 static GduPresentable *
 gdu_linux_md_drive_get_enclosing_presentable (GduPresentable *presentable)
 {
+        GduLinuxMdDrive *drive = GDU_LINUX_MD_DRIVE (presentable);
+        if (drive->priv->enclosing_presentable != NULL)
+                return g_object_ref (drive->priv->enclosing_presentable);
         return NULL;
 }
 
@@ -764,6 +777,34 @@ gdu_linux_md_drive_presentable_iface_init (GduPresentableIface *iface)
 
 /* ---------------------------------------------------------------------------------------------------- */
 
+void
+_gdu_linux_md_drive_rewrite_enclosing_presentable (GduLinuxMdDrive *drive)
+{
+        if (drive->priv->enclosing_presentable != NULL) {
+                const gchar *enclosing_presentable_id;
+                GduPresentable *new_enclosing_presentable;
+
+                enclosing_presentable_id = gdu_presentable_get_id (drive->priv->enclosing_presentable);
+
+                new_enclosing_presentable = gdu_pool_get_presentable_by_id (drive->priv->pool,
+                                                                            enclosing_presentable_id);
+                if (new_enclosing_presentable == NULL) {
+                        g_warning ("Error rewriting enclosing_presentable for %s, no such id %s",
+                                   drive->priv->id,
+                                   enclosing_presentable_id);
+                        goto out;
+                }
+
+                g_object_unref (drive->priv->enclosing_presentable);
+                drive->priv->enclosing_presentable = new_enclosing_presentable;
+        }
+
+ out:
+        ;
+}
+
+/* ---------------------------------------------------------------------------------------------------- */
+
 /* GduDrive virtual method overrides */
 
 static gboolean
diff --git a/src/gdu/gdu-machine.c b/src/gdu/gdu-machine.c
new file mode 100644
index 0000000..85a0031
--- /dev/null
+++ b/src/gdu/gdu-machine.c
@@ -0,0 +1,225 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- */
+/* gdu-machine.c
+ *
+ * Copyright (C) 2007 David Zeuthen
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ */
+
+#include "config.h"
+#include <glib/gi18n-lib.h>
+
+#include <string.h>
+#include <dbus/dbus-glib.h>
+#include <stdlib.h>
+
+#include "gdu-private.h"
+#include "gdu-util.h"
+#include "gdu-pool.h"
+#include "gdu-adapter.h"
+#include "gdu-expander.h"
+#include "gdu-machine.h"
+#include "gdu-presentable.h"
+#include "gdu-linux-md-drive.h"
+
+/**
+ * SECTION:gdu-machine
+ * @title: GduMachine
+ * @short_description: Machines
+ *
+ * #GduMachine objects are used to represent connections to a udisk
+ * instance on a local or remote machine.
+ *
+ * See the documentation for #GduPresentable for the big picture.
+ */
+
+struct _GduMachinePrivate
+{
+        GduPool *pool;
+};
+
+static GObjectClass *parent_class = NULL;
+
+static void gdu_machine_presentable_iface_init (GduPresentableIface *iface);
+G_DEFINE_TYPE_WITH_CODE (GduMachine, gdu_machine, G_TYPE_OBJECT,
+                         G_IMPLEMENT_INTERFACE (GDU_TYPE_PRESENTABLE,
+                                                gdu_machine_presentable_iface_init))
+
+
+static void
+gdu_machine_finalize (GObject *object)
+{
+        GduMachine *machine = GDU_MACHINE (object);
+
+        if (machine->priv->pool != NULL)
+                g_object_unref (machine->priv->pool);
+
+        if (G_OBJECT_CLASS (parent_class)->finalize != NULL)
+                (* G_OBJECT_CLASS (parent_class)->finalize) (object);
+}
+
+static void
+gdu_machine_class_init (GduMachineClass *klass)
+{
+        GObjectClass *obj_class = (GObjectClass *) klass;
+
+        parent_class = g_type_class_peek_parent (klass);
+
+        obj_class->finalize = gdu_machine_finalize;
+
+        g_type_class_add_private (klass, sizeof (GduMachinePrivate));
+}
+
+static void
+gdu_machine_init (GduMachine *machine)
+{
+        machine->priv = G_TYPE_INSTANCE_GET_PRIVATE (machine, GDU_TYPE_MACHINE, GduMachinePrivate);
+}
+
+GduMachine *
+_gdu_machine_new (GduPool *pool)
+{
+        GduMachine *machine;
+        machine = GDU_MACHINE (g_object_new (GDU_TYPE_MACHINE, NULL));
+        machine->priv->pool = g_object_ref (pool);
+        return machine;
+}
+
+static const gchar *
+gdu_machine_get_id (GduPresentable *presentable)
+{
+        return "__root__"; /* TODO: include address? */
+}
+
+static GduDevice *
+gdu_machine_get_device (GduPresentable *presentable)
+{
+        return NULL;
+}
+
+static GduPresentable *
+gdu_machine_get_enclosing_presentable (GduPresentable *presentable)
+{
+        return NULL;
+}
+
+static char *
+gdu_machine_get_name (GduPresentable *presentable)
+{
+        GduMachine *machine = GDU_MACHINE (presentable);
+        const gchar *ssh_address;
+        gchar *ret;
+
+        ssh_address = gdu_pool_get_ssh_address (machine->priv->pool);
+
+        if (ssh_address == NULL) {
+                ret = g_strdup (_("This Machine"));
+        } else {
+                /* TODO: use display-hostname */
+                ret = g_strdup_printf (_("Storage on %s"), ssh_address);
+        }
+
+        return ret;
+}
+
+static gchar *
+gdu_machine_get_vpd_name (GduPresentable *presentable)
+{
+        GduMachine *machine = GDU_MACHINE (presentable);
+        const gchar *ssh_user_name;
+        const gchar *ssh_address;
+        gchar *ret;
+
+        ssh_user_name = gdu_pool_get_ssh_user_name (machine->priv->pool);
+        if (ssh_user_name == NULL)
+                ssh_user_name = g_get_user_name ();
+        ssh_address = gdu_pool_get_ssh_address (machine->priv->pool);
+
+        if (ssh_address == NULL) {
+                ret = g_strdup_printf ("%s localhost", ssh_user_name);
+        } else {
+                /* TODO: include IP address */
+                ret = g_strdup_printf ("%s %s", ssh_user_name, ssh_address);
+
+        }
+
+        /* TODO: include udisks and OS version numbers? */
+
+        return ret;
+
+}
+
+static gchar *
+gdu_machine_get_description (GduPresentable *presentable)
+{
+        return gdu_machine_get_vpd_name (presentable);
+}
+
+static GIcon *
+gdu_machine_get_icon (GduPresentable *presentable)
+{
+        GIcon *icon;
+        icon = g_themed_icon_new_with_default_fallbacks ("computer"); /* TODO? */
+        return icon;
+}
+
+static guint64
+gdu_machine_get_offset (GduPresentable *presentable)
+{
+        return 0;
+}
+
+static guint64
+gdu_machine_get_size (GduPresentable *presentable)
+{
+        return 0;
+}
+
+static GduPool *
+gdu_machine_get_pool (GduPresentable *presentable)
+{
+        GduMachine *machine = GDU_MACHINE (presentable);
+        return g_object_ref (machine->priv->pool);
+}
+
+static gboolean
+gdu_machine_is_allocated (GduPresentable *presentable)
+{
+        return FALSE;
+}
+
+static gboolean
+gdu_machine_is_recognized (GduPresentable *presentable)
+{
+        return FALSE;
+}
+
+static void
+gdu_machine_presentable_iface_init (GduPresentableIface *iface)
+{
+        iface->get_id                    = gdu_machine_get_id;
+        iface->get_device                = gdu_machine_get_device;
+        iface->get_enclosing_presentable = gdu_machine_get_enclosing_presentable;
+        iface->get_name                  = gdu_machine_get_name;
+        iface->get_description           = gdu_machine_get_description;
+        iface->get_vpd_name              = gdu_machine_get_vpd_name;
+        iface->get_icon                  = gdu_machine_get_icon;
+        iface->get_offset                = gdu_machine_get_offset;
+        iface->get_size                  = gdu_machine_get_size;
+        iface->get_pool                  = gdu_machine_get_pool;
+        iface->is_allocated              = gdu_machine_is_allocated;
+        iface->is_recognized             = gdu_machine_is_recognized;
+}
diff --git a/src/gdu/gdu-machine.h b/src/gdu/gdu-machine.h
new file mode 100644
index 0000000..a7248c2
--- /dev/null
+++ b/src/gdu/gdu-machine.h
@@ -0,0 +1,60 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- */
+/* gdu-machine.h
+ *
+ * Copyright (C) 2009 David Zeuthen
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ */
+
+#if !defined (__GDU_INSIDE_GDU_H) && !defined (GDU_COMPILATION)
+#error "Only <gdu/gdu.h> can be included directly, this file may disappear or change contents."
+#endif
+
+#ifndef __GDU_MACHINE_H
+#define __GDU_MACHINE_H
+
+#include <gdu/gdu-types.h>
+
+G_BEGIN_DECLS
+
+#define GDU_TYPE_MACHINE           (gdu_machine_get_type ())
+#define GDU_MACHINE(o)             (G_TYPE_CHECK_INSTANCE_CAST ((o), GDU_TYPE_MACHINE, GduMachine))
+#define GDU_MACHINE_CLASS(k)       (G_TYPE_CHECK_CLASS_CAST ((k), GDU_MACHINE,  GduMachineClass))
+#define GDU_IS_MACHINE(o)          (G_TYPE_CHECK_INSTANCE_TYPE ((o), GDU_TYPE_MACHINE))
+#define GDU_IS_MACHINE_CLASS(k)    (G_TYPE_CHECK_CLASS_TYPE ((k), GDU_TYPE_MACHINE))
+#define GDU_MACHINE_GET_CLASS(k)   (G_TYPE_INSTANCE_GET_CLASS ((k), GDU_TYPE_MACHINE, GduMachineClass))
+
+typedef struct _GduMachineClass       GduMachineClass;
+typedef struct _GduMachinePrivate     GduMachinePrivate;
+
+struct _GduMachine
+{
+        GObject parent;
+
+        /* private */
+        GduMachinePrivate *priv;
+};
+
+struct _GduMachineClass
+{
+        GObjectClass parent_class;
+};
+
+GType        gdu_machine_get_type     (void);
+
+G_END_DECLS
+
+#endif /* __GDU_MACHINE_H */
diff --git a/src/gdu/gdu-pool.c b/src/gdu/gdu-pool.c
index 5370901..e3630de 100644
--- a/src/gdu/gdu-pool.c
+++ b/src/gdu/gdu-pool.c
@@ -80,6 +80,9 @@ static guint signals[LAST_SIGNAL] = { 0 };
 
 struct _GduPoolPrivate
 {
+        gchar *ssh_user_name;
+        gchar *ssh_address;
+
         DBusGConnection *bus;
         DBusGProxy *proxy;
 
@@ -821,6 +824,7 @@ recompute_presentables (GduPool *pool)
         GHashTable *hash_map_from_linux_md_uuid_to_drive;
         GHashTable *hash_map_from_adapter_objpath_to_hub;
         GHashTable *hash_map_from_expander_objpath_to_hub;
+        GduPresentable *machine;
 
         /* The general strategy for (re-)computing presentables is rather brute force; we
          * compute the complete set of presentables every time and diff it against the
@@ -835,6 +839,9 @@ recompute_presentables (GduPool *pool)
         new_presentables = NULL;
         new_partitioned_drives = NULL;
 
+        machine = GDU_PRESENTABLE (_gdu_machine_new (pool));
+        new_presentables = g_list_prepend (new_presentables, machine);
+
         hash_map_from_drive_to_extended_partition = g_hash_table_new_full ((GHashFunc) gdu_presentable_hash,
                                                                            (GEqualFunc) gdu_presentable_equals,
                                                                            NULL,
@@ -863,8 +870,8 @@ recompute_presentables (GduPool *pool)
 
                 hub = _gdu_hub_new (pool,
                                     adapter,
-                                    NULL,   /* expander */
-                                    NULL);  /* enclosing_presentable */
+                                    NULL,      /* expander */
+                                    machine);  /* enclosing_presentable */
 
                 g_hash_table_insert (hash_map_from_adapter_objpath_to_hub,
                                      (gpointer) gdu_adapter_get_object_path (adapter),
@@ -941,6 +948,7 @@ recompute_presentables (GduPool *pool)
 
                         if (gdu_device_is_linux_md (device)) {
                                 const gchar *uuid;
+                                GduPresentable *linux_md_parent;
 
                                 uuid = gdu_device_linux_md_get_uuid (device);
 
@@ -948,8 +956,11 @@ recompute_presentables (GduPool *pool)
                                 if (uuid != NULL && strlen (uuid) == 0)
                                         uuid = NULL;
 
+                                /* TODO: Create transient GduHub object for all RAID arrays? */
+                                linux_md_parent = machine;
+
                                 if (uuid != NULL) {
-                                        drive = GDU_DRIVE (_gdu_linux_md_drive_new (pool, uuid, NULL));
+                                        drive = GDU_DRIVE (_gdu_linux_md_drive_new (pool, uuid, NULL, linux_md_parent));
 
                                         /* Due to the topological sorting of devices, we are guaranteed that
                                          * that running Linux MD arrays come before the slaves.
@@ -962,7 +973,8 @@ recompute_presentables (GduPool *pool)
                                 } else {
                                         drive = GDU_DRIVE (_gdu_linux_md_drive_new (pool,
                                                                                     NULL,
-                                                                                    gdu_device_get_device_file (device)));
+                                                                                    gdu_device_get_device_file (device),
+                                                                                    linux_md_parent));
                                 }
 
 
@@ -997,6 +1009,14 @@ recompute_presentables (GduPool *pool)
                                         }
                                 }
 
+                                if (drive_parent == NULL) {
+                                        /* TODO: Create transient GduHub object for
+                                         *
+                                         *   - USB/Firewire/SDIO connected drives
+                                         */
+                                        drive_parent = machine;
+                                }
+
                                 drive = _gdu_drive_new_from_device (pool, device, drive_parent);
                         }
                         new_presentables = g_list_prepend (new_presentables, drive);
@@ -1099,8 +1119,12 @@ recompute_presentables (GduPool *pool)
                         uuid = gdu_device_linux_md_component_get_uuid (device);
                         if (g_hash_table_lookup (hash_map_from_linux_md_uuid_to_drive, uuid) == NULL) {
                                 GduDrive *drive;
+                                GduPresentable *linux_md_parent;
 
-                                drive = GDU_DRIVE (_gdu_linux_md_drive_new (pool, uuid, NULL));
+                                /* TODO: Create transient GduHub object for all RAID arrays? */
+                                linux_md_parent = machine;
+
+                                drive = GDU_DRIVE (_gdu_linux_md_drive_new (pool, uuid, NULL, linux_md_parent));
                                 new_presentables = g_list_prepend (new_presentables, drive);
 
                                 g_hash_table_insert (hash_map_from_linux_md_uuid_to_drive,
@@ -1167,6 +1191,8 @@ recompute_presentables (GduPool *pool)
                         _gdu_hub_rewrite_enclosing_presentable (GDU_HUB (p));
                 else if (GDU_IS_DRIVE (p))
                         _gdu_drive_rewrite_enclosing_presentable (GDU_DRIVE (p));
+                else if (GDU_IS_LINUX_MD_DRIVE (p))
+                        _gdu_linux_md_drive_rewrite_enclosing_presentable (GDU_LINUX_MD_DRIVE (p));
                 else if (GDU_IS_VOLUME (p))
                         _gdu_volume_rewrite_enclosing_presentable (GDU_VOLUME (p));
                 else if (GDU_IS_VOLUME_HOLE (p))
@@ -1670,7 +1696,7 @@ gdu_pool_new (void)
         GError *error;
 
         error = NULL;
-        pool = gdu_pool_new_for_address (NULL, &error);
+        pool = gdu_pool_new_for_address (NULL, NULL, &error);
         if (pool == NULL) {
                 g_printerr ("Error constructing pool: %s\n", error->message);
                 g_error_free (error);
@@ -1686,7 +1712,8 @@ _gdu_pool_get_connection (GduPool *pool)
 }
 
 GduPool *
-gdu_pool_new_for_address (const gchar     *ssh_address,
+gdu_pool_new_for_address (const gchar     *ssh_user_name,
+                          const gchar     *ssh_address,
                           GError         **error)
 {
         int n;
@@ -1707,10 +1734,12 @@ gdu_pool_new_for_address (const gchar     *ssh_address,
                         goto error;
                 }
         } else {
-                pool->priv->bus = _gdu_ssh_bridge_connect (pool, ssh_address, error);
+                pool->priv->bus = _gdu_ssh_bridge_connect (pool, ssh_user_name, ssh_address, error);
                 if (pool->priv->bus == NULL) {
                         goto error;
                 }
+                pool->priv->ssh_user_name = g_strdup (ssh_user_name);
+                pool->priv->ssh_address  = g_strdup (ssh_address);
         }
 
         dbus_g_object_register_marshaller (
@@ -2678,4 +2707,15 @@ gdu_pool_supports_luks_devices (GduPool *pool)
         return pool->priv->supports_luks_devices;
 }
 
+const gchar *
+gdu_pool_get_ssh_user_name (GduPool *pool)
+{
+        return pool->priv->ssh_user_name;
+}
+
+const gchar *
+gdu_pool_get_ssh_address (GduPool *pool)
+{
+        return pool->priv->ssh_address;
+}
 
diff --git a/src/gdu/gdu-pool.h b/src/gdu/gdu-pool.h
index 1199487..0bb5d38 100644
--- a/src/gdu/gdu-pool.h
+++ b/src/gdu/gdu-pool.h
@@ -79,8 +79,12 @@ struct _GduPoolClass
 
 GType       gdu_pool_get_type           (void);
 GduPool    *gdu_pool_new                (void);
-GduPool    *gdu_pool_new_for_address    (const gchar     *ssh_address,
-                                         GError         **error);
+GduPool    *gdu_pool_new_for_address    (const gchar  *ssh_user_name,
+                                         const gchar  *ssh_address,
+                                         GError      **error);
+
+const gchar *gdu_pool_get_ssh_user_name (GduPool *pool);
+const gchar *gdu_pool_get_ssh_address   (GduPool *pool);
 
 char       *gdu_pool_get_daemon_version (GduPool *pool);
 gboolean    gdu_pool_is_daemon_inhibited (GduPool *pool);
diff --git a/src/gdu/gdu-private.h b/src/gdu/gdu-private.h
index e2fe806..ac5a2c0 100644
--- a/src/gdu/gdu-private.h
+++ b/src/gdu/gdu-private.h
@@ -92,7 +92,8 @@ GduVolumeHole   *_gdu_volume_hole_new       (GduPool *pool, guint64 offset, guin
 
 GduLinuxMdDrive   *_gdu_linux_md_drive_new             (GduPool              *pool,
                                                         const gchar          *uuid,
-                                                        const gchar          *device_file);
+                                                        const gchar          *device_file,
+                                                        GduPresentable *enclosing_presentable);
 
 gboolean _gdu_linux_md_drive_has_uuid (GduLinuxMdDrive  *drive,
                                        const gchar      *uuid);
@@ -120,8 +121,11 @@ GduHub     *_gdu_hub_new                        (GduPool        *pool,
 GduPort    *_gdu_port_new_from_object_path (GduPool *pool, const char *object_path);
 gboolean    _gdu_port_changed               (GduPort   *port);
 
+GduMachine *_gdu_machine_new (GduPool *pool);
+
 void _gdu_hub_rewrite_enclosing_presentable (GduHub *hub);
 void _gdu_drive_rewrite_enclosing_presentable (GduDrive *drive);
+void _gdu_linux_md_drive_rewrite_enclosing_presentable (GduLinuxMdDrive *drive);
 void _gdu_volume_rewrite_enclosing_presentable (GduVolume *volume);
 void _gdu_volume_hole_rewrite_enclosing_presentable (GduVolumeHole *volume_hole);
 
diff --git a/src/gdu/gdu-ssh-bridge.c b/src/gdu/gdu-ssh-bridge.c
index f1efd52..b5780a5 100644
--- a/src/gdu/gdu-ssh-bridge.c
+++ b/src/gdu/gdu-ssh-bridge.c
@@ -57,7 +57,8 @@
 
 /* TODO: Need to do all this async (or in a thread) so we can have API like this
  *
- *   void gdu_pool_new_for_address            (const gchar         *ssh_address,
+ *   void gdu_pool_new_for_address            (const gchar         *ssh_user_name,
+ *                                             const gchar         *ssh_address,
  *                                             GMountOperation     *connect_operation,
  *                                             GCancellable        *cancellable,
  *                                             GAsyncReadyCallback  callback,
@@ -222,6 +223,7 @@ fixup_newlines (gchar *s)
 
 DBusGConnection *
 _gdu_ssh_bridge_connect (GduPool          *pool,
+                         const gchar      *ssh_user_name,
                          const gchar      *ssh_address,
                          GError          **error)
 {
@@ -330,8 +332,10 @@ _gdu_ssh_bridge_connect (GduPool          *pool,
                                         "-o \"ForwardAgent no\" "
                                         "-o \"Protocol 2\" "
                                         "-o \"NoHostAuthenticationForLocalhost yes\" "
-                                        "%s",
+                                        "%s%c%s",
                                         local_port,
+                                        ssh_user_name != NULL ? ssh_user_name : "",
+                                        ssh_user_name != NULL ? '@' : ' ',
                                         ssh_address);
         //g_print ("command line: `%s'\n", command_line);
         if (!g_shell_parse_argv (command_line,
diff --git a/src/gdu/gdu-ssh-bridge.h b/src/gdu/gdu-ssh-bridge.h
index 30f7361..73758ba 100644
--- a/src/gdu/gdu-ssh-bridge.h
+++ b/src/gdu/gdu-ssh-bridge.h
@@ -30,6 +30,7 @@
 #include "gdu-types.h"
 
 DBusGConnection * _gdu_ssh_bridge_connect (GduPool          *pool,
+                                           const gchar      *ssh_user_name,
                                            const gchar      *ssh_address,
                                            GError          **error);
 
diff --git a/src/gdu/gdu-types.h b/src/gdu/gdu-types.h
index d107d90..8de117f 100644
--- a/src/gdu/gdu-types.h
+++ b/src/gdu/gdu-types.h
@@ -40,11 +40,13 @@ typedef struct _GduExpander               GduExpander;
 typedef struct _GduPort                   GduPort;
 
 typedef struct _GduPresentable            GduPresentable; /* Dummy typedef */
+
 typedef struct _GduDrive                  GduDrive;
 typedef struct _GduLinuxMdDrive           GduLinuxMdDrive;
 typedef struct _GduVolume                 GduVolume;
 typedef struct _GduVolumeHole             GduVolumeHole;
 typedef struct _GduHub                    GduHub;
+typedef struct _GduMachine                GduMachine;
 
 typedef struct _GduKnownFilesystem        GduKnownFilesystem;
 typedef struct _GduProcess                GduProcess;
diff --git a/src/gdu/gdu.h b/src/gdu/gdu.h
index 1dc0d88..8c805ec 100644
--- a/src/gdu/gdu.h
+++ b/src/gdu/gdu.h
@@ -44,6 +44,7 @@
 #include <gdu/gdu-volume.h>
 #include <gdu/gdu-volume-hole.h>
 #include <gdu/gdu-hub.h>
+#include <gdu/gdu-machine.h>
 #include <gdu/gdu-callbacks.h>
 
 #undef __GDU_INSIDE_GDU_H
diff --git a/src/palimpsest/gdu-main.c b/src/palimpsest/gdu-main.c
index 9a33e5a..c3704cc 100644
--- a/src/palimpsest/gdu-main.c
+++ b/src/palimpsest/gdu-main.c
@@ -38,16 +38,18 @@ show_volume (GduShell   *shell,
         GduPresentable *presentable;
 
         presentable = NULL;
-        pool = gdu_shell_get_pool (shell);
-        device = gdu_pool_get_by_device_file (pool, device_file);
-        if (device) {
-                presentable = gdu_pool_get_volume_by_device (pool, device);
-                g_object_unref (device);
-        }
-        if (presentable) {
-                gdu_shell_select_presentable (shell, presentable);
-                g_object_unref (presentable);
-                return TRUE;
+        pool = gdu_shell_get_pool_for_selected_presentable (shell);
+        if (pool != NULL) {
+                device = gdu_pool_get_by_device_file (pool, device_file);
+                if (device != NULL) {
+                        presentable = gdu_pool_get_volume_by_device (pool, device);
+                        g_object_unref (device);
+                }
+                if (presentable != NULL) {
+                        gdu_shell_select_presentable (shell, presentable);
+                        g_object_unref (presentable);
+                        return TRUE;
+                }
         }
 
         return FALSE;
@@ -62,16 +64,18 @@ show_drive (GduShell   *shell,
         GduPresentable *presentable;
 
         presentable = NULL;
-        pool = gdu_shell_get_pool (shell);
-        device = gdu_pool_get_by_device_file (pool, device_file);
-        if (device) {
-                presentable = gdu_pool_get_drive_by_device (pool, device);
-                g_object_unref (device);
-        }
-        if (presentable) {
-                gdu_shell_select_presentable (shell, presentable);
-                g_object_unref (presentable);
-                return TRUE;
+        pool = gdu_shell_get_pool_for_selected_presentable (shell);
+        if (pool != NULL) {
+                device = gdu_pool_get_by_device_file (pool, device_file);
+                if (device != NULL) {
+                        presentable = gdu_pool_get_drive_by_device (pool, device);
+                        g_object_unref (device);
+                }
+                if (presentable != NULL) {
+                        gdu_shell_select_presentable (shell, presentable);
+                        g_object_unref (presentable);
+                        return TRUE;
+                }
         }
 
         return FALSE;
diff --git a/src/palimpsest/gdu-shell.c b/src/palimpsest/gdu-shell.c
index c7512e0..a4cd7f8 100644
--- a/src/palimpsest/gdu-shell.c
+++ b/src/palimpsest/gdu-shell.c
@@ -40,13 +40,19 @@
 #include "gdu-section-volumes.h"
 #include "gdu-section-hub.h"
 
+static gboolean add_pool (GduShell     *shell,
+                          const gchar  *ssh_user_name,
+                          const gchar  *ssh_address,
+                          GError      **error);
+
 struct _GduShellPrivate
 {
         gchar *ssh_address;
 
         GtkWidget *app_window;
-        GduPool *pool;
+        GPtrArray *pools;
 
+        GduPoolTreeModel *model;
         GtkWidget *tree_view;
 
         /* -------------------------------------------------------------------------------- */
@@ -93,6 +99,8 @@ static void
 gdu_shell_init (GduShell *shell)
 {
         shell->priv = G_TYPE_INSTANCE_GET_PRIVATE (shell, GDU_TYPE_SHELL, GduShellPrivate);
+
+        shell->priv->pools = g_ptr_array_new ();
 }
 
 GduShell *
@@ -112,9 +120,18 @@ gdu_shell_get_toplevel (GduShell *shell)
 }
 
 GduPool *
-gdu_shell_get_pool (GduShell *shell)
+gdu_shell_get_pool_for_selected_presentable (GduShell *shell)
 {
-        return shell->priv->pool;
+        GduPool *pool;
+
+        if (shell->priv->presentable_now_showing != NULL) {
+                pool = gdu_presentable_get_pool (shell->priv->presentable_now_showing);
+                g_object_unref (pool);
+        } else {
+                pool = NULL;
+        }
+
+        return pool;
 }
 
 
@@ -128,12 +145,11 @@ void
 gdu_shell_select_presentable (GduShell *shell, GduPresentable *presentable)
 {
         gboolean selected;
+        GduPool *pool;
 
-        if (GDU_IS_DRIVE (presentable)) {
-                gdu_pool_tree_view_select_presentable (GDU_POOL_TREE_VIEW (shell->priv->tree_view), presentable);
-                gtk_widget_grab_focus (shell->priv->tree_view);
-                selected = TRUE;
-        } else if (GDU_IS_VOLUME (presentable)) {
+        pool = gdu_presentable_get_pool (presentable);
+
+        if (GDU_IS_VOLUME (presentable)) {
                 GduDevice *device;
                 GduPresentable *p_to_select;
 
@@ -142,14 +158,14 @@ gdu_shell_select_presentable (GduShell *shell, GduPresentable *presentable)
                 if (device != NULL) {
                         if (gdu_device_is_partition (device)) {
                                 GduDevice *drive_device;
-                                drive_device = gdu_pool_get_by_object_path (shell->priv->pool,
+                                drive_device = gdu_pool_get_by_object_path (pool,
                                                                             gdu_device_partition_get_slave (device));
                                 if (drive_device != NULL) {
-                                        p_to_select = gdu_pool_get_drive_by_device (shell->priv->pool, drive_device);
+                                        p_to_select = gdu_pool_get_drive_by_device (pool, drive_device);
                                         g_object_unref (drive_device);
                                 }
                         } else {
-                                p_to_select = gdu_pool_get_drive_by_device (shell->priv->pool, device);
+                                p_to_select = gdu_pool_get_drive_by_device (pool, device);
                         }
                         g_object_unref (device);
                 }
@@ -172,6 +188,9 @@ gdu_shell_select_presentable (GduShell *shell, GduPresentable *presentable)
                         g_object_unref (p_to_select);
                 }
         } else {
+                gdu_pool_tree_view_select_presentable (GDU_POOL_TREE_VIEW (shell->priv->tree_view), presentable);
+                gtk_widget_grab_focus (shell->priv->tree_view);
+                selected = TRUE;
         }
 
         if (!selected) {
@@ -179,6 +198,8 @@ gdu_shell_select_presentable (GduShell *shell, GduPresentable *presentable)
                            G_STRLOC, G_STRFUNC,
                            gdu_presentable_get_id (presentable));
         }
+
+        g_object_unref (pool);
 }
 
 /* ---------------------------------------------------------------------------------------------------- */
@@ -416,6 +437,7 @@ help_contents_action_callback (GtkAction *action, gpointer user_data)
 
 typedef struct {
         GduShell *shell;
+        GduPool *pool;
 
         /* data obtained from GduCreateLinuxMdDialog */
         gchar *level;
@@ -434,6 +456,7 @@ static void
 create_linux_md_data_free (CreateLinuxMdData *data)
 {
         g_object_unref (data->shell);
+        g_object_unref (data->pool);
         g_free (data->level);
         g_free (data->name);
         g_ptr_array_unref (data->drives);
@@ -461,13 +484,19 @@ new_linux_md_create_part_cb (GduDevice  *device,
                 //g_debug ("Error creating component");
         } else {
                 GduDevice *d;
-                d = gdu_pool_get_by_object_path (data->shell->priv->pool, created_device_object_path);
+                GduPool *pool;
+
+                pool = gdu_device_get_pool (device);
+
+                d = gdu_pool_get_by_object_path (pool, created_device_object_path);
                 g_ptr_array_add (data->components, d);
 
                 //g_debug ("Done creating component");
 
                 /* now that we have a component... carry on... */
                 create_linux_md_do (data);
+
+                g_object_unref (pool);
         }
 }
 
@@ -517,8 +546,8 @@ new_linux_md_create_array_cb (GduPool    *pool,
                 GduPresentable *p;
 
                 /* YAY - array has been created - switch the shell to it */
-                d = gdu_pool_get_by_object_path (data->shell->priv->pool, array_object_path);
-                p = gdu_pool_get_drive_by_device (data->shell->priv->pool, d);
+                d = gdu_pool_get_by_object_path (pool, array_object_path);
+                p = gdu_pool_get_drive_by_device (pool, d);
                 gdu_shell_select_presentable (data->shell, p);
                 g_object_unref (p);
                 g_object_unref (d);
@@ -545,7 +574,7 @@ create_linux_md_do (CreateLinuxMdData *data)
                         g_ptr_array_add (objpaths, (gpointer) gdu_device_get_object_path (d));
                 }
 
-                gdu_pool_op_linux_md_create (data->shell->priv->pool,
+                gdu_pool_op_linux_md_create (data->pool,
                                              objpaths,
                                              data->level,
                                              data->stripe_size,
@@ -641,11 +670,13 @@ new_linux_md_array_callback (GtkAction *action, gpointer user_data)
         GduShell *shell = GDU_SHELL (user_data);
         GtkWidget *dialog;
         gint response;
+        GduPool *pool;
 
         //g_debug ("New Linux MD Array!");
 
-        dialog = gdu_create_linux_md_dialog_new (GTK_WINDOW (shell->priv->app_window),
-                                                 shell->priv->pool);
+        pool = gdu_shell_get_pool_for_selected_presentable (shell);
+
+        dialog = gdu_create_linux_md_dialog_new (GTK_WINDOW (shell->priv->app_window), pool);
 
         gtk_widget_show_all (dialog);
         response = gtk_dialog_run (GTK_DIALOG (dialog));
@@ -655,6 +686,7 @@ new_linux_md_array_callback (GtkAction *action, gpointer user_data)
                 CreateLinuxMdData *data;
 
                 data = g_new0 (CreateLinuxMdData, 1);
+                data->pool           = g_object_ref (pool);
                 data->shell          = g_object_ref (shell);
                 data->level          = gdu_create_linux_md_dialog_get_level (GDU_CREATE_LINUX_MD_DIALOG (dialog));
                 data->name           = gdu_create_linux_md_dialog_get_name (GDU_CREATE_LINUX_MD_DIALOG (dialog));
@@ -684,9 +716,38 @@ on_file_connect_action (GtkAction *action,
         gtk_widget_show_all (dialog);
         response = gtk_dialog_run (GTK_DIALOG (dialog));
 
-        g_debug ("response = %d", response);
+        if (response == GTK_RESPONSE_OK) {
+                const gchar *user_name;
+                const gchar *address;
+                GError *error;
 
-        gtk_widget_destroy (dialog);
+                user_name = gdu_connect_to_server_dialog_get_user_name (GDU_CONNECT_TO_SERVER_DIALOG (dialog));
+                address = gdu_connect_to_server_dialog_get_address (GDU_CONNECT_TO_SERVER_DIALOG (dialog));
+
+                gtk_widget_destroy (dialog);
+
+                error = NULL;
+                if (!add_pool (shell, user_name, address, &error)) {
+                        GtkWidget *dialog;
+                        gchar *s;
+
+                        s = g_strdup_printf (_("Error connecting to â??%sâ??"), address);
+
+                        dialog = gdu_error_dialog_new (GTK_WINDOW (gdu_shell_get_toplevel (shell)),
+                                                       NULL,
+                                                       s,
+                                                       error);
+                        g_free (s);
+                        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);
+                }
+        } else {
+                gtk_widget_destroy (dialog);
+        }
 }
 
 /* ---------------------------------------------------------------------------------------------------- */
@@ -951,6 +1012,43 @@ gdu_shell_raise_error (GduShell       *shell,
         g_free (error_text);
 }
 
+static gboolean
+add_pool (GduShell     *shell,
+          const gchar  *ssh_user_name,
+          const gchar  *ssh_address,
+          GError      **error)
+{
+        GduPool *pool;
+        gboolean ret;
+
+        ret = FALSE;
+
+        pool = gdu_pool_new_for_address (ssh_user_name, ssh_address, error);
+        if (pool == NULL)
+                goto out;
+
+        g_signal_connect (pool, "presentable-added", (GCallback) presentable_added, shell);
+        g_signal_connect (pool, "presentable-removed", (GCallback) presentable_removed, shell);
+
+        g_ptr_array_add (shell->priv->pools, pool);
+
+        if (shell->priv->model != NULL) {
+                GduPresentable *selected_presentable;
+
+                selected_presentable = gdu_shell_get_selected_presentable (shell);
+
+                gdu_pool_tree_model_set_pools (shell->priv->model, shell->priv->pools);
+
+                if (selected_presentable != NULL)
+                        gdu_shell_select_presentable (shell, selected_presentable);
+        }
+
+        ret = TRUE;
+
+ out:
+        return ret;
+}
+
 static void
 create_window (GduShell *shell)
 {
@@ -963,18 +1061,14 @@ create_window (GduShell *shell)
         GtkWidget *tree_view_scrolled_window;
         GtkTreeSelection *select;
         GtkWidget *label;
-        GduPoolTreeModel *model;
         GtkTreeViewColumn *column;
         GError *error;
 
         error = NULL;
-        shell->priv->pool = gdu_pool_new_for_address (shell->priv->ssh_address, &error);
-        if (error != NULL) {
-                g_printerr ("Error connecting to `%s': `%s'\n",
-                            shell->priv->ssh_address,
-                            error->message);
+        if (!add_pool (shell, NULL, NULL, &error)) {
+                g_printerr ("Error creating pool: `%s'\n", error->message);
                 g_error_free (error);
-                g_critical ("Exiting");
+                g_critical ("Bailing out");
         }
 
         shell->priv->app_window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
@@ -999,12 +1093,12 @@ create_window (GduShell *shell)
                                         GTK_POLICY_AUTOMATIC);
         gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (tree_view_scrolled_window),
                                              GTK_SHADOW_IN);
-        model = gdu_pool_tree_model_new (shell->priv->pool,
-                                         NULL,
-                                         GDU_POOL_TREE_MODEL_FLAGS_NO_VOLUMES);
-        shell->priv->tree_view = gdu_pool_tree_view_new (model,
+        shell->priv->model = gdu_pool_tree_model_new (shell->priv->pools,
+                                                      NULL,
+                                                      GDU_POOL_TREE_MODEL_FLAGS_NO_VOLUMES);
+        shell->priv->tree_view = gdu_pool_tree_view_new (shell->priv->model,
                                                          GDU_POOL_TREE_VIEW_FLAGS_NONE);
-        g_object_unref (model);
+        g_object_unref (shell->priv->model);
         gtk_container_add (GTK_CONTAINER (tree_view_scrolled_window), shell->priv->tree_view);
 
 
@@ -1051,8 +1145,6 @@ create_window (GduShell *shell)
         /* when starting up, set focus on tree view */
         gtk_widget_grab_focus (shell->priv->tree_view);
 
-        g_signal_connect (shell->priv->pool, "presentable-added", (GCallback) presentable_added, shell);
-        g_signal_connect (shell->priv->pool, "presentable-removed", (GCallback) presentable_removed, shell);
         g_signal_connect (shell->priv->app_window, "delete-event", gtk_main_quit, NULL);
 
         gtk_widget_show_all (vbox);
diff --git a/src/palimpsest/gdu-shell.h b/src/palimpsest/gdu-shell.h
index 5e4c594..c3a7f87 100644
--- a/src/palimpsest/gdu-shell.h
+++ b/src/palimpsest/gdu-shell.h
@@ -53,18 +53,18 @@ struct _GduShellClass
         GObjectClass parent_class;
 };
 
-GType           gdu_shell_get_type                 (void);
-GduShell       *gdu_shell_new                      (const char      *ssh_address);
-GtkWidget      *gdu_shell_get_toplevel             (GduShell       *shell);
-GduPool        *gdu_shell_get_pool                 (GduShell       *shell);
-void            gdu_shell_update                   (GduShell       *shell);
-GduPresentable *gdu_shell_get_selected_presentable (GduShell       *shell);
-void            gdu_shell_select_presentable       (GduShell       *shell,
-                                                    GduPresentable *presentable);
-void            gdu_shell_raise_error              (GduShell       *shell,
-                                                    GduPresentable *presentable,
-                                                    GError         *error,
-                                                    const char     *primary_markup_format,
-                                                    ...);
+GType           gdu_shell_get_type                          (void);
+GduShell       *gdu_shell_new                               (const char      *ssh_address);
+GtkWidget      *gdu_shell_get_toplevel                      (GduShell       *shell);
+GduPool        *gdu_shell_get_pool_for_selected_presentable (GduShell       *shell);
+void            gdu_shell_update                            (GduShell       *shell);
+GduPresentable *gdu_shell_get_selected_presentable          (GduShell       *shell);
+void            gdu_shell_select_presentable                (GduShell       *shell,
+                                                             GduPresentable *presentable);
+void            gdu_shell_raise_error                       (GduShell       *shell,
+                                                             GduPresentable *presentable,
+                                                             GError         *error,
+                                                             const char     *primary_markup_format,
+                                                             ...);
 
 #endif /* GDU_SHELL_H */



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