[gnome-disk-utility] port to new DeviceKit-disks that uses libatasmart



commit 74b935d6ac6a2b856ba30ed320ccee15ff3acc3a
Author: David Zeuthen <davidz redhat com>
Date:   Mon Mar 23 19:15:42 2009 -0400

    port to new DeviceKit-disks that uses libatasmart
---
 src/gdu-gtk/Makefile.am                 |   16 +-
 src/gdu-gtk/gdu-gtk-types.h             |   39 +++
 src/gdu-gtk/gdu-gtk.h                   |    6 +-
 src/gdu-gtk/gdu-time-label.c            |  230 +++++++++++++
 src/gdu-gtk/gdu-time-label.h            |   60 ++++
 src/gdu/Makefile.am                     |    8 +-
 src/gdu/gdu-ata-smart-attribute.c       |  446 ++++++++++++++++++++++++
 src/gdu/gdu-ata-smart-attribute.h       |   86 +++++
 src/gdu/gdu-ata-smart-historical-data.c |  181 ++++++++++
 src/gdu/gdu-ata-smart-historical-data.h |   72 ++++
 src/gdu/gdu-callbacks.h                 |   24 +-
 src/gdu/gdu-device.c                    |  361 +++++++++++++++------
 src/gdu/gdu-device.h                    |   70 +++-
 src/gdu/gdu-private.h                   |   51 ++--
 src/gdu/gdu-smart-data-attribute.c      |  395 ---------------------
 src/gdu/gdu-smart-data-attribute.h      |   71 ----
 src/gdu/gdu-smart-data.c                |  231 -------------
 src/gdu/gdu-smart-data.h                |   72 ----
 src/gdu/gdu-types.h                     |   24 +-
 src/gdu/gdu.h                           |    4 +-
 src/palimpsest/Makefile.am              |    1 -
 src/palimpsest/gdu-section-health.c     |  566 ++++++++++++++++++-------------
 src/palimpsest/gdu-shell.c              |    2 +-
 src/palimpsest/gdu-time-label.c         |  225 ------------
 src/palimpsest/gdu-time-label.h         |   60 ----
 25 files changed, 1839 insertions(+), 1462 deletions(-)

diff --git a/src/gdu-gtk/Makefile.am b/src/gdu-gtk/Makefile.am
index cf84363..a2c2806 100644
--- a/src/gdu-gtk/Makefile.am
+++ b/src/gdu-gtk/Makefile.am
@@ -1,13 +1,21 @@
 
+NULL =
+
 lib_LTLIBRARIES=libgdu-gtk.la
 
 libgdu_gtkincludedir=$(includedir)/gnome-disk-utility/gdu-gtk
 
-libgdu_gtkinclude_HEADERS =              		\
-	gdu-gtk.h
+libgdu_gtkinclude_HEADERS =              				\
+	gdu-gtk.h							\
+	gdu-gtk-types.h							\
+	gdu-time-label.h						\
+	$(NULL)
 
-libgdu_gtk_la_SOURCES =                                	\
-	gdu-gtk.h		gdu-gtk.c
+libgdu_gtk_la_SOURCES =                 	               		\
+	gdu-gtk.h			gdu-gtk.c			\
+	gdu-gtk-types.h							\
+	gdu-time-label.h		gdu-time-label.c		\
+	$(NULL)
 
 libgdu_gtk_la_CPPFLAGS = 				\
 	-I$(top_srcdir)/src				\
diff --git a/src/gdu-gtk/gdu-gtk-types.h b/src/gdu-gtk/gdu-gtk-types.h
new file mode 100644
index 0000000..50dd6a1
--- /dev/null
+++ b/src/gdu-gtk/gdu-gtk-types.h
@@ -0,0 +1,39 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- */
+/* gdu-drive.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.
+ */
+
+#if !defined (__GDU_GTK_INSIDE_GDU_GTK_H) && !defined (GDU_GTK_COMPILATION)
+#error "Only <gdu-gtk/gdu-gtk.h> can be included directly, this file may disappear or change contents."
+#endif
+
+#ifndef __GDU_GTK_TYPES_H
+#define __GDU_GTK_TYPES_H
+
+#include <glib-object.h>
+#include <gdu/gdu.h>
+#include <gtk/gtk.h>
+
+G_BEGIN_DECLS
+
+typedef struct GduTimeLabel             GduTimeLabel;
+
+G_END_DECLS
+
+#endif /* __GDU_GTK_TYPES_H */
diff --git a/src/gdu-gtk/gdu-gtk.h b/src/gdu-gtk/gdu-gtk.h
index 11f050e..0b6052c 100644
--- a/src/gdu-gtk/gdu-gtk.h
+++ b/src/gdu-gtk/gdu-gtk.h
@@ -26,8 +26,10 @@
 #error  libgdu-gtk is unstable API. You must define GDU_GTK_API_IS_SUBJECT_TO_CHANGE before including gdu-gtk/gdu-gtk.h
 #endif
 
-#include <gtk/gtk.h>
-#include <gdu/gdu.h>
+#define __GDU_GTK_INSIDE_GDU_GTK_H
+#include <gdu-gtk/gdu-gtk-types.h>
+#include <gdu-gtk/gdu-time-label.h>
+#undef __GDU_GTK_INSIDE_GDU_GTK_H
 
 G_BEGIN_DECLS
 
diff --git a/src/gdu-gtk/gdu-time-label.c b/src/gdu-gtk/gdu-time-label.c
new file mode 100644
index 0000000..d9b9e44
--- /dev/null
+++ b/src/gdu-gtk/gdu-time-label.c
@@ -0,0 +1,230 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- */
+/* gdu-time-label.c
+ *
+ * Copyright (C) 2007 David Zeuthen
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ */
+
+#include <config.h>
+#include <glib/gi18n.h>
+#include <string.h>
+
+#include "gdu-time-label.h"
+
+struct GduTimeLabelPrivate
+{
+        GTimeVal time;
+        guint update_timer_id;
+};
+
+static GObjectClass *parent_class = NULL;
+
+G_DEFINE_TYPE (GduTimeLabel, gdu_time_label, GTK_TYPE_LABEL)
+
+enum {
+        PROP_0,
+        PROP_TIME,
+};
+
+static void do_update (GduTimeLabel *time_label);
+
+static gboolean
+timeout_func (GduTimeLabel *time_label)
+{
+        time_label->priv->update_timer_id = 0;
+        do_update (time_label);
+        return FALSE;
+}
+
+static void
+do_update (GduTimeLabel *time_label)
+{
+        char *s;
+        GTimeVal now;
+        int age;
+        int next_update;
+
+        next_update = -1;
+
+        g_get_current_time (&now);
+
+        age = (int) (now.tv_sec - time_label->priv->time.tv_sec);
+
+        //g_warning ("updating; age=%d was: %s", age, gtk_label_get_label (GTK_LABEL (time_label)));
+
+        if (age < 60) {
+                s = g_strdup_printf (_("Less than a minute ago"));
+                next_update = 60 - age;
+        } else if (age < 60 * 60) {
+                if (age / 60 == 1) {
+                        s = g_strdup_printf (_("1 minute ago"));
+                } else {
+                        s = g_strdup_printf (_("%d minutes ago"), age / 60);
+                }
+                next_update = 60*(age/60 + 1) - age;
+        } else {
+                if (age / 60 / 60 == 1) {
+                        s = g_strdup_printf (_("1 hour ago"));
+                } else {
+                        s = g_strdup_printf (_("%d hours ago"), age / 60 / 60);
+                }
+                next_update = 60*60*(age/(60*60) + 1) - age;
+        }
+        gtk_label_set_text (GTK_LABEL (time_label), s);
+        g_free (s);
+
+        //g_warning ("updating; next=%d now: %s", next_update, gtk_label_get_label (GTK_LABEL (time_label)));
+
+        if (next_update > 0) {
+                if (time_label->priv->update_timer_id > 0)
+                        g_source_remove (time_label->priv->update_timer_id);
+                time_label->priv->update_timer_id =
+                        g_timeout_add_seconds (next_update, (GSourceFunc) timeout_func, time_label);
+        }
+}
+
+static void
+gdu_time_label_set_property (GObject      *object,
+                             guint         prop_id,
+                             const GValue *value,
+                             GParamSpec   *pspec)
+{
+        GduTimeLabel *time_label = GDU_TIME_LABEL (object);
+        GTimeVal *time_val;
+
+        switch (prop_id) {
+        case PROP_TIME:
+                time_val = (GTimeVal *) g_value_get_boxed (value);
+                if (time_val != NULL) {
+                        time_label->priv->time = * time_val;
+                        do_update (time_label);
+                } else {
+                        if (time_label->priv->update_timer_id > 0) {
+                                g_source_remove (time_label->priv->update_timer_id);
+                                time_label->priv->update_timer_id = 0;
+                        }
+                }
+                break;
+
+        default:
+                G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+                break;
+        }
+}
+
+static void
+gdu_time_label_get_property (GObject     *object,
+                             guint        prop_id,
+                             GValue      *value,
+                             GParamSpec  *pspec)
+{
+        GduTimeLabel *time_label = GDU_TIME_LABEL (object);
+
+        switch (prop_id) {
+        case PROP_TIME:
+                g_value_set_boxed (value, &time_label->priv->time);
+                break;
+
+        default:
+                G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+                break;
+    }
+}
+
+static void
+gdu_time_label_finalize (GduTimeLabel *time_label)
+{
+        if (time_label->priv->update_timer_id > 0)
+                g_source_remove (time_label->priv->update_timer_id);
+        if (G_OBJECT_CLASS (parent_class)->finalize)
+                (* G_OBJECT_CLASS (parent_class)->finalize) (G_OBJECT (time_label));
+}
+
+static GTimeVal *
+time_val_copy (GTimeVal *t)
+{
+        GTimeVal *copy;
+
+        copy = NULL;
+
+        if (t == NULL)
+                goto out;
+
+        copy = g_new0 (GTimeVal, 1);
+        memcpy (copy, t, sizeof (GTimeVal));
+
+out:
+        return copy;
+}
+
+static void
+time_val_free (GTimeVal *t)
+{
+        g_free (t);
+}
+
+static void
+gdu_time_label_class_init (GduTimeLabelClass *klass)
+{
+        GObjectClass *obj_class = (GObjectClass *) klass;
+        GType boxed_type;
+
+        parent_class = g_type_class_peek_parent (klass);
+
+        obj_class->finalize = (GObjectFinalizeFunc) gdu_time_label_finalize;
+        obj_class->set_property = gdu_time_label_set_property;
+        obj_class->get_property = gdu_time_label_get_property;
+
+        g_type_class_add_private (klass, sizeof (GduTimeLabelPrivate));
+
+        boxed_type = g_boxed_type_register_static ("GduTimeLabelBoxedGTimeVal",
+                                                   (GBoxedCopyFunc) time_val_copy,
+                                                   (GBoxedFreeFunc) time_val_free);
+
+        /**
+         * GduTimeLabel:time:
+         *
+         * The time (a #GTimeVal) used for computing the label of the string.
+         */
+        g_object_class_install_property (obj_class,
+                                         PROP_TIME,
+                                         g_param_spec_boxed ("time",
+                                                             NULL,
+                                                             NULL,
+                                                             boxed_type,
+                                                             G_PARAM_WRITABLE |
+                                                             G_PARAM_READABLE));
+}
+
+static void
+gdu_time_label_init (GduTimeLabel *time_label)
+{
+        time_label->priv = G_TYPE_INSTANCE_GET_PRIVATE (time_label, GDU_TYPE_TIME_LABEL, GduTimeLabelPrivate);
+}
+
+GtkWidget *
+gdu_time_label_new (GTimeVal *time)
+{
+        return GTK_WIDGET (g_object_new (GDU_TYPE_TIME_LABEL, "time", time, NULL));
+}
+
+void
+gdu_time_label_set_time (GduTimeLabel *time_label, GTimeVal     *time)
+{
+        g_object_set (time_label, "time", time, NULL);
+}
+
diff --git a/src/gdu-gtk/gdu-time-label.h b/src/gdu-gtk/gdu-time-label.h
new file mode 100644
index 0000000..76359a5
--- /dev/null
+++ b/src/gdu-gtk/gdu-time-label.h
@@ -0,0 +1,60 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- */
+/* gdu-time-label.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.
+ */
+
+#if !defined (__GDU_GTK_INSIDE_GDU_GTK_H) && !defined (GDU_GTK_COMPILATION)
+#error "Only <gdu-gtk/gdu-gtk.h> can be included directly, this file may disappear or change contents."
+#endif
+
+#ifndef GDU_TIME_LABEL_H
+#define GDU_TIME_LABEL_H
+
+#include <gdu-gtk/gdu-gtk-types.h>
+
+#define GDU_TYPE_TIME_LABEL             (gdu_time_label_get_type ())
+#define GDU_TIME_LABEL(obj)             (G_TYPE_CHECK_INSTANCE_CAST ((obj), GDU_TYPE_TIME_LABEL, GduTimeLabel))
+#define GDU_TIME_LABEL_CLASS(obj)       (G_TYPE_CHECK_CLASS_CAST ((obj), GDU_TIME_LABEL,  GduTimeLabelClass))
+#define GDU_IS_TIME_LABEL(obj)          (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GDU_TYPE_TIME_LABEL))
+#define GDU_IS_TIME_LABEL_CLASS(obj)    (G_TYPE_CHECK_CLASS_TYPE ((obj), GDU_TYPE_TIME_LABEL))
+#define GDU_TIME_LABEL_GET_CLASS(obj)   (G_TYPE_INSTANCE_GET_CLASS ((obj), GDU_TYPE_TIME_LABEL, GduTimeLabelClass))
+
+typedef struct GduTimeLabelClass       GduTimeLabelClass;
+typedef struct GduTimeLabelPrivate     GduTimeLabelPrivate;
+
+struct GduTimeLabel
+{
+        GtkLabel parent;
+
+        /* private */
+        GduTimeLabelPrivate *priv;
+};
+
+struct GduTimeLabelClass
+{
+        GtkLabelClass parent_class;
+};
+
+
+GType      gdu_time_label_get_type     (void);
+GtkWidget *gdu_time_label_new          (GTimeVal     *time);
+void       gdu_time_label_set_time     (GduTimeLabel *time_label,
+                                        GTimeVal     *time);
+
+#endif /* GDU_TIME_LABEL_H */
diff --git a/src/gdu/Makefile.am b/src/gdu/Makefile.am
index e970c2a..7bd608e 100644
--- a/src/gdu/Makefile.am
+++ b/src/gdu/Makefile.am
@@ -32,8 +32,8 @@ libgduinclude_HEADERS =              			\
 	gdu-pool.h					\
 	gdu-presentable.h				\
 	gdu-process.h					\
-	gdu-smart-data-attribute.h			\
-	gdu-smart-data.h				\
+	gdu-ata-smart-attribute.h			\
+	gdu-ata-smart-historical-data.h			\
 	gdu-util.h					\
 	gdu-volume.h					\
 	gdu-volume-hole.h
@@ -44,8 +44,8 @@ libgdu_la_SOURCES =                                					\
 						gdu-callbacks.h				\
 	gdu-util.h				gdu-util.c				\
 	gdu-pool.c				gdu-pool.h				\
-	gdu-smart-data.c			gdu-smart-data.h			\
-	gdu-smart-data-attribute.c		gdu-smart-data-attribute.h		\
+	gdu-ata-smart-historical-data.c		gdu-ata-smart-historical-data.h		\
+	gdu-ata-smart-attribute.c		gdu-ata-smart-attribute.h		\
 	gdu-device.c				gdu-device.h				\
 	gdu-drive.c				gdu-drive.h				\
 	gdu-linux-md-drive.c			gdu-linux-md-drive.h			\
