[gnome-disk-utility/new-ui] Show HBAs in the tree view



commit b41bedec136a4eb62c3be46ae8a0adb2b38329d2
Author: David Zeuthen <davidz redhat com>
Date:   Fri Nov 27 20:30:00 2009 -0500

    Show HBAs in the tree view
    
    Also remove a lot of unneeded code in gdu-shell. And nuke BlingSpinner
    as it is no longer needed.

 src/gdu/Makefile.am              |   15 +-
 src/gdu/gdu-controller.c         |  315 ++++++++++++++++++
 src/gdu/gdu-controller.h         |   75 +++++
 src/gdu/gdu-device.c             |   11 +
 src/gdu/gdu-device.h             |    1 +
 src/gdu/gdu-drive.c              |   36 ++-
 src/gdu/gdu-hba.c                |  232 +++++++++++++
 src/gdu/gdu-hba.h                |   61 ++++
 src/gdu/gdu-pool.c               |  279 ++++++++++++++++-
 src/gdu/gdu-pool.h               |    8 +
 src/gdu/gdu-private.h            |    7 +-
 src/gdu/gdu-types.h              |    3 +
 src/gdu/gdu.h                    |    2 +
 src/palimpsest/Makefile.am       |    3 +-
 src/palimpsest/bling-color.c     |   86 -----
 src/palimpsest/bling-color.h     |   35 --
 src/palimpsest/bling-spinner.c   |  309 ------------------
 src/palimpsest/bling-spinner.h   |   58 ----
 src/palimpsest/gdu-section-hba.c |  181 +++++++++++
 src/palimpsest/gdu-section-hba.h |   58 ++++
 src/palimpsest/gdu-shell.c       |  665 +-------------------------------------
 21 files changed, 1284 insertions(+), 1156 deletions(-)
---
diff --git a/src/gdu/Makefile.am b/src/gdu/Makefile.am
index b81700a..00f3125 100644
--- a/src/gdu/Makefile.am
+++ b/src/gdu/Makefile.am
@@ -1,7 +1,9 @@
+NULL =
 
 BUILT_SOURCES =                                         	\
         devkit-disks-daemon-glue.h                      	\
         devkit-disks-device-glue.h				\
+        devkit-disks-controller-glue.h				\
 	gdu-marshal.h			gdu-marshal.c
 
 gdu-marshal.h: gdu-marshal.list
@@ -16,6 +18,9 @@ devkit-disks-daemon-glue.h: /usr/share/dbus-1/interfaces/org.freedesktop.DeviceK
 devkit-disks-device-glue.h: /usr/share/dbus-1/interfaces/org.freedesktop.DeviceKit.Disks.Device.xml Makefile.am
 	dbus-binding-tool --prefix=devkit_disks_daemon --mode=glib-client --output=devkit-disks-device-glue.h /usr/share/dbus-1/interfaces/org.freedesktop.DeviceKit.Disks.Device.xml
 
+devkit-disks-controller-glue.h: /usr/share/dbus-1/interfaces/org.freedesktop.DeviceKit.Disks.Controller.xml Makefile.am
+	dbus-binding-tool --prefix=devkit_disks_daemon --mode=glib-client --output=devkit-disks-controller-glue.h /usr/share/dbus-1/interfaces/org.freedesktop.DeviceKit.Disks.Controller.xml
+
 lib_LTLIBRARIES=libgdu.la
 
 libgduincludedir=$(includedir)/gnome-disk-utility/gdu
@@ -25,6 +30,7 @@ libgduinclude_HEADERS =              			\
 	gdu-types.h					\
 	gdu-callbacks.h					\
 	gdu-device.h					\
+	gdu-controller.h				\
 	gdu-drive.h					\
 	gdu-linux-md-drive.h				\
 	gdu-error.h					\
@@ -34,7 +40,9 @@ libgduinclude_HEADERS =              			\
 	gdu-process.h					\
 	gdu-util.h					\
 	gdu-volume.h					\
-	gdu-volume-hole.h
+	gdu-volume-hole.h				\
+	gdu-hba.h					\
+	$(NULL)
 
 libgdu_la_SOURCES =                                					\
 						gdu.h					\
@@ -43,6 +51,7 @@ libgdu_la_SOURCES =                                					\
 	gdu-util.h				gdu-util.c				\
 	gdu-pool.c				gdu-pool.h				\
 	gdu-device.c				gdu-device.h				\
+	gdu-controller.c			gdu-controller.h			\
 	gdu-drive.c				gdu-drive.h				\
 	gdu-linux-md-drive.c			gdu-linux-md-drive.h			\
 	gdu-volume.c				gdu-volume.h				\
@@ -51,8 +60,10 @@ libgdu_la_SOURCES =                                					\
 	gdu-known-filesystem.c			gdu-known-filesystem.h			\
 	gdu-error.c				gdu-error.h				\
 	gdu-process.c				gdu-process.h				\
+	gdu-hba.c				gdu-hba.h				\
 						gdu-private.h				\
-	$(BUILT_SOURCES)
+	$(BUILT_SOURCES)								\
+	$(NULL)
 
 libgdu_la_CPPFLAGS = 					\
 	-I$(top_srcdir)/src				\
diff --git a/src/gdu/gdu-controller.c b/src/gdu/gdu-controller.c
new file mode 100644
index 0000000..9052ce3
--- /dev/null
+++ b/src/gdu/gdu-controller.c
@@ -0,0 +1,315 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- */
+/* gdu-controller.c
+ *
+ * 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.
+ */
+
+#include <config.h>
+#include <stdlib.h>
+#include <string.h>
+#include <glib/gi18n-lib.h>
+#include <dbus/dbus-glib.h>
+#include <time.h>
+#include <unistd.h>
+#include <sys/types.h>
+
+#include "gdu-private.h"
+#include "gdu-pool.h"
+#include "gdu-controller.h"
+#include "devkit-disks-controller-glue.h"
+
+/* --- SUCKY CODE BEGIN --- */
+
+/* This totally sucks; dbus-bindings-tool and dbus-glib should be able
+ * to do this for us.
+ *
+ * TODO: keep in sync with code in tools/devkit-disks in DeviceKit-disks.
+ */
+
+typedef struct
+{
+        gchar *native_path;
+
+        gchar *vendor;
+        gchar *model;
+        gchar *driver;
+} ControllerProperties;
+
+static void
+collect_props (const char *key, const GValue *value, ControllerProperties *props)
+{
+        gboolean handled = TRUE;
+
+        if (strcmp (key, "NativePath") == 0)
+                props->native_path = g_strdup (g_value_get_string (value));
+
+        else if (strcmp (key, "Vendor") == 0)
+                props->vendor = g_value_dup_string (value);
+        else if (strcmp (key, "Model") == 0)
+                props->model = g_value_dup_string (value);
+        else if (strcmp (key, "Driver") == 0)
+                props->driver = g_value_dup_string (value);
+        else
+                handled = FALSE;
+
+        if (!handled)
+                g_warning ("unhandled property '%s'", key);
+}
+
+static void
+controller_properties_free (ControllerProperties *props)
+{
+        g_free (props->native_path);
+        g_free (props->vendor);
+        g_free (props->model);
+        g_free (props->driver);
+        g_free (props);
+}
+
+static ControllerProperties *
+controller_properties_get (DBusGConnection *bus,
+                           const char *object_path)
+{
+        ControllerProperties *props;
+        GError *error;
+        GHashTable *hash_table;
+        DBusGProxy *prop_proxy;
+        const char *ifname = "org.freedesktop.DeviceKit.Disks.Controller";
+
+        props = g_new0 (ControllerProperties, 1);
+
+	prop_proxy = dbus_g_proxy_new_for_name (bus,
+                                                "org.freedesktop.DeviceKit.Disks",
+                                                object_path,
+                                                "org.freedesktop.DBus.Properties");
+        error = NULL;
+        if (!dbus_g_proxy_call (prop_proxy,
+                                "GetAll",
+                                &error,
+                                G_TYPE_STRING,
+                                ifname,
+                                G_TYPE_INVALID,
+                                dbus_g_type_get_map ("GHashTable", G_TYPE_STRING, G_TYPE_VALUE),
+                                &hash_table,
+                                G_TYPE_INVALID)) {
+                g_warning ("Couldn't call GetAll() to get properties for %s: %s", object_path, error->message);
+                g_error_free (error);
+
+                controller_properties_free (props);
+                props = NULL;
+                goto out;
+        }
+
+        g_hash_table_foreach (hash_table, (GHFunc) collect_props, props);
+
+        g_hash_table_unref (hash_table);
+
+#if 0
+        g_print ("----------------------------------------------------------------------\n");
+        g_print ("native_path: %s\n", props->native_path);
+        g_print ("vendor:      %s\n", props->vendor);
+        g_print ("model:       %s\n", props->model);
+        g_print ("driver:      %s\n", props->driver);
+#endif
+
+out:
+        g_object_unref (prop_proxy);
+        return props;
+}
+
+/* --- SUCKY CODE END --- */
+
+struct _GduControllerPrivate
+{
+        DBusGConnection *bus;
+        DBusGProxy *proxy;
+        GduPool *pool;
+
+        char *object_path;
+
+        ControllerProperties *props;
+};
+
+enum {
+        CHANGED,
+        REMOVED,
+        LAST_SIGNAL,
+};
+
+static GObjectClass *parent_class = NULL;
+static guint signals[LAST_SIGNAL] = { 0 };
+
+G_DEFINE_TYPE (GduController, gdu_controller, G_TYPE_OBJECT);
+
+GduPool *
+gdu_controller_get_pool (GduController *controller)
+{
+        return g_object_ref (controller->priv->pool);
+}
+
+static void
+gdu_controller_finalize (GduController *controller)
+{
+        g_debug ("##### finalized controller %s",
+                 controller->priv->props != NULL ? controller->priv->props->native_path : controller->priv->object_path);
+
+        dbus_g_connection_unref (controller->priv->bus);
+        g_free (controller->priv->object_path);
+        if (controller->priv->proxy != NULL)
+                g_object_unref (controller->priv->proxy);
+        if (controller->priv->pool != NULL)
+                g_object_unref (controller->priv->pool);
+        if (controller->priv->props != NULL)
+                controller_properties_free (controller->priv->props);
+
+        if (G_OBJECT_CLASS (parent_class)->finalize)
+                (* G_OBJECT_CLASS (parent_class)->finalize) (G_OBJECT (controller));
+}
+
+static void
+gdu_controller_class_init (GduControllerClass *klass)
+{
+        GObjectClass *obj_class = (GObjectClass *) klass;
+
+        parent_class = g_type_class_peek_parent (klass);
+
+        obj_class->finalize = (GObjectFinalizeFunc) gdu_controller_finalize;
+
+        g_type_class_add_private (klass, sizeof (GduControllerPrivate));
+
+        signals[CHANGED] =
+                g_signal_new ("changed",
+                              G_TYPE_FROM_CLASS (klass),
+                              G_SIGNAL_RUN_LAST,
+                              G_STRUCT_OFFSET (GduControllerClass, changed),
+                              NULL, NULL,
+                              g_cclosure_marshal_VOID__VOID,
+                              G_TYPE_NONE, 0);
+        signals[REMOVED] =
+                g_signal_new ("removed",
+                              G_TYPE_FROM_CLASS (klass),
+                              G_SIGNAL_RUN_LAST,
+                              G_STRUCT_OFFSET (GduControllerClass, removed),
+                              NULL, NULL,
+                              g_cclosure_marshal_VOID__VOID,
+                              G_TYPE_NONE, 0);
+}
+
+static void
+gdu_controller_init (GduController *controller)
+{
+        controller->priv = G_TYPE_INSTANCE_GET_PRIVATE (controller, GDU_TYPE_CONTROLLER, GduControllerPrivate);
+}
+
+static gboolean
+update_info (GduController *controller)
+{
+        ControllerProperties *new_properties;
+
+        new_properties = controller_properties_get (controller->priv->bus, controller->priv->object_path);
+        if (new_properties != NULL) {
+                if (controller->priv->props != NULL)
+                        controller_properties_free (controller->priv->props);
+                controller->priv->props = new_properties;
+                return TRUE;
+        } else {
+                return FALSE;
+        }
+}
+
+
+GduController *
+_gdu_controller_new_from_object_path (GduPool *pool, const char *object_path)
+{
+        GError *error;
+        GduController *controller;
+
+        controller = GDU_CONTROLLER (g_object_new (GDU_TYPE_CONTROLLER, NULL));
+        controller->priv->object_path = g_strdup (object_path);
+        controller->priv->pool = g_object_ref (pool);
+
+        error = NULL;
+        controller->priv->bus = dbus_g_bus_get (DBUS_BUS_SYSTEM, &error);
+        if (controller->priv->bus == NULL) {
+                g_warning ("Couldn't connect to system bus: %s", error->message);
+                g_error_free (error);
+                goto error;
+        }
+
+	controller->priv->proxy = dbus_g_proxy_new_for_name (controller->priv->bus,
+                                                         "org.freedesktop.DeviceKit.Disks",
+                                                         controller->priv->object_path,
+                                                         "org.freedesktop.DeviceKit.Disks.Controller");
+        dbus_g_proxy_set_default_timeout (controller->priv->proxy, INT_MAX);
+        dbus_g_proxy_add_signal (controller->priv->proxy, "Changed", G_TYPE_INVALID);
+
+        /* TODO: connect signals */
+
+        if (!update_info (controller))
+                goto error;
+
+        g_debug ("_gdu_controller_new_from_object_path: %s", controller->priv->props->native_path);
+
+        return controller;
+error:
+        g_object_unref (controller);
+        return NULL;
+}
+
+gboolean
+_gdu_controller_changed (GduController *controller)
+{
+        g_debug ("_gdu_controller_changed: %s", controller->priv->props->native_path);
+        if (update_info (controller)) {
+                g_signal_emit (controller, signals[CHANGED], 0);
+                return TRUE;
+        } else {
+                return FALSE;
+        }
+}
+
+const gchar *
+gdu_controller_get_object_path (GduController *controller)
+{
+        return controller->priv->object_path;
+}
+
+
+const gchar *
+gdu_controller_get_native_path (GduController *controller)
+{
+        return controller->priv->props->native_path;
+}
+
+const gchar *
+gdu_controller_get_vendor (GduController *controller)
+{
+        return controller->priv->props->vendor;
+}
+
+const gchar *
+gdu_controller_get_model (GduController *controller)
+{
+        return controller->priv->props->model;
+}
+
+const gchar *
+gdu_controller_get_driver (GduController *controller)
+{
+        return controller->priv->props->driver;
+}
diff --git a/src/gdu/gdu-controller.h b/src/gdu/gdu-controller.h
new file mode 100644
index 0000000..09d7454
--- /dev/null
+++ b/src/gdu/gdu-controller.h
@@ -0,0 +1,75 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- */
+/* gdu-controller.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_CONTROLLER_H
+#define __GDU_CONTROLLER_H
+
+#include <unistd.h>
+#include <sys/types.h>
+
+#include <gdu/gdu-types.h>
+#include <gdu/gdu-callbacks.h>
+
+G_BEGIN_DECLS
+
+#define GDU_TYPE_CONTROLLER           (gdu_controller_get_type ())
+#define GDU_CONTROLLER(o)             (G_TYPE_CHECK_INSTANCE_CAST ((o), GDU_TYPE_CONTROLLER, GduController))
+#define GDU_CONTROLLER_CLASS(k)       (G_TYPE_CHECK_CLASS_CAST ((k), GDU_CONTROLLER,  GduControllerClass))
+#define GDU_IS_CONTROLLER(o)          (G_TYPE_CHECK_INSTANCE_TYPE ((o), GDU_TYPE_CONTROLLER))
+#define GDU_IS_CONTROLLER_CLASS(k)    (G_TYPE_CHECK_CLASS_TYPE ((k), GDU_TYPE_CONTROLLER))
+#define GDU_CONTROLLER_GET_CLASS(k)   (G_TYPE_INSTANCE_GET_CLASS ((k), GDU_TYPE_CONTROLLER, GduControllerClass))
+
+typedef struct _GduControllerClass    GduControllerClass;
+typedef struct _GduControllerPrivate  GduControllerPrivate;
+
+struct _GduController
+{
+        GObject parent;
+
+        /* private */
+        GduControllerPrivate *priv;
+};
+
+struct _GduControllerClass
+{
+        GObjectClass parent_class;
+
+        /* signals */
+        void (*changed)     (GduController *controller);
+        void (*removed)     (GduController *controller);
+};
+
+GType        gdu_controller_get_type              (void);
+const char  *gdu_controller_get_object_path       (GduController   *controller);
+GduPool     *gdu_controller_get_pool              (GduController   *controller);
+
+const gchar *gdu_controller_get_native_path       (GduController   *controller);
+const gchar *gdu_controller_get_vendor            (GduController   *controller);
+const gchar *gdu_controller_get_model             (GduController   *controller);
+const gchar *gdu_controller_get_driver            (GduController   *controller);
+
+G_END_DECLS
+
+#endif /* __GDU_CONTROLLER_H */
diff --git a/src/gdu/gdu-device.c b/src/gdu/gdu-device.c
index d41220c..affe23a 100644
--- a/src/gdu/gdu-device.c
+++ b/src/gdu/gdu-device.c
@@ -123,6 +123,7 @@ typedef struct
         gboolean drive_is_rotational;
         guint    drive_rotation_rate;
         char    *drive_write_cache;