diff --git a/src/gdu/gdu-ata-smart-attribute.c b/src/gdu/gdu-ata-smart-attribute.c
new file mode 100644
index 0000000..0f16013
--- /dev/null
+++ b/src/gdu/gdu-ata-smart-attribute.c
@@ -0,0 +1,446 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- */
+/* gdu-ata-smart-attribute.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 <stdlib.h>
+#include <string.h>
+#include <glib/gi18n.h>
+#include <dbus/dbus-glib.h>
+#include <time.h>
+
+#include "gdu-private.h"
+#include "gdu-ata-smart-attribute.h"
+
+struct _GduAtaSmartAttributePrivate {
+        guint id;
+        gchar *name;
+        guint flags;
+        gboolean online, prefailure;
+        guchar current;
+        gboolean current_valid;
+        guchar worst;
+        gboolean worst_valid;
+        guchar threshold;
+        gboolean threshold_valid;
+        gboolean good, good_valid;
+        guint pretty_unit;
+        guint64 pretty_value;
+};
+
+static GObjectClass *parent_class = NULL;
+
+G_DEFINE_TYPE (GduAtaSmartAttribute, gdu_ata_smart_attribute, G_TYPE_OBJECT);
+
+static void
+gdu_ata_smart_attribute_finalize (GduAtaSmartAttribute *attribute)
+{
+        g_free (attribute->priv->name);
+        if (G_OBJECT_CLASS (parent_class)->finalize)
+                (* G_OBJECT_CLASS (parent_class)->finalize) (G_OBJECT (attribute));
+}
+
+static void
+gdu_ata_smart_attribute_class_init (GduAtaSmartAttributeClass *klass)
+{
+        GObjectClass *obj_class = (GObjectClass *) klass;
+
+        parent_class = g_type_class_peek_parent (klass);
+
+        obj_class->finalize = (GObjectFinalizeFunc) gdu_ata_smart_attribute_finalize;
+
+        g_type_class_add_private (klass, sizeof (GduAtaSmartAttributePrivate));
+}
+
+static void
+gdu_ata_smart_attribute_init (GduAtaSmartAttribute *attribute)
+{
+        attribute->priv = G_TYPE_INSTANCE_GET_PRIVATE (attribute, GDU_TYPE_ATA_SMART_ATTRIBUTE, GduAtaSmartAttributePrivate);
+}
+
+guint
+gdu_ata_smart_attribute_get_id (GduAtaSmartAttribute *attribute)
+{
+        return attribute->priv->id;
+}
+
+guint
+gdu_ata_smart_attribute_get_flags (GduAtaSmartAttribute *attribute)
+{
+        return attribute->priv->flags;
+}
+
+gboolean
+gdu_ata_smart_attribute_get_online (GduAtaSmartAttribute *attribute)
+{
+        return attribute->priv->online;
+}
+
+gboolean
+gdu_ata_smart_attribute_get_prefailure (GduAtaSmartAttribute *attribute)
+{
+        return attribute->priv->prefailure;
+}
+
+guint
+gdu_ata_smart_attribute_get_current (GduAtaSmartAttribute *attribute)
+{
+        return attribute->priv->current;
+}
+
+gboolean
+gdu_ata_smart_attribute_get_current_valid (GduAtaSmartAttribute *attribute)
+{
+        return attribute->priv->current_valid;
+}
+
+guint
+gdu_ata_smart_attribute_get_worst (GduAtaSmartAttribute *attribute)
+{
+        return attribute->priv->worst;
+}
+
+gboolean
+gdu_ata_smart_attribute_get_worst_valid (GduAtaSmartAttribute *attribute)
+{
+        return attribute->priv->worst_valid;
+}
+
+guint
+gdu_ata_smart_attribute_get_threshold (GduAtaSmartAttribute *attribute)
+{
+        return attribute->priv->threshold;
+}
+
+gboolean
+gdu_ata_smart_attribute_get_threshold_valid (GduAtaSmartAttribute *attribute)
+{
+        return attribute->priv->threshold_valid;
+}
+
+gboolean
+gdu_ata_smart_attribute_get_good (GduAtaSmartAttribute *attribute)
+{
+        return attribute->priv->good;
+}
+
+gboolean
+gdu_ata_smart_attribute_get_good_valid (GduAtaSmartAttribute *attribute)
+{
+        return attribute->priv->good_valid;
+}
+
+guint64
+gdu_ata_smart_attribute_get_pretty_value (GduAtaSmartAttribute *attribute)
+{
+        return attribute->priv->pretty_value;
+}
+
+GduAtaSmartAttributeUnit
+gdu_ata_smart_attribute_get_pretty_unit (GduAtaSmartAttribute *attribute)
+{
+        return attribute->priv->pretty_unit;
+}
+
+static void
+attribute_get_details (GduAtaSmartAttribute  *attr,
+                       gchar                    **out_name,
+                       gchar                    **out_description,
+                       gboolean                  *out_warn)
+{
+        const char *n;
+        const char *d;
+        gboolean warn;
+
+        /* See http://ata_smartmontools.sourceforge.net/doc.html
+         *     http://en.wikipedia.org/wiki/S.M.A.R.T
+         *     http://www.t13.org/Documents/UploadedDocuments/docs2005/e05148r0-ACS-ATA_SMARTAttributesAnnex.pdf
+         */
+
+        n = NULL;
+        d = NULL;
+        warn = FALSE;
+        switch (attr->priv->id) {
+        case 1:
+                n = _("Read Error Rate");
+                d = _("Frequency of errors while reading raw data from the disk. "
+                      "A non-zero value indicates a problem with "
+                      "either the disk surface or read/write heads.");
+                break;
+        case 2:
+                n = _("Throughput Performance");
+                d = _("Average effeciency of the disk.");
+                break;
+        case 3:
+                n = _("Spinup Time");
+                d = _("Time needed to spin up the disk.");
+                break;
+        case 4:
+                n = _("Start/Stop Count");
+                d = _("Number of spindle start/stop cycles.");
+                break;
+        case 5:
+                n = _("Reallocated Sector Count");
+                d = _("Count of remapped sectors. "
+                      "When the hard drive finds a read/write/verification error, it mark the sector "
+                      "as \"reallocated\" and transfers data to a special reserved area (spare area).");
+                break;
+        case 7:
+                n = _("Seek Error Rate");
+                d = _("Frequency of errors while positioning.");
+                break;
+        case 8:
+                n = _("Seek Timer Performance");
+                d = _("Average efficiency of operatings while positioning");
+                break;
+        case 9:
+                n = _("Power-On Hours");
+                d = _("Number of hours elapsed in the power-on state.");
+                break;
+        case 10:
+                n = _("Spinup Retry Count");
+                d = _("Number of retry attempts to spin up.");
+                break;
+        case 11:
+                n = _("Calibration Retry Count");
+                d = _("Number of attempts to calibrate the device.");
+                break;
+        case 12:
+                n = _("Power Cycle Count");
+                d = _("Number of power-on events.");
+                break;
+        case 13:
+                n = _("Soft read error rate");
+                d = _("Frequency of 'program' errors while reading from the disk.");
+                break;
+
+        case 191:
+                n = _("G-sense Error Rate");
+                d = _("Frequency of mistakes as a result of impact loads.");
+                break;
+        case 192:
+                n = _("Power-off Retract Count");
+                d = _("Number of power-off or emergency retract cycles.");
+                break;
+        case 193:
+                n = _("Load/Unload Cycle Count");
+                d = _("Number of cycles into landing zone position.");
+                break;
+        case 194:
+                n = _("Temperature");
+                d = _("Current internal temperature in degrees Celcius.");
+                break;
+        case 195:
+                n = _("Hardware ECC Recovered");
+                d = _("Number of ECC on-the-fly errors.");
+                break;
+        case 196:
+                n = _("Reallocation Count");
+                d = _("Number of remapping operations. "
+                      "The raw value of this attribute shows the total number of (successful "
+                      "and unsucessful) attempts to transfer data from reallocated sectors "
+                      "to a spare area.");
+                break;
+        case 197:
+                n = _("Current Pending Sector Count");
+                d = _("Number of sectors waiting to be remapped. "
+                      "If the sector waiting to be remapped is subsequently written or read "
+                      "successfully, this value is decreased and the sector is not remapped. Read "
+                      "errors on the sector will not remap the sector, it will only be remapped on "
+                      "a failed write attempt.");
+                if (attr->priv->pretty_value > 0)
+                        warn = TRUE;
+                break;
+        case 198:
+                n = _("Uncorrectable Sector Count");
+                d = _("The total number of uncorrectable errors when reading/writing a sector. "
+                      "A rise in the value of this attribute indicates defects of the "
+                      "disk surface and/or problems in the mechanical subsystem.");
+                break;
+        case 199:
+                n = _("UDMA CRC Error Rate");
+                d = _("Number of CRC errors during UDMA mode.");
+                break;
+        case 200:
+                n = _("Write Error Rate");
+                d = _("Number of errors while writing to disk (or) multi-zone error rate (or) flying-height.");
+                break;
+        case 201:
+                n = _("Soft Read Error Rate");
+                d = _("Number of off-track errors.");
+                break;
+        case 202:
+                n = _("Data Address Mark Errors");
+                d = _("Number of Data Address Mark (DAM) errors (or) vendor-specific.");
+                break;
+        case 203:
+                n = _("Run Out Cancel");
+                d = _("Number of ECC errors.");
+                break;
+        case 204:
+                n = _("Soft ECC correction");
+                d = _("Number of errors corrected by software ECC.");
+                break;
+        case 205:
+                n = _("Thermal Asperity Rate");
+                d = _("Number of Thermal Asperity Rate errors.");
+                break;
+        case 206:
+                n = _("Flying Height");
+                d = _("Height of heads above the disk surface.");
+                break;
+        case 207:
+                n = _("Spin High Current");
+                d = _("Amount of high current used to spin up the drive.");
+                break;
+        case 208:
+                n = _("Spin Buzz");
+                d = _("Number of buzz routines to spin up the drive.");
+                break;
+        case 209:
+                n = _("Offline Seek Performance");
+                d = _("Drive's seek performance during offline operations.");
+                break;
+
+        case 220:
+                n = _("Disk Shift");
+                d = _("Shift of disk os possible as a result of strong shock loading in the store, "
+                      "as a result of falling (or) temperature.");
+                break;
+        case 221:
+                n = _("G-sense Error Rate");
+                d = _("Number of errors as a result of impact loads as detected by a shock sensor.");
+                break;
+        case 222:
+                n = _("Loaded Hours");
+                d = _("Number of hours in general operational state.");
+                break;
+        case 223:
+                n = _("Load/Unload Retry Count");
+                d = _("Loading on drive caused by numerous recurrences of operations, like reading, "
+                      "recording, positioning of heads, etc.");
+                break;
+        case 224:
+                n = _("Load Friction");
+                d = _("Load on drive cause by friction in mechanical parts of the store.");
+                break;
+        case 225:
+                n = _("Load/Unload Cycle Count");
+                d = _("Total number of load cycles.");
+                break;
+        case 226:
+                n = _("Load-in Time");
+                d = _("General time for loading in a drive.");
+                break;
+        case 227:
+                n = _("Torque Amplification Count");
+                d = _("Quantity efforts of the rotating moment of a drive.");
+                break;
+        case 228:
+                n = _("Power-off Retract Count");
+                d = _("Number of power-off retract events.");
+                break;
+
+        case 230:
+                n = _("GMR Head Amplitude");
+                d = _("Amplitude of heads trembling (GMR-head) in running mode.");
+                break;
+        case 231:
+                n = _("Temperature");
+                d = _("Temperature of the drive.");
+                break;
+
+        case 240:
+                n = _("Head Flying Hours");
+                d = _("Time while head is positioning.");
+                break;
+        case 250:
+                n = _("Read Error Retry Rate");
+                d = _("Number of errors while reading from a disk.");
+                break;
+        default:
+                break;
+        }
+
+        if (out_name != NULL)
+                *out_name = g_strdup (n);
+        if (out_description != NULL)
+                *out_description = g_strdup (d);
+        if (out_warn != NULL)
+                *out_warn = warn;
+}
+
+
+const gchar *
+gdu_ata_smart_attribute_get_name (GduAtaSmartAttribute *attribute)
+{
+        return attribute->priv->name;
+}
+
+gchar *
+gdu_ata_smart_attribute_get_localized_name (GduAtaSmartAttribute *attribute)
+{
+        char *s;
+        attribute_get_details (attribute, &s, NULL, NULL);
+        if (s == NULL)
+                s = g_strdup (attribute->priv->name);
+        return s;
+}
+
+gchar *
+gdu_ata_smart_attribute_get_localized_description (GduAtaSmartAttribute *attribute)
+{
+        char *s;
+        attribute_get_details (attribute, NULL, &s, NULL);
+        return s;
+}
+
+GduAtaSmartAttribute *
+_gdu_ata_smart_attribute_new (gpointer data)
+{
+        GValue elem = {0};
+        GduAtaSmartAttribute *attribute;
+
+        attribute = GDU_ATA_SMART_ATTRIBUTE (g_object_new (GDU_TYPE_ATA_SMART_ATTRIBUTE, NULL));
+
+        g_value_init (&elem, ATA_SMART_ATTRIBUTE_STRUCT_TYPE);
+        g_value_set_static_boxed (&elem, data);
+
+        dbus_g_type_struct_get (&elem,
+                                0, &attribute->priv->id,
+                                1, &attribute->priv->name,
+                                2, &attribute->priv->flags,
+                                3, &attribute->priv->online,
+                                4, &attribute->priv->prefailure,
+                                5, &attribute->priv->current,
+                                6, &attribute->priv->current_valid,
+                                7, &attribute->priv->worst,
+                                8, &attribute->priv->worst_valid,
+                                9, &attribute->priv->threshold,
+                                10, &attribute->priv->threshold_valid,
+                                11, &attribute->priv->good,
+                                12, &attribute->priv->good_valid,
+                                13, &attribute->priv->pretty_unit,
+                                14, &attribute->priv->pretty_value,
+                                //15, &raw_data,
+                                G_MAXUINT);
+
+        return attribute;
+}
diff --git a/src/gdu/gdu-ata-smart-attribute.h b/src/gdu/gdu-ata-smart-attribute.h
new file mode 100644
index 0000000..d0ea3f2
--- /dev/null
+++ b/src/gdu/gdu-ata-smart-attribute.h
@@ -0,0 +1,86 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- */
+/* gdu-ata-smart-attribute.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_ATA_SMART_ATTRIBUTE_H
+#define __GDU_ATA_SMART_ATTRIBUTE_H
+
+#include <gdu/gdu-types.h>
+
+G_BEGIN_DECLS
+
+#define GDU_TYPE_ATA_SMART_ATTRIBUTE         (gdu_ata_smart_attribute_get_type ())
+#define GDU_ATA_SMART_ATTRIBUTE(o)           (G_TYPE_CHECK_INSTANCE_CAST ((o), GDU_TYPE_ATA_SMART_ATTRIBUTE, GduAtaSmartAttribute))
+#define GDU_ATA_SMART_ATTRIBUTE_CLASS(k)     (G_TYPE_CHECK_CLASS_CAST ((k), GDU_ATA_SMART_ATTRIBUTE,  GduAtaSmartAttributeClass))
+#define GDU_IS_ATA_SMART_ATTRIBUTE(o)        (G_TYPE_CHECK_INSTANCE_TYPE ((o), GDU_TYPE_ATA_SMART_ATTRIBUTE))
+#define GDU_IS_ATA_SMART_ATTRIBUTE_CLASS(k)  (G_TYPE_CHECK_CLASS_TYPE ((k), GDU_TYPE_ATA_SMART_ATTRIBUTE))
+#define GDU_ATA_SMART_ATTRIBUTE_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), GDU_TYPE_ATA_SMART_ATTRIBUTE, GduAtaSmartAttributeClass))
+
+typedef struct _GduAtaSmartAttributeClass       GduAtaSmartAttributeClass;
+typedef struct _GduAtaSmartAttributePrivate     GduAtaSmartAttributePrivate;
+
+struct _GduAtaSmartAttribute
+{
+        GObject parent;
+
+        /*< private >*/
+        GduAtaSmartAttributePrivate *priv;
+};
+
+struct _GduAtaSmartAttributeClass
+{
+        GObjectClass parent_class;
+
+};
+
+typedef enum {
+        GDU_ATA_SMART_ATTRIBUTE_UNIT_UNKNOWN,
+        GDU_ATA_SMART_ATTRIBUTE_UNIT_NONE,
+        GDU_ATA_SMART_ATTRIBUTE_UNIT_MSECONDS,
+        GDU_ATA_SMART_ATTRIBUTE_UNIT_SECTORS,
+        GDU_ATA_SMART_ATTRIBUTE_UNIT_MKELVIN,
+} GduAtaSmartAttributeUnit;
+
+GType                    gdu_ata_smart_attribute_get_type                  (void);
+guint                    gdu_ata_smart_attribute_get_id                    (GduAtaSmartAttribute *attribute);
+const gchar             *gdu_ata_smart_attribute_get_name                  (GduAtaSmartAttribute *attribute);
+gchar                   *gdu_ata_smart_attribute_get_localized_name        (GduAtaSmartAttribute *attribute);
+gchar                   *gdu_ata_smart_attribute_get_localized_description (GduAtaSmartAttribute *attribute);
+guint                    gdu_ata_smart_attribute_get_flags                 (GduAtaSmartAttribute *attribute);
+gboolean                 gdu_ata_smart_attribute_get_online                (GduAtaSmartAttribute *attribute);
+gboolean                 gdu_ata_smart_attribute_get_prefailure            (GduAtaSmartAttribute *attribute);
+guint                    gdu_ata_smart_attribute_get_current               (GduAtaSmartAttribute *attribute);
+gboolean                 gdu_ata_smart_attribute_get_current_valid         (GduAtaSmartAttribute *attribute);
+guint                    gdu_ata_smart_attribute_get_worst                 (GduAtaSmartAttribute *attribute);
+gboolean                 gdu_ata_smart_attribute_get_worst_valid           (GduAtaSmartAttribute *attribute);
+guint                    gdu_ata_smart_attribute_get_threshold             (GduAtaSmartAttribute *attribute);
+gboolean                 gdu_ata_smart_attribute_get_threshold_valid       (GduAtaSmartAttribute *attribute);
+gboolean                 gdu_ata_smart_attribute_get_good                  (GduAtaSmartAttribute *attribute);
+gboolean                 gdu_ata_smart_attribute_get_good_valid            (GduAtaSmartAttribute *attribute);
+guint64                  gdu_ata_smart_attribute_get_pretty_value          (GduAtaSmartAttribute *attribute);
+GduAtaSmartAttributeUnit gdu_ata_smart_attribute_get_pretty_unit           (GduAtaSmartAttribute *attribute);
+
+G_END_DECLS
+
+#endif /* __GDU_ATA_SMART_ATTRIBUTE_H */
diff --git a/src/gdu/gdu-ata-smart-historical-data.c b/src/gdu/gdu-ata-smart-historical-data.c
new file mode 100644
index 0000000..dfc427c
--- /dev/null
+++ b/src/gdu/gdu-ata-smart-historical-data.c
@@ -0,0 +1,181 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- */
+/* gdu-ata-smart-historical-data.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.h>
+#include <dbus/dbus-glib.h>
+#include <time.h>
+
+#include "gdu-private.h"
+#include "gdu-ata-smart-historical-data.h"
+#include "gdu-ata-smart-attribute.h"
+
+struct _GduAtaSmartHistoricalDataPrivate {
+        guint64 time_collected;
+        gboolean is_failing;
+        gboolean is_failing_valid;
+        gboolean has_bad_sectors;
+        gboolean has_bad_attributes;
+        gdouble temperature_kelvin;
+        guint64 power_on_seconds;
+        GList *attrs;
+};
+
+static GObjectClass *parent_class = NULL;
+
+G_DEFINE_TYPE (GduAtaSmartHistoricalData, gdu_ata_smart_historical_data, G_TYPE_OBJECT);
+
+static void
+gdu_ata_smart_historical_data_finalize (GduAtaSmartHistoricalData *ata_smart_historical_data)
+{
+        g_list_foreach (ata_smart_historical_data->priv->attrs, (GFunc) g_object_unref, NULL);
+        g_list_free (ata_smart_historical_data->priv->attrs);
+        if (G_OBJECT_CLASS (parent_class)->finalize)
+                (* G_OBJECT_CLASS (parent_class)->finalize) (G_OBJECT (ata_smart_historical_data));
+}
+
+static void
+gdu_ata_smart_historical_data_class_init (GduAtaSmartHistoricalDataClass *klass)
+{
+        GObjectClass *obj_class = (GObjectClass *) klass;
+
+        parent_class = g_type_class_peek_parent (klass);
+
+        obj_class->finalize = (GObjectFinalizeFunc) gdu_ata_smart_historical_data_finalize;
+
+        g_type_class_add_private (klass, sizeof (GduAtaSmartHistoricalDataPrivate));
+}
+
+static void
+gdu_ata_smart_historical_data_init (GduAtaSmartHistoricalData *ata_smart_historical_data)
+{
+        ata_smart_historical_data->priv = G_TYPE_INSTANCE_GET_PRIVATE (ata_smart_historical_data, GDU_TYPE_ATA_SMART_HISTORICAL_DATA, GduAtaSmartHistoricalDataPrivate);
+}
+
+guint64
+gdu_ata_smart_historical_data_get_time_collected (GduAtaSmartHistoricalData *data)
+{
+        return data->priv->time_collected;
+}
+
+gboolean
+gdu_ata_smart_historical_data_get_is_failing (GduAtaSmartHistoricalData *data)
+{
+        return data->priv->is_failing;
+}
+
+gboolean
+gdu_ata_smart_historical_data_get_is_failing_valid (GduAtaSmartHistoricalData *data)
+{
+        return data->priv->is_failing_valid;
+}
+
+gboolean
+gdu_ata_smart_historical_data_get_has_bad_sectors (GduAtaSmartHistoricalData *data)
+{
+        return data->priv->has_bad_sectors;
+}
+
+gboolean
+gdu_ata_smart_historical_data_get_has_bad_attributes (GduAtaSmartHistoricalData *data)
+{
+        return data->priv->has_bad_attributes;
+}
+
+gdouble
+gdu_ata_smart_historical_data_get_temperature_kelvin (GduAtaSmartHistoricalData *data)
+{
+        return data->priv->temperature_kelvin;
+}
+
+guint64
+gdu_ata_smart_historical_data_get_power_on_seconds (GduAtaSmartHistoricalData *data)
+{
+        return data->priv->power_on_seconds;
+}
+
+GList *
+gdu_ata_smart_historical_data_get_attributes (GduAtaSmartHistoricalData *data)
+{
+        GList *ret;
+        ret = g_list_copy (data->priv->attrs);
+        g_list_foreach (ret, (GFunc) g_object_ref, NULL);
+        return ret;
+}
+
+GduAtaSmartAttribute *
+gdu_ata_smart_historical_data_get_attribute (GduAtaSmartHistoricalData *data,
+                                             const gchar               *attr_name)
+{
+        GList *l;
+        GduAtaSmartAttribute *ret;
+
+        /* TODO: if this is slow we can do a hash table */
+
+        ret = NULL;
+
+        for (l = data->priv->attrs; l != NULL; l = l->next) {
+                GduAtaSmartAttribute *a = GDU_ATA_SMART_ATTRIBUTE (l->data);
+                if (g_strcmp0 (attr_name, gdu_ata_smart_attribute_get_name (a)) == 0) {
+                        ret = g_object_ref (a);
+                        goto out;
+                }
+        }
+out:
+        return ret;
+}
+
+GduAtaSmartHistoricalData *
+_gdu_ata_smart_historical_data_new (gpointer data)
+{
+        GduAtaSmartHistoricalData *ret;
+        GValue elem0 = {0};
+        GPtrArray *attrs;
+        int n;
+
+        ret = GDU_ATA_SMART_HISTORICAL_DATA (g_object_new (GDU_TYPE_ATA_SMART_HISTORICAL_DATA, NULL));
+
+        g_value_init (&elem0, ATA_SMART_HISTORICAL_DATA_STRUCT_TYPE);
+        g_value_set_static_boxed (&elem0, data);
+        dbus_g_type_struct_get (&elem0,
+                                0, &(ret->priv->time_collected),
+                                1, &(ret->priv->is_failing),
+                                2, &(ret->priv->is_failing_valid),
+                                3, &(ret->priv->has_bad_sectors),
+                                4, &(ret->priv->has_bad_attributes),
+                                5, &(ret->priv->temperature_kelvin),
+                                6, &(ret->priv->power_on_seconds),
+                                7, &attrs,
+                                G_MAXUINT);
+
+        ret->priv->attrs = NULL;
+        if (attrs != NULL) {
+                for (n = 0; n < (int) attrs->len; n++) {
+                        ret->priv->attrs = g_list_prepend (ret->priv->attrs,
+                                                           _gdu_ata_smart_attribute_new (attrs->pdata[n]));
+                }
+                ret->priv->attrs = g_list_reverse (ret->priv->attrs);
+        }
+
+        return ret;
+}
diff --git a/src/gdu/gdu-ata-smart-historical-data.h b/src/gdu/gdu-ata-smart-historical-data.h
new file mode 100644
index 0000000..87031f0
--- /dev/null
+++ b/src/gdu/gdu-ata-smart-historical-data.h
@@ -0,0 +1,72 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- */
+/* gdu-ata-smart-historical-data.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.
+ */
+
+
+#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_ATA_SMART_HISTORICAL_DATA_H
+#define __GDU_ATA_SMART_HISTORICAL_DATA_H
+
+#include <gdu/gdu-types.h>
+
+G_BEGIN_DECLS
+
+#define GDU_TYPE_ATA_SMART_HISTORICAL_DATA           (gdu_ata_smart_historical_data_get_type ())
+#define GDU_ATA_SMART_HISTORICAL_DATA(o)             (G_TYPE_CHECK_INSTANCE_CAST ((o), GDU_TYPE_ATA_SMART_HISTORICAL_DATA, GduAtaSmartHistoricalData))
+#define GDU_ATA_SMART_HISTORICAL_DATA_CLASS(k)       (G_TYPE_CHECK_CLASS_CAST ((k), GDU_ATA_SMART_HISTORICAL_DATA,  GduAtaSmartHistoricalDataClass))
+#define GDU_IS_ATA_SMART_HISTORICAL_DATA(o)          (G_TYPE_CHECK_INSTANCE_TYPE ((o), GDU_TYPE_ATA_SMART_HISTORICAL_DATA))
+#define GDU_IS_ATA_SMART_HISTORICAL_DATA_CLASS(k)    (G_TYPE_CHECK_CLASS_TYPE ((k), GDU_TYPE_ATA_SMART_HISTORICAL_DATA))
+#define GDU_ATA_SMART_HISTORICAL_DATA_GET_CLASS(o)   (G_TYPE_INSTANCE_GET_CLASS ((o), GDU_TYPE_ATA_SMART_HISTORICAL_DATA, GduAtaSmartHistoricalDataClass))
+
+typedef struct _GduAtaSmartHistoricalDataClass       GduAtaSmartHistoricalDataClass;
+typedef struct _GduAtaSmartHistoricalDataPrivate     GduAtaSmartHistoricalDataPrivate;
+
+struct _GduAtaSmartHistoricalData
+{
+        GObject parent;
+
+        /* private */
+        GduAtaSmartHistoricalDataPrivate *priv;
+};
+
+struct _GduAtaSmartHistoricalDataClass
+{
+        GObjectClass parent_class;
+
+};
+
+GType                     gdu_ata_smart_historical_data_get_type                (void);
+guint64                   gdu_ata_smart_historical_data_get_time_collected      (GduAtaSmartHistoricalData *data);
+gboolean                  gdu_ata_smart_historical_data_get_is_failing          (GduAtaSmartHistoricalData *data);
+gboolean                  gdu_ata_smart_historical_data_get_is_failing_valid    (GduAtaSmartHistoricalData *data);
+gboolean                  gdu_ata_smart_historical_data_get_has_bad_sectors     (GduAtaSmartHistoricalData *data);
+gboolean                  gdu_ata_smart_historical_data_get_has_bad_attributes  (GduAtaSmartHistoricalData *data);
+gdouble                   gdu_ata_smart_historical_data_get_temperature_kelvin  (GduAtaSmartHistoricalData *data);
+guint64                   gdu_ata_smart_historical_data_get_power_on_seconds    (GduAtaSmartHistoricalData *data);
+GList                    *gdu_ata_smart_historical_data_get_attributes          (GduAtaSmartHistoricalData *data);
+GduAtaSmartAttribute     *gdu_ata_smart_historical_data_get_attribute           (GduAtaSmartHistoricalData *data,
+                                                                                 const gchar               *attr_name);
+
+G_END_DECLS
+
+#endif /* __GDU_ATA_SMART_HISTORICAL_DATA_H */
diff --git a/src/gdu/gdu-callbacks.h b/src/gdu/gdu-callbacks.h
index 890d9b5..1d68603 100644
--- a/src/gdu/gdu-callbacks.h
+++ b/src/gdu/gdu-callbacks.h
@@ -84,13 +84,13 @@ typedef void (*GduDeviceFilesystemSetLabelCompletedFunc) (GduDevice    *device,
                                                           GError       *error,
                                                           gpointer      user_data);
 
-typedef void (*GduDeviceDriveSmartInitiateSelftestCompletedFunc) (GduDevice    *device,
-                                                                  GError       *error,
-                                                                  gpointer      user_data);
+typedef void (*GduDeviceDriveAtaSmartInitiateSelftestCompletedFunc) (GduDevice    *device,
+                                                                     GError       *error,
+                                                                     gpointer      user_data);
 
-typedef void (*GduDeviceDriveSmartRefreshDataCompletedFunc) (GduDevice  *device,
-                                                             GError     *error,
-                                                             gpointer    user_data);
+typedef void (*GduDeviceDriveAtaSmartRefreshDataCompletedFunc) (GduDevice  *device,
+                                                                GError     *error,
+                                                                gpointer    user_data);
 
 typedef void (*GduDeviceLinuxMdStopCompletedFunc) (GduDevice    *device,
                                                    GError       *error,
@@ -117,14 +117,10 @@ typedef void (*GduDeviceCancelJobCompletedFunc) (GduDevice  *device,
                                                  GError     *error,
                                                  gpointer    user_data);
 
-typedef void (*GduDeviceDriveSmartGetHistoricalDataCompletedFunc) (GduDevice *device,
-                                                                   GList     *smart_data,
-                                                                   GError    *error,
-                                                                   gpointer   user_data);
-
-void gdu_device_drive_smart_get_historical_data (GduDevice                                         *device,
-                                                 GduDeviceDriveSmartGetHistoricalDataCompletedFunc  callback,
-                                                 gpointer                                           user_data);
+typedef void (*GduDeviceDriveAtaSmartGetHistoricalDataCompletedFunc) (GduDevice *device,
+                                                                      GList     *smart_data,
+                                                                      GError    *error,
+                                                                      gpointer   user_data);
 
 typedef void (*GduDeviceFilesystemListOpenFilesCompletedFunc) (GduDevice    *device,
                                                                GList        *processes,
diff --git a/src/gdu/gdu-device.c b/src/gdu/gdu-device.c
index 60ec7e7..8205151 100644
--- a/src/gdu/gdu-device.c
+++ b/src/gdu/gdu-device.c
@@ -31,6 +31,7 @@
 #include "gdu-private.h"
 #include "gdu-pool.h"
 #include "gdu-device.h"
+#include "gdu-ata-smart-attribute.h"
 #include "devkit-disks-device-glue.h"
 
 /* --- SUCKY CODE BEGIN --- */
@@ -127,14 +128,26 @@ typedef struct
         guint optical_disc_num_audio_tracks;
         guint optical_disc_num_sessions;
 
-        gboolean               drive_smart_is_capable;
-        gboolean               drive_smart_is_enabled;
-        guint64                drive_smart_time_collected;
-        gboolean               drive_smart_is_failing;
-        double                 drive_smart_temperature;
-        guint64                drive_smart_time_powered_on;
-        char                  *drive_smart_last_self_test_result;
-        GValue                 drive_smart_attributes;
+        gboolean drive_ata_smart_is_available;
+        gboolean drive_ata_smart_is_failing;
+        gboolean drive_ata_smart_is_failing_valid;
+        gboolean drive_ata_smart_has_bad_sectors;
+        gboolean drive_ata_smart_has_bad_attributes;
+        gdouble drive_ata_smart_temperature_kelvin;
+        guint64 drive_ata_smart_power_on_seconds;
+        guint64 drive_ata_smart_time_collected;
+        guint drive_ata_smart_offline_data_collection_status;
+        guint drive_ata_smart_offline_data_collection_seconds;
+        guint drive_ata_smart_self_test_execution_status;
+        guint drive_ata_smart_self_test_execution_percent_remaining;
+        gboolean drive_ata_smart_short_and_extended_self_test_available;
+        gboolean drive_ata_smart_conveyance_self_test_available;
+        gboolean drive_ata_smart_start_self_test_available;
+        gboolean drive_ata_smart_abort_self_test_available;
+        guint drive_ata_smart_short_self_test_polling_minutes;
+        guint drive_ata_smart_extended_self_test_polling_minutes;
+        guint drive_ata_smart_conveyance_self_test_polling_minutes;
+        GValue drive_ata_smart_attributes;
 
         char    *linux_md_component_level;
         int      linux_md_component_num_raid_devices;
@@ -329,22 +342,46 @@ collect_props (const char *key, const GValue *value, DeviceProperties *props)
         else if (strcmp (key, "optical-disc-num-sessions") == 0)
                 props->optical_disc_num_sessions = g_value_get_uint (value);
 
-        else if (strcmp (key, "drive-smart-is-capable") == 0)
-                props->drive_smart_is_capable = g_value_get_boolean (value);
-        else if (strcmp (key, "drive-smart-is-enabled") == 0)
-                props->drive_smart_is_enabled = g_value_get_boolean (value);
-        else if (strcmp (key, "drive-smart-time-collected") == 0)
-                props->drive_smart_time_collected = g_value_get_uint64 (value);
-        else if (strcmp (key, "drive-smart-is-failing") == 0)
-                props->drive_smart_is_failing = g_value_get_boolean (value);
-        else if (strcmp (key, "drive-smart-temperature") == 0)
-                props->drive_smart_temperature = g_value_get_double (value);
-        else if (strcmp (key, "drive-smart-time-powered-on") == 0)
-                props->drive_smart_time_powered_on = g_value_get_uint64 (value);
-        else if (strcmp (key, "drive-smart-last-self-test-result") == 0)
-                props->drive_smart_last_self_test_result = g_strdup (g_value_get_string (value));
-        else if (strcmp (key, "drive-smart-attributes") == 0) {
-                g_value_copy (value, &(props->drive_smart_attributes));
+        else if (strcmp (key, "drive-ata-smart-is-available") == 0)
+                props->drive_ata_smart_is_available = g_value_get_boolean (value);
+        else if (strcmp (key, "drive-ata-smart-is-failing") == 0)
+                props->drive_ata_smart_is_failing = g_value_get_boolean (value);
+        else if (strcmp (key, "drive-ata-smart-is-failing-valid") == 0)
+                props->drive_ata_smart_is_failing_valid = g_value_get_boolean (value);
+        else if (strcmp (key, "drive-ata-smart-has-bad-sectors") == 0)
+                props->drive_ata_smart_has_bad_sectors = g_value_get_boolean (value);
+        else if (strcmp (key, "drive-ata-smart-has-bad-attributes") == 0)
+                props->drive_ata_smart_has_bad_attributes = g_value_get_boolean (value);
+        else if (strcmp (key, "drive-ata-smart-temperature-kelvin") == 0)
+                props->drive_ata_smart_temperature_kelvin = g_value_get_double (value);
+        else if (strcmp (key, "drive-ata-smart-power-on-seconds") == 0)
+                props->drive_ata_smart_power_on_seconds = g_value_get_uint64 (value);
+        else if (strcmp (key, "drive-ata-smart-time-collected") == 0)
+                props->drive_ata_smart_time_collected = g_value_get_uint64 (value);
+        else if (strcmp (key, "drive-ata-smart-offline-data-collection-status") == 0)
+                props->drive_ata_smart_offline_data_collection_status = g_value_get_uint (value);
+        else if (strcmp (key, "drive-ata-smart-offline-data-collection-seconds") == 0)
+                props->drive_ata_smart_offline_data_collection_seconds = g_value_get_uint (value);
+        else if (strcmp (key, "drive-ata-smart-self-test-execution-status") == 0)
+                props->drive_ata_smart_self_test_execution_status = g_value_get_uint (value);
+        else if (strcmp (key, "drive-ata-smart-self-test-execution-percent-remaining") == 0)
+                props->drive_ata_smart_self_test_execution_percent_remaining = g_value_get_uint (value);
+        else if (strcmp (key, "drive-ata-smart-short-and-extended-self-test-available") == 0)
+                props->drive_ata_smart_short_and_extended_self_test_available = g_value_get_boolean (value);
+        else if (strcmp (key, "drive-ata-smart-conveyance-self-test-available") == 0)
+                props->drive_ata_smart_conveyance_self_test_available = g_value_get_boolean (value);
+        else if (strcmp (key, "drive-ata-smart-start-self-test-available") == 0)
+                props->drive_ata_smart_start_self_test_available = g_value_get_boolean (value);
+        else if (strcmp (key, "drive-ata-smart-abort-self-test-available") == 0)
+                props->drive_ata_smart_abort_self_test_available = g_value_get_boolean (value);
+        else if (strcmp (key, "drive-ata-smart-short-self-test-polling-minutes") == 0)
+                props->drive_ata_smart_short_self_test_polling_minutes = g_value_get_uint (value);
+        else if (strcmp (key, "drive-ata-smart-extended-self-test-polling-minutes") == 0)
+                props->drive_ata_smart_extended_self_test_polling_minutes = g_value_get_uint (value);
+        else if (strcmp (key, "drive-ata-smart-conveyance-self-test-polling-minutes") == 0)
+                props->drive_ata_smart_conveyance_self_test_polling_minutes = g_value_get_uint (value);
+        else if (strcmp (key, "drive-ata-smart-attributes") == 0) {
+                g_value_copy (value, &(props->drive_ata_smart_attributes));
         }
 
         else if (strcmp (key, "linux-md-component-level") == 0)
@@ -441,8 +478,9 @@ 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_smart_last_self_test_result);
-        g_value_unset (&(props->drive_smart_attributes));
+
+        g_value_unset (&(props->drive_ata_smart_attributes));
+
         g_free (props->linux_md_component_level);
         g_free (props->linux_md_component_uuid);
         g_free (props->linux_md_component_home_host);
@@ -473,8 +511,8 @@ device_properties_get (DBusGConnection *bus,
         const char *ifname = "org.freedesktop.DeviceKit.Disks.Device";
 
         props = g_new0 (DeviceProperties, 1);
-        g_value_init (&(props->drive_smart_attributes),
-                      dbus_g_type_get_collection ("GPtrArray", SMART_DATA_STRUCT_TYPE));
+        g_value_init (&(props->drive_ata_smart_attributes),
+                      dbus_g_type_get_collection ("GPtrArray", ATA_SMART_ATTRIBUTE_STRUCT_TYPE));
 
 	prop_proxy = dbus_g_proxy_new_for_name (bus,
                                                 "org.freedesktop.DeviceKit.Disks",
@@ -1113,30 +1151,6 @@ gdu_device_optical_disc_get_num_sessions (GduDevice *device)
         return device->priv->props->optical_disc_num_sessions;
 }
 
-
-gboolean
-gdu_device_drive_smart_get_is_capable (GduDevice *device)
-{
-        return device->priv->props->drive_smart_is_capable;
-}
-
-gboolean
-gdu_device_drive_smart_get_is_enabled (GduDevice *device)
-{
-        return device->priv->props->drive_smart_is_enabled;
-}
-
-GduSmartData *
-gdu_device_get_smart_data (GduDevice *device)
-{
-        return _gdu_smart_data_new_from_values (device->priv->props->drive_smart_time_collected,
-                                                device->priv->props->drive_smart_temperature,
-                                                device->priv->props->drive_smart_time_powered_on,
-                                                device->priv->props->drive_smart_last_self_test_result,
-                                                device->priv->props->drive_smart_is_failing,
-                                                g_value_get_boxed (&(device->priv->props->drive_smart_attributes)));
-}
-
 const char *
 gdu_device_linux_md_component_get_level (GduDevice *device)
 {
@@ -1260,6 +1274,161 @@ gdu_device_linux_md_get_sync_speed (GduDevice *device)
 /* ---------------------------------------------------------------------------------------------------- */
 
 gboolean
+gdu_device_drive_ata_smart_get_is_available (GduDevice *device)
+{
+        return device->priv->props->drive_ata_smart_is_available;
+}
+
+gboolean
+gdu_device_drive_ata_smart_get_is_failing (GduDevice *device)
+{
+        return device->priv->props->drive_ata_smart_is_failing;
+}
+
+gboolean
+gdu_device_drive_ata_smart_get_is_failing_valid (GduDevice *device)
+{
+        return device->priv->props->drive_ata_smart_is_failing_valid;
+}
+
+gboolean
+gdu_device_drive_ata_smart_get_has_bad_sectors (GduDevice *device)
+{
+        return device->priv->props->drive_ata_smart_has_bad_sectors;
+}
+
+gboolean
+gdu_device_drive_ata_smart_get_has_bad_attributes (GduDevice *device)
+{
+        return device->priv->props->drive_ata_smart_has_bad_attributes;
+}
+
+gdouble
+gdu_device_drive_ata_smart_get_temperature_kelvin (GduDevice *device)
+{
+        return device->priv->props->drive_ata_smart_temperature_kelvin;
+}
+
+guint64 gdu_device_drive_ata_smart_get_power_on_seconds (GduDevice *device)
+{
+        return device->priv->props->drive_ata_smart_power_on_seconds;
+}
+
+guint64
+gdu_device_drive_ata_smart_get_time_collected (GduDevice *device)
+{
+        return device->priv->props->drive_ata_smart_time_collected;
+}
+
+GduAtaSmartOfflineDataCollectionStatus
+gdu_device_drive_ata_smart_get_offline_data_collection_status (GduDevice *device)
+{
+        return device->priv->props->drive_ata_smart_offline_data_collection_status;
+}
+
+guint
+gdu_device_drive_ata_smart_get_offline_data_collection_seconds (GduDevice *device)
+{
+        return device->priv->props->drive_ata_smart_offline_data_collection_seconds;
+}
+
+GduAtaSmartSelfTestExecutionStatus
+gdu_device_drive_ata_smart_get_self_test_execution_status (GduDevice *device)
+{
+        return device->priv->props->drive_ata_smart_self_test_execution_status;
+}
+
+guint
+gdu_device_drive_ata_smart_get_self_test_execution_percent_remaining (GduDevice *device)
+{
+        return device->priv->props->drive_ata_smart_self_test_execution_percent_remaining;
+}
+
+gboolean
+gdu_device_drive_ata_smart_get_short_and_extended_self_test_available (GduDevice *device)
+{
+        return device->priv->props->drive_ata_smart_short_and_extended_self_test_available;
+}
+
+gboolean
+gdu_device_drive_ata_smart_get_conveyance_self_test_available (GduDevice *device)
+{
+        return device->priv->props->drive_ata_smart_conveyance_self_test_available;
+}
+
+gboolean
+gdu_device_drive_ata_smart_get_start_self_test_available (GduDevice *device)
+{
+        return device->priv->props->drive_ata_smart_start_self_test_available;
+}
+
+gboolean
+gdu_device_drive_ata_smart_get_abort_self_test_available (GduDevice *device)
+{
+        return device->priv->props->drive_ata_smart_abort_self_test_available;
+}
+
+guint
+gdu_device_drive_ata_smart_get_short_self_test_polling_minutes (GduDevice *device)
+{
+        return device->priv->props->drive_ata_smart_short_self_test_polling_minutes;
+}
+
+guint
+gdu_device_drive_ata_smart_get_extended_self_test_polling_minutes (GduDevice *device)
+{
+        return device->priv->props->drive_ata_smart_extended_self_test_polling_minutes;
+}
+
+guint
+gdu_device_drive_ata_smart_get_conveyance_self_test_polling_minutes (GduDevice *device)
+{
+        return device->priv->props->drive_ata_smart_conveyance_self_test_polling_minutes;
+}
+
+GList *
+gdu_device_drive_ata_smart_get_attributes (GduDevice *device)
+{
+        GList *ret;
+        GPtrArray *p;
+        guint n;
+
+        ret = NULL;
+
+        p = g_value_get_boxed (&(device->priv->props->drive_ata_smart_attributes));
+        for (n = 0; n < p->len; n++) {
+                ret = g_list_prepend (ret, _gdu_ata_smart_attribute_new (p->pdata[n]));
+        }
+
+        return ret;
+}
+
+GduAtaSmartAttribute *
+gdu_device_drive_ata_smart_get_attribute (GduDevice *device, const gchar *attr_name)
+{
+        GList *attrs;
+        GList *l;
+        GduAtaSmartAttribute *ret;
+
+        ret = NULL;
+
+        attrs = gdu_device_drive_ata_smart_get_attributes (device);
+        for (l = attrs; l != NULL; l = l->next) {
+                GduAtaSmartAttribute *a = GDU_ATA_SMART_ATTRIBUTE (l->data);
+                if (g_strcmp0 (attr_name, gdu_ata_smart_attribute_get_name (a)) == 0) {
+                        ret = g_object_ref (a);
+                        break;
+                }
+        }
+        g_list_foreach (attrs, (GFunc) g_object_unref, NULL);
+        g_list_free (attrs);
+
+        return ret;
+}
+
+/* ---------------------------------------------------------------------------------------------------- */
+
+gboolean
 gdu_device_job_in_progress (GduDevice *device)
 {
         return device->priv->props->job_in_progress;
@@ -1949,14 +2118,14 @@ out:
 
 typedef struct {
         GduDevice *device;
-        GduDeviceDriveSmartRefreshDataCompletedFunc callback;
+        GduDeviceDriveAtaSmartRefreshDataCompletedFunc callback;
         gpointer user_data;
-} RetrieveSmartDataData;
+} RetrieveAtaSmartDataData;
 
 static void
-op_retrieve_smart_data_cb (DBusGProxy *proxy, GError *error, gpointer user_data)
+op_retrieve_ata_smart_data_cb (DBusGProxy *proxy, GError *error, gpointer user_data)
 {
-        RetrieveSmartDataData *data = user_data;
+        RetrieveAtaSmartDataData *data = user_data;
         _gdu_error_fixup (error);
         if (data->callback != NULL)
                 data->callback (data->device, error, data->user_data);
@@ -1965,23 +2134,23 @@ op_retrieve_smart_data_cb (DBusGProxy *proxy, GError *error, gpointer user_data)
 }
 
 void
-gdu_device_drive_smart_refresh_data (GduDevice                                  *device,
-                                     GduDeviceDriveSmartRefreshDataCompletedFunc callback,
+gdu_device_drive_ata_smart_refresh_data (GduDevice                                  *device,
+                                     GduDeviceDriveAtaSmartRefreshDataCompletedFunc callback,
                                      gpointer                                    user_data)
 {
-        RetrieveSmartDataData *data;
+        RetrieveAtaSmartDataData *data;
         char *options[16];
 
         options[0] = NULL;
 
-        data = g_new0 (RetrieveSmartDataData, 1);
+        data = g_new0 (RetrieveAtaSmartDataData, 1);
         data->device = g_object_ref (device);
         data->callback = callback;
         data->user_data = user_data;
 
-        org_freedesktop_DeviceKit_Disks_Device_drive_smart_refresh_data_async (device->priv->proxy,
+        org_freedesktop_DeviceKit_Disks_Device_drive_ata_smart_refresh_data_async (device->priv->proxy,
                                                                                (const char **) options,
-                                                                               op_retrieve_smart_data_cb,
+                                                                               op_retrieve_ata_smart_data_cb,
                                                                                data);
 }
 
@@ -1989,14 +2158,14 @@ gdu_device_drive_smart_refresh_data (GduDevice
 
 typedef struct {
         GduDevice *device;
-        GduDeviceDriveSmartInitiateSelftestCompletedFunc callback;
+        GduDeviceDriveAtaSmartInitiateSelftestCompletedFunc callback;
         gpointer user_data;
-} DriveSmartInitiateSelftestData;
+} DriveAtaSmartInitiateSelftestData;
 
 static void
-op_run_smart_selftest_cb (DBusGProxy *proxy, GError *error, gpointer user_data)
+op_run_ata_smart_selftest_cb (DBusGProxy *proxy, GError *error, gpointer user_data)
 {
-        DriveSmartInitiateSelftestData *data = user_data;
+        DriveAtaSmartInitiateSelftestData *data = user_data;
         _gdu_error_fixup (error);
         if (data->callback != NULL)
                 data->callback (data->device, error, data->user_data);
@@ -2005,24 +2174,24 @@ op_run_smart_selftest_cb (DBusGProxy *proxy, GError *error, gpointer user_data)
 }
 
 void
-gdu_device_op_drive_smart_initiate_selftest (GduDevice                                        *device,
-                                             const char                                       *test,
-                                             gboolean                                          captive,
-                                             GduDeviceDriveSmartInitiateSelftestCompletedFunc  callback,
-                                             gpointer                                          user_data)
+gdu_device_op_drive_ata_smart_initiate_selftest (GduDevice                                        *device,
+                                                 const char                                       *test,
+                                                 GduDeviceDriveAtaSmartInitiateSelftestCompletedFunc  callback,
+                                                 gpointer                                          user_data)
 {
-        DriveSmartInitiateSelftestData *data;
+        DriveAtaSmartInitiateSelftestData *data;
+        gchar *options = {NULL};
 
-        data = g_new0 (DriveSmartInitiateSelftestData, 1);
+        data = g_new0 (DriveAtaSmartInitiateSelftestData, 1);
         data->device = g_object_ref (device);
         data->callback = callback;
         data->user_data = user_data;
 
-        org_freedesktop_DeviceKit_Disks_Device_drive_smart_initiate_selftest_async (device->priv->proxy,
-                                                                                    test,
-                                                                                    captive,
-                                                                                    op_run_smart_selftest_cb,
-                                                                                    data);
+        org_freedesktop_DeviceKit_Disks_Device_drive_ata_smart_initiate_selftest_async (device->priv->proxy,
+                                                                                        test,
+                                                                                        (const gchar **) options,
+                                                                                        op_run_ata_smart_selftest_cb,
+                                                                                        data);
 }
 
 /* -------------------------------------------------------------------------------- */
@@ -2198,35 +2367,35 @@ gdu_device_op_cancel_job (GduDevice *device, GduDeviceCancelJobCompletedFunc cal
 
 typedef struct {
         GduDevice *device;
-        GduDeviceDriveSmartGetHistoricalDataCompletedFunc callback;
+        GduDeviceDriveAtaSmartGetHistoricalDataCompletedFunc callback;
         gpointer user_data;
-} DriveSmartGetHistoricalDataData;
+} DriveAtaSmartGetHistoricalDataData;
 
 static GList *
-op_smart_historical_data_compute_ret (GPtrArray *historical_data)
+op_ata_smart_historical_data_compute_ret (GPtrArray *historical_data)
 {
         GList *ret;
         int n;
 
         ret = NULL;
         for (n = 0; n < (int) historical_data->len; n++) {
-                ret = g_list_prepend (ret, _gdu_smart_data_new (historical_data->pdata[n]));
+                ret = g_list_prepend (ret, _gdu_ata_smart_historical_data_new (historical_data->pdata[n]));
         }
         ret = g_list_reverse (ret);
         return ret;
 }
 
 static void
-op_smart_historical_data_cb (DBusGProxy *proxy, GPtrArray *historical_data, GError *error, gpointer user_data)
+op_ata_smart_historical_data_cb (DBusGProxy *proxy, GPtrArray *historical_data, GError *error, gpointer user_data)
 {
-        DriveSmartGetHistoricalDataData *data = user_data;
+        DriveAtaSmartGetHistoricalDataData *data = user_data;
         GList *ret;
 
         _gdu_error_fixup (error);
 
         ret = NULL;
         if (historical_data != NULL && error == NULL)
-                ret = op_smart_historical_data_compute_ret (historical_data);
+                ret = op_ata_smart_historical_data_compute_ret (historical_data);
 
         if (data->callback == NULL)
                 data->callback (data->device, ret, error, data->user_data);
@@ -2236,42 +2405,42 @@ op_smart_historical_data_cb (DBusGProxy *proxy, GPtrArray *historical_data, GErr
 }
 
 void
-gdu_device_drive_smart_get_historical_data (GduDevice                                         *device,
-                                            GduDeviceDriveSmartGetHistoricalDataCompletedFunc  callback,
-                                            gpointer                                           user_data)
+gdu_device_drive_ata_smart_get_historical_data (GduDevice                                         *device,
+                                                GduDeviceDriveAtaSmartGetHistoricalDataCompletedFunc  callback,
+                                                gpointer                                           user_data)
 {
-        DriveSmartGetHistoricalDataData *data;
+        DriveAtaSmartGetHistoricalDataData *data;
 
-        data = g_new0 (DriveSmartGetHistoricalDataData, 1);
+        data = g_new0 (DriveAtaSmartGetHistoricalDataData, 1);
         data->device = g_object_ref (device);
         data->callback = callback;
         data->user_data = user_data;
 
         /* TODO: since, until */
-        org_freedesktop_DeviceKit_Disks_Device_drive_smart_get_historical_data_async (device->priv->proxy,
+        org_freedesktop_DeviceKit_Disks_Device_drive_ata_smart_get_historical_data_async (device->priv->proxy,
                                                                                       0,
                                                                                       0,
-                                                                                      op_smart_historical_data_cb,
+                                                                                      op_ata_smart_historical_data_cb,
                                                                                       data);
 }
 
 GList *
-gdu_device_drive_smart_get_historical_data_sync (GduDevice  *device,
-                                                 GError    **error)
+gdu_device_drive_ata_smart_get_historical_data_sync (GduDevice  *device,
+                                                     GError    **error)
 {
         GList *ret;
         GPtrArray *historical_data;
 
         ret = NULL;
         /* TODO: since, until */
-        if (!org_freedesktop_DeviceKit_Disks_Device_drive_smart_get_historical_data (device->priv->proxy,
+        if (!org_freedesktop_DeviceKit_Disks_Device_drive_ata_smart_get_historical_data (device->priv->proxy,
                                                                                      0,
                                                                                      0,
                                                                                      &historical_data,
                                                                                      error))
                 goto out;
 
-        ret = op_smart_historical_data_compute_ret (historical_data);
+        ret = op_ata_smart_historical_data_compute_ret (historical_data);
 out:
         return ret;
 }
diff --git a/src/gdu/gdu-device.h b/src/gdu/gdu-device.h
index c631aa8..c3e03ce 100644
--- a/src/gdu/gdu-device.h
+++ b/src/gdu/gdu-device.h
@@ -147,10 +147,6 @@ guint gdu_device_optical_disc_get_num_tracks (GduDevice *device);
 guint gdu_device_optical_disc_get_num_audio_tracks (GduDevice *device);
 guint gdu_device_optical_disc_get_num_sessions (GduDevice *device);
 
-gboolean gdu_device_drive_smart_get_is_capable (GduDevice *device);
-gboolean gdu_device_drive_smart_get_is_enabled (GduDevice *device);
-GduSmartData *gdu_device_get_smart_data (GduDevice *device);
-
 const char *gdu_device_linux_md_component_get_level (GduDevice *device);
 int         gdu_device_linux_md_component_get_num_raid_devices (GduDevice *device);
 const char *gdu_device_linux_md_component_get_uuid (GduDevice *device);
@@ -173,6 +169,51 @@ const char *gdu_device_linux_md_get_sync_action (GduDevice *device);
 double      gdu_device_linux_md_get_sync_percentage (GduDevice *device);
 guint64     gdu_device_linux_md_get_sync_speed (GduDevice *device);
 
+typedef enum {
+        GDU_ATA_SMART_OFFLINE_DATA_COLLECTION_STATUS_NEVER,
+        GDU_ATA_SMART_OFFLINE_DATA_COLLECTION_STATUS_SUCCESS,
+        GDU_ATA_SMART_OFFLINE_DATA_COLLECTION_STATUS_INPROGRESS,
+        GDU_ATA_SMART_OFFLINE_DATA_COLLECTION_STATUS_SUSPENDED,
+        GDU_ATA_SMART_OFFLINE_DATA_COLLECTION_STATUS_ABORTED,
+        GDU_ATA_SMART_OFFLINE_DATA_COLLECTION_STATUS_FATAL,
+        GDU_ATA_SMART_OFFLINE_DATA_COLLECTION_STATUS_UNKNOWN,
+} GduAtaSmartOfflineDataCollectionStatus;
+
+typedef enum {
+        GDU_ATA_SMART_SELF_TEST_EXECUTION_STATUS_SUCCESS_OR_NEVER = 0,
+        GDU_ATA_SMART_SELF_TEST_EXECUTION_STATUS_ABORTED = 1,
+        GDU_ATA_SMART_SELF_TEST_EXECUTION_STATUS_INTERRUPTED = 2,
+        GDU_ATA_SMART_SELF_TEST_EXECUTION_STATUS_FATAL = 3,
+        GDU_ATA_SMART_SELF_TEST_EXECUTION_STATUS_ERROR_UNKNOWN = 4,
+        GDU_ATA_SMART_SELF_TEST_EXECUTION_STATUS_ERROR_ELECTRICAL = 5,
+        GDU_ATA_SMART_SELF_TEST_EXECUTION_STATUS_ERROR_SERVO = 6,
+        GDU_ATA_SMART_SELF_TEST_EXECUTION_STATUS_ERROR_READ = 7,
+        GDU_ATA_SMART_SELF_TEST_EXECUTION_STATUS_ERROR_HANDLING = 8,
+        GDU_ATA_SMART_SELF_TEST_EXECUTION_STATUS_INPROGRESS = 15,
+} GduAtaSmartSelfTestExecutionStatus;
+
+gboolean    gdu_device_drive_ata_smart_get_is_available (GduDevice *device);
+gboolean    gdu_device_drive_ata_smart_get_is_failing (GduDevice *device);
+gboolean    gdu_device_drive_ata_smart_get_is_failing_valid (GduDevice *device);
+gboolean    gdu_device_drive_ata_smart_get_has_bad_sectors (GduDevice *device);
+gboolean    gdu_device_drive_ata_smart_get_has_bad_attributes (GduDevice *device);
+gdouble     gdu_device_drive_ata_smart_get_temperature_kelvin (GduDevice *device);
+guint64     gdu_device_drive_ata_smart_get_power_on_seconds (GduDevice *device);
+guint64     gdu_device_drive_ata_smart_get_time_collected (GduDevice *device);
+GduAtaSmartOfflineDataCollectionStatus gdu_device_drive_ata_smart_get_offline_data_collection_status (GduDevice *device);
+guint       gdu_device_drive_ata_smart_get_offline_data_collection_seconds (GduDevice *device);
+GduAtaSmartSelfTestExecutionStatus gdu_device_drive_ata_smart_get_self_test_execution_status (GduDevice *device);
+guint       gdu_device_drive_ata_smart_get_self_test_execution_percent_remaining (GduDevice *device);
+gboolean    gdu_device_drive_ata_smart_get_short_and_extended_self_test_available (GduDevice *device);
+gboolean    gdu_device_drive_ata_smart_get_conveyance_self_test_available (GduDevice *device);
+gboolean    gdu_device_drive_ata_smart_get_start_self_test_available (GduDevice *device);
+gboolean    gdu_device_drive_ata_smart_get_abort_self_test_available (GduDevice *device);
+guint       gdu_device_drive_ata_smart_get_short_self_test_polling_minutes (GduDevice *device);
+guint       gdu_device_drive_ata_smart_get_extended_self_test_polling_minutes (GduDevice *device);
+guint       gdu_device_drive_ata_smart_get_conveyance_self_test_polling_minutes (GduDevice *device);
+GList      *gdu_device_drive_ata_smart_get_attributes (GduDevice *device);
+GduAtaSmartAttribute *gdu_device_drive_ata_smart_get_attribute (GduDevice *device, const gchar *attr_name);
+
 /* ---------------------------------------------------------------------------------------------------- */
 
 void gdu_device_op_filesystem_mount                   (GduDevice                             *device,
@@ -245,17 +286,16 @@ void gdu_device_op_filesystem_set_label (GduDevice
 
 /* ---------------------------------------------------------------------------------------------------- */
 
-void gdu_device_op_drive_smart_initiate_selftest      (GduDevice                                        *device,
-                                                       const char                                       *test,
-                                                       gboolean                                          captive,
-                                                       GduDeviceDriveSmartInitiateSelftestCompletedFunc  callback,
-                                                       gpointer                                          user_data);
+void gdu_device_op_drive_ata_smart_initiate_selftest      (GduDevice                                        *device,
+                                                           const char                                       *test,
+                                                           GduDeviceDriveAtaSmartInitiateSelftestCompletedFunc  callback,
+                                                           gpointer                                          user_data);
 
 /* ---------------------------------------------------------------------------------------------------- */
 
-void  gdu_device_drive_smart_refresh_data (GduDevice                                  *device,
-                                           GduDeviceDriveSmartRefreshDataCompletedFunc callback,
-                                           gpointer                                    user_data);
+void  gdu_device_drive_ata_smart_refresh_data (GduDevice                                  *device,
+                                               GduDeviceDriveAtaSmartRefreshDataCompletedFunc callback,
+                                               gpointer                                    user_data);
 
 /* ---------------------------------------------------------------------------------------------------- */
 
@@ -313,7 +353,11 @@ void gdu_device_op_cancel_job (GduDevice *device,
 
 /* ---------------------------------------------------------------------------------------------------- */
 
-GList *gdu_device_drive_smart_get_historical_data_sync (GduDevice  *device,
+void gdu_device_drive_ata_smart_get_historical_data (GduDevice                                         *device,
+                                                     GduDeviceDriveAtaSmartGetHistoricalDataCompletedFunc  callback,
+                                                     gpointer                                           user_data);
+
+GList *gdu_device_drive_ata_smart_get_historical_data_sync (GduDevice  *device,
                                                         GError    **error);
 
 /* ---------------------------------------------------------------------------------------------------- */
diff --git a/src/gdu/gdu-private.h b/src/gdu/gdu-private.h
index 2beaa9f..6c5e45b 100644
--- a/src/gdu/gdu-private.h
+++ b/src/gdu/gdu-private.h
@@ -28,24 +28,29 @@
 
 #include "gdu-types.h"
 
-#define SMART_DATA_STRUCT_TYPE (dbus_g_type_get_struct ("GValueArray",   \
-                                                        G_TYPE_INT,      \
-                                                        G_TYPE_STRING,   \
-                                                        G_TYPE_INT,      \
-                                                        G_TYPE_INT,      \
-                                                        G_TYPE_INT,      \
-                                                        G_TYPE_INT,      \
-                                                        G_TYPE_STRING,   \
-                                                        G_TYPE_INVALID))
-
-#define HISTORICAL_SMART_DATA_STRUCT_TYPE (dbus_g_type_get_struct ("GValueArray",   \
-                                                                   G_TYPE_UINT64, \
-                                                                   G_TYPE_DOUBLE, \
-                                                                   G_TYPE_UINT64, \
-                                                                   G_TYPE_STRING, \
-                                                                   G_TYPE_BOOLEAN, \
-                                                                   dbus_g_type_get_collection ("GPtrArray", SMART_DATA_STRUCT_TYPE), \
-                                                                   G_TYPE_INVALID))
+#define ATA_SMART_ATTRIBUTE_STRUCT_TYPE (dbus_g_type_get_struct ("GValueArray", \
+                                                                 G_TYPE_UINT, \
+                                                                 G_TYPE_STRING, \
+                                                                 G_TYPE_UINT, \
+                                                                 G_TYPE_BOOLEAN, G_TYPE_BOOLEAN, \
+                                                                 G_TYPE_UCHAR, G_TYPE_BOOLEAN, \
+                                                                 G_TYPE_UCHAR, G_TYPE_BOOLEAN, \
+                                                                 G_TYPE_UCHAR, G_TYPE_BOOLEAN, \
+                                                                 G_TYPE_BOOLEAN, G_TYPE_BOOLEAN, \
+                                                                 G_TYPE_UINT, G_TYPE_UINT64, \
+                                                                 dbus_g_type_get_collection ("GArray", G_TYPE_UCHAR), \
+                                                                 G_TYPE_INVALID))
+
+#define ATA_SMART_HISTORICAL_DATA_STRUCT_TYPE (dbus_g_type_get_struct ("GValueArray",   \
+                                                                       G_TYPE_UINT64, \
+                                                                       G_TYPE_BOOLEAN, \
+                                                                       G_TYPE_BOOLEAN, \
+                                                                       G_TYPE_BOOLEAN, \
+                                                                       G_TYPE_BOOLEAN, \
+                                                                       G_TYPE_DOUBLE, \
+                                                                       G_TYPE_UINT64, \
+                                                                       dbus_g_type_get_collection ("GPtrArray", ATA_SMART_ATTRIBUTE_STRUCT_TYPE), \
+                                                                       G_TYPE_INVALID))
 
 #define KNOWN_FILESYSTEMS_STRUCT_TYPE (dbus_g_type_get_struct ("GValueArray",   \
                                                                G_TYPE_STRING, \
@@ -70,15 +75,9 @@
                                                      G_TYPE_STRING,   \
                                                      G_TYPE_INVALID))
 
-GduSmartDataAttribute *_gdu_smart_data_attribute_new   (gpointer data);
-GduSmartData          *_gdu_smart_data_new_from_values (guint64     time_collected,
-                                                        double      temperature,
-                                                        guint64     time_powered_on,
-                                                        const char *last_self_test_result,
-                                                        gboolean    is_failing,
-                                                        GPtrArray  *attrs);
+GduAtaSmartAttribute *_gdu_ata_smart_attribute_new   (gpointer data);
 
-GduSmartData          * _gdu_smart_data_new            (gpointer data);
+GduAtaSmartHistoricalData * _gdu_ata_smart_historical_data_new            (gpointer data);
 
 GduKnownFilesystem    *_gdu_known_filesystem_new       (gpointer data);
 
diff --git a/src/gdu/gdu-smart-data-attribute.c b/src/gdu/gdu-smart-data-attribute.c
deleted file mode 100644
index 4415267..0000000
--- a/src/gdu/gdu-smart-data-attribute.c
+++ /dev/null
@@ -1,395 +0,0 @@
-/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- */
-/* gdu-smart-data-attribute.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 <stdlib.h>
-#include <string.h>
-#include <glib/gi18n.h>
-#include <dbus/dbus-glib.h>
-#include <time.h>
-
-#include "gdu-private.h"
-#include "gdu-smart-data-attribute.h"
-
-struct _GduSmartDataAttributePrivate {
-        /* TODO: use guint8 */
-        int id;
-        int value;
-        int worst;
-        int threshold;
-        int flags;
-        char *raw;
-        char *name;
-};
-
-static GObjectClass *parent_class = NULL;
-
-G_DEFINE_TYPE (GduSmartDataAttribute, gdu_smart_data_attribute, G_TYPE_OBJECT);
-
-static void
-gdu_smart_data_attribute_finalize (GduSmartDataAttribute *smart_data_attribute)
-{
-        g_free (smart_data_attribute->priv->raw);
-        g_free (smart_data_attribute->priv->name);
-        if (G_OBJECT_CLASS (parent_class)->finalize)
-                (* G_OBJECT_CLASS (parent_class)->finalize) (G_OBJECT (smart_data_attribute));
-}
-
-static void
-gdu_smart_data_attribute_class_init (GduSmartDataAttributeClass *klass)
-{
-        GObjectClass *obj_class = (GObjectClass *) klass;
-
-        parent_class = g_type_class_peek_parent (klass);
-
-        obj_class->finalize = (GObjectFinalizeFunc) gdu_smart_data_attribute_finalize;
-
-        g_type_class_add_private (klass, sizeof (GduSmartDataAttributePrivate));
-}
-
-static void
-gdu_smart_data_attribute_init (GduSmartDataAttribute *smart_data_attribute)
-{
-        smart_data_attribute->priv = G_TYPE_INSTANCE_GET_PRIVATE (smart_data_attribute, GDU_TYPE_SMART_DATA_ATTRIBUTE, GduSmartDataAttributePrivate);
-}
-
-int
-gdu_smart_data_attribute_get_id (GduSmartDataAttribute *smart_data_attribute)
-{
-        return smart_data_attribute->priv->id;
-}
-
-int
-gdu_smart_data_attribute_get_flags (GduSmartDataAttribute *smart_data_attribute)
-{
-        return smart_data_attribute->priv->flags;
-}
-
-int
-gdu_smart_data_attribute_get_value (GduSmartDataAttribute *smart_data_attribute)
-{
-        return smart_data_attribute->priv->value;
-}
-
-int
-gdu_smart_data_attribute_get_worst (GduSmartDataAttribute *smart_data_attribute)
-{
-        return smart_data_attribute->priv->worst;
-}
-
-int
-gdu_smart_data_attribute_get_threshold (GduSmartDataAttribute *smart_data_attribute)
-{
-        return smart_data_attribute->priv->threshold;
-}
-
-char *
-gdu_smart_data_attribute_get_raw (GduSmartDataAttribute *smart_data_attribute)
-{
-        return g_strdup (smart_data_attribute->priv->raw);
-}
-
-static void
-attribute_get_details (GduSmartDataAttribute  *attr,
-                       char                  **out_name,
-                       char                  **out_description,
-                       gboolean               *out_should_warn)
-{
-        const char *n;
-        const char *d;
-        gboolean warn;
-        int raw_int;
-
-        raw_int = atoi (attr->priv->raw);
-
-        /* See http://smartmontools.sourceforge.net/doc.html
-         *     http://en.wikipedia.org/wiki/S.M.A.R.T
-         *     http://www.t13.org/Documents/UploadedDocuments/docs2005/e05148r0-ACS-SMARTAttributesAnnex.pdf
-         */
-
-        n = NULL;
-        d = NULL;
-        warn = FALSE;
-        switch (attr->priv->id) {
-        case 1:
-                n = _("Read Error Rate");
-                d = _("Frequency of errors while reading raw data from the disk. "
-                      "A non-zero value indicates a problem with "
-                      "either the disk surface or read/write heads.");
-                break;
-        case 2:
-                n = _("Throughput Performance");
-                d = _("Average effeciency of the disk.");
-                break;
-        case 3:
-                n = _("Spinup Time");
-                d = _("Time needed to spin up the disk.");
-                break;
-        case 4:
-                n = _("Start/Stop Count");
-                d = _("Number of spindle start/stop cycles.");
-                break;
-        case 5:
-                n = _("Reallocated Sector Count");
-                d = _("Count of remapped sectors. "
-                      "When the hard drive finds a read/write/verification error, it mark the sector "
-                      "as \"reallocated\" and transfers data to a special reserved area (spare area).");
-                break;
-        case 7:
-                n = _("Seek Error Rate");
-                d = _("Frequency of errors while positioning.");
-                break;
-        case 8:
-                n = _("Seek Timer Performance");
-                d = _("Average efficiency of operatings while positioning");
-                break;
-        case 9:
-                n = _("Power-On Hours");
-                d = _("Number of hours elapsed in the power-on state.");
-                break;
-        case 10:
-                n = _("Spinup Retry Count");
-                d = _("Number of retry attempts to spin up.");
-                break;
-        case 11:
-                n = _("Calibration Retry Count");
-                d = _("Number of attempts to calibrate the device.");
-                break;
-        case 12:
-                n = _("Power Cycle Count");
-                d = _("Number of power-on events.");
-                break;
-        case 13:
-                n = _("Soft read error rate");
-                d = _("Frequency of 'program' errors while reading from the disk.");
-                break;
-
-        case 191:
-                n = _("G-sense Error Rate");
-                d = _("Frequency of mistakes as a result of impact loads.");
-                break;
-        case 192:
-                n = _("Power-off Retract Count");
-                d = _("Number of power-off or emergency retract cycles.");
-                break;
-        case 193:
-                n = _("Load/Unload Cycle Count");
-                d = _("Number of cycles into landing zone position.");
-                break;
-        case 194:
-                n = _("Temperature");
-                d = _("Current internal temperature in degrees Celcius.");
-                break;
-        case 195:
-                n = _("Hardware ECC Recovered");
-                d = _("Number of ECC on-the-fly errors.");
-                break;
-        case 196:
-                n = _("Reallocation Count");
-                d = _("Number of remapping operations. "
-                      "The raw value of this attribute shows the total number of (successful "
-                      "and unsucessful) attempts to transfer data from reallocated sectors "
-                      "to a spare area.");
-                break;
-        case 197:
-                n = _("Current Pending Sector Count");
-                d = _("Number of sectors waiting to be remapped. "
-                      "If the sector waiting to be remapped is subsequently written or read "
-                      "successfully, this value is decreased and the sector is not remapped. Read "
-                      "errors on the sector will not remap the sector, it will only be remapped on "
-                      "a failed write attempt.");
-                if (raw_int > 0)
-                        warn = TRUE;
-                break;
-        case 198:
-                n = _("Uncorrectable Sector Count");
-                d = _("The total number of uncorrectable errors when reading/writing a sector. "
-                      "A rise in the value of this attribute indicates defects of the "
-                      "disk surface and/or problems in the mechanical subsystem.");
-                break;
-        case 199:
-                n = _("UDMA CRC Error Rate");
-                d = _("Number of CRC errors during UDMA mode.");
-                break;
-        case 200:
-                n = _("Write Error Rate");
-                d = _("Number of errors while writing to disk (or) multi-zone error rate (or) flying-height.");
-                break;
-        case 201:
-                n = _("Soft Read Error Rate");
-                d = _("Number of off-track errors.");
-                break;
-        case 202:
-                n = _("Data Address Mark Errors");
-                d = _("Number of Data Address Mark (DAM) errors (or) vendor-specific.");
-                break;
-        case 203:
-                n = _("Run Out Cancel");
-                d = _("Number of ECC errors.");
-                break;
-        case 204:
-                n = _("Soft ECC correction");
-                d = _("Number of errors corrected by software ECC.");
-                break;
-        case 205:
-                n = _("Thermal Asperity Rate");
-                d = _("Number of Thermal Asperity Rate errors.");
-                break;
-        case 206:
-                n = _("Flying Height");
-                d = _("Height of heads above the disk surface.");
-                break;
-        case 207:
-                n = _("Spin High Current");
-                d = _("Amount of high current used to spin up the drive.");
-                break;
-        case 208:
-                n = _("Spin Buzz");
-                d = _("Number of buzz routines to spin up the drive.");
-                break;
-        case 209:
-                n = _("Offline Seek Performance");
-                d = _("Drive's seek performance during offline operations.");
-                break;
-
-        case 220:
-                n = _("Disk Shift");
-                d = _("Shift of disk os possible as a result of strong shock loading in the store, "
-                      "as a result of falling (or) temperature.");
-                break;
-        case 221:
-                n = _("G-sense Error Rate");
-                d = _("Number of errors as a result of impact loads as detected by a shock sensor.");
-                break;
-        case 222:
-                n = _("Loaded Hours");
-                d = _("Number of hours in general operational state.");
-                break;
-        case 223:
-                n = _("Load/Unload Retry Count");
-                d = _("Loading on drive caused by numerous recurrences of operations, like reading, "
-                      "recording, positioning of heads, etc.");
-                break;
-        case 224:
-                n = _("Load Friction");
-                d = _("Load on drive cause by friction in mechanical parts of the store.");
-                break;
-        case 225:
-                n = _("Load/Unload Cycle Count");
-                d = _("Total number of load cycles.");
-                break;
-        case 226:
-                n = _("Load-in Time");
-                d = _("General time for loading in a drive.");
-                break;
-        case 227:
-                n = _("Torque Amplification Count");
-                d = _("Quantity efforts of the rotating moment of a drive.");
-                break;
-        case 228:
-                n = _("Power-off Retract Count");
-                d = _("Number of power-off retract events.");
-                break;
-
-        case 230:
-                n = _("GMR Head Amplitude");
-                d = _("Amplitude of heads trembling (GMR-head) in running mode.");
-                break;
-        case 231:
-                n = _("Temperature");
-                d = _("Temperature of the drive.");
-                break;
-
-        case 240:
-                n = _("Head Flying Hours");
-                d = _("Time while head is positioning.");
-                break;
-        case 250:
-                n = _("Read Error Retry Rate");
-                d = _("Number of errors while reading from a disk.");
-                break;
-        default:
-                break;
-        }
-
-        if (out_name != NULL)
-                *out_name = g_strdup (n);
-        if (out_description != NULL)
-                *out_description = g_strdup (d);
-        if (out_should_warn != NULL)
-                *out_should_warn = warn;
-}
-
-
-char *
-gdu_smart_data_attribute_get_name (GduSmartDataAttribute *smart_data_attribute)
-{
-        char *s;
-        attribute_get_details (smart_data_attribute, &s, NULL, NULL);
-        if (s == NULL)
-                s = g_strdup (smart_data_attribute->priv->name);
-        return s;
-}
-
-char *
-gdu_smart_data_attribute_get_description (GduSmartDataAttribute *smart_data_attribute)
-{
-        char *s;
-        attribute_get_details (smart_data_attribute, NULL, &s, NULL);
-        return s;
-}
-
-gboolean
-gdu_smart_data_attribute_is_warning (GduSmartDataAttribute *smart_data_attribute)
-{
-        gboolean should_warn;
-        attribute_get_details (smart_data_attribute, NULL, NULL, &should_warn);
-        return should_warn;
-}
-
-gboolean
-gdu_smart_data_attribute_is_failing (GduSmartDataAttribute *smart_data_attribute)
-{
-        return smart_data_attribute->priv->value < smart_data_attribute->priv->threshold;
-}
-
-GduSmartDataAttribute *
-_gdu_smart_data_attribute_new (gpointer data)
-{
-        GValue elem = {0};
-        GduSmartDataAttribute *smart_data_attribute;
-
-        smart_data_attribute = GDU_SMART_DATA_ATTRIBUTE (g_object_new (GDU_TYPE_SMART_DATA_ATTRIBUTE, NULL));
-
-        g_value_init (&elem, SMART_DATA_STRUCT_TYPE);
-        g_value_set_static_boxed (&elem, data);
-        dbus_g_type_struct_get (&elem,
-                                0, &(smart_data_attribute->priv->id),
-                                1, &(smart_data_attribute->priv->name),
-                                2, &(smart_data_attribute->priv->flags),
-                                3, &(smart_data_attribute->priv->value),
-                                4, &(smart_data_attribute->priv->worst),
-                                5, &(smart_data_attribute->priv->threshold),
-                                6, &(smart_data_attribute->priv->raw),
-                                G_MAXUINT);
-
-        return smart_data_attribute;
-}
diff --git a/src/gdu/gdu-smart-data-attribute.h b/src/gdu/gdu-smart-data-attribute.h
deleted file mode 100644
index 7d05134..0000000
--- a/src/gdu/gdu-smart-data-attribute.h
+++ /dev/null
@@ -1,71 +0,0 @@
-/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- */
-/* gdu-smart-data-attribute.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.
- */
-
-#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_SMART_DATA_ATTRIBUTE_H
-#define __GDU_SMART_DATA_ATTRIBUTE_H
-
-#include <gdu/gdu-types.h>
-
-G_BEGIN_DECLS
-
-#define GDU_TYPE_SMART_DATA_ATTRIBUTE         (gdu_smart_data_attribute_get_type ())
-#define GDU_SMART_DATA_ATTRIBUTE(o)           (G_TYPE_CHECK_INSTANCE_CAST ((o), GDU_TYPE_SMART_DATA_ATTRIBUTE, GduSmartDataAttribute))
-#define GDU_SMART_DATA_ATTRIBUTE_CLASS(k)     (G_TYPE_CHECK_CLASS_CAST ((k), GDU_SMART_DATA_ATTRIBUTE,  GduSmartDataAttributeClass))
-#define GDU_IS_SMART_DATA_ATTRIBUTE(o)        (G_TYPE_CHECK_INSTANCE_TYPE ((o), GDU_TYPE_SMART_DATA_ATTRIBUTE))
-#define GDU_IS_SMART_DATA_ATTRIBUTE_CLASS(k)  (G_TYPE_CHECK_CLASS_TYPE ((k), GDU_TYPE_SMART_DATA_ATTRIBUTE))
-#define GDU_SMART_DATA_ATTRIBUTE_GET_CLASS(k) (G_TYPE_INSTANCE_GET_CLASS ((k), GDU_TYPE_SMART_DATA_ATTRIBUTE, GduSmartDataAttributeClass))
-
-typedef struct _GduSmartDataAttributeClass       GduSmartDataAttributeClass;
-typedef struct _GduSmartDataAttributePrivate     GduSmartDataAttributePrivate;
-
-struct _GduSmartDataAttribute
-{
-        GObject parent;
-
-        /* private */
-        GduSmartDataAttributePrivate *priv;
-};
-
-struct _GduSmartDataAttributeClass
-{
-        GObjectClass parent_class;
-
-};
-
-GType    gdu_smart_data_attribute_get_type        (void);
-int      gdu_smart_data_attribute_get_id          (GduSmartDataAttribute *smart_data_attribute);
-int      gdu_smart_data_attribute_get_flags       (GduSmartDataAttribute *smart_data_attribute);
-int      gdu_smart_data_attribute_get_value       (GduSmartDataAttribute *smart_data_attribute);
-int      gdu_smart_data_attribute_get_worst       (GduSmartDataAttribute *smart_data_attribute);
-int      gdu_smart_data_attribute_get_threshold   (GduSmartDataAttribute *smart_data_attribute);
-char    *gdu_smart_data_attribute_get_raw         (GduSmartDataAttribute *smart_data_attribute);
-char    *gdu_smart_data_attribute_get_name        (GduSmartDataAttribute *smart_data_attribute);
-char    *gdu_smart_data_attribute_get_description (GduSmartDataAttribute *smart_data_attribute);
-gboolean gdu_smart_data_attribute_is_warning      (GduSmartDataAttribute *smart_data_attribute);
-gboolean gdu_smart_data_attribute_is_failing      (GduSmartDataAttribute *smart_data_attribute);
-
-G_END_DECLS
-
-#endif /* __GDU_SMART_DATA_ATTRIBUTE_H */
diff --git a/src/gdu/gdu-smart-data.c b/src/gdu/gdu-smart-data.c
deleted file mode 100644
index cc83764..0000000
--- a/src/gdu/gdu-smart-data.c
+++ /dev/null
@@ -1,231 +0,0 @@
-/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- */
-/* gdu-smart-data.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 <stdlib.h>
-#include <string.h>
-#include <glib/gi18n.h>
-#include <dbus/dbus-glib.h>
-#include <time.h>
-
-#include "gdu-private.h"
-#include "gdu-smart-data.h"
-#include "gdu-smart-data-attribute.h"
-
-struct _GduSmartDataPrivate {
-        guint64 time_collected;
-        double temperature;
-        guint64 time_powered_on;
-        char *last_self_test_result;
-        gboolean is_failing;
-        GList *attrs;
-};
-
-static GObjectClass *parent_class = NULL;
-
-G_DEFINE_TYPE (GduSmartData, gdu_smart_data, G_TYPE_OBJECT);
-
-static void
-gdu_smart_data_finalize (GduSmartData *smart_data)
-{
-        g_free (smart_data->priv->last_self_test_result);
-        g_list_foreach (smart_data->priv->attrs, (GFunc) g_object_unref, NULL);
-        g_list_free (smart_data->priv->attrs);
-        if (G_OBJECT_CLASS (parent_class)->finalize)
-                (* G_OBJECT_CLASS (parent_class)->finalize) (G_OBJECT (smart_data));
-}
-
-static void
-gdu_smart_data_class_init (GduSmartDataClass *klass)
-{
-        GObjectClass *obj_class = (GObjectClass *) klass;
-
-        parent_class = g_type_class_peek_parent (klass);
-
-        obj_class->finalize = (GObjectFinalizeFunc) gdu_smart_data_finalize;
-
-        g_type_class_add_private (klass, sizeof (GduSmartDataPrivate));
-}
-
-static void
-gdu_smart_data_init (GduSmartData *smart_data)
-{
-        smart_data->priv = G_TYPE_INSTANCE_GET_PRIVATE (smart_data, GDU_TYPE_SMART_DATA, GduSmartDataPrivate);
-}
-
-guint64
-gdu_smart_data_get_time_collected (GduSmartData *smart_data)
-{
-        return smart_data->priv->time_collected;
-}
-
-double
-gdu_smart_data_get_temperature (GduSmartData *smart_data)
-{
-        return smart_data->priv->temperature;
-}
-
-guint64
-gdu_smart_data_get_time_powered_on (GduSmartData *smart_data)
-{
-        return smart_data->priv->time_powered_on;
-}
-
-char *
-gdu_smart_data_get_last_self_test_result (GduSmartData *smart_data)
-{
-        return g_strdup (smart_data->priv->last_self_test_result);
-}
-
-gboolean
-gdu_smart_data_get_attribute_warning (GduSmartData *smart_data)
-{
-        GList *l;
-        gboolean ret;
-
-        ret = FALSE;
-        for (l = smart_data->priv->attrs; l != NULL; l = l->next) {
-                GduSmartDataAttribute *attr = GDU_SMART_DATA_ATTRIBUTE (l->data);
-                if (gdu_smart_data_attribute_is_warning (attr)) {
-                        ret = TRUE;
-                        goto out;
-                }
-        }
-out:
-        return ret;
-}
-
-gboolean
-gdu_smart_data_get_attribute_failing (GduSmartData *smart_data)
-{
-        GList *l;
-        gboolean ret;
-
-        ret = FALSE;
-        for (l = smart_data->priv->attrs; l != NULL; l = l->next) {
-                GduSmartDataAttribute *attr = GDU_SMART_DATA_ATTRIBUTE (l->data);
-                if (gdu_smart_data_attribute_is_failing (attr)) {
-                        ret = TRUE;
-                        goto out;
-                }
-        }
-out:
-        return ret;
-}
-
-gboolean
-gdu_smart_data_get_is_failing (GduSmartData *smart_data)
-{
-        return smart_data->priv->is_failing;
-}
-
-GList *
-gdu_smart_data_get_attributes (GduSmartData *smart_data)
-{
-        GList *ret;
-        ret = g_list_copy (smart_data->priv->attrs);
-        g_list_foreach (ret, (GFunc) g_object_ref, NULL);
-        return ret;
-}
-
-GduSmartDataAttribute *
-gdu_smart_data_get_attribute (GduSmartData *smart_data,
-                              int id)
-{
-        GList *l;
-        GduSmartDataAttribute *ret;
-
-        /* TODO: if this is slow we can do a hash table */
-
-        ret = NULL;
-
-        for (l = smart_data->priv->attrs; l != NULL; l = l->next) {
-                GduSmartDataAttribute *a = l->data;
-                if (gdu_smart_data_attribute_get_id (a) == id) {
-                        ret = g_object_ref (a);
-                        goto out;
-                }
-        }
-out:
-        return ret;
-}
-
-GduSmartData *
-_gdu_smart_data_new (gpointer data)
-{
-        GduSmartData *smart_data;
-        GValue elem0 = {0};
-        GPtrArray *attrs;
-        int n;
-
-        smart_data = GDU_SMART_DATA (g_object_new (GDU_TYPE_SMART_DATA, NULL));
-
-        g_value_init (&elem0, HISTORICAL_SMART_DATA_STRUCT_TYPE);
-        g_value_set_static_boxed (&elem0, data);
-        dbus_g_type_struct_get (&elem0,
-                                0, &(smart_data->priv->time_collected),
-                                1, &(smart_data->priv->temperature),
-                                2, &(smart_data->priv->time_powered_on),
-                                3, &(smart_data->priv->last_self_test_result),
-                                4, &(smart_data->priv->is_failing),
-                                5, &attrs,
-                                G_MAXUINT);
-
-        smart_data->priv->attrs = NULL;
-        if (attrs != NULL) {
-                for (n = 0; n < (int) attrs->len; n++) {
-                        smart_data->priv->attrs = g_list_prepend (smart_data->priv->attrs,
-                                                                  _gdu_smart_data_attribute_new (attrs->pdata[n]));
-                }
-                smart_data->priv->attrs = g_list_reverse (smart_data->priv->attrs);
-        }
-
-        return smart_data;
-}
-
-GduSmartData *
-_gdu_smart_data_new_from_values (guint64 time_collected,
-                                 double temperature,
-                                 guint64 time_powered_on,
-                                 const char *last_self_test_result,
-                                 gboolean is_failing,
-                                 GPtrArray *attrs)
-{
-        GduSmartData *smart_data;
-        int n;
-
-        smart_data = GDU_SMART_DATA (g_object_new (GDU_TYPE_SMART_DATA, NULL));
-        smart_data->priv->time_collected = time_collected;
-        smart_data->priv->temperature = temperature;
-        smart_data->priv->time_powered_on = time_powered_on;
-        smart_data->priv->last_self_test_result = g_strdup (last_self_test_result);
-        smart_data->priv->is_failing = is_failing;
-
-        smart_data->priv->attrs = NULL;
-        if (attrs != NULL) {
-                for (n = 0; n < (int) attrs->len; n++) {
-                        smart_data->priv->attrs = g_list_prepend (smart_data->priv->attrs,
-                                                                  _gdu_smart_data_attribute_new (attrs->pdata[n]));
-                }
-                smart_data->priv->attrs = g_list_reverse (smart_data->priv->attrs);
-        }
-        return smart_data;
-}
diff --git a/src/gdu/gdu-smart-data.h b/src/gdu/gdu-smart-data.h
deleted file mode 100644
index b5816b6..0000000
--- a/src/gdu/gdu-smart-data.h
+++ /dev/null
@@ -1,72 +0,0 @@
-/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- */
-/* gdu-smart-data.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.
- */
-
-
-#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_SMART_DATA_H
-#define __GDU_SMART_DATA_H
-
-#include <gdu/gdu-types.h>
-
-G_BEGIN_DECLS
-
-#define GDU_TYPE_SMART_DATA           (gdu_smart_data_get_type ())
-#define GDU_SMART_DATA(o)             (G_TYPE_CHECK_INSTANCE_CAST ((o), GDU_TYPE_SMART_DATA, GduSmartData))
-#define GDU_SMART_DATA_CLASS(k)       (G_TYPE_CHECK_CLASS_CAST ((k), GDU_SMART_DATA,  GduSmartDataClass))
-#define GDU_IS_SMART_DATA(o)          (G_TYPE_CHECK_INSTANCE_TYPE ((o), GDU_TYPE_SMART_DATA))
-#define GDU_IS_SMART_DATA_CLASS(k)    (G_TYPE_CHECK_CLASS_TYPE ((k), GDU_TYPE_SMART_DATA))
-#define GDU_SMART_DATA_GET_CLASS(k)   (G_TYPE_INSTANCE_GET_CLASS ((k), GDU_TYPE_SMART_DATA, GduSmartDataClass))
-
-typedef struct _GduSmartDataClass       GduSmartDataClass;
-typedef struct _GduSmartDataPrivate     GduSmartDataPrivate;
-
-struct _GduSmartData
-{
-        GObject parent;
-
-        /* private */
-        GduSmartDataPrivate *priv;
-};
-
-struct _GduSmartDataClass
-{
-        GObjectClass parent_class;
-
-};
-
-GType                  gdu_smart_data_get_type                  (void);
-guint64                gdu_smart_data_get_time_collected        (GduSmartData *smart_data);
-double                 gdu_smart_data_get_temperature           (GduSmartData *smart_data);
-guint64                gdu_smart_data_get_time_powered_on       (GduSmartData *smart_data);
-char                  *gdu_smart_data_get_last_self_test_result (GduSmartData *smart_data);
-gboolean               gdu_smart_data_get_is_failing            (GduSmartData *smart_data);
-GList                 *gdu_smart_data_get_attributes            (GduSmartData *smart_data);
-gboolean               gdu_smart_data_get_attribute_warning     (GduSmartData *smart_data);
-gboolean               gdu_smart_data_get_attribute_failing     (GduSmartData *smart_data);
-GduSmartDataAttribute *gdu_smart_data_get_attribute             (GduSmartData *smart_data,
-                                                                 int id);
-
-G_END_DECLS
-
-#endif /* __GDU_SMART_DATA_H */
diff --git a/src/gdu/gdu-types.h b/src/gdu/gdu-types.h
index b31054e..8e3c826 100644
--- a/src/gdu/gdu-types.h
+++ b/src/gdu/gdu-types.h
@@ -33,18 +33,18 @@ G_BEGIN_DECLS
 
 /* forward type definitions */
 
-typedef struct _GduPool                GduPool;
-typedef struct _GduDevice              GduDevice;
-typedef struct _GduPresentable         GduPresentable; /* Dummy typedef */
-typedef struct _GduDrive               GduDrive;
-typedef struct _GduLinuxMdDrive        GduLinuxMdDrive;
-typedef struct _GduVolume              GduVolume;
-typedef struct _GduVolumeHole          GduVolumeHole;
-
-typedef struct _GduKnownFilesystem     GduKnownFilesystem;
-typedef struct _GduProcess             GduProcess;
-typedef struct _GduSmartData           GduSmartData;
-typedef struct _GduSmartDataAttribute  GduSmartDataAttribute;
+typedef struct _GduPool                   GduPool;
+typedef struct _GduDevice                 GduDevice;
+typedef struct _GduPresentable            GduPresentable; /* Dummy typedef */
+typedef struct _GduDrive                  GduDrive;
+typedef struct _GduLinuxMdDrive           GduLinuxMdDrive;
+typedef struct _GduVolume                 GduVolume;
+typedef struct _GduVolumeHole             GduVolumeHole;
+
+typedef struct _GduKnownFilesystem        GduKnownFilesystem;
+typedef struct _GduProcess                GduProcess;
+typedef struct _GduAtaSmartHistoricalData GduAtaSmartHistoricalData;
+typedef struct _GduAtaSmartAttribute      GduAtaSmartAttribute;
 
 G_END_DECLS
 
diff --git a/src/gdu/gdu.h b/src/gdu/gdu.h
index d4e8b9d..67aa4a2 100644
--- a/src/gdu/gdu.h
+++ b/src/gdu/gdu.h
@@ -37,8 +37,8 @@
 #include <gdu/gdu-pool.h>
 #include <gdu/gdu-presentable.h>
 #include <gdu/gdu-process.h>
-#include <gdu/gdu-smart-data.h>
-#include <gdu/gdu-smart-data-attribute.h>
+#include <gdu/gdu-ata-smart-historical-data.h>
+#include <gdu/gdu-ata-smart-attribute.h>
 #include <gdu/gdu-util.h>
 #include <gdu/gdu-volume.h>
 #include <gdu/gdu-volume-hole.h>
diff --git a/src/palimpsest/Makefile.am b/src/palimpsest/Makefile.am
index db5c57d..21322c8 100644
--- a/src/palimpsest/Makefile.am
+++ b/src/palimpsest/Makefile.am
@@ -3,7 +3,6 @@ bin_PROGRAMS = palimpsest
 
 palimpsest_SOURCES = 									\
 						gdu-main.c				\
-	gdu-time-label.h			gdu-time-label.c			\
 	gdu-shell.h				gdu-shell.c				\
 	gdu-section.h				gdu-section.c				\
 	gdu-section-health.h			gdu-section-health.c			\
diff --git a/src/palimpsest/gdu-section-health.c b/src/palimpsest/gdu-section-health.c
index f8288eb..db54235 100644
--- a/src/palimpsest/gdu-section-health.c
+++ b/src/palimpsest/gdu-section-health.c
@@ -28,7 +28,7 @@
 #include <polkit-gnome/polkit-gnome.h>
 
 #include <gdu/gdu.h>
-#include "gdu-time-label.h"
+#include <gdu-gtk/gdu-gtk.h>
 #include "gdu-section-health.h"
 
 struct _GduSectionHealthPrivate
@@ -54,6 +54,50 @@ static GObjectClass *parent_class = NULL;
 G_DEFINE_TYPE (GduSectionHealth, gdu_section_health, GDU_TYPE_SECTION)
 
 /* ---------------------------------------------------------------------------------------------------- */
+static gchar *
+pretty_to_string (guint64 pretty_value, GduAtaSmartAttributeUnit pretty_unit)
+{
+        gchar *ret;
+        gdouble celcius;
+        gdouble fahrenheit;
+
+        switch (pretty_unit) {
+
+        case GDU_ATA_SMART_ATTRIBUTE_UNIT_MSECONDS:
+                if (pretty_value > 1000 * 60 * 60 * 24) {
+                        ret = g_strdup_printf (_("%.3g days"), pretty_value / 1000.0 / 60.0 / 60.0 / 24.0);
+                } else if (pretty_value > 1000 * 60 * 60) {
+                        ret = g_strdup_printf (_("%.3g hours"), pretty_value / 1000.0 / 60.0 / 60.0);
+                } else if (pretty_value > 1000 * 60) {
+                        ret = g_strdup_printf (_("%.3g mins"), pretty_value / 1000.0 / 60.0);
+                } else if (pretty_value > 1000) {
+                        ret = g_strdup_printf (_("%.3g secs"), pretty_value / 1000.0);
+                } else {
+                        ret = g_strdup_printf (_("%" G_GUINT64_FORMAT " msec"), pretty_value);
+                }
+                break;
+
+        case GDU_ATA_SMART_ATTRIBUTE_UNIT_SECTORS:
+                ret = g_strdup_printf (_("%" G_GUINT64_FORMAT " Sectors"), pretty_value);
+                break;
+
+        case GDU_ATA_SMART_ATTRIBUTE_UNIT_MKELVIN:
+                celcius = pretty_value / 1000.0 - 273.15;
+                fahrenheit = 9.0 * celcius / 5.0 + 32.0;
+                ret = g_strdup_printf (_("%.3g\302\260 C / %.3g\302\260 F"), celcius, fahrenheit);
+                break;
+
+        default:
+        case GDU_ATA_SMART_ATTRIBUTE_UNIT_NONE:
+        case GDU_ATA_SMART_ATTRIBUTE_UNIT_UNKNOWN:
+                ret = g_strdup_printf (_("%" G_GUINT64_FORMAT), pretty_value);
+                break;
+        }
+
+        return ret;
+}
+
+/* ---------------------------------------------------------------------------------------------------- */
 
 static void
 smart_data_set_pending (GduSectionHealth *section)
@@ -79,7 +123,7 @@ smart_data_set_not_supported (GduSectionHealth *section)
         gtk_image_set_from_icon_name (GTK_IMAGE (section->priv->health_status_image),
                                       "gdu-smart-unknown",
                                       GTK_ICON_SIZE_MENU);
-        gtk_label_set_markup (GTK_LABEL (section->priv->health_status_label), _("<i>S.M.A.R.T. Not Supported</i>"));
+        gtk_label_set_markup (GTK_LABEL (section->priv->health_status_label), _("<i>ATA SMART Not Supported</i>"));
         gtk_label_set_text (GTK_LABEL (section->priv->health_power_on_hours_label), _("-"));
         gtk_label_set_text (GTK_LABEL (section->priv->health_temperature_label), _("-"));
         gtk_label_set_text (GTK_LABEL (section->priv->health_updated_label), _("-"));
@@ -91,24 +135,40 @@ smart_data_set_not_supported (GduSectionHealth *section)
         gtk_widget_hide (section->priv->health_status_explanation_label);
 }
 
+enum
+{
+        ATTR_ID_NAME_COLUMN,
+        ATTR_ID_INT_COLUMN,
+        ATTR_ID_COLUMN,
+        ATTR_DESC_COLUMN,
+        ATTR_CURRENT_COLUMN,
+        ATTR_WORST_COLUMN,
+        ATTR_THRESHOLD_COLUMN,
+        ATTR_VALUE_COLUMN,
+        ATTR_STATUS_PIXBUF_COLUMN,
+        ATTR_STATUS_TEXT_COLUMN,
+        ATTR_TYPE_COLUMN,
+        ATTR_UPDATES_COLUMN,
+        ATTR_TOOLTIP_COLUMN,
+        ATTR_N_COLUMNS,
+};
+
 static void
 smart_data_set (GduSectionHealth *section)
 {
         char *s;
-        double fahrenheit;
-        const char *last;
-        gboolean passed;
-        int power_on_hours;
-        double temperature;
-        char *last_self_test_result;
+        guint64 temperature_mkelvin;
+        guint64 power_on_msec;
         GduDevice *device;
-        gboolean attr_warn;
-        gboolean attr_fail;
         GTimeVal updated;
-        GduSmartData *sd;
-
-        sd = NULL;
-        last_self_test_result = NULL;
+        const gchar *text;
+        const gchar *explanation;
+        const gchar *icon_name;
+        gboolean is_failing;
+        gboolean is_failing_valid;
+        gboolean has_bad_sectors;
+        gboolean has_bad_attributes;
+        GduAtaSmartSelfTestExecutionStatus self_test_status;
 
         device = gdu_presentable_get_device (gdu_section_get_presentable (GDU_SECTION (section)));
         if (device == NULL) {
@@ -116,126 +176,149 @@ smart_data_set (GduSectionHealth *section)
                 goto out;
         }
 
-        sd = gdu_device_get_smart_data (device);
-        if (sd == NULL) {
-                g_warning ("%s: no smart data for device", __FUNCTION__);
+        if (!gdu_device_drive_ata_smart_get_is_available (device)) {
+                g_warning ("%s: device does not support ATA SMART", __FUNCTION__);
                 goto out;
         }
 
-        passed = ! gdu_smart_data_get_is_failing (sd);
-        attr_warn = gdu_smart_data_get_attribute_warning (sd);
-        attr_fail = gdu_smart_data_get_attribute_failing (sd);
-        power_on_hours = gdu_smart_data_get_time_powered_on (sd) / 3600;
-        temperature = gdu_smart_data_get_temperature (sd);
-        last_self_test_result = gdu_smart_data_get_last_self_test_result (sd);
+        is_failing = gdu_device_drive_ata_smart_get_is_failing (device);
+        is_failing_valid = gdu_device_drive_ata_smart_get_is_failing_valid (device);
+
+        self_test_status = gdu_device_drive_ata_smart_get_self_test_execution_status (device);
+
+        power_on_msec = 1000 * gdu_device_drive_ata_smart_get_power_on_seconds (device);
+        temperature_mkelvin = (guint64) (gdu_device_drive_ata_smart_get_temperature_kelvin (device) * 1000.0);
+
+        has_bad_sectors = gdu_device_drive_ata_smart_get_has_bad_sectors (device);
+        has_bad_attributes = gdu_device_drive_ata_smart_get_has_bad_attributes (device);
 
         polkit_gnome_action_set_sensitive (section->priv->health_refresh_action, TRUE);
         polkit_gnome_action_set_sensitive (section->priv->health_details_action, TRUE);
         polkit_gnome_action_set_sensitive (section->priv->health_selftest_action, TRUE);
         gtk_widget_show (section->priv->health_status_image);
 
-        if (passed) {
-                if (attr_fail) {
-                        gtk_image_set_from_icon_name (GTK_IMAGE (section->priv->health_status_image),
-                                                      "gdu-smart-threshold",
-                                                      GTK_ICON_SIZE_MENU);
-                        gtk_label_set_text (GTK_LABEL (section->priv->health_status_label),
-                                            _("Passed"));
-                        gtk_label_set_markup (GTK_LABEL (section->priv->health_status_explanation_label),
-                                              _("<small><i><b>"
-                                                "One or more attributes failing."
-                                                "</b></i></small>"));
-                } else if (attr_warn) {
-                        gtk_image_set_from_icon_name (GTK_IMAGE (section->priv->health_status_image),
-                                                      "gdu-smart-threshold",
-                                                      GTK_ICON_SIZE_MENU);
-                        gtk_label_set_text (GTK_LABEL (section->priv->health_status_label),
-                                            _("Passed"));
-                        gtk_label_set_markup (GTK_LABEL (section->priv->health_status_explanation_label),
-                                              _("<small><i><b>"
-                                                "One or more attributes non-zero but within threshold."
-                                                "</b></i></small>"));
+        explanation = NULL;
+        if (is_failing_valid) {
+                if (!is_failing) {
+                        if (has_bad_sectors) {
+                                icon_name = "gdu-smart-threshold";
+                                text = _("Passed");
+                                explanation = _("<small><i>"
+                                                "The disk has bad sectors."
+                                                "</i></small>");
+                        } else if (has_bad_attributes) {
+                                icon_name = "gdu-smart-threshold";
+                                text = _("Passed");
+                                explanation = _("<small><i>"
+                                                "One or more attributes exceeding threshold."
+                                                "</i></small>");
+                        } else {
+                                icon_name = "gdu-smart-healthy";
+                                text = _("Passed");
+                        }
                 } else {
-                        gtk_image_set_from_icon_name (GTK_IMAGE (section->priv->health_status_image),
-                                                      "gdu-smart-healthy",
-                                                      GTK_ICON_SIZE_MENU);
-                        gtk_label_set_text (GTK_LABEL (section->priv->health_status_label),
-                                            _("Passed"));
-                        gtk_widget_hide (section->priv->health_status_explanation_label);
-                }
-        } else {
-                gtk_image_set_from_icon_name (GTK_IMAGE (section->priv->health_status_image),
-                                              "gdu-smart-failing",
-                                              GTK_ICON_SIZE_MENU);
-                gtk_label_set_markup (GTK_LABEL (section->priv->health_status_label), _("<span foreground='red'><b>FAILING</b></span>"));
-                gtk_label_set_markup (GTK_LABEL (section->priv->health_status_explanation_label),
-                                      _("<small><i><b>"
+                        icon_name = "gdu-smart-failing";
+                        text = _("<span foreground='red'><b>FAILING</b></span>");
+                        explanation = _("<small><i>"
                                         "Drive failure expected in less than 24 hours. "
                                         "Save all data immediately."
-                                        "</b></i></small>"));
+                                        "</i></small>");
+                }
+        } else {
+                if (has_bad_sectors) {
+                        icon_name = "gdu-smart-threshold";
+                        text = _("Unknown");
+                        explanation = _("<small><i>"
+                                        "The disk has bad sectors."
+                                        "</i></small>");
+                } else if (has_bad_attributes) {
+                        icon_name = "gdu-smart-threshold";
+                        text = _("Unknown");
+                        explanation = _("<small><i>"
+                                        "One or more attributes exceeding threshold."
+                                        "</i></small>");
+                } else {
+                        icon_name = "gdu-smart-unknown";
+                        text = _("Unknown");
+                }
+        }
+
+        gtk_label_set_text (GTK_LABEL (section->priv->health_status_label), text);
+        if (explanation == NULL) {
+                        gtk_widget_hide (section->priv->health_status_explanation_label);
+        } else {
+                gtk_label_set_markup (GTK_LABEL (section->priv->health_status_explanation_label), explanation);
+                gtk_widget_show (section->priv->health_status_explanation_label);
         }
+        gtk_image_set_from_icon_name (GTK_IMAGE (section->priv->health_status_image), icon_name, GTK_ICON_SIZE_MENU);
+
         /* TODO: use gdu-smart-threshold if one or more attributes exceeds threshold */
 
-        if (power_on_hours < 24)
-                s = g_strdup_printf (_("%d hours"), power_on_hours);
-        else {
-                int d;
-                int h;
-
-                d = power_on_hours / 24;
-                h = power_on_hours - d * 24;
-
-                if (d == 0)
-                        s = g_strdup_printf (_("%d days"), d);
-                else if (d == 1)
-                        s = g_strdup_printf (_("%d days, 1 hour"), d);
-                else
-                        s = g_strdup_printf (_("%d days, %d hours"), d, h);
+        if (power_on_msec == 0) {
+                s = g_strdup (_("Unknown"));
+        } else {
+                s = pretty_to_string (power_on_msec, GDU_ATA_SMART_ATTRIBUTE_UNIT_MSECONDS);
         }
         gtk_label_set_text (GTK_LABEL (section->priv->health_power_on_hours_label), s);
         g_free (s);
 
-        fahrenheit = 9.0 * temperature / 5.0 + 32.0;
-        s = g_strdup_printf (_("%g° C / %g° F"), temperature, fahrenheit);
+        if (temperature_mkelvin == 0) {
+                s = g_strdup (_("Unknown"));
+        } else {
+                s = pretty_to_string (temperature_mkelvin, GDU_ATA_SMART_ATTRIBUTE_UNIT_MKELVIN);
+        }
         gtk_label_set_text (GTK_LABEL (section->priv->health_temperature_label), s);
         g_free (s);
 
-        updated.tv_sec = gdu_smart_data_get_time_collected (sd);
+        updated.tv_sec = gdu_device_drive_ata_smart_get_time_collected (device);
         updated.tv_usec = 0;
         gdu_time_label_set_time (GDU_TIME_LABEL (section->priv->health_updated_label), &updated);
 
-        last = _("Unknown");
-        if (strcmp (last_self_test_result, "completed_ok") == 0) {
-                last = _("Completed OK");
-        } else if (strcmp (last_self_test_result, "not_completed_aborted") == 0) {
-                last = _("Cancelled");
-        } else if (strcmp (last_self_test_result, "not_completed_aborted_reset") == 0) {
-                last = _("Cancelled (with hard or soft reset)");
-        } else if (strcmp (last_self_test_result, "not_completed_unknown_reason") == 0) {
-                last = _("Not completed (a fatal error might have occured)");
-        } else if (strcmp (last_self_test_result, "completed_failed_electrical") == 0) {
-                last = _("<span foreground='red'><b>FAILED</b></span> (electrical test)");
-        } else if (strcmp (last_self_test_result, "completed_failed_servo") == 0) {
-                last = _("<span foreground='red'><b>FAILED</b></span> (servo/seek test)");
-        } else if (strcmp (last_self_test_result, "completed_failed_read") == 0) {
-                last = _("<span foreground='red'><b>FAILED</b></span> (read test)");
-        } else if (strcmp (last_self_test_result, "completed_failed_damage") == 0) {
-                last = _("<span foreground='red'><b>FAILED</b></span> (device is suspected of having handled damage");
+        switch (self_test_status) {
+        case GDU_ATA_SMART_SELF_TEST_EXECUTION_STATUS_SUCCESS_OR_NEVER:
+                s = _("Completed OK");
+                break;
+        case GDU_ATA_SMART_SELF_TEST_EXECUTION_STATUS_ABORTED:
+                s = _("Cancelled");
+                break;
+        case GDU_ATA_SMART_SELF_TEST_EXECUTION_STATUS_INTERRUPTED:
+                s = _("Cancelled (with hard or soft reset)");
+                break;
+        case GDU_ATA_SMART_SELF_TEST_EXECUTION_STATUS_FATAL:
+                s = _("Not completed (a fatal error might have occured)");
+                break;
+        case GDU_ATA_SMART_SELF_TEST_EXECUTION_STATUS_ERROR_ELECTRICAL:
+                s = _("<span foreground='red'><b>FAILED</b></span> (Electrical)");
+                break;
+        case GDU_ATA_SMART_SELF_TEST_EXECUTION_STATUS_ERROR_SERVO:
+                s = _("<span foreground='red'><b>FAILED</b></span> (Servo)");
+                break;
+        case GDU_ATA_SMART_SELF_TEST_EXECUTION_STATUS_ERROR_READ:
+                s = _("<span foreground='red'><b>FAILED</b></span> (Read)");
+                break;
+        case GDU_ATA_SMART_SELF_TEST_EXECUTION_STATUS_ERROR_HANDLING:
+                s = _("<span foreground='red'><b>FAILED</b></span> (Suspected of having handled damage");
+                break;
+        case GDU_ATA_SMART_SELF_TEST_EXECUTION_STATUS_INPROGRESS:
+                s = _("In progress");
+                break;
+
+        default:
+        case GDU_ATA_SMART_SELF_TEST_EXECUTION_STATUS_ERROR_UNKNOWN:
+                s = _("Unknown");
+                break;
         }
-        gtk_label_set_markup (GTK_LABEL (section->priv->health_last_self_test_result_label), last);
+        gtk_label_set_markup (GTK_LABEL (section->priv->health_last_self_test_result_label), s);
 
 out:
-        g_free (last_self_test_result);
         if (device != NULL)
                 g_object_unref (device);
-        if (sd != NULL)
-                g_object_unref (sd);
 }
 
 static void
-retrieve_smart_data_cb (GduDevice  *device,
-                        GError     *error,
-                        gpointer    user_data)
+retrieve_ata_smart_data_cb (GduDevice  *device,
+                            GError     *error,
+                            gpointer    user_data)
 {
         GduSectionHealth *section = GDU_SECTION_HEALTH (user_data);
 
@@ -264,28 +347,13 @@ health_refresh_action_callback (GtkAction *action, gpointer user_data)
         }
 
         smart_data_set_pending (section);
-        gdu_device_drive_smart_refresh_data (device, retrieve_smart_data_cb, g_object_ref (section));
+        gdu_device_drive_ata_smart_refresh_data (device, retrieve_ata_smart_data_cb, g_object_ref (section));
 
 out:
         if (device != NULL)
                 g_object_unref (device);
 }
 
-enum
-{
-        ATTR_ID_INT_COLUMN,
-        ATTR_ID_COLUMN,
-        ATTR_DESC_COLUMN,
-        ATTR_VALUE_COLUMN,
-        ATTR_WORST_COLUMN,
-        ATTR_THRESHOLD_COLUMN,
-        ATTR_RAW_COLUMN,
-        ATTR_STATUS_PIXBUF_COLUMN,
-        ATTR_STATUS_TEXT_COLUMN,
-        ATTR_TOOLTIP_COLUMN,
-        ATTR_N_COLUMNS,
-};
-
 typedef struct
 {
         GList *history;
@@ -640,28 +708,24 @@ expose_event_callback (GtkWidget *widget, GdkEventExpose *event, gpointer user_d
         GtkTreeSelection *tree_selection;
         GtkTreeModel *tree_model;
         GtkTreeIter iter;
-        int selected_attr_id;
-
-        selected_attr_id = -1;
+        gchar *selected_attr_name;
 
+        selected_attr_name = NULL;
         tree_selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (data->tree_view));
         if (gtk_tree_selection_get_selected (tree_selection, &tree_model, &iter)) {
                 gtk_tree_model_get (tree_model, &iter,
-                                    ATTR_ID_INT_COLUMN,
-                                    &selected_attr_id,
+                                    ATTR_ID_NAME_COLUMN,
+                                    &selected_attr_name,
                                     -1);
         }
 
-        SegmentSet *temperature_segset;
         SegmentSet *attr_value_segset;
         SegmentSet *attr_thres_segset;
         SegmentSet *attr_raw_segset;
-        temperature_segset = segment_set_new ();
         attr_value_segset = segment_set_new ();
         attr_thres_segset = segment_set_new ();
         attr_raw_segset = segment_set_new ();
 
-        /* draw temperature graph (TODO: draw a smooth curve) */
         GList *l;
 
         cairo_new_path (cr);
@@ -675,19 +739,18 @@ expose_event_callback (GtkWidget *widget, GdkEventExpose *event, gpointer user_d
         last_segment_xpos = 0;
         for (l = data->history; l != NULL; l = l->next) {
                 double x;
-                double temperature_y;
-                GduSmartData *sd = GDU_SMART_DATA (l->data);
+                GduAtaSmartHistoricalData *sd = GDU_ATA_SMART_HISTORICAL_DATA (l->data);
 
-                x = gx + gw * ((double) gdu_smart_data_get_time_collected (sd) - (double) t_left) /
+                x = gx + gw * ((double) gdu_ata_smart_historical_data_get_time_collected (sd) - (double) t_left) /
                         ((double) t_right - (double) t_left);
 
                 if (x < gx) {
                         /* point is not in graph.. but do consider it if the *following* point is */
 
                         if (l->next != NULL) {
-                                GduSmartData *nsd = GDU_SMART_DATA (l->next->data);
+                                GduAtaSmartHistoricalData *nsd = GDU_ATA_SMART_HISTORICAL_DATA (l->next->data);
                                 double nx;
-                                nx = gx + gw * ((double) gdu_smart_data_get_time_collected (nsd) - (double) t_left) /
+                                nx = gx + gw * ((double) gdu_ata_smart_historical_data_get_time_collected (nsd) - (double) t_left) /
                                         ((double) t_right - (double) t_left);
                                 if (nx < gx)
                                         continue;
@@ -699,12 +762,11 @@ expose_event_callback (GtkWidget *widget, GdkEventExpose *event, gpointer user_d
                 /* If there's a discontinuity in the samples (more than 30 minutes between consecutive
                  * samples), draw a grey rectangle to convey this
                  */
-                if (prev_time_collected != 0 && (gdu_smart_data_get_time_collected (sd) -
+                if (prev_time_collected != 0 && (gdu_ata_smart_historical_data_get_time_collected (sd) -
                                                  prev_time_collected) > 30 * 60) {
                         cairo_pattern_t *pat;
                         double stop_size;
 
-                        segment_set_close (temperature_segset);
                         segment_set_close (attr_value_segset);
                         segment_set_close (attr_thres_segset);
                         segment_set_close (attr_raw_segset);
@@ -731,14 +793,10 @@ expose_event_callback (GtkWidget *widget, GdkEventExpose *event, gpointer user_d
                         cairo_pattern_destroy (pat);
                 }
 
-                temperature_y = gy + gh - gh * (gdu_smart_data_get_temperature (sd) - val_y_bottom) /
-                        (val_y_top - val_y_bottom);
-                segment_set_add_point (temperature_segset, x, temperature_y);
+                if (selected_attr_name != NULL) {
+                        GduAtaSmartAttribute *a;
 
-                if (selected_attr_id != -1) {
-                        GduSmartDataAttribute *a;
-
-                        a = gdu_smart_data_get_attribute (sd, selected_attr_id);
+                        a = gdu_ata_smart_historical_data_get_attribute (sd, selected_attr_name);
                         if (a != NULL) {
                                 double attr_value_y;
                                 double attr_thres_y;
@@ -746,8 +804,8 @@ expose_event_callback (GtkWidget *widget, GdkEventExpose *event, gpointer user_d
                                 int attr_value;
                                 int attr_thres;
 
-                                attr_value = gdu_smart_data_attribute_get_value (a);
-                                attr_thres = gdu_smart_data_attribute_get_threshold (a);
+                                attr_value = gdu_ata_smart_attribute_get_current (a);
+                                attr_thres = gdu_ata_smart_attribute_get_threshold (a);
 
                                 attr_value_y = gy + (256 - attr_value) * gh / 256.0;
                                 attr_thres_y = gy + (256 - attr_thres) * gh / 256.0;
@@ -755,22 +813,21 @@ expose_event_callback (GtkWidget *widget, GdkEventExpose *event, gpointer user_d
                                 segment_set_add_point (attr_value_segset, x, attr_value_y);
                                 segment_set_add_point (attr_thres_segset, x, attr_thres_y);
 
-                                attr_raw_y = atof (gdu_smart_data_attribute_get_raw (a));
+                                attr_raw_y = gdu_ata_smart_attribute_get_pretty_value (a);
                                 segment_set_add_point (attr_raw_segset, x, attr_raw_y);
 
                                 g_object_unref (a);
                         }
                 }
 
-                prev_time_collected = gdu_smart_data_get_time_collected (sd);
+                prev_time_collected = gdu_ata_smart_historical_data_get_time_collected (sd);
                 last_segment_xpos = x;
         }
 
         cairo_set_line_width (cr, 1.0);
         cairo_set_source_rgb (cr, 1.0, 0.64, 0.0);
-        segment_set_draw (temperature_segset, cr);
 
-        if (selected_attr_id != -1) {
+        if (selected_attr_name != NULL) {
                 double min_y, max_y;
                 double dashes[1] = {1.0};
                 cairo_set_dash (cr, dashes, 1, 0.0);
@@ -788,7 +845,8 @@ expose_event_callback (GtkWidget *widget, GdkEventExpose *event, gpointer user_d
                 segment_set_draw (attr_thres_segset, cr);
         }
 
-        segment_set_free (temperature_segset);
+        g_free (selected_attr_name);
+
         segment_set_free (attr_value_segset);
         segment_set_free (attr_thres_segset);
 
@@ -830,7 +888,7 @@ health_details_action_callback (GtkAction *action, gpointer user_data)
         GtkListStore *list_store;
         GtkCellRenderer *renderer;
         GtkTreeViewColumn *column;
-        GduSmartData *sd;
+        GduAtaSmartHistoricalData *sd;
         GList *attrs;
         GList *l;
 
@@ -843,7 +901,7 @@ health_details_action_callback (GtkAction *action, gpointer user_data)
                 goto out;
         }
 
-        dialog = gtk_dialog_new_with_buttons (_("S.M.A.R.T. Attributes"),
+        dialog = gtk_dialog_new_with_buttons (_("ATA SMART Attributes"),
                                               GTK_WINDOW (gdu_shell_get_toplevel (gdu_section_get_shell (GDU_SECTION (section)))),
                                               GTK_DIALOG_MODAL|GTK_DIALOG_DESTROY_WITH_PARENT|GTK_DIALOG_NO_SEPARATOR,
                                               GTK_STOCK_CLOSE,
@@ -863,7 +921,8 @@ health_details_action_callback (GtkAction *action, gpointer user_data)
 
         HealthGraphData *data;
         data = g_new0 (HealthGraphData, 1);
-        data->history = gdu_device_drive_smart_get_historical_data_sync (device, NULL);
+        /* TODO: do this async */
+        data->history = gdu_device_drive_ata_smart_get_historical_data_sync (device, NULL);
 
         GtkWidget *history_label;
         history_label = gtk_label_new (_("View:"));
@@ -894,6 +953,7 @@ health_details_action_callback (GtkAction *action, gpointer user_data)
         g_signal_connect (history_combo_box, "changed", G_CALLBACK (history_combo_box_changed), data);
 
         list_store = gtk_list_store_new (ATTR_N_COLUMNS,
+                                         G_TYPE_STRING,
                                          G_TYPE_INT,
                                          G_TYPE_STRING,
                                          G_TYPE_STRING,
@@ -903,6 +963,8 @@ health_details_action_callback (GtkAction *action, gpointer user_data)
                                          G_TYPE_STRING,
                                          GDK_TYPE_PIXBUF,
                                          G_TYPE_STRING,
+                                         G_TYPE_STRING,
+                                         G_TYPE_STRING,
                                          G_TYPE_STRING);
 
         tree_view = gtk_tree_view_new_with_model (GTK_TREE_MODEL (list_store));
@@ -913,6 +975,10 @@ health_details_action_callback (GtkAction *action, gpointer user_data)
                           "changed",
                           G_CALLBACK (smart_attr_tree_selection_changed), data);
 
+        gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (list_store),
+                                              ATTR_ID_INT_COLUMN,
+                                              GTK_SORT_ASCENDING);
+
         column = gtk_tree_view_column_new ();
         gtk_tree_view_column_set_title (column, "ID");
         renderer = gtk_cell_renderer_text_new ();
@@ -932,12 +998,12 @@ health_details_action_callback (GtkAction *action, gpointer user_data)
         gtk_tree_view_append_column (GTK_TREE_VIEW (tree_view), column);
 
         column = gtk_tree_view_column_new ();
-        gtk_tree_view_column_set_title (column, "Value");
+        gtk_tree_view_column_set_title (column, "Current");
         renderer = gtk_cell_renderer_text_new ();
         g_object_set (renderer, "xalign", 1.0, NULL);
         gtk_tree_view_column_pack_start (column, renderer, TRUE);
         gtk_tree_view_column_set_attributes (column, renderer,
-                                             "text", ATTR_VALUE_COLUMN,
+                                             "text", ATTR_CURRENT_COLUMN,
                                              NULL);
         gtk_tree_view_append_column (GTK_TREE_VIEW (tree_view), column);
 
@@ -963,12 +1029,12 @@ health_details_action_callback (GtkAction *action, gpointer user_data)
         gtk_tree_view_append_column (GTK_TREE_VIEW (tree_view), column);
 
         column = gtk_tree_view_column_new ();
-        gtk_tree_view_column_set_title (column, "Raw Value");
+        gtk_tree_view_column_set_title (column, "Value");
         renderer = gtk_cell_renderer_text_new ();
         g_object_set (renderer, "xalign", 1.0, NULL);
         gtk_tree_view_column_pack_start (column, renderer, TRUE);
         gtk_tree_view_column_set_attributes (column, renderer,
-                                             "text", ATTR_RAW_COLUMN,
+                                             "text", ATTR_VALUE_COLUMN,
                                              NULL);
         gtk_tree_view_append_column (GTK_TREE_VIEW (tree_view), column);
 
@@ -986,6 +1052,26 @@ health_details_action_callback (GtkAction *action, gpointer user_data)
                                              NULL);
         gtk_tree_view_append_column (GTK_TREE_VIEW (tree_view), column);
 
+        column = gtk_tree_view_column_new ();
+        gtk_tree_view_column_set_title (column, "Type");
+        renderer = gtk_cell_renderer_text_new ();
+        g_object_set (renderer, "xalign", 1.0, NULL);
+        gtk_tree_view_column_pack_start (column, renderer, TRUE);
+        gtk_tree_view_column_set_attributes (column, renderer,
+                                             "text", ATTR_TYPE_COLUMN,
+                                             NULL);
+        gtk_tree_view_append_column (GTK_TREE_VIEW (tree_view), column);
+
+        column = gtk_tree_view_column_new ();
+        gtk_tree_view_column_set_title (column, "Updates");
+        renderer = gtk_cell_renderer_text_new ();
+        g_object_set (renderer, "xalign", 1.0, NULL);
+        gtk_tree_view_column_pack_start (column, renderer, TRUE);
+        gtk_tree_view_column_set_attributes (column, renderer,
+                                             "text", ATTR_UPDATES_COLUMN,
+                                             NULL);
+        gtk_tree_view_append_column (GTK_TREE_VIEW (tree_view), column);
+
 
         scrolled_window = gtk_scrolled_window_new (NULL, NULL);
         gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled_window),
@@ -996,109 +1082,125 @@ health_details_action_callback (GtkAction *action, gpointer user_data)
 
 	gtk_box_pack_start (GTK_BOX (vbox), scrolled_window, TRUE, TRUE, 0);
 
-        sd = gdu_device_get_smart_data (device);
-        if (sd != NULL)
-                attrs = gdu_smart_data_get_attributes (sd);
+        attrs = gdu_device_drive_ata_smart_get_attributes (device);
         for (l = attrs; l != NULL; l = l->next) {
-                GduSmartDataAttribute *a = l->data;
+                GduAtaSmartAttribute *a = l->data;
                 GtkTreeIter iter;
                 char *col_str;
                 char *name_str;
-                char *value_str;
+                char *current_str;
                 char *worst_str;
                 char *threshold_str;
-                char *raw_str;
+                char *pretty_str;
                 char *status_str;
                 GdkPixbuf *status_pixbuf;
                 char *tooltip_str;
                 int icon_width, icon_height;
-                gboolean threshold_exceeded;
-                gboolean threshold_exceeded_in_the_past;
-                gboolean should_warn;
                 char *desc_str;
+                const gchar *type_str;
+                const gchar *updates_str;
+                const gchar *tips_type_str;
+                const gchar *tips_updates_str;
+                gboolean is_good;
+                gboolean is_good_valid;
 
-                col_str = g_strdup_printf ("%d", gdu_smart_data_attribute_get_id (a));
+                col_str = g_strdup_printf ("%d", gdu_ata_smart_attribute_get_id (a));
 
-                name_str = gdu_smart_data_attribute_get_name (a);
-                desc_str = gdu_smart_data_attribute_get_description (a);
-                should_warn = gdu_smart_data_attribute_is_warning (a);
+                name_str = gdu_ata_smart_attribute_get_localized_name (a);
+                desc_str = gdu_ata_smart_attribute_get_localized_description (a);
 
                 if (desc_str == NULL) {
                         desc_str = g_strdup_printf (_("No description for attribute %d."),
-                                                    gdu_smart_data_attribute_get_id (a));
+                                                    gdu_ata_smart_attribute_get_id (a));
+                }
+
+                if (gdu_ata_smart_attribute_get_online (a)) {
+                        updates_str = _("Online");
+                        tips_updates_str = _("Every time data is collected.");
+                } else {
+                        updates_str = _("Offline");
+                        tips_updates_str = _("Only when performing a self-test.");
+                }
+
+                if (gdu_ata_smart_attribute_get_prefailure (a)) {
+                        type_str = _("Pre-fail");
+                        tips_type_str = _("Failure is a sign of imminent disk failure.");
+                } else {
+                        type_str = _("Old-age");
+                        tips_type_str = _("Failure is a sign of old age.");
                 }
 
-                tooltip_str = g_strdup_printf (_("<b>Flags:</b> 0x%04x\n"
-                                                 "<b>Type:</b> %s\n"
-                                                 "<b>Updated:</b> %s\n"
+                tooltip_str = g_strdup_printf (_("<b>Type:</b> %s\n"
+                                                 "<b>Updates:</b> %s\n"
                                                  "<b>Description</b>: %s"),
-                                               gdu_smart_data_attribute_get_flags (a),
-                                               (gdu_smart_data_attribute_get_flags (a) & 0x0001) ? _("Pre-Fail") : _("Old-Age"),
-                                               (gdu_smart_data_attribute_get_flags (a) & 0x0002) ? _("Always") : _("Offline"),
+                                               tips_type_str,
+                                               tips_updates_str,
                                                desc_str);
 
-                value_str = g_strdup_printf ("%d", gdu_smart_data_attribute_get_value (a));
-                worst_str = g_strdup_printf ("%d", gdu_smart_data_attribute_get_worst (a));
-                threshold_str = g_strdup_printf ("%d", gdu_smart_data_attribute_get_threshold (a));
-                raw_str = gdu_smart_data_attribute_get_raw (a);
+                current_str = g_strdup_printf ("%d", gdu_ata_smart_attribute_get_current (a));
+                worst_str = g_strdup_printf ("%d", gdu_ata_smart_attribute_get_worst (a));
+                threshold_str = g_strdup_printf ("%d", gdu_ata_smart_attribute_get_threshold (a));
+
 
-                threshold_exceeded = (gdu_smart_data_attribute_get_value (a) < gdu_smart_data_attribute_get_threshold (a));
-                threshold_exceeded_in_the_past = (gdu_smart_data_attribute_get_worst (a) < gdu_smart_data_attribute_get_threshold (a));
+                guint64 pretty_value;
+                GduAtaSmartAttributeUnit pretty_unit;
+                pretty_value = gdu_ata_smart_attribute_get_pretty_value (a);
+                pretty_unit = gdu_ata_smart_attribute_get_pretty_unit (a);
+                pretty_str = pretty_to_string (pretty_value, pretty_unit);
+
+                is_good = gdu_ata_smart_attribute_get_good (a);
+                is_good_valid = gdu_ata_smart_attribute_get_good_valid (a);
 
                 if (!gtk_icon_size_lookup (GTK_ICON_SIZE_MENU, &icon_width, &icon_height))
                         icon_height = 48;
 
-                if (threshold_exceeded) {
-                        status_pixbuf = gtk_icon_theme_load_icon (gtk_icon_theme_get_default (),
-                                                                  "gdu-smart-failing",
-                                                                  icon_height,
-                                                                  GTK_ICON_LOOKUP_GENERIC_FALLBACK,
-                                                                  NULL);
-                        status_str = g_strdup (_("<span foreground='red'><b>FAILING NOW</b></span>"));
-                } else if (threshold_exceeded_in_the_past) {
-                        status_pixbuf = gtk_icon_theme_load_icon (gtk_icon_theme_get_default (),
-                                                                  "gdu-smart-threshold",
-                                                                  icon_height,
-                                                                  GTK_ICON_LOOKUP_GENERIC_FALLBACK,
-                                                                  NULL);
-                        status_str = g_strdup (_("OK (Failed in the past)"));
-                } else {
-                        if (should_warn) {
+                if (!is_good_valid) {
                                 status_pixbuf = gtk_icon_theme_load_icon (gtk_icon_theme_get_default (),
-                                                                          "gdu-smart-threshold",
+                                                                          "gdu-smart-unknown",
                                                                           icon_height,
                                                                           GTK_ICON_LOOKUP_GENERIC_FALLBACK,
                                                                           NULL);
-                                status_str = g_strdup (_("OK (Non-zero)"));
-                        } else {
+                                status_str = g_strdup (_("N/A"));
+                } else {
+                        if (is_good) {
                                 status_pixbuf = gtk_icon_theme_load_icon (gtk_icon_theme_get_default (),
                                                                           "gdu-smart-healthy",
                                                                           icon_height,
                                                                           GTK_ICON_LOOKUP_GENERIC_FALLBACK,
                                                                           NULL);
                                 status_str = g_strdup (_("OK"));
+                        } else {
+                                status_pixbuf = gtk_icon_theme_load_icon (gtk_icon_theme_get_default (),
+                                                                          "gdu-smart-failing",
+                                                                          icon_height,
+                                                                          GTK_ICON_LOOKUP_GENERIC_FALLBACK,
+                                                                          NULL);
+                                status_str = g_strdup (_("<span foreground='red'><b>FAILING</b></span>"));
                         }
                 }
 
                 gtk_list_store_append (list_store, &iter);
                 gtk_list_store_set (list_store, &iter,
-                                    ATTR_ID_INT_COLUMN, gdu_smart_data_attribute_get_id (a),
+                                    ATTR_ID_NAME_COLUMN, gdu_ata_smart_attribute_get_name (a),
+                                    ATTR_ID_INT_COLUMN, gdu_ata_smart_attribute_get_id (a),
                                     ATTR_ID_COLUMN, col_str,
                                     ATTR_DESC_COLUMN, name_str,
-                                    ATTR_VALUE_COLUMN, value_str,
+                                    ATTR_CURRENT_COLUMN, current_str,
                                     ATTR_WORST_COLUMN, worst_str,
                                     ATTR_THRESHOLD_COLUMN, threshold_str,
-                                    ATTR_RAW_COLUMN, raw_str,
+                                    ATTR_VALUE_COLUMN, pretty_str,
                                     ATTR_STATUS_PIXBUF_COLUMN, status_pixbuf,
                                     ATTR_STATUS_TEXT_COLUMN, status_str,
+                                    ATTR_TYPE_COLUMN, type_str,
+                                    ATTR_UPDATES_COLUMN, updates_str,
                                     ATTR_TOOLTIP_COLUMN, tooltip_str,
                                     -1);
                 g_free (col_str);
                 g_free (name_str);
-                g_free (value_str);
+                g_free (current_str);
                 g_free (worst_str);
                 g_free (threshold_str);
-                g_free (raw_str);
+                g_free (pretty_str);
                 g_object_unref (status_pixbuf);
                 g_free (status_str);
                 g_free (tooltip_str);
@@ -1130,8 +1232,9 @@ out:
                 g_object_unref (sd);
 }
 
+
 static void
-run_smart_selftest_callback (GduDevice *device,
+run_ata_smart_selftest_callback (GduDevice *device,
                              GError *error,
                              gpointer user_data)
 {
@@ -1140,7 +1243,7 @@ run_smart_selftest_callback (GduDevice *device,
                 gdu_shell_raise_error (gdu_section_get_shell (section),
                                        gdu_section_get_presentable (section),
                                        error,
-                                       _("Error initiating S.M.A.R.T. Self Test"));
+                                       _("Error initiating ATA SMART Self Test"));
         }
         g_object_unref (section);
 }
@@ -1158,6 +1261,7 @@ health_selftest_action_callback (GtkAction *action, gpointer user_data)
         GtkWidget *label;
         GtkWidget *radio0;
         GtkWidget *radio1;
+        GtkWidget *radio2;
         const char *test;
 
         test = NULL;
@@ -1169,7 +1273,7 @@ health_selftest_action_callback (GtkAction *action, gpointer user_data)
         }
 
 
-        dialog = gtk_dialog_new_with_buttons (_("S.M.A.R.T. Self Test"),
+        dialog = gtk_dialog_new_with_buttons (_("ATA SMART Self Test"),
                                               GTK_WINDOW (gdu_shell_get_toplevel (gdu_section_get_shell (GDU_SECTION (section)))),
                                               GTK_DIALOG_MODAL|GTK_DIALOG_DESTROY_WITH_PARENT|GTK_DIALOG_NO_SEPARATOR,
                                               NULL);
@@ -1192,7 +1296,7 @@ health_selftest_action_callback (GtkAction *action, gpointer user_data)
 	gtk_box_pack_start (GTK_BOX (hbox), main_vbox, TRUE, TRUE, 0);
 
 	label = gtk_label_new (NULL);
-        gtk_label_set_markup (GTK_LABEL (label), _("<big><b>Select what S.M.A.R.T. test to run on the drive.</b></big>"));
+        gtk_label_set_markup (GTK_LABEL (label), _("<big><b>Select what ATA SMART test to run on the drive.</b></big>"));
 	gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
 	gtk_label_set_line_wrap (GTK_LABEL (label), TRUE);
 	gtk_box_pack_start (GTK_BOX (main_vbox), GTK_WIDGET (label), FALSE, FALSE, 0);
@@ -1208,10 +1312,13 @@ health_selftest_action_callback (GtkAction *action, gpointer user_data)
         radio0 = gtk_radio_button_new_with_mnemonic_from_widget (NULL,
                                                                  _("_Short (usually less than ten minutes)"));
         radio1 = gtk_radio_button_new_with_mnemonic_from_widget (GTK_RADIO_BUTTON (radio0),
-                                                                 _("_Long (usually tens of minutes)"));
+                                                                 _("_Extended (usually tens of minutes)"));
+        radio2 = gtk_radio_button_new_with_mnemonic_from_widget (GTK_RADIO_BUTTON (radio0),
+                                                                 _("C_onveyance (usually less than ten minutes)"));
 
 	gtk_box_pack_start (GTK_BOX (main_vbox), GTK_WIDGET (radio0), FALSE, FALSE, 0);
 	gtk_box_pack_start (GTK_BOX (main_vbox), GTK_WIDGET (radio1), FALSE, FALSE, 0);
+	gtk_box_pack_start (GTK_BOX (main_vbox), GTK_WIDGET (radio2), FALSE, FALSE, 0);
 
         gtk_dialog_add_button (GTK_DIALOG (dialog), GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL);
         gtk_dialog_add_button (GTK_DIALOG (dialog), _("_Initiate Self Test"), 0);
@@ -1223,19 +1330,19 @@ health_selftest_action_callback (GtkAction *action, gpointer user_data)
         if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (radio0))) {
                 test = "short";
         } else if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (radio1))) {
-                test = "long";
+                test = "extended";
+        } else if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (radio2))) {
+                test = "conveyance";
         }
 
         gtk_widget_destroy (dialog);
         if (response != 0)
                 goto out;
 
-        /* TODO: option for captive */
-        gdu_device_op_drive_smart_initiate_selftest (device,
-                                                     test,
-                                                     FALSE,
-                                                     run_smart_selftest_callback,
-                                                     g_object_ref (section));
+        gdu_device_op_drive_ata_smart_initiate_selftest (device,
+                                                         test,
+                                                         run_ata_smart_selftest_callback,
+                                                         g_object_ref (section));
 out:
         if (device != NULL)
                 g_object_unref (device);
@@ -1249,29 +1356,24 @@ update (GduSectionHealth *section)
         GduDevice *device;
         guint64 collect_time;
         GTimeVal now;
-        GduSmartData *sd;
 
-        sd = NULL;
         device = gdu_presentable_get_device (gdu_section_get_presentable (GDU_SECTION (section)));
         if (device == NULL) {
                 g_warning ("%s: device is not supposed to be NULL", __FUNCTION__);
                 goto out;
         }
 
-        if (!gdu_device_drive_smart_get_is_capable (device)) {
+        if (!gdu_device_drive_ata_smart_get_is_available (device)) {
                 smart_data_set_not_supported (section);
                 goto out;
         }
 
         /* refresh if data is more than an hour old */
         g_get_current_time (&now);
-        sd = gdu_device_get_smart_data (device);
-        collect_time = 0;
-        if (sd != NULL)
-                collect_time = gdu_smart_data_get_time_collected (sd);
-        if (sd == NULL || collect_time == 0 || (now.tv_sec - collect_time) > 60 * 60) {
+        collect_time = gdu_device_drive_ata_smart_get_time_collected (device);
+        if (collect_time == 0 || (now.tv_sec - collect_time) > 60 * 60) {
                 smart_data_set_pending (section);
-                gdu_device_drive_smart_refresh_data (device, retrieve_smart_data_cb, g_object_ref (section));
+                gdu_device_drive_ata_smart_refresh_data (device, retrieve_ata_smart_data_cb, g_object_ref (section));
         } else {
                 smart_data_set (section);
         }
@@ -1279,8 +1381,6 @@ update (GduSectionHealth *section)
 out:
         if (device != NULL)
                 g_object_unref (device);
-        if (sd != NULL)
-                g_object_unref (sd);
 }
 
 /* ---------------------------------------------------------------------------------------------------- */
@@ -1329,15 +1429,15 @@ gdu_section_health_init (GduSectionHealth *section)
 
         section->priv->pk_smart_refresh_action = polkit_action_new ();
         polkit_action_set_action_id (section->priv->pk_smart_refresh_action,
-                                     "org.freedesktop.devicekit.disks.drive-smart-refresh");
+                                     "org.freedesktop.devicekit.disks.drive-ata-smart-refresh");
 
         section->priv->pk_smart_retrieve_historical_data_action = polkit_action_new ();
         polkit_action_set_action_id (section->priv->pk_smart_retrieve_historical_data_action,
-                                     "org.freedesktop.devicekit.disks.drive-smart-retrieve-historical-data");
+                                     "org.freedesktop.devicekit.disks.drive-ata-smart-retrieve-historical-data");
 
         section->priv->pk_smart_selftest_action = polkit_action_new ();
         polkit_action_set_action_id (section->priv->pk_smart_selftest_action,
-                                     "org.freedesktop.devicekit.disks.drive-smart-selftest");
+                                     "org.freedesktop.devicekit.disks.drive-ata-smart-selftest");
 
         label = gtk_label_new (NULL);
         gtk_label_set_markup (GTK_LABEL (label), _("<b>Health</b>"));
@@ -1351,7 +1451,7 @@ gdu_section_health_init (GduSectionHealth *section)
 
         /* explanatory text */
         label = gtk_label_new (NULL);
-        gtk_label_set_markup (GTK_LABEL (label), _("Some disks supports S.M.A.R.T., a monitoring system for "
+        gtk_label_set_markup (GTK_LABEL (label), _("Some disks supports ATA SMART, a monitoring system for "
                                                    "disks to detect and report on various indicators of "
                                                    "reliability, in the hope of anticipating failures."));
         gtk_label_set_line_wrap (GTK_LABEL (label), TRUE);
@@ -1465,7 +1565,7 @@ gdu_section_health_init (GduSectionHealth *section)
                 "refresh",
                 section->priv->pk_smart_refresh_action,
                 _("Refre_sh"),
-                _("Collect S.M.A.R.T. data from the device"));
+                _("Refresh ATA SMART data from the device"));
         g_object_set (section->priv->health_refresh_action,
                       "auth-label", _("Refre_sh..."),
                       "yes-icon-name", GTK_STOCK_REFRESH,
@@ -1482,7 +1582,7 @@ gdu_section_health_init (GduSectionHealth *section)
                 "details",
                 section->priv->pk_smart_retrieve_historical_data_action,
                 _("_Details..."),
-                _("Show S.M.A.R.T. Historical Data"));
+                _("Show ATA SMART Historical Data"));
         g_object_set (section->priv->health_details_action,
                       "auth-label", _("_Details..."),
                       "yes-icon-name", GTK_STOCK_DIALOG_INFO,
@@ -1499,7 +1599,7 @@ gdu_section_health_init (GduSectionHealth *section)
                 "selftest",
                 section->priv->pk_smart_selftest_action,
                 _("Se_lf Test..."),
-                _("Run a S.M.A.R.T. Self Test"));
+                _("Run an ATA SMART Self Test"));
         g_object_set (section->priv->health_selftest_action,
                       "auth-label", _("Se_lf Test..."),
                       "yes-icon-name", GTK_STOCK_EXECUTE,
diff --git a/src/palimpsest/gdu-shell.c b/src/palimpsest/gdu-shell.c
index 324f57c..49e8859 100644
--- a/src/palimpsest/gdu-shell.c
+++ b/src/palimpsest/gdu-shell.c
@@ -517,7 +517,7 @@ compute_sections_to_show (GduShell *shell, gboolean showing_job)
 
                         } else {
 
-                                if (gdu_device_drive_smart_get_is_enabled (device)) {
+                                if (gdu_device_drive_ata_smart_get_is_available (device)) {
                                                 sections_to_show = g_list_append (sections_to_show,
                                                                                   (gpointer) GDU_TYPE_SECTION_HEALTH);
                                 }
diff --git a/src/palimpsest/gdu-time-label.c b/src/palimpsest/gdu-time-label.c
deleted file mode 100644
index c36e7cb..0000000
--- a/src/palimpsest/gdu-time-label.c
+++ /dev/null
@@ -1,225 +0,0 @@
-/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- */
-/* gdu-time-label.c
- *
- * Copyright (C) 2007 David Zeuthen
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public License
- * as published by the Free Software Foundation; either version 2 of
- * the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
- * 02111-1307, USA.
- */
-
-#include <config.h>
-#include <glib/gi18n.h>
-#include <string.h>
-
-#include "gdu-time-label.h"
-
-struct _GduTimeLabelPrivate
-{
-        GTimeVal time;
-        guint update_timer_id;
-};
-
-static GObjectClass *parent_class = NULL;
-
-G_DEFINE_TYPE (GduTimeLabel, gdu_time_label, GTK_TYPE_LABEL)
-
-enum {
-        PROP_0,
-        PROP_TIME,
-};
-
-static void do_update (GduTimeLabel *time_label);
-
-static gboolean
-timeout_func (GduTimeLabel *time_label)
-{
-        time_label->priv->update_timer_id = 0;
-        do_update (time_label);
-        return FALSE;
-}
-
-static void
-do_update (GduTimeLabel *time_label)
-{
-        char *s;
-        GTimeVal now;
-        int age;
-        int next_update;
-
-        next_update = -1;
-
-        g_get_current_time (&now);
-
-        age = (int) (now.tv_sec - time_label->priv->time.tv_sec);
-
-        //g_warning ("updating; age=%d was: %s", age, gtk_label_get_label (GTK_LABEL (time_label)));
-
-        if (age < 60) {
-                s = g_strdup_printf (_("Less than a minute ago"));
-                next_update = 60 - age;
-        } else if (age < 60 * 60) {
-                if (age / 60 == 1) {
-                        s = g_strdup_printf (_("1 minute ago"));
-                } else {
-                        s = g_strdup_printf (_("%d minutes ago"), age / 60);
-                }
-                next_update = 60*(age/60 + 1) - age;
-        } else {
-                if (age / 60 / 60 == 1) {
-                        s = g_strdup_printf (_("1 hour ago"));
-                } else {
-                        s = g_strdup_printf (_("%d hours ago"), age / 60 / 60);
-                }
-                next_update = 60*60*(age/(60*60) + 1) - age;
-        }
-        gtk_label_set_text (GTK_LABEL (time_label), s);
-        g_free (s);
-
-        //g_warning ("updating; next=%d now: %s", next_update, gtk_label_get_label (GTK_LABEL (time_label)));
-
-        if (next_update > 0) {
-                if (time_label->priv->update_timer_id > 0)
-                        g_source_remove (time_label->priv->update_timer_id);
-                time_label->priv->update_timer_id =
-                        g_timeout_add_seconds (next_update, (GSourceFunc) timeout_func, time_label);
-        }
-}
-
-static void
-gdu_time_label_set_property (GObject      *object,
-                             guint         prop_id,
-                             const GValue *value,
-                             GParamSpec   *pspec)
-{
-        GduTimeLabel *time_label = GDU_TIME_LABEL (object);
-        GTimeVal *time_val;
-
-        switch (prop_id) {
-        case PROP_TIME:
-                time_val = (GTimeVal *) g_value_get_boxed (value);
-                if (time_val != NULL) {
-                        time_label->priv->time = * time_val;
-                        do_update (time_label);
-                }
-                break;
-
-        default:
-                G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
-                break;
-        }
-}
-
-static void
-gdu_time_label_get_property (GObject     *object,
-                             guint        prop_id,
-                             GValue      *value,
-                             GParamSpec  *pspec)
-{
-        GduTimeLabel *time_label = GDU_TIME_LABEL (object);
-
-        switch (prop_id) {
-        case PROP_TIME:
-                g_value_set_boxed (value, &time_label->priv->time);
-                break;
-
-        default:
-                G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
-                break;
-    }
-}
-
-static void
-gdu_time_label_finalize (GduTimeLabel *time_label)
-{
-        if (time_label->priv->update_timer_id > 0)
-                g_source_remove (time_label->priv->update_timer_id);
-        if (G_OBJECT_CLASS (parent_class)->finalize)
-                (* G_OBJECT_CLASS (parent_class)->finalize) (G_OBJECT (time_label));
-}
-
-static GTimeVal *
-time_val_copy (GTimeVal *t)
-{
-        GTimeVal *copy;
-
-        copy = NULL;
-
-        if (t == NULL)
-                goto out;
-
-        copy = g_new0 (GTimeVal, 1);
-        memcpy (copy, t, sizeof (GTimeVal));
-
-out:
-        return copy;
-}
-
-static void
-time_val_free (GTimeVal *t)
-{
-        g_free (t);
-}
-
-static void
-gdu_time_label_class_init (GduTimeLabelClass *klass)
-{
-        GObjectClass *obj_class = (GObjectClass *) klass;
-        GType boxed_type;
-
-        parent_class = g_type_class_peek_parent (klass);
-
-        obj_class->finalize = (GObjectFinalizeFunc) gdu_time_label_finalize;
-        obj_class->set_property = gdu_time_label_set_property;
-        obj_class->get_property = gdu_time_label_get_property;
-
-        g_type_class_add_private (klass, sizeof (GduTimeLabelPrivate));
-
-        boxed_type = g_boxed_type_register_static ("GduTimeLabelBoxedGTimeVal",
-                                                   (GBoxedCopyFunc) time_val_copy,
-                                                   (GBoxedFreeFunc) time_val_free);
-
-        /**
-         * GduTimeLabel:time:
-         *
-         * The time (a #GTimeVal) used for computing the label of the string.
-         */
-        g_object_class_install_property (obj_class,
-                                         PROP_TIME,
-                                         g_param_spec_boxed ("time",
-                                                             NULL,
-                                                             NULL,
-                                                             boxed_type,
-                                                             G_PARAM_WRITABLE |
-                                                             G_PARAM_READABLE));
-}
-
-static void
-gdu_time_label_init (GduTimeLabel *time_label)
-{
-        time_label->priv = G_TYPE_INSTANCE_GET_PRIVATE (time_label, GDU_TYPE_TIME_LABEL, GduTimeLabelPrivate);
-}
-
-GtkWidget *
-gdu_time_label_new (GTimeVal *time)
-{
-        return GTK_WIDGET (g_object_new (GDU_TYPE_TIME_LABEL, "time", time, NULL));
-}
-
-void
-gdu_time_label_set_time (GduTimeLabel *time_label, GTimeVal     *time)
-{
-        g_object_set (time_label, "time", time, NULL);
-}
-
diff --git a/src/palimpsest/gdu-time-label.h b/src/palimpsest/gdu-time-label.h
deleted file mode 100644
index b23d6b8..0000000
--- a/src/palimpsest/gdu-time-label.h
+++ /dev/null
@@ -1,60 +0,0 @@
-/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- */
-/* gdu-time-label.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>
-
-#ifndef GDU_TIME_LABEL_H
-#define GDU_TIME_LABEL_H
-
-#define GDU_TYPE_TIME_LABEL             (gdu_time_label_get_type ())
-#define GDU_TIME_LABEL(obj)             (G_TYPE_CHECK_INSTANCE_CAST ((obj), GDU_TYPE_TIME_LABEL, GduTimeLabel))
-#define GDU_TIME_LABEL_CLASS(obj)       (G_TYPE_CHECK_CLASS_CAST ((obj), GDU_TIME_LABEL,  GduTimeLabelClass))
-#define GDU_IS_TIME_LABEL(obj)          (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GDU_TYPE_TIME_LABEL))
-#define GDU_IS_TIME_LABEL_CLASS(obj)    (G_TYPE_CHECK_CLASS_TYPE ((obj), GDU_TYPE_TIME_LABEL))
-#define GDU_TIME_LABEL_GET_CLASS        (G_TYPE_INSTANCE_GET_CLASS ((obj), GDU_TYPE_TIME_LABEL, GduTimeLabelClass))
-
-typedef struct _GduTimeLabelClass       GduTimeLabelClass;
-typedef struct _GduTimeLabel            GduTimeLabel;
-
-struct _GduTimeLabelPrivate;
-typedef struct _GduTimeLabelPrivate     GduTimeLabelPrivate;
-
-struct _GduTimeLabel
-{
-        GtkLabel parent;
-
-        /* private */
-        GduTimeLabelPrivate *priv;
-};
-
-struct _GduTimeLabelClass
-{
-        GtkLabelClass parent_class;
-};
-
-
-GType      gdu_time_label_get_type     (void);
-GtkWidget *gdu_time_label_new          (GTimeVal     *time);
-void       gdu_time_label_set_time     (GduTimeLabel *time_label,
-                                        GTimeVal     *time);
-
-#endif /* GDU_TIME_LABEL_H */



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