+        char    *drive_controller;
 
         gboolean optical_disc_is_blank;
         gboolean optical_disc_is_appendable;
@@ -318,6 +319,8 @@ collect_props (const char *key, const GValue *value, DeviceProperties *props)
                 props->drive_rotation_rate = g_value_get_uint (value);
         else if (strcmp (key, "DriveWriteCache") == 0)
                 props->drive_write_cache = g_strdup (g_value_get_string (value));
+        else if (strcmp (key, "DriveController") == 0)
+                props->drive_controller = g_strdup (g_value_get_boxed (value));
 
         else if (strcmp (key, "OpticalDiscIsBlank") == 0)
                 props->optical_disc_is_blank = g_value_get_boolean (value);
@@ -437,6 +440,8 @@ device_properties_free (DeviceProperties *props)
         g_free (props->drive_connection_interface);
         g_strfreev (props->drive_media_compatibility);
         g_free (props->drive_media);
+        g_free (props->drive_write_cache);
+        g_free (props->drive_controller);
 
         g_free (props->drive_ata_smart_status);
         g_free (props->drive_ata_smart_blob);
@@ -1081,6 +1086,12 @@ gdu_device_drive_get_write_cache (GduDevice *device)
         return device->priv->props->drive_write_cache;
 }
 
+const char *
+gdu_device_drive_get_controller (GduDevice *device)
+{
+        return device->priv->props->drive_controller;
+}
+
 gboolean
 gdu_device_drive_get_is_media_ejectable (GduDevice *device)
 {
diff --git a/src/gdu/gdu-device.h b/src/gdu/gdu-device.h
index 6d66902..4e59c48 100644
--- a/src/gdu/gdu-device.h
+++ b/src/gdu/gdu-device.h
@@ -144,6 +144,7 @@ gboolean gdu_device_drive_get_can_spindown (GduDevice *device);
 gboolean gdu_device_drive_get_is_rotational (GduDevice *device);
 guint    gdu_device_drive_get_rotation_rate (GduDevice *device);
 const char *gdu_device_drive_get_write_cache (GduDevice *device);
+const char *gdu_device_drive_get_controller (GduDevice *device);
 
 gboolean gdu_device_optical_disc_get_is_blank (GduDevice *device);
 gboolean gdu_device_optical_disc_get_is_appendable (GduDevice *device);
diff --git a/src/gdu/gdu-drive.c b/src/gdu/gdu-drive.c
index e9e40a1..96dfea2 100644
--- a/src/gdu/gdu-drive.c
+++ b/src/gdu/gdu-drive.c
@@ -53,6 +53,7 @@ struct _GduDrivePrivate
 {
         GduDevice *device;
         GduPool *pool;
+        GduPresentable *enclosing_presentable;
         gchar *id;
 };
 
@@ -85,6 +86,9 @@ gdu_drive_finalize (GduDrive *drive)
         if (drive->priv->pool != NULL)
                 g_object_unref (drive->priv->pool);
 
+        if (drive->priv->enclosing_presentable != NULL)
+                g_object_unref (drive->priv->enclosing_presentable);
+
         g_free (drive->priv->id);
 
         if (G_OBJECT_CLASS (parent_class)->finalize)
@@ -468,13 +472,15 @@ device_job_changed (GduDevice *device, gpointer user_data)
 }
 
 GduDrive *
-_gdu_drive_new_from_device (GduPool *pool, GduDevice *device)
+_gdu_drive_new_from_device (GduPool *pool, GduDevice *device, GduPresentable *enclosing_presentable)
 {
         GduDrive *drive;
 
         drive = GDU_DRIVE (g_object_new (GDU_TYPE_DRIVE, NULL));
         drive->priv->device = g_object_ref (device);
         drive->priv->pool = g_object_ref (pool);
+        drive->priv->enclosing_presentable =
+                enclosing_presentable != NULL ? g_object_ref (enclosing_presentable) : NULL;
         drive->priv->id = g_strdup_printf ("drive_%s", gdu_device_get_device_file (drive->priv->device));
 
         g_signal_connect (device, "changed", (GCallback) device_changed, drive);
@@ -500,6 +506,9 @@ gdu_drive_get_device (GduPresentable *presentable)
 static GduPresentable *
 gdu_drive_get_enclosing_presentable (GduPresentable *presentable)
 {
+        GduDrive *drive = GDU_DRIVE (presentable);
+        if (drive->priv->enclosing_presentable != NULL)
+                return g_object_ref (drive->priv->enclosing_presentable);
         return NULL;
 }
 
@@ -1009,3 +1018,28 @@ gdu_drive_presentable_iface_init (GduPresentableIface *iface)
         iface->is_recognized             = gdu_drive_is_recognized;
 }
 
+void
+_gdu_drive_rewrite_enclosing_presentable (GduDrive *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:
+        ;
+}
diff --git a/src/gdu/gdu-hba.c b/src/gdu/gdu-hba.c
new file mode 100644
index 0000000..1a09d4a
--- /dev/null
+++ b/src/gdu/gdu-hba.c
@@ -0,0 +1,232 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- */
+/* gdu-hba.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 <string.h>
+#include <glib/gi18n-lib.h>
+#include <dbus/dbus-glib.h>
+#include <stdlib.h>
+
+#include "gdu-private.h"
+#include "gdu-util.h"
+#include "gdu-pool.h"
+#include "gdu-controller.h"
+#include "gdu-hba.h"
+#include "gdu-presentable.h"
+#include "gdu-linux-md-drive.h"
+
+/**
+ * SECTION:gdu-hba
+ * @title: GduHba
+ * @short_description: HBAs
+ *
+ * #GduHba objects are used to represent host board adapters (also
+ * called disk controllers).
+ *
+ * See the documentation for #GduPresentable for the big picture.
+ */
+
+struct _GduHbaPrivate
+{
+        GduController *controller;
+        GduPool *pool;
+        gchar *id;
+};
+
+static GObjectClass *parent_class = NULL;
+
+static void gdu_hba_presentable_iface_init (GduPresentableIface *iface);
+G_DEFINE_TYPE_WITH_CODE (GduHba, gdu_hba, G_TYPE_OBJECT,
+                         G_IMPLEMENT_INTERFACE (GDU_TYPE_PRESENTABLE,
+                                                gdu_hba_presentable_iface_init))
+
+static void controller_changed (GduController *controller, gpointer user_data);
+
+
+static void
+gdu_hba_finalize (GObject *object)
+{
+        GduHba *hba = GDU_HBA (object);
+
+        //g_debug ("##### finalized hba '%s' %p", hba->priv->id, hba);
+
+        if (hba->priv->controller != NULL) {
+                g_signal_handlers_disconnect_by_func (hba->priv->controller, controller_changed, hba);
+                g_object_unref (hba->priv->controller);
+        }
+
+        if (hba->priv->pool != NULL)
+                g_object_unref (hba->priv->pool);
+
+        g_free (hba->priv->id);
+
+        if (G_OBJECT_CLASS (parent_class)->finalize != NULL)
+                (* G_OBJECT_CLASS (parent_class)->finalize) (object);
+}
+
+static void
+gdu_hba_class_init (GduHbaClass *klass)
+{
+        GObjectClass *obj_class = (GObjectClass *) klass;
+
+        parent_class = g_type_class_peek_parent (klass);
+
+        obj_class->finalize = gdu_hba_finalize;
+
+        g_type_class_add_private (klass, sizeof (GduHbaPrivate));
+}
+
+static void
+gdu_hba_init (GduHba *hba)
+{
+        hba->priv = G_TYPE_INSTANCE_GET_PRIVATE (hba, GDU_TYPE_HBA, GduHbaPrivate);
+}
+
+static void
+controller_changed (GduController *controller, gpointer user_data)
+{
+        GduHba *hba = GDU_HBA (user_data);
+        g_signal_emit_by_name (hba, "changed");
+        g_signal_emit_by_name (hba->priv->pool, "presentable-changed", hba);
+}
+
+GduHba *
+_gdu_hba_new_from_controller (GduPool *pool, GduController *controller)
+{
+        GduHba *hba;
+
+        hba = GDU_HBA (g_object_new (GDU_TYPE_HBA, NULL));
+        hba->priv->controller = g_object_ref (controller);
+        hba->priv->pool = g_object_ref (pool);
+        hba->priv->id = g_strdup (gdu_controller_get_native_path (hba->priv->controller));
+        g_signal_connect (controller, "changed", (GCallback) controller_changed, hba);
+        return hba;
+}
+
+static const gchar *
+gdu_hba_get_id (GduPresentable *presentable)
+{
+        GduHba *hba = GDU_HBA (presentable);
+        return hba->priv->id;
+}
+
+static GduDevice *
+gdu_hba_get_device (GduPresentable *presentable)
+{
+        return NULL;
+}
+
+static GduPresentable *
+gdu_hba_get_enclosing_presentable (GduPresentable *presentable)
+{
+        return NULL;
+}
+
+static char *
+gdu_hba_get_name (GduPresentable *presentable)
+{
+        /* TODO: include type e.g. SATA-I, SATA-II, SAS etc */
+        return g_strdup (_("Host Adapter"));
+}
+
+static gchar *
+gdu_hba_get_vpd_name (GduPresentable *presentable)
+{
+        GduHba *hba = GDU_HBA (presentable);
+        gchar *s;
+        const gchar *vendor;
+        const gchar *model;
+
+        vendor = gdu_controller_get_vendor (hba->priv->controller);
+        model = gdu_controller_get_model (hba->priv->controller);
+        //s = g_strdup_printf ("%s %s", vendor, model);
+        s = g_strdup (model);
+        return s;
+}
+
+static gchar *
+gdu_hba_get_description (GduPresentable *presentable)
+{
+        /* TODO: include number of ports, speed, receptable type etc. */
+        return gdu_hba_get_vpd_name (presentable);
+}
+
+static GIcon *
+gdu_hba_get_icon (GduPresentable *presentable)
+{
+        GIcon *icon;
+        icon = g_themed_icon_new_with_default_fallbacks ("gdu-hba");
+        return icon;
+}
+
+static guint64
+gdu_hba_get_offset (GduPresentable *presentable)
+{
+        return 0;
+}
+
+static guint64
+gdu_hba_get_size (GduPresentable *presentable)
+{
+        return 0;
+}
+
+static GduPool *
+gdu_hba_get_pool (GduPresentable *presentable)
+{
+        GduHba *hba = GDU_HBA (presentable);
+        return gdu_controller_get_pool (hba->priv->controller);
+}
+
+static gboolean
+gdu_hba_is_allocated (GduPresentable *presentable)
+{
+        return FALSE;
+}
+
+static gboolean
+gdu_hba_is_recognized (GduPresentable *presentable)
+{
+        return FALSE;
+}
+
+GduController *
+gdu_hba_get_controller (GduHba *hba)
+{
+        return g_object_ref (hba->priv->controller);
+}
+
+static void
+gdu_hba_presentable_iface_init (GduPresentableIface *iface)
+{
+        iface->get_id                    = gdu_hba_get_id;
+        iface->get_device                = gdu_hba_get_device;
+        iface->get_enclosing_presentable = gdu_hba_get_enclosing_presentable;
+        iface->get_name                  = gdu_hba_get_name;
+        iface->get_description           = gdu_hba_get_description;
+        iface->get_vpd_name              = gdu_hba_get_vpd_name;
+        iface->get_icon                  = gdu_hba_get_icon;
+        iface->get_offset                = gdu_hba_get_offset;
+        iface->get_size                  = gdu_hba_get_size;
+        iface->get_pool                  = gdu_hba_get_pool;
+        iface->is_allocated              = gdu_hba_is_allocated;
+        iface->is_recognized             = gdu_hba_is_recognized;
+}
diff --git a/src/gdu/gdu-hba.h b/src/gdu/gdu-hba.h
new file mode 100644
index 0000000..760ec78
--- /dev/null
+++ b/src/gdu/gdu-hba.h
@@ -0,0 +1,61 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- */
+/* gdu-hba.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_HBA_H
+#define __GDU_HBA_H
+
+#include <gdu/gdu-types.h>
+
+G_BEGIN_DECLS
+
+#define GDU_TYPE_HBA           (gdu_hba_get_type ())
+#define GDU_HBA(o)             (G_TYPE_CHECK_INSTANCE_CAST ((o), GDU_TYPE_HBA, GduHba))
+#define GDU_HBA_CLASS(k)       (G_TYPE_CHECK_CLASS_CAST ((k), GDU_HBA,  GduHbaClass))
+#define GDU_IS_HBA(o)          (G_TYPE_CHECK_INSTANCE_TYPE ((o), GDU_TYPE_HBA))
+#define GDU_IS_HBA_CLASS(k)    (G_TYPE_CHECK_CLASS_TYPE ((k), GDU_TYPE_HBA))
+#define GDU_HBA_GET_CLASS(k)   (G_TYPE_INSTANCE_GET_CLASS ((k), GDU_TYPE_HBA, GduHbaClass))
+
+typedef struct _GduHbaClass       GduHbaClass;
+typedef struct _GduHbaPrivate     GduHbaPrivate;
+
+struct _GduHba
+{
+        GObject parent;
+
+        /* private */
+        GduHbaPrivate *priv;
+};
+
+struct _GduHbaClass
+{
+        GObjectClass parent_class;
+};
+
+GType          gdu_hba_get_type       (void);
+GduController *gdu_hba_get_controller (GduHba *hba);
+
+G_END_DECLS
+
+#endif /* __GDU_HBA_H */
diff --git a/src/gdu/gdu-pool.c b/src/gdu/gdu-pool.c
index c4dcb96..adcc5f3 100644
--- a/src/gdu/gdu-pool.c
+++ b/src/gdu/gdu-pool.c
@@ -27,6 +27,7 @@
 #include "gdu-pool.h"
 #include "gdu-presentable.h"
 #include "gdu-device.h"
+#include "gdu-controller.h"
 #include "gdu-drive.h"
 #include "gdu-linux-md-drive.h"
 #include "gdu-volume.h"
@@ -50,6 +51,9 @@ enum {
         DEVICE_REMOVED,
         DEVICE_CHANGED,
         DEVICE_JOB_CHANGED,
+        CONTROLLER_ADDED,
+        CONTROLLER_REMOVED,
+        CONTROLLER_CHANGED,
         PRESENTABLE_ADDED,
         PRESENTABLE_REMOVED,
         PRESENTABLE_CHANGED,
@@ -74,6 +78,9 @@ struct _GduPoolPrivate
 
         /* the current set of devices we know about */
         GHashTable *object_path_to_device;
+
+        /* the current set of devices we know about */
+        GHashTable *object_path_to_controller;
 };
 
 G_DEFINE_TYPE (GduPool, gdu_pool, G_TYPE_OBJECT);
@@ -91,6 +98,8 @@ gdu_pool_finalize (GduPool *pool)
 
         g_hash_table_unref (pool->priv->object_path_to_device);
 
+        g_hash_table_unref (pool->priv->object_path_to_controller);
+
         g_list_foreach (pool->priv->presentables, (GFunc) g_object_unref, NULL);
         g_list_free (pool->priv->presentables);
 
@@ -179,6 +188,59 @@ gdu_pool_class_init (GduPoolClass *klass)
                               GDU_TYPE_DEVICE);
 
         /**
+         * GduPool::controller-added
+         * @pool: The #GduPool emitting the signal.
+         * @controller: The #GduController that was added.
+         *
+         * Emitted when @controller is added to @pool.
+         **/
+        signals[CONTROLLER_ADDED] =
+                g_signal_new ("controller-added",
+                              G_TYPE_FROM_CLASS (klass),
+                              G_SIGNAL_RUN_LAST,
+                              G_STRUCT_OFFSET (GduPoolClass, controller_added),
+                              NULL, NULL,
+                              g_cclosure_marshal_VOID__OBJECT,
+                              G_TYPE_NONE, 1,
+                              GDU_TYPE_CONTROLLER);
+
+        /**
+         * GduPool::controller-removed
+         * @pool: The #GduPool emitting the signal.
+         * @controller: The #GduController that was removed.
+         *
+         * Emitted when @controller is removed from @pool. Recipients
+         * should release references to @controller.
+         **/
+        signals[CONTROLLER_REMOVED] =
+                g_signal_new ("controller-removed",
+                              G_TYPE_FROM_CLASS (klass),
+                              G_SIGNAL_RUN_LAST,
+                              G_STRUCT_OFFSET (GduPoolClass, controller_removed),
+                              NULL, NULL,
+                              g_cclosure_marshal_VOID__OBJECT,
+                              G_TYPE_NONE, 1,
+                              GDU_TYPE_CONTROLLER);
+
+        /**
+         * GduPool::controller-changed
+         * @pool: The #GduPool emitting the signal.
+         * @controller: A #GduController.
+         *
+         * Emitted when @controller is changed.
+         **/
+        signals[CONTROLLER_CHANGED] =
+                g_signal_new ("controller-changed",
+                              G_TYPE_FROM_CLASS (klass),
+                              G_SIGNAL_RUN_LAST,
+                              G_STRUCT_OFFSET (GduPoolClass, controller_changed),
+                              NULL, NULL,
+                              g_cclosure_marshal_VOID__OBJECT,
+                              G_TYPE_NONE, 1,
+                              GDU_TYPE_CONTROLLER);
+
+
+        /**
          * GduPool::presentable-added
          * @pool: The #GduPool emitting the signal.
          * @presentable: The #GduPresentable that was added.
@@ -289,6 +351,11 @@ gdu_pool_init (GduPool *pool)
                                                                    g_str_equal,
                                                                    NULL,
                                                                    g_object_unref);
+
+        pool->priv->object_path_to_controller = g_hash_table_new_full (g_str_hash,
+                                                                       g_str_equal,
+                                                                       NULL,
+                                                                       g_object_unref);
 }
 
 /* ---------------------------------------------------------------------------------------------------- */
@@ -604,12 +671,14 @@ recompute_presentables (GduPool *pool)
 {
         GList *l;
         GList *devices;
+        GList *controllers;
         GList *new_partitioned_drives;
         GList *new_presentables;
         GList *added_presentables;
         GList *removed_presentables;
         GHashTable *hash_map_from_drive_to_extended_partition;
         GHashTable *hash_map_from_linux_md_uuid_to_drive;
+        GHashTable *hash_map_from_controller_objpath_to_hba;
 
         /* 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
@@ -634,6 +703,26 @@ recompute_presentables (GduPool *pool)
                                                                       NULL,
                                                                       NULL);
 
+        hash_map_from_controller_objpath_to_hba = g_hash_table_new_full (g_str_hash,
+                                                                         g_str_equal,
+                                                                         NULL,
+                                                                         NULL);
+
+        /* First add all HBAs */
+        controllers = gdu_pool_get_controllers (pool);
+        for (l = controllers; l != NULL; l = l->next) {
+                GduController *controller = GDU_CONTROLLER (l->data);
+                GduHba *hba;
+
+                hba = _gdu_hba_new_from_controller (pool, controller);
+
+                g_hash_table_insert (hash_map_from_controller_objpath_to_hba,
+                                     (gpointer) gdu_controller_get_object_path (controller),
+                                     hba);
+
+                new_presentables = g_list_prepend (new_presentables, hba);
+        } /* for all controllers */
+
         /* TODO: Ensure that pool->priv->devices is in topological sort order, then just loop
          *       through it and handle devices sequentially.
          *
@@ -683,7 +772,17 @@ recompute_presentables (GduPool *pool)
 
 
                         } else {
-                                drive = _gdu_drive_new_from_device (pool, device);
+                                const gchar *controller_objpath;
+                                GduPresentable *hba;
+
+                                hba = NULL;
+
+                                controller_objpath = gdu_device_drive_get_controller (device);
+                                if (controller_objpath != NULL)
+                                        hba = g_hash_table_lookup (hash_map_from_controller_objpath_to_hba,
+                                                                   controller_objpath);
+
+                                drive = _gdu_drive_new_from_device (pool, device, hba);
                         }
                         new_presentables = g_list_prepend (new_presentables, drive);
 
@@ -815,6 +914,7 @@ recompute_presentables (GduPool *pool)
         g_list_free (new_partitioned_drives);
         g_hash_table_unref (hash_map_from_drive_to_extended_partition);
         g_hash_table_unref (hash_map_from_linux_md_uuid_to_drive);
+        g_hash_table_unref (hash_map_from_controller_objpath_to_hba);
 
         /* figure out the diff */
         new_presentables = g_list_sort (new_presentables, (GCompareFunc) gdu_presentable_compare);
@@ -847,7 +947,9 @@ recompute_presentables (GduPool *pool)
                 /* rewrite all enclosing_presentable references for presentables we are going to add
                  * such that they really refer to presentables _previously_ added
                  */
-                if (GDU_IS_VOLUME (p))
+                if (GDU_IS_DRIVE (p))
+                        _gdu_drive_rewrite_enclosing_presentable (GDU_DRIVE (p));
+                else if (GDU_IS_VOLUME (p))
                         _gdu_volume_rewrite_enclosing_presentable (GDU_VOLUME (p));
                 else if (GDU_IS_VOLUME_HOLE (p))
                         _gdu_volume_hole_rewrite_enclosing_presentable (GDU_VOLUME_HOLE (p));
@@ -868,6 +970,8 @@ recompute_presentables (GduPool *pool)
         g_list_free (new_presentables);
         g_list_foreach (devices, (GFunc) g_object_unref, NULL);
         g_list_free (devices);
+        g_list_foreach (controllers, (GFunc) g_object_unref, NULL);
+        g_list_free (controllers);
 }
 
 /* ---------------------------------------------------------------------------------------------------- */
@@ -987,6 +1091,98 @@ device_job_changed_signal_handler (DBusGProxy *proxy,
         }
 }
 
+/* ---------------------------------------------------------------------------------------------------- */
+
+static void
+controller_changed_signal_handler (DBusGProxy *proxy, const char *object_path, gpointer user_data);
+
+static void
+controller_added_signal_handler (DBusGProxy *proxy, const char *object_path, gpointer user_data)
+{
+        GduPool *pool;
+        GduController *controller;
+
+        pool = GDU_POOL (user_data);
+
+        controller = gdu_pool_get_controller_by_object_path (pool, object_path);
+        if (controller != NULL) {
+                g_object_unref (controller);
+                g_warning ("Treating add for previously added controller %s as change", object_path);
+                controller_changed_signal_handler (proxy, object_path, user_data);
+                goto out;
+        }
+
+        controller = _gdu_controller_new_from_object_path (pool, object_path);
+        if (controller == NULL)
+                goto out;
+
+        g_hash_table_insert (pool->priv->object_path_to_controller,
+                             (gpointer) gdu_controller_get_object_path (controller),
+                             controller);
+        g_signal_emit (pool, signals[CONTROLLER_ADDED], 0, controller);
+        //g_debug ("Added controller %s", object_path);
+
+        recompute_presentables (pool);
+
+ out:
+        ;
+}
+
+static void
+controller_removed_signal_handler (DBusGProxy *proxy, const char *object_path, gpointer user_data)
+{
+        GduPool *pool;
+        GduController *controller;
+
+        pool = GDU_POOL (user_data);
+
+        controller = gdu_pool_get_controller_by_object_path (pool, object_path);
+        if (controller == NULL) {
+                g_warning ("No controller to remove for remove %s", object_path);
+                goto out;
+        }
+
+        g_hash_table_remove (pool->priv->object_path_to_controller,
+                             gdu_controller_get_object_path (controller));
+        g_signal_emit (pool, signals[CONTROLLER_REMOVED], 0, controller);
+        g_signal_emit_by_name (controller, "removed");
+        g_object_unref (controller);
+        g_debug ("Removed controller %s", object_path);
+
+        recompute_presentables (pool);
+
+ out:
+        ;
+}
+
+static void
+controller_changed_signal_handler (DBusGProxy *proxy, const char *object_path, gpointer user_data)
+{
+        GduPool *pool;
+        GduController *controller;
+
+        pool = GDU_POOL (user_data);
+
+        controller = gdu_pool_get_controller_by_object_path (pool, object_path);
+        if (controller == NULL) {
+                g_warning ("Ignoring change event on non-existant controller %s", object_path);
+                goto out;
+        }
+
+        if (_gdu_controller_changed (controller)) {
+                g_signal_emit (pool, signals[CONTROLLER_CHANGED], 0, controller);
+                g_signal_emit_by_name (controller, "changed");
+        }
+        g_object_unref (controller);
+
+        recompute_presentables (pool);
+
+ out:
+        ;
+}
+
+/* ---------------------------------------------------------------------------------------------------- */
+
 static gboolean
 get_properties (GduPool *pool)
 {
@@ -1067,6 +1263,7 @@ gdu_pool_new (void)
 {
         int n;
         GPtrArray *devices;
+        GPtrArray *controllers;
         GduPool *pool;
         GError *error;
 
@@ -1117,6 +1314,16 @@ gdu_pool_new (void)
         dbus_g_proxy_connect_signal (pool->priv->proxy, "DeviceJobChanged",
                                      G_CALLBACK (device_job_changed_signal_handler), pool, NULL);
 
+        dbus_g_proxy_add_signal (pool->priv->proxy, "ControllerAdded", DBUS_TYPE_G_OBJECT_PATH, G_TYPE_INVALID);
+        dbus_g_proxy_add_signal (pool->priv->proxy, "ControllerRemoved", DBUS_TYPE_G_OBJECT_PATH, G_TYPE_INVALID);
+        dbus_g_proxy_add_signal (pool->priv->proxy, "ControllerChanged", DBUS_TYPE_G_OBJECT_PATH, G_TYPE_INVALID);
+        dbus_g_proxy_connect_signal (pool->priv->proxy, "ControllerAdded",
+                                     G_CALLBACK (controller_added_signal_handler), pool, NULL);
+        dbus_g_proxy_connect_signal (pool->priv->proxy, "ControllerRemoved",
+                                     G_CALLBACK (controller_removed_signal_handler), pool, NULL);
+        dbus_g_proxy_connect_signal (pool->priv->proxy, "ControllerChanged",
+                                     G_CALLBACK (controller_changed_signal_handler), pool, NULL);
+
         /* get the properties on the daemon object at / */
         if (!get_properties (pool)) {
                 g_warning ("Couldn't get daemon properties");
@@ -1148,6 +1355,29 @@ gdu_pool_new (void)
         g_ptr_array_foreach (devices, (GFunc) g_free, NULL);
         g_ptr_array_free (devices, TRUE);
 
+        /* prime the list of controllers */
+        error = NULL;
+        if (!org_freedesktop_DeviceKit_Disks_enumerate_controllers (pool->priv->proxy, &controllers, &error)) {
+                g_warning ("Couldn't enumerate controllers: %s", error->message);
+                g_error_free (error);
+                goto error;
+        }
+        for (n = 0; n < (int) controllers->len; n++) {
+                const char *object_path;
+                GduController *controller;
+
+                object_path = controllers->pdata[n];
+
+                controller = _gdu_controller_new_from_object_path (pool, object_path);
+
+                g_hash_table_insert (pool->priv->object_path_to_controller,
+                                     (gpointer) gdu_controller_get_object_path (controller),
+                                     controller);
+        }
+        g_ptr_array_foreach (controllers, (GFunc) g_free, NULL);
+        g_ptr_array_free (controllers, TRUE);
+
+        /* and finally compute all presentables */
         recompute_presentables (pool);
 
         return pool;
@@ -1173,9 +1403,31 @@ gdu_pool_get_by_object_path (GduPool *pool, const char *object_path)
         GduDevice *ret;
 
         ret = g_hash_table_lookup (pool->priv->object_path_to_device, object_path);
-        if (ret != NULL)
+        if (ret != NULL) {
                 g_object_ref (ret);
+        }
+        return ret;
+}
+
+/**
+ * gdu_pool_get_by_object_path:
+ * @pool: the pool
+ * @object_path: the D-Bus object path
+ *
+ * Looks up #GduController object for @object_path.
+ *
+ * Returns: A #GduController object for @object_path, otherwise
+ * #NULL. Caller must unref this object using g_object_unref().
+ **/
+GduController *
+gdu_pool_get_controller_by_object_path (GduPool *pool, const char *object_path)
+{
+        GduController *ret;
 
+        ret = g_hash_table_lookup (pool->priv->object_path_to_controller, object_path);
+        if (ret != NULL) {
+                g_object_ref (ret);
+        }
         return ret;
 }
 
@@ -1362,6 +1614,27 @@ gdu_pool_get_devices (GduPool *pool)
 }
 
 /**
+ * gdu_pool_get_controllers:
+ * @pool: A #GduPool.
+ *
+ * Get a list of all controllers. 
+ *
+ * Returns: A #GList of #GduController objects. Caller must free this
+ * (unref all objects, then use g_list_free()).
+ **/
+GList *
+gdu_pool_get_controllers (GduPool *pool)
+{
+        GList *ret;
+
+        ret = NULL;
+
+        ret = g_hash_table_get_values (pool->priv->object_path_to_controller);
+        g_list_foreach (ret, (GFunc) g_object_ref, NULL);
+        return ret;
+}
+
+/**
  * gdu_pool_get_presentables:
  * @pool: A #GduPool
  *
diff --git a/src/gdu/gdu-pool.h b/src/gdu/gdu-pool.h
index 555e331..7cabbd6 100644
--- a/src/gdu/gdu-pool.h
+++ b/src/gdu/gdu-pool.h
@@ -58,6 +58,11 @@ struct _GduPoolClass
         void (*device_removed) (GduPool *pool, GduDevice *device);
         void (*device_changed) (GduPool *pool, GduDevice *device);
         void (*device_job_changed) (GduPool *pool, GduDevice *device);
+
+        void (*controller_added) (GduPool *pool, GduDevice *device);
+        void (*controller_removed) (GduPool *pool, GduDevice *device);
+        void (*controller_changed) (GduPool *pool, GduDevice *device);
+
         void (*presentable_added) (GduPool *pool, GduPresentable *presentable);
         void (*presentable_removed) (GduPool *pool, GduPresentable *presentable);
         void (*presentable_changed) (GduPool *pool, GduPresentable *presentable);
@@ -86,6 +91,9 @@ GList      *gdu_pool_get_devices               (GduPool *pool);
 GList      *gdu_pool_get_presentables          (GduPool *pool);
 GList      *gdu_pool_get_enclosed_presentables (GduPool *pool, GduPresentable *presentable);
 
+GduController  *gdu_pool_get_controller_by_object_path (GduPool *pool, const char *object_path);
+GList      *gdu_pool_get_controllers           (GduPool *pool);
+
 /* ---------------------------------------------------------------------------------------------------- */
 
 void gdu_pool_op_linux_md_start (GduPool *pool,
diff --git a/src/gdu/gdu-private.h b/src/gdu/gdu-private.h
index 6cb82d5..fa9bee0 100644
--- a/src/gdu/gdu-private.h
+++ b/src/gdu/gdu-private.h
@@ -84,7 +84,7 @@ void _gdu_error_fixup (GError *error);
 GduDevice  *_gdu_device_new_from_object_path  (GduPool     *pool, const char  *object_path);
 
 GduVolume   *_gdu_volume_new_from_device      (GduPool *pool, GduDevice *volume, GduPresentable *enclosing_presentable);
-GduDrive    *_gdu_drive_new_from_device       (GduPool *pool, GduDevice *drive);
+GduDrive    *_gdu_drive_new_from_device       (GduPool *pool, GduDevice *drive, GduPresentable *enclosing_presentable);
 GduVolumeHole   *_gdu_volume_hole_new       (GduPool *pool, guint64 offset, guint64 size, GduPresentable *enclosing_presentable);
 
 
@@ -104,6 +104,11 @@ void        _gdu_device_job_changed           (GduDevice   *device,
                                                gboolean     job_is_cancellable,
                                                double       job_percentage);
 
+GduController *_gdu_controller_new_from_object_path (GduPool *pool, const char *object_path);
+gboolean    _gdu_controller_changed               (GduController   *controller);
+GduHba *_gdu_hba_new_from_controller (GduPool *pool, GduController *controller);
+
+void _gdu_drive_rewrite_enclosing_presentable (GduDrive *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-types.h b/src/gdu/gdu-types.h
index de1a929..be79c37 100644
--- a/src/gdu/gdu-types.h
+++ b/src/gdu/gdu-types.h
@@ -35,11 +35,14 @@ G_BEGIN_DECLS
 
 typedef struct _GduPool                   GduPool;
 typedef struct _GduDevice                 GduDevice;
+typedef struct _GduController             GduController;
+
 typedef struct _GduPresentable            GduPresentable; /* Dummy typedef */
 typedef struct _GduDrive                  GduDrive;
 typedef struct _GduLinuxMdDrive           GduLinuxMdDrive;
 typedef struct _GduVolume                 GduVolume;
 typedef struct _GduVolumeHole             GduVolumeHole;
+typedef struct _GduHba                    GduHba;
 
 typedef struct _GduKnownFilesystem        GduKnownFilesystem;
 typedef struct _GduProcess                GduProcess;
diff --git a/src/gdu/gdu.h b/src/gdu/gdu.h
index 5588b97..1f249e6 100644
--- a/src/gdu/gdu.h
+++ b/src/gdu/gdu.h
@@ -31,6 +31,7 @@
 #include <gdu/gdu-types.h>
 #include <gdu/gdu-linux-md-drive.h>
 #include <gdu/gdu-device.h>
+#include <gdu/gdu-controller.h>
 #include <gdu/gdu-drive.h>
 #include <gdu/gdu-error.h>
 #include <gdu/gdu-known-filesystem.h>
@@ -40,6 +41,7 @@
 #include <gdu/gdu-util.h>
 #include <gdu/gdu-volume.h>
 #include <gdu/gdu-volume-hole.h>
+#include <gdu/gdu-hba.h>
 #include <gdu/gdu-callbacks.h>
 
 #undef __GDU_INSIDE_GDU_H
diff --git a/src/palimpsest/Makefile.am b/src/palimpsest/Makefile.am
index 66685a8..8423f49 100644
--- a/src/palimpsest/Makefile.am
+++ b/src/palimpsest/Makefile.am
@@ -4,8 +4,6 @@ NULL =
 bin_PROGRAMS = palimpsest
 
 palimpsest_SOURCES = 									\
-	bling-color.h				bling-color.c				\
-	bling-spinner.h				bling-spinner.c				\
 						gdu-main.c				\
 	gdu-shell.h				gdu-shell.c				\
 	gdu-section.h				gdu-section.c				\
@@ -20,6 +18,7 @@ palimpsest_SOURCES = 									\
 	gdu-section-no-media.h			gdu-section-no-media.c			\
 	gdu-section-drive.h			gdu-section-drive.c			\
 	gdu-section-volumes.h			gdu-section-volumes.c			\
+	gdu-section-hba.h			gdu-section-hba.c			\
 	$(NULL)
 
 palimpsest_CPPFLAGS = 					\
diff --git a/src/palimpsest/gdu-section-hba.c b/src/palimpsest/gdu-section-hba.c
new file mode 100644
index 0000000..8bf1cf7
--- /dev/null
+++ b/src/palimpsest/gdu-section-hba.c
@@ -0,0 +1,181 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- */
+/* gdu-section-hba.c
+ *
+ * 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.
+ */
+
+#include <config.h>
+#include <string.h>
+#include <glib/gi18n.h>
+#include <dbus/dbus-glib.h>
+#include <stdlib.h>
+#include <math.h>
+#include <gio/gdesktopappinfo.h>
+
+#include <gdu-gtk/gdu-gtk.h>
+#include "gdu-section-hba.h"
+
+struct _GduSectionHbaPrivate
+{
+        GduDetailsElement *vendor_element;
+        GduDetailsElement *model_element;
+        GduDetailsElement *driver_element;
+};
+
+G_DEFINE_TYPE (GduSectionHba, gdu_section_hba, GDU_TYPE_SECTION)
+
+/* ---------------------------------------------------------------------------------------------------- */
+
+static void
+gdu_section_hba_finalize (GObject *object)
+{
+        //GduSectionHba *section = GDU_SECTION_HBA (object);
+
+        if (G_OBJECT_CLASS (gdu_section_hba_parent_class)->finalize != NULL)
+                G_OBJECT_CLASS (gdu_section_hba_parent_class)->finalize (object);
+}
+
+/* ---------------------------------------------------------------------------------------------------- */
+
+static void
+gdu_section_hba_update (GduSection *_section)
+{
+        GduSectionHba *section = GDU_SECTION_HBA (_section);
+        GduPresentable *p;
+        GduController *c;
+        const gchar *vendor;
+        const gchar *model;
+        const gchar *driver;
+
+        c = NULL;
+        p = gdu_section_get_presentable (_section);
+
+        c = gdu_hba_get_controller (GDU_HBA (p));
+        if (c == NULL)
+                goto out;
+
+        vendor = gdu_controller_get_vendor (c);
+        model = gdu_controller_get_model (c);
+        driver = gdu_controller_get_driver (c);
+        gdu_details_element_set_text (section->priv->vendor_element, vendor);
+        gdu_details_element_set_text (section->priv->model_element, model);
+        gdu_details_element_set_text (section->priv->driver_element, driver);
+
+
+ out:
+        if (c != NULL)
+                g_object_unref (c);
+}
+
+/* ---------------------------------------------------------------------------------------------------- */
+
+static void
+gdu_section_hba_constructed (GObject *object)
+{
+        GduSectionHba *section = GDU_SECTION_HBA (object);
+        GtkWidget *align;
+        GtkWidget *label;
+        GtkWidget *table;
+        GtkWidget *vbox;
+        gchar *s;
+        GduPresentable *p;
+        GduDevice *d;
+        GPtrArray *elements;
+        GduDetailsElement *element;
+
+        p = gdu_section_get_presentable (GDU_SECTION (section));
+        d = gdu_presentable_get_device (p);
+
+        gtk_box_set_spacing (GTK_BOX (section), 12);
+
+        /*------------------------------------- */
+
+        label = gtk_label_new (NULL);
+        gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
+        s = g_strconcat ("<b>", _("Host Adapter"), "</b>", NULL);
+        gtk_label_set_markup (GTK_LABEL (label), s);
+        g_free (s);
+        gtk_box_pack_start (GTK_BOX (section), label, FALSE, FALSE, 0);
+
+        align = gtk_alignment_new (0.5, 0.5, 1.0, 1.0);
+        gtk_alignment_set_padding (GTK_ALIGNMENT (align), 0, 0, 12, 0);
+        gtk_box_pack_start (GTK_BOX (section), align, FALSE, FALSE, 0);
+
+        vbox = gtk_vbox_new (FALSE, 6);
+        gtk_container_add (GTK_CONTAINER (align), vbox);
+
+        elements = g_ptr_array_new_with_free_func (g_object_unref);
+
+        element = gdu_details_element_new (_("Vendor:"), NULL, NULL);
+        g_ptr_array_add (elements, element);
+        section->priv->vendor_element = element;
+
+        element = gdu_details_element_new (_("Model:"), NULL, NULL);
+        g_ptr_array_add (elements, element);
+        section->priv->model_element = element;
+
+        element = gdu_details_element_new (_("Driver:"), NULL, NULL);
+        g_ptr_array_add (elements, element);
+        section->priv->driver_element = element;
+
+        table = gdu_details_table_new (1, elements);
+        g_ptr_array_unref (elements);
+        gtk_box_pack_start (GTK_BOX (vbox), table, FALSE, FALSE, 0);
+
+        /* -------------------------------------------------------------------------------- */
+
+        gtk_widget_show_all (GTK_WIDGET (section));
+
+        if (d != NULL)
+                g_object_unref (d);
+
+        if (G_OBJECT_CLASS (gdu_section_hba_parent_class)->constructed != NULL)
+                G_OBJECT_CLASS (gdu_section_hba_parent_class)->constructed (object);
+}
+
+static void
+gdu_section_hba_class_init (GduSectionHbaClass *klass)
+{
+        GObjectClass *gobject_class;
+        GduSectionClass *section_class;
+
+        gobject_class = G_OBJECT_CLASS (klass);
+        section_class = GDU_SECTION_CLASS (klass);
+
+        gobject_class->finalize    = gdu_section_hba_finalize;
+        gobject_class->constructed = gdu_section_hba_constructed;
+        section_class->update      = gdu_section_hba_update;
+
+        g_type_class_add_private (klass, sizeof (GduSectionHbaPrivate));
+}
+
+static void
+gdu_section_hba_init (GduSectionHba *section)
+{
+        section->priv = G_TYPE_INSTANCE_GET_PRIVATE (section, GDU_TYPE_SECTION_HBA, GduSectionHbaPrivate);
+}
+
+GtkWidget *
+gdu_section_hba_new (GduShell       *shell,
+                     GduPresentable *presentable)
+{
+        return GTK_WIDGET (g_object_new (GDU_TYPE_SECTION_HBA,
+                                         "shell", shell,
+                                         "presentable", presentable,
+                                         NULL));
+}
diff --git a/src/palimpsest/gdu-section-hba.h b/src/palimpsest/gdu-section-hba.h
new file mode 100644
index 0000000..1962152
--- /dev/null
+++ b/src/palimpsest/gdu-section-hba.h
@@ -0,0 +1,58 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- */
+/* gdu-section-hba.h
+ *
+ * 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 <gtk/gtk.h>
+#include "gdu-section.h"
+
+#ifndef GDU_SECTION_HBA_H
+#define GDU_SECTION_HBA_H
+
+#define GDU_TYPE_SECTION_HBA           (gdu_section_hba_get_type ())
+#define GDU_SECTION_HBA(o)             (G_TYPE_CHECK_INSTANCE_CAST ((o), GDU_TYPE_SECTION_HBA, GduSectionHba))
+#define GDU_SECTION_HBA_CLASS(k)       (G_TYPE_CHECK_CLASS_CAST ((k), GDU_TYPE_SECTION_HBA,  GduSectionHbaClass))
+#define GDU_IS_SECTION_HBA(o)          (G_TYPE_CHECK_INSTANCE_TYPE ((o), GDU_TYPE_SECTION_HBA))
+#define GDU_IS_SECTION_HBA_CLASS(k)    (G_TYPE_CHECK_CLASS_TYPE ((k), GDU_TYPE_SECTION_HBA))
+#define GDU_SECTION_HBA_GET_CLASS(o)   (G_TYPE_INSTANCE_GET_CLASS ((o), GDU_TYPE_SECTION_HBA, GduSectionHbaClass))
+
+typedef struct _GduSectionHbaClass       GduSectionHbaClass;
+typedef struct _GduSectionHba            GduSectionHba;
+
+struct _GduSectionHbaPrivate;
+typedef struct _GduSectionHbaPrivate     GduSectionHbaPrivate;
+
+struct _GduSectionHba
+{
+        GduSection parent;
+
+        /* private */
+        GduSectionHbaPrivate *priv;
+};
+
+struct _GduSectionHbaClass
+{
+        GduSectionClass parent_class;
+};
+
+GType            gdu_section_hba_get_type (void);
+GtkWidget       *gdu_section_hba_new      (GduShell       *shell,
+                                           GduPresentable *presentable);
+
+#endif /* GDU_SECTION_HBA_H */
diff --git a/src/palimpsest/gdu-shell.c b/src/palimpsest/gdu-shell.c
index 4e4bde2..9c37727 100644
--- a/src/palimpsest/gdu-shell.c
+++ b/src/palimpsest/gdu-shell.c
@@ -45,7 +45,7 @@
 #include "gdu-section-no-media.h"
 #include "gdu-section-drive.h"
 #include "gdu-section-volumes.h"
-#include "bling-spinner.h"
+#include "gdu-section-hba.h"
 
 struct _GduShellPrivate
 {
@@ -54,20 +54,8 @@ struct _GduShellPrivate
 
         GtkWidget *tree_view;
 
-        GtkWidget *icon_image;
-        GtkWidget *name_label;
-        GtkWidget *details0_label;
-        GtkWidget *details1_label;
-        GtkWidget *details2_label;
-        GtkWidget *details3_label;
-
         /* -------------------------------------------------------------------------------- */
 
-        GtkWidget *job_bar;
-        GtkWidget *job_description_label;
-        GtkWidget *job_progress_bar;
-        GtkWidget *job_spinner;
-
         GtkWidget *sections_vbox;
 
         /* -------------------------------------------------------------------------------- */
@@ -196,347 +184,6 @@ gdu_shell_select_presentable (GduShell *shell, GduPresentable *presentable)
 
 /* ---------------------------------------------------------------------------------------------------- */
 
-static gboolean
-details_update (GduShell *shell)
-{
-        GduPresentable *presentable;
-        gboolean ret;
-        char *s;
-        char *p;
-        char *detail_color;
-        char *name;
-        GIcon *icon;
-        GdkPixbuf *pixbuf;
-        GduDevice *device;
-        const char *usage;
-        const char *type;
-        const char *device_file;
-        guint64 presentable_size;
-        char *strsize_long;
-        GduPresentable *toplevel_presentable;
-        GduDevice *toplevel_device;
-        GPtrArray *details;
-        guint n;
-
-        ret = TRUE;
-
-        details = g_ptr_array_new ();
-
-        presentable = shell->priv->presentable_now_showing;
-
-        device = gdu_presentable_get_device (presentable);
-
-        toplevel_presentable = gdu_presentable_get_toplevel (presentable);
-        if (toplevel_presentable != NULL)
-                toplevel_device = gdu_presentable_get_device (toplevel_presentable);
-
-        icon = gdu_presentable_get_icon (presentable);
-        name = gdu_presentable_get_name (presentable);
-
-        pixbuf = gdu_util_get_pixbuf_for_presentable_at_pixel_size (presentable, 112);
-        gtk_image_set_from_pixbuf (GTK_IMAGE (shell->priv->icon_image), pixbuf);
-        g_object_unref (pixbuf);
-
-        s = g_strdup_printf ("<span font_desc='18'><b>%s</b></span>", name);
-        gtk_label_set_markup (GTK_LABEL (shell->priv->name_label), s);
-        g_free (s);
-
-        usage = NULL;
-        type = NULL;
-        device_file = NULL;
-        if (device != NULL) {
-                usage = gdu_device_id_get_usage (device);
-                type = gdu_device_id_get_type (device);
-                device_file = gdu_device_get_device_file (device);
-        }
-
-        presentable_size = gdu_presentable_get_size (presentable);
-        if (presentable_size > 0) {
-                strsize_long = gdu_util_get_size_for_display (presentable_size,
-                                                              FALSE,
-                                                              TRUE);
-        } else {
-                strsize_long = g_strdup (_("Unknown Size"));
-        }
-
-        if (GDU_IS_DRIVE (presentable)) {
-
-                g_ptr_array_add (details,
-                                 g_strdup (strsize_long));
-
-                if (device == NULL) {
-                        /* TODO */
-                } else {
-                        if (gdu_device_is_removable (device)) {
-                                if (gdu_device_is_partition_table (device)) {
-                                        const char *scheme;
-                                        scheme = gdu_device_partition_table_get_scheme (device);
-                                        if (strcmp (scheme, "apm") == 0) {
-                                                s = g_strdup (_("Apple Partition Map"));
-                                        } else if (strcmp (scheme, "mbr") == 0) {
-                                                s = g_strdup (_("Master Boot Record"));
-                                        } else if (strcmp (scheme, "gpt") == 0) {
-                                                s = g_strdup (_("GUID Partition Table"));
-                                        } else {
-                                                /* Translators: 'scheme' refers to a partition table format here, like 'mbr' or 'gpt' */
-                                                s = g_strdup_printf (_("Unknown Scheme: %s"), scheme);
-                                        }
-
-                                        g_ptr_array_add (details,
-                                                         /* Translators: %s is the name of the partition table format, like 'Master Boot Record' */
-                                                         g_strdup_printf (_("Partitioned Media (%s)"), s));
-
-                                        g_free (s);
-                                } else if (usage != NULL && strlen (usage) > 0) {
-                                        g_ptr_array_add (details,
-                                                         g_strdup (_("Unpartitioned Media")));
-                                } else if (!gdu_device_is_media_available (device)) {
-                                        g_ptr_array_add (details,
-                                                         g_strdup_printf (_("No Media Detected")));
-                                } else {
-                                        g_ptr_array_add (details,
-                                                         g_strdup_printf (_("Unrecognized")));
-                                }
-                        } else {
-                                if (gdu_device_is_partition_table (device)) {
-                                        const char *scheme;
-                                        scheme = gdu_device_partition_table_get_scheme (device);
-                                        if (strcmp (scheme, "apm") == 0) {
-                                                s = g_strdup (_("Apple Partition Map"));
-                                        } else if (strcmp (scheme, "mbr") == 0) {
-                                                s = g_strdup (_("Master Boot Record"));
-                                        } else if (strcmp (scheme, "gpt") == 0) {
-                                                s = g_strdup (_("GUID Partition Table"));
-                                        } else {
-                                                s = g_strdup_printf (_("Unknown Scheme: %s"), scheme);
-                                        }
-                                        g_ptr_array_add (details, s);
-                                } else if (usage != NULL && strlen (usage) > 0) {
-                                        g_ptr_array_add (details,
-                                                         g_strdup_printf (_("Not Partitioned")));
-                                } else if (!gdu_device_is_media_available (device)) {
-                                        g_ptr_array_add (details,
-                                                         g_strdup_printf (_("No Media Detected")));
-                                } else {
-                                        g_ptr_array_add (details,
-                                                         g_strdup_printf (_("Unrecognized")));
-                                }
-                        }
-                }
-
-                if (GDU_IS_LINUX_MD_DRIVE (presentable)) {
-                        g_ptr_array_add (details,
-                                         g_strdup (_("Linux Software RAID")));
-                } else {
-                        if (gdu_device_drive_ata_smart_get_is_available (device) &&
-                            gdu_device_drive_ata_smart_get_time_collected (device) > 0) {
-                                gchar *smart_status;
-                                gchar *status_desc;
-                                gboolean highlight;
-                                gboolean rtl;
-
-                                rtl = (gtk_widget_get_direction (GTK_WIDGET (shell->priv->app_window)) == GTK_TEXT_DIR_RTL);
-
-                                status_desc = gdu_util_ata_smart_status_to_desc (gdu_device_drive_ata_smart_get_status (device),
-                                                                                 &highlight,
-                                                                                 NULL,
-                                                                                 NULL);
-                                /* Translators: the %s is the SMART status of the disk e.g. 'Healthy' */
-                                if (highlight) {
-                                        s = g_strdup_printf ("<span fgcolor=\"red\"><b>%s</b></span>", status_desc);
-                                        g_free (status_desc);
-                                        status_desc = s;
-                                }
-                                smart_status = g_strdup_printf (_("SMART status: %s"),
-                                                                status_desc);
-                                g_free (status_desc);
-
-                                s = g_strdup_printf (rtl ? "<a href=\"gnome-disk-utility://show-smart\" title=\"%2$s\">%3$s</a> â?? %1$s" :
-                                                     "%s â?? <a href=\"gnome-disk-utility://show-smart\" title=\"%s\">%s</a>",
-                                                     smart_status,
-                                                     /* Translators: this the SMART hyperlink tooltip */
-                                                     _("View details about SMART for this disk"),
-                                                     /* Translators: this is the text for the SMART hyperlink */
-                                                     _("More Information"));
-                                g_free (smart_status);
-
-                                g_ptr_array_add (details, s);
-
-                        } else {
-                                g_ptr_array_add (details, g_strdup (_("SMART is not available")));
-                        }
-                }
-
-                if (device_file != NULL) {
-                        if (gdu_device_is_read_only (device)) {
-                        /* Translators: %s is the device file */
-                        g_ptr_array_add (details,
-                                         g_strdup_printf (_("%s (Read Only)"), device_file));
-                        } else {
-                        g_ptr_array_add (details,
-                                         g_strdup (device_file));
-                        }
-                } else {
-                        g_ptr_array_add (details,
-                                         g_strdup (_("Not running")));
-                }
-
-        } else if (GDU_IS_VOLUME (presentable)) {
-
-                g_ptr_array_add (details,
-                                 g_strdup (strsize_long));
-
-                if (strcmp (usage, "filesystem") == 0) {
-                        char *fsname;
-                        fsname = gdu_util_get_fstype_for_display (
-                                gdu_device_id_get_type (device),
-                                gdu_device_id_get_version (device),
-                                TRUE);
-                        /* Translators: %s is the filesystem name */
-                        g_ptr_array_add (details,
-                                         g_strdup_printf (_("%s File System"), fsname));
-                        g_free (fsname);
-                } else if (strcmp (usage, "raid") == 0) {
-                        char *fsname;
-                        fsname = gdu_util_get_fstype_for_display (
-                                gdu_device_id_get_type (device),
-                                gdu_device_id_get_version (device),
-                                TRUE);
-                        g_ptr_array_add (details, fsname);
-                } else if (strcmp (usage, "crypto") == 0) {
-                        g_ptr_array_add (details,
-                                         g_strdup (_("Encrypted LUKS Device")));
-                } else if (strcmp (usage, "other") == 0) {
-                        if (strcmp (type, "swap") == 0) {
-                                g_ptr_array_add (details,
-                                                 g_strdup (_("Swap Space")));
-                        } else {
-                                g_ptr_array_add (details,
-                                                 g_strdup (_("Data")));
-                        }
-                } else {
-                        g_ptr_array_add (details,
-                                         g_strdup (_("Unrecognized")));
-                }
-
-                if (gdu_device_is_luks_cleartext (device)) {
-                        g_ptr_array_add (details,
-                                         g_strdup (_("Cleartext LUKS Device")));
-                } else {
-                        if (gdu_device_is_partition (device)) {
-                                char *part_desc;
-                                part_desc = gdu_util_get_desc_for_part_type (gdu_device_partition_get_scheme (device),
-                                                                             gdu_device_partition_get_type (device));
-                                g_ptr_array_add (details,
-                                                 g_strdup_printf (_("Partition %d (%s)"),
-                                                                  gdu_device_partition_get_number (device), part_desc));
-                                g_free (part_desc);
-                        } else {
-                                g_ptr_array_add (details,
-                                                 g_strdup (_("Not Partitioned")));
-                        }
-                }
-
-                s = g_strdup (device_file);
-                if (gdu_device_is_read_only (device)) {
-                        p = s;
-                        s = g_strdup_printf (_("%s (Read Only)"), s);
-                        g_free (p);
-                }
-
-                if (gdu_device_is_mounted (device)) {
-                        gchar **mount_paths;
-                        GString *str;
-
-                        mount_paths = gdu_device_get_mount_paths (device);
-
-                        str = g_string_new (s);
-                        g_free (s);
-                        g_string_append (str, _(" mounted at "));
-                        for (n = 0; mount_paths[n] != NULL; n++) {
-                                if (n > 0)
-                                        g_string_append (str, ", ");
-                                g_string_append_printf (str, "<a href=\"file://%s\">%s</a>",
-                                                        mount_paths[n],
-                                                        mount_paths[n]);
-                        }
-                        s = g_string_free (str, FALSE);
-                }
-                g_ptr_array_add (details, s);
-
-
-        } else if (GDU_IS_VOLUME_HOLE (presentable)) {
-
-                g_ptr_array_add (details,
-                                 g_strdup (strsize_long));
-
-                g_ptr_array_add (details,
-                                 g_strdup (_("Unallocated Space")));
-
-                if (toplevel_device != NULL) {
-                        if (gdu_device_is_read_only (toplevel_device))
-                                g_ptr_array_add (details, g_strdup_printf (_("%s (Read Only)"), gdu_device_get_device_file (toplevel_device)));
-                        else
-                                g_ptr_array_add (details, g_strdup (gdu_device_get_device_file (toplevel_device)));
-                }
-        }
-
-        /* TODO: use symbolic colors (how?) or infer from current theme */
-        detail_color = g_strdup ("#808080");
-
-        for (n = 0; n < 4; n++) {
-                GtkWidget *label;
-                const gchar *detail_str;
-
-                switch (n) {
-                case 0:
-                        label = shell->priv->details0_label;
-                        break;
-                case 1:
-                        label = shell->priv->details1_label;
-                        break;
-                case 2:
-                        label = shell->priv->details2_label;
-                        break;
-                case 3:
-                        label = shell->priv->details3_label;
-                        break;
-                }
-
-                if (n < details->len)
-                        detail_str = details->pdata[n];
-                else
-                        detail_str = "";
-
-                s = g_strdup_printf ("<span foreground='%s'>%s</span>", detail_color, detail_str);
-                gtk_label_set_markup (GTK_LABEL (label), s);
-                gtk_label_set_track_visited_links (GTK_LABEL (label), FALSE);
-                g_free (s);
-        }
-
-        if (icon != NULL)
-                g_object_unref (icon);
-        g_free (name);
-        g_free (strsize_long);
-
-        g_ptr_array_foreach (details, (GFunc) g_free, NULL);
-        g_ptr_array_free (details, TRUE);
-        g_free (detail_color);
-
-        if (device != NULL)
-                g_object_unref (device);
-
-        if (toplevel_presentable != NULL)
-                g_object_unref (toplevel_presentable);
-
-        if (toplevel_device != NULL)
-                g_object_unref (toplevel_device);
-
-        return ret;
-}
-
-/* ---------------------------------------------------------------------------------------------------- */
-
 static void
 remove_section (GtkWidget *widget, gpointer callback_data)
 {
@@ -558,7 +205,11 @@ compute_sections_to_show (GduShell *shell)
         sections_to_show = NULL;
         device = gdu_presentable_get_device (shell->priv->presentable_now_showing);
 
-        if (GDU_IS_LINUX_MD_DRIVE (shell->priv->presentable_now_showing)) {
+        if (GDU_IS_HBA (shell->priv->presentable_now_showing)) {
+
+                sections_to_show = g_list_append (sections_to_show, (gpointer) GDU_TYPE_SECTION_HBA);
+
+        } else if (GDU_IS_LINUX_MD_DRIVE (shell->priv->presentable_now_showing)) {
 
                 sections_to_show = g_list_append (sections_to_show, (gpointer) GDU_TYPE_SECTION_LINUX_MD_DRIVE);
                 sections_to_show = g_list_append (sections_to_show, (gpointer) GDU_TYPE_SECTION_VOLUMES);
@@ -630,26 +281,6 @@ compute_sections_to_show (GduShell *shell)
         return sections_to_show;
 }
 
-static void
-on_job_bar_response (GtkInfoBar *info_bar,
-                     gint        response_id,
-                     gpointer    user_data)
-{
-        GduShell *shell = GDU_SHELL (user_data);
-
-        if (response_id == GTK_RESPONSE_CANCEL) {
-                if (shell->priv->presentable_now_showing != NULL) {
-                        GduDevice *device;
-
-                        device = gdu_presentable_get_device (shell->priv->presentable_now_showing);
-                        if (device != NULL) {
-                                gdu_device_op_cancel_job (device, NULL, NULL);
-                                g_object_unref (device);
-                        }
-                }
-        }
-}
-
 /* called when a new presentable is selected
  *  - or a presentable changes
  *  - or the job state of a presentable changes
@@ -659,175 +290,15 @@ on_job_bar_response (GtkInfoBar *info_bar,
 void
 gdu_shell_update (GduShell *shell)
 {
-        GduDevice *device;
-        gboolean job_in_progress;
-        gboolean can_mount;
-        gboolean can_unmount;
-        gboolean can_eject;
-        gboolean can_detach;
-        gboolean can_lock;
-        gboolean can_unlock;
-        gboolean can_start;
-        gboolean can_stop;
-        gboolean can_fsck;
-        gboolean can_erase;
         static GduPresentable *last_presentable = NULL;
         gboolean reset_sections;
         GList *sections_to_show;
-        uid_t unlocked_by_uid;
-
-        job_in_progress = FALSE;
-        can_mount = FALSE;
-        can_fsck = FALSE;
-        can_unmount = FALSE;
-        can_eject = FALSE;
-        can_detach = FALSE;
-        can_unlock = FALSE;
-        can_lock = FALSE;
-        unlocked_by_uid = 0;
-        can_start = FALSE;
-        can_stop = FALSE;
-        can_erase = FALSE;
-
-        device = gdu_presentable_get_device (shell->priv->presentable_now_showing);
-        if (device != NULL) {
-                if (gdu_device_job_in_progress (device)) {
-                        job_in_progress = TRUE;
-                }
-
-                if (GDU_IS_VOLUME (shell->priv->presentable_now_showing)) {
-
-                        if (strcmp (gdu_device_id_get_usage (device), "filesystem") == 0) {
-                                GduKnownFilesystem *kfs;
-
-                                kfs = gdu_pool_get_known_filesystem_by_id (shell->priv->pool,
-                                                                           gdu_device_id_get_type (device));
-
-                                if (gdu_device_is_mounted (device)) {
-                                        can_unmount = TRUE;
-                                        if (kfs != NULL && gdu_known_filesystem_get_supports_online_fsck (kfs))
-                                                can_fsck = TRUE;
-                                } else {
-                                        can_mount = TRUE;
-                                        can_erase = TRUE;
-                                        if (kfs != NULL && gdu_known_filesystem_get_supports_fsck (kfs))
-                                                can_fsck = TRUE;
-                                }
-                        } else if (strcmp (gdu_device_id_get_usage (device), "crypto") == 0) {
-                                GList *enclosed_presentables;
-                                enclosed_presentables = gdu_pool_get_enclosed_presentables (
-                                        shell->priv->pool,
-                                        shell->priv->presentable_now_showing);
-                                if (enclosed_presentables != NULL && g_list_length (enclosed_presentables) == 1) {
-                                        GduPresentable *enclosed_presentable;
-                                        GduDevice *enclosed_device;
-
-                                        can_lock = TRUE;
-
-                                        enclosed_presentable = GDU_PRESENTABLE (enclosed_presentables->data);
-                                        enclosed_device = gdu_presentable_get_device (enclosed_presentable);
-                                        unlocked_by_uid = gdu_device_luks_cleartext_unlocked_by_uid (enclosed_device);
-                                        g_object_unref (enclosed_device);
-                                } else {
-                                        can_unlock = TRUE;
-                                        can_erase = TRUE;
-                                }
-                                g_list_foreach (enclosed_presentables, (GFunc) g_object_unref, NULL);
-                                g_list_free (enclosed_presentables);
-                        } else {
-                                can_erase = TRUE;
-                        }
-                }
-
-                if (GDU_IS_DRIVE (shell->priv->presentable_now_showing)) {
-                        if (gdu_device_is_removable (device) &&
-                            gdu_device_is_media_available (device))
-                                can_eject = TRUE;
-
-                        if (gdu_device_drive_get_can_detach (device))
-                                can_detach = TRUE;
-
-                        can_erase = TRUE;
-                        if (gdu_drive_is_activatable (GDU_DRIVE (shell->priv->presentable_now_showing)) &&
-                            !gdu_drive_is_active (GDU_DRIVE (shell->priv->presentable_now_showing)))
-                                can_erase = FALSE;
-                }
-        }
-
-        if (GDU_IS_DRIVE (shell->priv->presentable_now_showing) &&
-            gdu_drive_is_activatable (GDU_DRIVE (shell->priv->presentable_now_showing))) {
-                GduDrive *drive = GDU_DRIVE (shell->priv->presentable_now_showing);
-
-                can_stop = gdu_drive_can_deactivate (drive);
-
-                can_start = gdu_drive_can_activate (drive, NULL);
-        }
-
-        gtk_action_set_sensitive (gtk_action_group_get_action (shell->priv->action_group, "mount"), can_mount);
-        gtk_action_set_sensitive (gtk_action_group_get_action (shell->priv->action_group, "unmount"), can_unmount);
-        gtk_action_set_sensitive (gtk_action_group_get_action (shell->priv->action_group, "eject"), can_eject);
-        gtk_action_set_sensitive (gtk_action_group_get_action (shell->priv->action_group, "detach"), can_detach);
-        gtk_action_set_sensitive (gtk_action_group_get_action (shell->priv->action_group, "fsck"), can_fsck);
-        gtk_action_set_sensitive (gtk_action_group_get_action (shell->priv->action_group, "lock"), can_lock);
-        gtk_action_set_sensitive (gtk_action_group_get_action (shell->priv->action_group, "unlock"), can_unlock);
-        gtk_action_set_sensitive (gtk_action_group_get_action (shell->priv->action_group, "start"), can_start);
-        gtk_action_set_sensitive (gtk_action_group_get_action (shell->priv->action_group, "stop"), can_stop);
-        gtk_action_set_sensitive (gtk_action_group_get_action (shell->priv->action_group, "erase"), can_erase);
 
         reset_sections = (shell->priv->presentable_now_showing != last_presentable);
 
         last_presentable = shell->priv->presentable_now_showing;
 
         sections_to_show = compute_sections_to_show (shell);
-        if (GDU_IS_DRIVE (shell->priv->presentable_now_showing)) {
-                gtk_widget_hide (shell->priv->icon_image);
-                gtk_widget_hide (shell->priv->name_label);
-                gtk_widget_hide (shell->priv->details0_label);
-                gtk_widget_hide (shell->priv->details1_label);
-                gtk_widget_hide (shell->priv->details2_label);
-                gtk_widget_hide (shell->priv->details3_label);
-        } else {
-                gtk_widget_show (shell->priv->icon_image);
-                gtk_widget_show (shell->priv->name_label);
-                gtk_widget_show (shell->priv->details0_label);
-                gtk_widget_show (shell->priv->details1_label);
-                gtk_widget_show (shell->priv->details2_label);
-                gtk_widget_show (shell->priv->details3_label);
-        }
-
-        if (job_in_progress) {
-                gchar *desc;
-                gchar *s;
-                gdouble percentage;
-
-                desc = gdu_get_job_description (gdu_device_job_get_id (device));
-
-                s = g_strdup_printf ("<small><b>%s</b></small>", desc);
-                gtk_label_set_markup (GTK_LABEL (shell->priv->job_description_label), s);
-                g_free (s);
-                g_free (desc);
-
-                gtk_widget_set_no_show_all (shell->priv->job_bar, FALSE);
-                gtk_widget_show_all (shell->priv->job_bar);
-
-                gtk_info_bar_set_response_sensitive (GTK_INFO_BAR (shell->priv->job_bar),
-                                                     GTK_RESPONSE_CANCEL,
-                                                     gdu_device_job_is_cancellable (device));
-
-                percentage = gdu_device_job_get_percentage (device);
-                if (percentage >= 0) {
-                        gtk_progress_bar_set_fraction (GTK_PROGRESS_BAR (shell->priv->job_progress_bar),
-                                                       percentage / 100.0);
-                        gtk_widget_hide (shell->priv->job_spinner);
-                } else {
-                        bling_spinner_start (BLING_SPINNER (shell->priv->job_spinner));
-                        gtk_widget_hide (shell->priv->job_progress_bar);
-                }
-
-        } else {
-                bling_spinner_stop (BLING_SPINNER (shell->priv->job_spinner));
-                gtk_widget_hide_all (shell->priv->job_bar);
-        }
 
         /* if this differs from what we currently show, prompt a reset */
         if (!reset_sections) {
@@ -881,11 +352,6 @@ gdu_shell_update (GduShell *shell)
         gtk_container_foreach (GTK_CONTAINER (shell->priv->sections_vbox),
                                update_section,
                                shell);
-
-        details_update (shell);
-
-        if (device != NULL)
-                g_object_unref (device);
 }
 
 static GduSection *
@@ -2240,33 +1706,6 @@ gdu_shell_raise_error (GduShell       *shell,
 }
 
 static void
-on_activate_link_for_details_label (GtkLabel    *label,
-                                    const gchar *uri,
-                                    gpointer     user_data)
-{
-        GduShell *shell = GDU_SHELL (user_data);
-
-        if (g_str_has_prefix (uri, "gnome-disk-utility://")) {
-
-                if (g_strcmp0 (uri, "gnome-disk-utility://show-smart") == 0) {
-                        if (GDU_IS_DRIVE (shell->priv->presentable_now_showing)) {
-                                GtkWidget *dialog;
-
-                                dialog = gdu_ata_smart_dialog_new (GTK_WINDOW (shell->priv->app_window),
-                                                                   GDU_DRIVE (shell->priv->presentable_now_showing));
-                                gtk_widget_show_all (dialog);
-                                gtk_dialog_run (GTK_DIALOG (dialog));
-                                gtk_widget_destroy (dialog);
-                        } else {
-                                g_warning ("Trying to show ATA SMART dialog for presentable that is not a drive");
-                        }
-                }
-
-                g_signal_stop_emission_by_name (label, "activate-link");
-        }
-}
-
-static void
 create_window (GduShell *shell)
 {
         GtkWidget *vbox;
@@ -2277,13 +1716,7 @@ create_window (GduShell *shell)
         GtkWidget *hpane;
         GtkWidget *tree_view_scrolled_window;
         GtkTreeSelection *select;
-        GtkWidget *content_area;
-        GtkWidget *button;
         GtkWidget *label;
-        GtkWidget *align;
-        GtkWidget *vbox3;
-        GtkWidget *hbox;
-        GtkWidget *image;
         GduPoolTreeModel *model;
         GtkTreeViewColumn *column;
 
@@ -2326,98 +1759,12 @@ create_window (GduShell *shell)
 
         /* --- */
 
-        shell->priv->job_bar = gtk_info_bar_new ();
-        button = gtk_button_new ();
-        label = gtk_label_new (NULL);
-        gtk_label_set_markup_with_mnemonic (GTK_LABEL (label),
-                                            _("<small>_Cancel</small>"));
-        gtk_container_add (GTK_CONTAINER (button), label);
-        gtk_info_bar_add_action_widget (GTK_INFO_BAR (shell->priv->job_bar),
-                                        button,
-                                        GTK_RESPONSE_CANCEL);
-        g_signal_connect (shell->priv->job_bar,
-                          "response",
-                          G_CALLBACK (on_job_bar_response),
-                          shell);
-        gtk_widget_set_no_show_all (shell->priv->job_bar, TRUE);
-        gtk_info_bar_set_message_type (GTK_INFO_BAR (shell->priv->job_bar),
-                                       GTK_MESSAGE_INFO);
-        gtk_box_pack_start (GTK_BOX (vbox1), shell->priv->job_bar, FALSE, FALSE, 0);
-
-        content_area = gtk_info_bar_get_content_area (GTK_INFO_BAR (shell->priv->job_bar));
-        shell->priv->job_description_label = gtk_label_new (NULL);
-        gtk_misc_set_alignment (GTK_MISC (shell->priv->job_description_label), 0.0, 0.5);
-        gtk_box_pack_start (GTK_BOX (content_area), shell->priv->job_description_label, FALSE, FALSE, 0);
-        shell->priv->job_progress_bar = gtk_progress_bar_new ();
-        gtk_box_pack_start (GTK_BOX (content_area), shell->priv->job_progress_bar, FALSE, FALSE, 0);
-
-        shell->priv->job_spinner = bling_spinner_new ();
-        gtk_widget_set_size_request (shell->priv->job_spinner, 16, 16);
-        gtk_box_pack_start (GTK_BOX (content_area), shell->priv->job_spinner, FALSE, FALSE, 0);
-
-        /* --- */
-
         vbox2 = gtk_vbox_new (FALSE, 0);
         //gtk_container_set_border_width (GTK_CONTAINER (vbox2), 12);
         gtk_box_pack_start (GTK_BOX (vbox1), vbox2, TRUE, TRUE, 0);
 
         /* --- */
 
-        hbox = gtk_hbox_new (FALSE, 12);
-        gtk_box_pack_start (GTK_BOX (vbox2), hbox, FALSE, TRUE, 0);
-
-        image = gtk_image_new ();
-        gtk_box_pack_start (GTK_BOX (hbox), image, FALSE, TRUE, 0);
-        shell->priv->icon_image = image;
-
-        vbox3 = gtk_vbox_new (FALSE, 0);
-        align = gtk_alignment_new (0.0, 0.5, 0.0, 0.0);
-        gtk_container_add (GTK_CONTAINER (align), vbox3);
-        gtk_box_pack_start (GTK_BOX (hbox), align, FALSE, TRUE, 0);
-
-        label = gtk_label_new (NULL);
-        gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
-        gtk_box_pack_start (GTK_BOX (vbox3), label, FALSE, TRUE, 0);
-        shell->priv->name_label = label;
-
-        label = gtk_label_new (NULL);
-        gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
-        gtk_box_pack_start (GTK_BOX (vbox3), label, FALSE, TRUE, 0);
-        g_signal_connect (label,
-                          "activate-link",
-                          G_CALLBACK (on_activate_link_for_details_label),
-                          shell);
-        shell->priv->details0_label = label;
-
-        label = gtk_label_new (NULL);
-        gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
-        gtk_box_pack_start (GTK_BOX (vbox3), label, FALSE, TRUE, 0);
-        g_signal_connect (label,
-                          "activate-link",
-                          G_CALLBACK (on_activate_link_for_details_label),
-                          shell);
-        shell->priv->details1_label = label;
-
-        label = gtk_label_new (NULL);
-        gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
-        gtk_box_pack_start (GTK_BOX (vbox3), label, FALSE, TRUE, 0);
-        g_signal_connect (label,
-                          "activate-link",
-                          G_CALLBACK (on_activate_link_for_details_label),
-                          shell);
-        shell->priv->details2_label = label;
-
-        label = gtk_label_new (NULL);
-        gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
-        gtk_box_pack_start (GTK_BOX (vbox3), label, FALSE, TRUE, 0);
-        g_signal_connect (label,
-                          "activate-link",
-                          G_CALLBACK (on_activate_link_for_details_label),
-                          shell);
-        shell->priv->details3_label = label;
-
-        /* --- */
-
         shell->priv->sections_vbox = gtk_vbox_new (FALSE, 12);
         gtk_container_set_border_width (GTK_CONTAINER (shell->priv->sections_vbox), 6);
         gtk_box_pack_start (GTK_BOX (vbox2), shell->priv->sections_vbox, TRUE, TRUE, 0);



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