[gnome-disk-utility/ata-smart-ui-rework] Land new ATA SMART user interface
- From: David Zeuthen <davidz src gnome org>
- To: svn-commits-list gnome org
- Cc:
- Subject: [gnome-disk-utility/ata-smart-ui-rework] Land new ATA SMART user interface
- Date: Sun, 23 Aug 2009 18:23:39 +0000 (UTC)
commit 9d910f0c70e85e4efd0cb6c26f4ee98997c89c1b
Author: David Zeuthen <davidz redhat com>
Date: Sun Aug 23 14:10:51 2009 -0400
Land new ATA SMART user interface
For now we don't have any graphs. It remains to be decided if we want
to add them back.
configure.ac | 4 +
src/gdu-gtk/Makefile.am | 14 +-
src/gdu-gtk/gdu-ata-smart-dialog.c | 3116 +++++++++++++++++++++++--------
src/gdu-gtk/gdu-ata-smart-dialog.h | 2 +-
src/gdu-gtk/gdu-curve.c | 499 -----
src/gdu-gtk/gdu-curve.h | 110 --
src/gdu-gtk/gdu-graph.c | 1312 -------------
src/gdu-gtk/gdu-graph.h | 75 -
src/gdu-gtk/gdu-gtk-enums.h | 24 -
src/gdu-gtk/gdu-gtk-enumtypes.h | 4 -
src/gdu-gtk/gdu-gtk-types.h | 1 +
src/gdu-gtk/gdu-gtk.h | 3 +-
src/gdu-gtk/gdu-pool-tree-view.c | 2 +-
src/gdu/Makefile.am | 4 -
src/gdu/gdu-ata-smart-attribute.c | 622 ------
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 | 5 -
src/gdu/gdu-device.c | 299 +---
src/gdu/gdu-device.h | 64 +-
src/gdu/gdu-private.h | 4 -
src/gdu/gdu-types.h | 2 -
src/gdu/gdu-util.c | 91 +-
src/gdu/gdu-util.h | 5 +
src/gdu/gdu.h | 2 -
src/notification/notification-main.c | 157 ++-
src/palimpsest/Makefile.am | 1 -
src/palimpsest/gdu-section-health.c | 1683 -----------------
src/palimpsest/gdu-section-health.h | 58 -
src/palimpsest/gdu-shell.c | 96 +-
31 files changed, 2707 insertions(+), 5891 deletions(-)
---
diff --git a/configure.ac b/configure.ac
index 1cce5ad..e22fd74 100644
--- a/configure.ac
+++ b/configure.ac
@@ -145,6 +145,10 @@ PKG_CHECK_MODULES(UNIQUE, unique-1.0 >= $UNIQUE_REQUIRED)
PKG_CHECK_MODULES(LIBNOTIFY, libnotify >= $LIBNOTIFY_REQUIRED)
PKG_CHECK_MODULES(DEVKIT_DISKS, DeviceKit-disks >= $DEVKIT_DISKS_REQUIRED)
+PKG_CHECK_MODULES(LIBATASMART, [libatasmart >= 0.14])
+AC_SUBST(LIBATASMART_CFLAGS)
+AC_SUBST(LIBATASMART_LIBS)
+
# *************
# Documentation
# *************
diff --git a/src/gdu-gtk/Makefile.am b/src/gdu-gtk/Makefile.am
index 419fa63..3eba71e 100644
--- a/src/gdu-gtk/Makefile.am
+++ b/src/gdu-gtk/Makefile.am
@@ -36,8 +36,7 @@ libgdu_gtkinclude_HEADERS = \
gdu-size-widget.h \
gdu-create-linux-md-dialog.h \
gdu-ata-smart-dialog.h \
- gdu-curve.h \
- gdu-graph.h \
+ gdu-spinner.h \
$(NULL)
libgdu_gtk_la_SOURCES = \
@@ -51,8 +50,7 @@ libgdu_gtk_la_SOURCES = \
gdu-size-widget.h gdu-size-widget.c \
gdu-create-linux-md-dialog.h gdu-create-linux-md-dialog.c \
gdu-ata-smart-dialog.h gdu-ata-smart-dialog.c \
- gdu-curve.h gdu-curve.c \
- gdu-graph.h gdu-graph.c \
+ gdu-spinner.h gdu-spinner.c \
$(NULL)
libgdu_gtk_la_CPPFLAGS = \
@@ -75,7 +73,9 @@ libgdu_gtk_la_CFLAGS = \
$(GNOME_KEYRING_CFLAGS) \
$(GTK2_CFLAGS) \
$(WARN_CFLAGS) \
- $(AM_CFLAGS)
+ $(AM_CFLAGS) \
+ $(LIBATASMART_CFLAGS) \
+ $(NULL)
libgdu_gtk_la_LIBADD = \
$(GLIB2_LIBS) \
@@ -84,7 +84,9 @@ libgdu_gtk_la_LIBADD = \
$(DBUS_GLIB_LIBS) \
$(GNOME_KEYRING_LIBS) \
$(GTK2_LIBS) \
- $(INTLLIBS)
+ $(INTLLIBS) \
+ $(LIBATASMART_LIBS) \
+ $(NULL)
libgdu_gtk_la_LDFLAGS = -version-info $(LT_CURRENT):$(LT_REVISION):$(LT_AGE) \
-export-dynamic -no-undefined -export-symbols-regex '(^gdu_.*)'
diff --git a/src/gdu-gtk/gdu-ata-smart-dialog.c b/src/gdu-gtk/gdu-ata-smart-dialog.c
index 809c536..164faa2 100644
--- a/src/gdu-gtk/gdu-ata-smart-dialog.c
+++ b/src/gdu-gtk/gdu-ata-smart-dialog.c
@@ -21,82 +21,637 @@
#include <config.h>
#include <glib/gi18n.h>
+#include <atasmart.h>
+#include <glib/gstdio.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <errno.h>
#include "gdu-time-label.h"
-#include "gdu-curve.h"
-#include "gdu-graph.h"
#include "gdu-ata-smart-dialog.h"
+#include "gdu-spinner.h"
+#include "gdu-pool-tree-model.h"
+
+/* ---------------------------------------------------------------------------------------------------- */
struct GduAtaSmartDialogPrivate
{
+ GduDrive *drive;
GduDevice *device;
guint64 last_updated;
gulong device_changed_signal_handler_id;
+ gulong device_job_changed_signal_handler_id;
+
+ GduPoolTreeModel *pool_tree_model;
+ GtkWidget *drive_combo_box;
+ GtkWidget *updated_label;
+ GtkWidget *updating_spinner;
+ GtkWidget *updating_label;
+ GtkWidget *update_link_label;
+
+ GtkWidget *self_test_result_label;
+ GtkWidget *self_test_progress_bar;
+ GtkWidget *self_test_run_link_label;
+ GtkWidget *self_test_cancel_link_label;
+
+ GtkWidget *model_label;
+ GtkWidget *firmware_label;
+ GtkWidget *serial_label;
GtkWidget *power_on_hours_label;
GtkWidget *temperature_label;
- GtkWidget *last_self_test_result_label;
- GtkWidget *updated_label;
- GtkWidget *assessment_label;
GtkWidget *sectors_label;
- GtkWidget *attributes_label;
+ GtkWidget *self_assessment_label;
+ GtkWidget *overall_assessment_image;
+ GtkWidget *overall_assessment_label;
+ GtkWidget *no_warn_check_button;
GtkWidget *tree_view;
GtkListStore *attr_list_store;
- GtkWidget *graph;
+ gboolean is_updating;
- GList *historical_data;
+ gboolean has_been_constructed;
};
enum
{
PROP_0,
- PROP_DEVICE,
+ PROP_DRIVE,
};
+/* ---------------------------------------------------------------------------------------------------- */
-enum
+#define _GDU_TYPE_SK_ATTR (_gdu_type_sk_attr_get_type ())
+
+static SkSmartAttributeParsedData *
+_gdu_sk_attr_copy (const SkSmartAttributeParsedData *instance)
+{
+ SkSmartAttributeParsedData *ret;
+
+ ret = g_new0 (SkSmartAttributeParsedData, 1);
+ memcpy (ret, instance, sizeof (SkSmartAttributeParsedData));
+ ret->name = g_strdup (instance->name);
+
+ return ret;
+}
+
+static void
+_gdu_sk_attr_free (SkSmartAttributeParsedData *instance)
+{
+ g_free ((gchar *) instance->name);
+ g_free (instance);
+}
+
+static GType
+_gdu_type_sk_attr_get_type (void)
{
- ATTR_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 volatile gsize type_volatile = 0;
+
+ if (g_once_init_enter (&type_volatile)) {
+ GType type = g_boxed_type_register_static (
+ g_intern_static_string ("_GduSkAttr"),
+ (GBoxedCopyFunc) _gdu_sk_attr_copy,
+ (GBoxedFreeFunc) _gdu_sk_attr_free);
+ g_once_init_leave (&type_volatile, type);
+ }
+
+ return type_volatile;
+}
+
+/* ---------------------------------------------------------------------------------------------------- */
+
+typedef struct {
+ const gchar *name;
+ const gchar *pretty_name;
+ const gchar *desc;
+} SmartDetails;
+
+/* 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-ATA_SMARTAttributesAnnex.pdf
+ *
+ * Keep in sync with libatasmart. Last sync: Thu Aug 20 2009
+ */
+static const SmartDetails smart_details[] = {
+ {
+ "raw-read-error-rate",
+ /* Translators: S.M.A.R.T attribute, see http://smartmontools.sourceforge.net/doc.html
+ * or the next string for a longer explanation.
+ */
+ N_("Read Error Rate"),
+ N_("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")
+ },
+ {
+ "throughput-performance",
+ /* Translators: S.M.A.R.T attribute, see http://smartmontools.sourceforge.net/doc.html
+ * or the next string for a longer explanation.
+ */
+ N_("Throughput Performance"),
+ N_("Average efficiency of the disk")
+ },
+ {
+ "spin-up-time",
+ /* Translators: S.M.A.R.T attribute, see http://smartmontools.sourceforge.net/doc.html
+ * or the next string for a longer explanation.
+ */
+ N_("Spinup Time"),
+ N_("Time needed to spin up the disk")
+ },
+ {
+ "start-stop-count",
+ /* Translators: S.M.A.R.T attribute, see http://smartmontools.sourceforge.net/doc.html
+ * or the next string for a longer explanation.
+ */
+ N_("Start/Stop Count"),
+ N_("Number of spindle start/stop cycles")
+ },
+ {
+ "reallocated-sector-count",
+ /* Translators: S.M.A.R.T attribute, see http://smartmontools.sourceforge.net/doc.html
+ * or the next string for a longer explanation.
+ */
+ N_("Reallocated Sector Count"),
+ N_("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)")
+ },
+ {
+ "read-channel-margin",
+ /* Translators: S.M.A.R.T attribute, see http://smartmontools.sourceforge.net/doc.html
+ * or the next string for a longer explanation.
+ */
+ N_("Read Channel Margin"),
+ N_("Margin of a channel while reading data.")
+ },
+ {
+ "seek-error-rate",
+ /* Translators: S.M.A.R.T attribute, see http://smartmontools.sourceforge.net/doc.html
+ * or the next string for a longer explanation.
+ */
+ N_("Seek Error Rate"),
+ N_("Frequency of errors while positioning")
+ },
+ {
+ "seek-time-performance",
+ /* Translators: S.M.A.R.T attribute, see http://smartmontools.sourceforge.net/doc.html
+ * or the next string for a longer explanation.
+ */
+ N_("Seek Timer Performance"),
+ N_("Average efficiency of operatings while positioning")
+ },
+ {
+ "power-on-hours",
+ /* Translators: S.M.A.R.T attribute, see http://smartmontools.sourceforge.net/doc.html
+ * or the next string for a longer explanation.
+ */
+ N_("Power-On Hours"),
+ N_("Number of hours elapsed in the power-on state")
+ },
+ {
+ "spin-retry-count",
+ /* Translators: S.M.A.R.T attribute, see http://smartmontools.sourceforge.net/doc.html
+ * or the next string for a longer explanation.
+ */
+ N_("Spinup Retry Count"),
+ N_("Number of retry attempts to spin up")
+ },
+ {
+ "calibration-retry-count",
+ /* Translators: S.M.A.R.T attribute, see http://smartmontools.sourceforge.net/doc.html
+ * or the next string for a longer explanation.
+ */
+ N_("Calibration Retry Count"),
+ N_("Number of attempts to calibrate the device")
+ },
+ {
+ "power-cycle-count",
+ /* Translators: S.M.A.R.T attribute, see http://smartmontools.sourceforge.net/doc.html
+ * or the next string for a longer explanation.
+ */
+ N_("Power Cycle Count"),
+ N_("Number of power-on events")
+ },
+ {
+ "read-soft-error-rate",
+ /* Translators: S.M.A.R.T attribute, see http://smartmontools.sourceforge.net/doc.html
+ * or the next string for a longer explanation.
+ */
+ N_("Soft read error rate"),
+ N_("Frequency of 'program' errors while reading from the disk")
+ },
+ {
+ "reported-uncorrect",
+ /* Translators: S.M.A.R.T attribute, see http://smartmontools.sourceforge.net/doc.html
+ * or the next string for a longer explanation.
+ */
+ N_("Reported Uncorrectable Errors"),
+ N_("Number of errors that could not be recovered using hardware ECC")
+ },
+ {
+ "high-fly-writes",
+ /* Translators: S.M.A.R.T attribute, see http://smartmontools.sourceforge.net/doc.html
+ * or the next string for a longer explanation.
+ */
+ N_("High Fly Writes"),
+ N_("Number of times a recording head is flying outside its normal operating range")
+ },
+ {
+ "airflow-temperature-celsius",
+ /* Translators: S.M.A.R.T attribute, see http://smartmontools.sourceforge.net/doc.html
+ * or the next string for a longer explanation.
+ */
+ N_("Airflow Temperature"),
+ N_("Airflow temperature of the drive")
+ },
+ {
+ "g-sense-error-rate",
+ /* Translators: S.M.A.R.T attribute, see http://smartmontools.sourceforge.net/doc.html
+ * or the next string for a longer explanation.
+ */
+ N_("G-sense Error Rate"),
+ N_("Frequency of mistakes as a result of impact loads")
+ },
+ {
+ "power-off-retract-count",
+ /* Translators: S.M.A.R.T attribute, see http://smartmontools.sourceforge.net/doc.html
+ * or the next string for a longer explanation.
+ */
+ N_("Power-off Retract Count"),
+ N_("Number of power-off or emergency retract cycles")
+ },
+ {
+ "load-cycle-count",
+ /* Translators: S.M.A.R.T attribute, see http://smartmontools.sourceforge.net/doc.html
+ * or the next string for a longer explanation.
+ */
+ N_("Load/Unload Cycle Count"),
+ N_("Number of cycles into landing zone position")
+ },
+ {
+ "temperature-celsius-2",
+ /* Translators: S.M.A.R.T attribute, see http://smartmontools.sourceforge.net/doc.html
+ * or the next string for a longer explanation.
+ */
+ N_("Temperature"),
+ N_("Current internal temperature of the drive")
+ },
+ {
+ "hardware-ecc-recovered",
+ /* Translators: S.M.A.R.T attribute, see http://smartmontools.sourceforge.net/doc.html
+ * or the next string for a longer explanation.
+ */
+ N_("Hardware ECC Recovered"),
+ N_("Number of ECC on-the-fly errors")
+ },
+ {
+ "reallocated-event-count",
+ /* Translators: S.M.A.R.T attribute, see http://smartmontools.sourceforge.net/doc.html
+ * or the next string for a longer explanation.
+ */
+ N_("Reallocation Count"),
+ N_("Number of remapping operations. "
+ "The raw value of this attribute shows the total number of (successful "
+ "and unsuccessful) attempts to transfer data from reallocated sectors "
+ "to a spare area")
+ },
+ {
+ "current-pending-sector",
+ /* Translators: S.M.A.R.T attribute, see http://smartmontools.sourceforge.net/doc.html
+ * or the next string for a longer explanation.
+ */
+ N_("Current Pending Sector Count"),
+ N_("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")
+ },
+ {
+ "offline-uncorrectable",
+ /* Translators: S.M.A.R.T attribute, see http://smartmontools.sourceforge.net/doc.html
+ * or the next string for a longer explanation.
+ */
+ N_("Uncorrectable Sector Count"),
+ N_("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")
+ },
+ {
+ "udma-crc-error-count",
+ /* Translators: S.M.A.R.T attribute, see http://smartmontools.sourceforge.net/doc.html
+ * or the next string for a longer explanation.
+ */
+ N_("UDMA CRC Error Rate"),
+ N_("Number of CRC errors during UDMA mode")
+ },
+ {
+ "multi-zone-error-rate",
+ /* Translators: S.M.A.R.T attribute, see http://smartmontools.sourceforge.net/doc.html
+ * or the next string for a longer explanation.
+ */
+ N_("Write Error Rate"),
+ N_("Number of errors while writing to disk (or) multi-zone error rate (or) flying-height")
+ },
+ {
+ "soft-read-error-rate",
+ /* Translators: S.M.A.R.T attribute, see http://smartmontools.sourceforge.net/doc.html
+ * or the next string for a longer explanation.
+ */
+ N_("Soft Read Error Rate"),
+ N_("Number of off-track errors")
+ },
+ {
+ "ta-increase-count",
+ /* Translators: S.M.A.R.T attribute, see http://smartmontools.sourceforge.net/doc.html
+ * or the next string for a longer explanation.
+ */
+ N_("Data Address Mark Errors"),
+ N_("Number of Data Address Mark (DAM) errors (or) vendor-specific")
+ },
+ {
+ "run-out-cancel",
+ /* Translators: S.M.A.R.T attribute, see http://smartmontools.sourceforge.net/doc.html
+ * or the next string for a longer explanation.
+ */
+ N_("Run Out Cancel"),
+ N_("Number of ECC errors")
+ },
+ {
+ "shock-count-write-open",
+ /* Translators: S.M.A.R.T attribute, see http://smartmontools.sourceforge.net/doc.html
+ * or the next string for a longer explanation.
+ */
+ N_("Soft ECC correction"),
+ N_("Number of errors corrected by software ECC")
+ },
+ {
+ "shock-rate-write-open",
+ /* Translators: S.M.A.R.T attribute, see http://smartmontools.sourceforge.net/doc.html
+ * or the next string for a longer explanation.
+ */
+ N_("Thermal Asperity Rate"),
+ N_("Number of Thermal Asperity Rate errors")
+ },
+ {
+ "flying-height",
+ /* Translators: S.M.A.R.T attribute, see http://smartmontools.sourceforge.net/doc.html
+ * or the next string for a longer explanation.
+ */
+ N_("Flying Height"),
+ N_("Height of heads above the disk surface")
+ },
+ {
+ "spin-high-current",
+ /* Translators: S.M.A.R.T attribute, see http://smartmontools.sourceforge.net/doc.html
+ * or the next string for a longer explanation.
+ */
+ N_("Spin High Current"),
+ N_("Amount of high current used to spin up the drive")
+ },
+ {
+ "spin-buzz",
+ /* Translators: S.M.A.R.T attribute, see http://smartmontools.sourceforge.net/doc.html
+ * or the next string for a longer explanation.
+ */
+ N_("Spin Buzz"),
+ N_("Number of buzz routines to spin up the drive")
+ },
+ {
+ "offline-seek-performance",
+ /* Translators: S.M.A.R.T attribute, see http://smartmontools.sourceforge.net/doc.html
+ * or the next string for a longer explanation.
+ */
+ N_("Offline Seek Performance"),
+ N_("Drive's seek performance during offline operations")
+ },
+ {
+ "disk-shift",
+ /* Translators: S.M.A.R.T attribute, see http://smartmontools.sourceforge.net/doc.html
+ * or the next string for a longer explanation.
+ */
+ N_("Disk Shift"),
+ N_("Shift of disk is possible as a result of strong shock loading in the store, "
+ "as a result of falling (or) temperature")
+ },
+ {
+ "g-sense-error-rate-2",
+ /* Translators: S.M.A.R.T attribute, see http://smartmontools.sourceforge.net/doc.html
+ * or the next string for a longer explanation.
+ */
+ N_("G-sense Error Rate"),
+ N_("Number of errors as a result of impact loads as detected by a shock sensor")
+ },
+ {
+ "loaded-hours",
+ /* Translators: S.M.A.R.T attribute, see http://smartmontools.sourceforge.net/doc.html
+ * or the next string for a longer explanation.
+ */
+ N_("Loaded Hours"),
+ N_("Number of hours in general operational state")
+ },
+ {
+ "load-retry-count",
+ /* Translators: S.M.A.R.T attribute, see http://smartmontools.sourceforge.net/doc.html
+ * or the next string for a longer explanation.
+ */
+ N_("Load/Unload Retry Count"),
+ N_("Loading on drive caused by numerous recurrences of operations, like reading, "
+ "recording, positioning of heads, etc")
+ },
+ {
+ "load-friction",
+ /* Translators: S.M.A.R.T attribute, see http://smartmontools.sourceforge.net/doc.html
+ * or the next string for a longer explanation.
+ */
+ N_("Load Friction"),
+ N_("Load on drive cause by friction in mechanical parts of the store")
+ },
+ {
+ "load-cycle-count-2",
+ /* Translators: S.M.A.R.T attribute, see http://smartmontools.sourceforge.net/doc.html
+ * or the next string for a longer explanation.
+ */
+ N_("Load/Unload Cycle Count"),
+ N_("Total number of load cycles")
+ },
+ {
+ "load-in-time",
+ /* Translators: S.M.A.R.T attribute, see http://smartmontools.sourceforge.net/doc.html
+ * or the next string for a longer explanation.
+ */
+ N_("Load-in Time"),
+ N_("General time for loading in a drive")
+ },
+ {
+ "torq-amp-count",
+ /* Translators: S.M.A.R.T attribute, see http://smartmontools.sourceforge.net/doc.html
+ * or the next string for a longer explanation.
+ */
+ N_("Torque Amplification Count"),
+ N_("Quantity efforts of the rotating moment of a drive")
+ },
+ {
+ "power-off-retract-count-2",
+ /* Translators: S.M.A.R.T attribute, see http://smartmontools.sourceforge.net/doc.html
+ * or the next string for a longer explanation.
+ */
+ N_("Power-off Retract Count"),
+ N_("Number of power-off retract events")
+ },
+ {
+ "head-amplitude",
+ /* Translators: S.M.A.R.T attribute, see http://smartmontools.sourceforge.net/doc.html
+ * or the next string for a longer explanation.
+ */
+ N_("GMR Head Amplitude"),
+ N_("Amplitude of heads trembling (GMR-head) in running mode")
+ },
+ {
+ "temperature-celsius",
+ /* Translators: S.M.A.R.T attribute, see http://smartmontools.sourceforge.net/doc.html
+ * or the next string for a longer explanation.
+ */
+ N_("Temperature"),
+ N_("Temperature of the drive")
+ },
+ {
+ "endurance-remaining",
+ /* Translators: S.M.A.R.T attribute, see http://smartmontools.sourceforge.net/doc.html
+ * or the next string for a longer explanation.
+ */
+ N_("Endurance Remaining"),
+ N_("Number of physical erase cycles completed on the drive as "
+ "a percentage of the maximum physical erase cycles the drive supports")
+ },
+ {
+ "power-on-seconds-2",
+ /* Translators: S.M.A.R.T attribute, see http://smartmontools.sourceforge.net/doc.html
+ * or the next string for a longer explanation.
+ */
+ N_("Power-On Hours"),
+ N_("Number of hours elapsed in the power-on state")
+ },
+ {
+ "uncorrectable-ecc-count",
+ /* Translators: S.M.A.R.T attribute, see http://smartmontools.sourceforge.net/doc.html
+ * or the next string for a longer explanation.
+ */
+ N_("Uncorrectable ECC Count"),
+ N_("Number of uncorrectable ECC errors")
+ },
+ {
+ "good-block-rate",
+ /* Translators: S.M.A.R.T attribute, see http://smartmontools.sourceforge.net/doc.html
+ * or the next string for a longer explanation.
+ */
+ N_("Good Block Rate"),
+ N_("Number of available reserved blocks as a percentage "
+ "of the total number of reserved blocks"),
+ },
+ {
+ "head-flying-hours",
+ /* Translators: S.M.A.R.T attribute, see http://smartmontools.sourceforge.net/doc.html
+ * or the next string for a longer explanation.
+ */
+ N_("Head Flying Hours"),
+ N_("Time while head is positioning")
+ },
+ {
+ "read-error-retry-rate",
+ /* Translators: S.M.A.R.T attribute, see http://smartmontools.sourceforge.net/doc.html
+ * or the next string for a longer explanation.
+ */
+ N_("Read Error Retry Rate"),
+ N_("Number of errors while reading from a disk")
+ },
+ {
+ NULL,
+ NULL,
+ NULL
+ }
+};
+
+
+static void
+attribute_get_details (SkSmartAttributeParsedData *a,
+ gchar **out_name,
+ gchar **out_description)
+{
+ const gchar *n;
+ const gchar *d;
+ SmartDetails *details;
+ static volatile gsize have_hash = 0;
+ static GHashTable *smart_details_map = NULL;
+
+ if (g_once_init_enter (&have_hash)) {
+ guint n;
+
+ smart_details_map = g_hash_table_new (g_str_hash, g_str_equal);
+ for (n = 0; smart_details[n].name != NULL; n++) {
+ g_hash_table_insert (smart_details_map,
+ (gpointer) smart_details[n].name,
+ (gpointer) &(smart_details[n]));
+ }
+ g_once_init_leave (&have_hash, 1);
+ }
+
+ n = NULL;
+ d = NULL;
+ details = g_hash_table_lookup (smart_details_map, a->name);
+ if (details != NULL) {
+ n = _(details->pretty_name);
+ d = _(details->desc);
+ }
+
+ if (out_name != NULL)
+ *out_name = g_strdup (n);
+ if (out_description != NULL)
+ *out_description = g_strdup (d);
+}
+
+/* ---------------------------------------------------------------------------------------------------- */
+
+enum {
+ ID_COLUMN,
+ NAME_COLUMN,
+ VALUE_COLUMN,
+ TOOLTIP_COLUMN,
+ SK_ATTR_COLUMN,
+ N_COLUMNS,
};
G_DEFINE_TYPE (GduAtaSmartDialog, gdu_ata_smart_dialog, GTK_TYPE_DIALOG)
static void update_dialog (GduAtaSmartDialog *dialog);
static void device_changed (GduDevice *device, gpointer user_data);
+static void device_job_changed (GduDevice *device, gpointer user_data);
static gchar *pretty_to_string (guint64 pretty_value,
- GduAtaSmartAttributeUnit pretty_unit,
- gboolean long_string);
+ SkSmartAttributeUnit pretty_unit);
+
+static gboolean get_ata_smart_no_warn (GduDevice *device);
+static gboolean set_ata_smart_no_warn (GduDevice *device,
+ gboolean no_warn);
static void
gdu_ata_smart_dialog_finalize (GObject *object)
{
GduAtaSmartDialog *dialog = GDU_ATA_SMART_DIALOG (object);
- g_signal_handler_disconnect (dialog->priv->device, dialog->priv->device_changed_signal_handler_id);
- g_object_unref (dialog->priv->device);
- g_object_unref (dialog->priv->attr_list_store);
-
- if (dialog->priv->historical_data != NULL) {
- g_list_foreach (dialog->priv->historical_data, (GFunc) g_object_unref, NULL);
- g_list_free (dialog->priv->historical_data);
+ if (dialog->priv->drive != NULL) {
+ g_object_unref (dialog->priv->drive);
}
+ if (dialog->priv->device != NULL) {
+ g_signal_handler_disconnect (dialog->priv->device, dialog->priv->device_changed_signal_handler_id);
+ g_signal_handler_disconnect (dialog->priv->device, dialog->priv->device_job_changed_signal_handler_id);
+ g_object_unref (dialog->priv->device);
+ }
+ g_object_unref (dialog->priv->attr_list_store);
if (G_OBJECT_CLASS (gdu_ata_smart_dialog_parent_class)->finalize != NULL)
G_OBJECT_CLASS (gdu_ata_smart_dialog_parent_class)->finalize (object);
@@ -111,8 +666,8 @@ gdu_ata_smart_dialog_get_property (GObject *object,
GduAtaSmartDialog *dialog = GDU_ATA_SMART_DIALOG (object);
switch (property_id) {
- case PROP_DEVICE:
- g_value_set_object (value, dialog->priv->device);
+ case PROP_DRIVE:
+ g_value_set_object (value, dialog->priv->drive);
break;
default:
@@ -129,8 +684,35 @@ gdu_ata_smart_dialog_set_property (GObject *object,
GduAtaSmartDialog *dialog = GDU_ATA_SMART_DIALOG (object);
switch (property_id) {
- case PROP_DEVICE:
- dialog->priv->device = g_value_dup_object (value);
+ case PROP_DRIVE:
+ if (dialog->priv->drive != NULL) {
+ g_object_unref (dialog->priv->drive);
+ }
+ if (dialog->priv->device != NULL) {
+ g_signal_handler_disconnect (dialog->priv->device,
+ dialog->priv->device_changed_signal_handler_id);
+ g_signal_handler_disconnect (dialog->priv->device,
+ dialog->priv->device_job_changed_signal_handler_id);
+ g_object_unref (dialog->priv->device);
+ }
+ if (g_value_get_object (value) != NULL) {
+ dialog->priv->drive = g_value_dup_object (value);
+ dialog->priv->device = gdu_presentable_get_device (GDU_PRESENTABLE (dialog->priv->drive));
+ if (dialog->priv->device != NULL) {
+ dialog->priv->device_changed_signal_handler_id = g_signal_connect (dialog->priv->device,
+ "changed",
+ G_CALLBACK (device_changed),
+ dialog);
+ dialog->priv->device_job_changed_signal_handler_id = g_signal_connect (dialog->priv->device,
+ "job-changed",
+ G_CALLBACK (device_job_changed),
+ dialog);
+ }
+ } else {
+ dialog->priv->drive = NULL;
+ dialog->priv->device = NULL;
+ }
+ update_dialog (dialog);
break;
default:
@@ -145,13 +727,9 @@ selection_changed (GtkTreeSelection *tree_selection,
GduAtaSmartDialog *dialog = GDU_ATA_SMART_DIALOG (user_data);
GtkTreeIter iter;
gchar *attr_name;
- guint n;
attr_name = NULL;
- if (dialog->priv->historical_data == NULL)
- goto out;
-
if (!gtk_tree_selection_get_selected (tree_selection,
NULL,
&iter))
@@ -159,268 +737,740 @@ selection_changed (GtkTreeSelection *tree_selection,
gtk_tree_model_get (GTK_TREE_MODEL (dialog->priv->attr_list_store),
&iter,
- ATTR_NAME_COLUMN,
+ NAME_COLUMN,
&attr_name,
-1);
- g_debug ("selected %s", attr_name);
-
- GArray *cur_samples;
- GArray *worst_samples;
- GArray *threshold_samples;
- GArray *raw_samples;
- GArray *band_samples;
- GduCurveUnit raw_unit;
- GList *l;
- guint64 now;
-
- cur_samples = g_array_new (FALSE, FALSE, sizeof (GduSample));
- worst_samples = g_array_new (FALSE, FALSE, sizeof (GduSample));
- threshold_samples = g_array_new (FALSE, FALSE, sizeof (GduSample));
- raw_samples = g_array_new (FALSE, FALSE, sizeof (GduSample));
- band_samples = g_array_new (FALSE, FALSE, sizeof (GduSample));
- raw_unit = GDU_CURVE_UNIT_INTEGER;
-
- guint64 tolerance;
- guint64 timespan;
-
- timespan = 5 * 24 * 60 * 60;
- tolerance = 2 * 60 * 60;
-
- guint64 last_age;
- now = (guint64) time (NULL);
- last_age = timespan;
-
- /* oldest samples first */
- for (l = dialog->priv->historical_data; l != NULL; l = l->next) {
- GduAtaSmartHistoricalData *data = GDU_ATA_SMART_HISTORICAL_DATA (l->data);
- GduAtaSmartAttribute *attr;
- guint64 time_collected;
- GduSample sample;
- guint64 age;
- gboolean use_sample;
-
- memset (&sample, '\0', sizeof (GduSample));
-
- time_collected = gdu_ata_smart_historical_data_get_time_collected (data);
- age = now - time_collected;
-
- /* skip old samples, except if the following sample is not too old */
- use_sample = FALSE;
- if (age < timespan) {
- use_sample = TRUE;
+ //g_debug ("selected %s", attr_name);
+
+ out:
+ g_free (attr_name);
+}
+
+static gchar *
+get_grey_color (GtkTreeView *tree_view,
+ GtkTreeIter *iter)
+{
+ GtkTreeSelection *tree_selection;
+ GtkStyle *style;
+ GdkColor desc_gdk_color = {0};
+ GtkStateType state;
+ gchar *desc_color;
+
+ /* This color business shouldn't be this hard... */
+ tree_selection = gtk_tree_view_get_selection (tree_view);
+ style = gtk_widget_get_style (GTK_WIDGET (tree_view));
+ if (gtk_tree_selection_iter_is_selected (tree_selection, iter)) {
+ if (GTK_WIDGET_HAS_FOCUS (GTK_WIDGET (tree_view)))
+ state = GTK_STATE_SELECTED;
+ else
+ state = GTK_STATE_ACTIVE;
+ } else {
+ state = GTK_STATE_NORMAL;
+ }
+#define BLEND_FACTOR 0.7
+ desc_gdk_color.red = style->text[state].red * BLEND_FACTOR +
+ style->base[state].red * (1.0 - BLEND_FACTOR);
+ desc_gdk_color.green = style->text[state].green * BLEND_FACTOR +
+ style->base[state].green * (1.0 - BLEND_FACTOR);
+ desc_gdk_color.blue = style->text[state].blue * BLEND_FACTOR +
+ style->base[state].blue * (1.0 - BLEND_FACTOR);
+#undef BLEND_FACTOR
+ desc_color = g_strdup_printf ("#%02x%02x%02x",
+ (desc_gdk_color.red >> 8),
+ (desc_gdk_color.green >> 8),
+ (desc_gdk_color.blue >> 8));
+
+ return desc_color;
+}
+
+static void
+format_markup_name (GtkCellLayout *cell_layout,
+ GtkCellRenderer *renderer,
+ GtkTreeModel *tree_model,
+ GtkTreeIter *iter,
+ gpointer user_data)
+{
+ GduAtaSmartDialog *dialog = GDU_ATA_SMART_DIALOG (user_data);
+ SkSmartAttributeParsedData *a;
+ gint id;
+ gchar *name;
+ gchar *desc;
+ gchar *markup;
+ gchar *desc_color;
+
+ gtk_tree_model_get (tree_model,
+ iter,
+ ID_COLUMN, &id,
+ SK_ATTR_COLUMN, &a,
+ -1);
+
+ attribute_get_details (a,
+ &name,
+ &desc);
+
+ if (name == NULL)
+ name = g_strdup (a->name);
+
+ if (desc == NULL) {
+ /* Translators: This is shown in the attribute treeview when no description is found.
+ * %d is the attribute number.
+ */
+ desc = g_strdup_printf (_("No description for attribute %d"), id);
+ }
+
+ desc_color = get_grey_color (GTK_TREE_VIEW (dialog->priv->tree_view), iter);
+ if (a->warn) {
+ markup = g_strdup_printf ("<b><span fgcolor='red'>%s</span></b>\n"
+ "<span fgcolor='darkred'><small>%s</small></span>",
+ name,
+ desc);
+ } else {
+ markup = g_strdup_printf ("<b>%s</b>\n"
+ "<span fgcolor=\"%s\"><small>%s</small></span>",
+ name,
+ desc_color,
+ desc);
+ }
+
+ g_object_set (renderer,
+ "markup", markup,
+ NULL);
+
+ _gdu_sk_attr_free (a);
+ g_free (name);
+ g_free (desc);
+ g_free (markup);
+ g_free (desc_color);
+}
+
+static void
+format_markup_id (GtkCellLayout *cell_layout,
+ GtkCellRenderer *renderer,
+ GtkTreeModel *tree_model,
+ GtkTreeIter *iter,
+ gpointer user_data)
+{
+ SkSmartAttributeParsedData *a;
+ gchar *markup;
+ gchar *id;
+
+ gtk_tree_model_get (tree_model,
+ iter,
+ SK_ATTR_COLUMN, &a,
+ -1);
+
+ id = g_strdup_printf ("%d", a->id);
+
+ if (a->warn)
+ markup = g_strdup_printf ("<span foreground='red'>%s</span>", id);
+ else
+ markup = g_strdup_printf ("%s", id);
+
+ g_object_set (renderer,
+ "markup", markup,
+ NULL);
+
+ _gdu_sk_attr_free (a);
+ g_free (id);
+ g_free (markup);
+}
+
+static void
+format_markup_value_headings (GtkCellLayout *cell_layout,
+ GtkCellRenderer *renderer,
+ GtkTreeModel *tree_model,
+ GtkTreeIter *iter,
+ gpointer user_data)
+{
+ SkSmartAttributeParsedData *a;
+ gchar *markup;
+ const gchar *s1, *s2, *s3, *s4;
+
+ gtk_tree_model_get (tree_model,
+ iter,
+ SK_ATTR_COLUMN, &a,
+ -1);
+
+ /* Translators: This is shown in the tree view for the normalized value of an attribute (0-254) */
+ s1 = _("Normalized:");
+ /* Translators: This is shown in the tree view for the worst value of an attribute (0-254) */
+ s2 = _("Worst:");
+ /* Translators: This is shown in the tree view for the threshold of an attribute (0-254) */
+ s3 = _("Threshold:");
+ /* Translators: This is shown in the tree view for the interpreted/pretty value of an attribute */
+ s4 = _("Value:");
+
+ if (a->warn)
+ markup = g_strdup_printf ("<span foreground='red'>"
+ "<small>"
+ "%s\n"
+ "%s\n"
+ "%s\n"
+ "%s"
+ "</small>"
+ "</span>",
+ s1, s2, s3, s4);
+ else
+ markup = g_strdup_printf ("<small>"
+ "%s\n"
+ "%s\n"
+ "%s\n"
+ "%s"
+ "</small>",
+ s1, s2, s3, s4);
+
+ g_object_set (renderer,
+ "markup", markup,
+ NULL);
+
+ _gdu_sk_attr_free (a);
+ g_free (markup);
+}
+
+static void
+format_markup_value (GtkCellLayout *cell_layout,
+ GtkCellRenderer *renderer,
+ GtkTreeModel *tree_model,
+ GtkTreeIter *iter,
+ gpointer user_data)
+{
+ SkSmartAttributeParsedData *a;
+ gchar *markup;
+ gchar *s1, *s2, *s3, *s4;
+
+ gtk_tree_model_get (tree_model,
+ iter,
+ SK_ATTR_COLUMN, &a,
+ -1);
+
+ if (a->worst_value_valid) {
+ s1 = g_strdup_printf ("%d", a->current_value);
+ } else {
+ /* Translators: This is used in the attribute treview when normalized/worst/treshold
+ * value isn't available */
+ s1 = g_strdup (_("N/A"));
+ }
+
+ if (a->worst_value_valid) {
+ s2 = g_strdup_printf ("%d", a->worst_value);
+ } else {
+ /* Translators: This is used in the attribute treview when normalized/worst/treshold
+ * value isn't available */
+ s2 = g_strdup (_("N/A"));
+ }
+
+ if (a->threshold_valid) {
+ s3 = g_strdup_printf ("%d", a->threshold);
+ } else {
+ /* Translators: This is used in the attribute treview when normalized/worst/treshold
+ * value isn't available */
+ s3 = g_strdup (_("N/A"));
+ }
+
+ s4 = pretty_to_string (a->pretty_value, a->pretty_unit);
+
+ if (a->warn)
+ markup = g_strdup_printf ("<span foreground='red'>"
+ "<small>"
+ "%s\n"
+ "%s\n"
+ "%s\n"
+ "%s"
+ "</small>"
+ "</span>",
+ s1, s2, s3, s4);
+ else
+ markup = g_strdup_printf ("<small>"
+ "%s\n"
+ "%s\n"
+ "%s\n"
+ "%s"
+ "</small>",
+ s1, s2, s3, s4);
+
+ g_object_set (renderer,
+ "markup", markup,
+ NULL);
+
+ _gdu_sk_attr_free (a);
+ g_free (s1);
+ g_free (s2);
+ g_free (s3);
+ g_free (s4);
+ g_free (markup);
+}
+
+static void
+format_markup_assessment (GtkCellLayout *cell_layout,
+ GtkCellRenderer *renderer,
+ GtkTreeModel *tree_model,
+ GtkTreeIter *iter,
+ gpointer user_data)
+{
+ SkSmartAttributeParsedData *a;
+ gchar *markup;
+ const gchar *assessment;
+ gboolean failed;
+ gboolean failed_in_the_past;
+
+ gtk_tree_model_get (tree_model,
+ iter,
+ SK_ATTR_COLUMN, &a,
+ -1);
+
+ failed = FALSE;
+ failed_in_the_past = FALSE;
+ if (a->prefailure) {
+ if (!a->good_now && a->good_now_valid) {
+ failed = TRUE;
+ }
+
+ if (!a->good_in_the_past && a->good_in_the_past_valid) {
+ failed_in_the_past = TRUE;
+ }
+ } else {
+ if (a->current_value_valid && a->threshold_valid &&
+ a->current_value <= a->threshold) {
+ failed = TRUE;
+ }
+
+ if (a->worst_value_valid && a->threshold_valid &&
+ a->worst_value <= a->threshold) {
+ failed_in_the_past = TRUE;
+ }
+ }
+
+ if (failed) {
+ /* Translators: Shown in the treeview for a failing attribute */
+ assessment = _("Failing");
+ } else if (failed_in_the_past) {
+ /* Translators: Shown in the treeview for an attribute that failed in the past */
+ assessment = _("Failed in the past");
+ } else if (a->good_now_valid) {
+ if (a->warn) {
+ /* Translators: Shown in the treeview for an attribute that we want to warn about */
+ assessment = _("Warning");
} else {
- if (l->next != NULL) {
- GduAtaSmartHistoricalData *next_data = GDU_ATA_SMART_HISTORICAL_DATA (l->next->data);
- guint64 next_age;
- next_age = now - gdu_ata_smart_historical_data_get_time_collected (next_data);
- if (next_age < timespan) {
- use_sample = TRUE;
- }
- }
+ /* Translators: Shown in the treeview for an attribute that is good */
+ assessment = _("Good");
}
+ } else {
+ if (a->warn) {
+ /* Translators: Shown in the treeview for an attribute that we want to warn about */
+ assessment = _("Warning");
+ } else {
+ /* Translators: Shown in the treeview for an attribute we don't know the status about */
+ assessment = _("N/A");
+ }
+ }
- if (use_sample) {
-
- sample.time_usec = time_collected * 1000L * 1000L;
-
- attr = gdu_ata_smart_historical_data_get_attribute (data, attr_name);
- if (attr != NULL) {
- guint current;
- guint worst;
- guint threshold;
- guint64 raw;
-
- current = gdu_ata_smart_attribute_get_current (attr);
- worst = gdu_ata_smart_attribute_get_worst (attr);
- threshold = gdu_ata_smart_attribute_get_threshold (attr);
- raw = gdu_ata_smart_attribute_get_pretty_value (attr);
-
- sample.value = current / 255.0f;
- g_array_append_val (cur_samples, sample);
-
- sample.value = worst / 255.0f;
- g_array_append_val (worst_samples, sample);
-
- sample.value = threshold / 255.0f;
- g_array_append_val (threshold_samples, sample);
-
- switch (gdu_ata_smart_attribute_get_pretty_unit (attr)) {
- case GDU_ATA_SMART_ATTRIBUTE_UNIT_MSECONDS:
- sample.value = ((gdouble) raw) / 1000.0;
- raw_unit = GDU_CURVE_UNIT_TIME_SECONDS;
- break;
- case GDU_ATA_SMART_ATTRIBUTE_UNIT_MKELVIN:
- sample.value = ((gdouble) raw) / 1000.0;
- raw_unit = GDU_CURVE_UNIT_TEMPERATURE_KELVIN;
- break;
- default:
- case GDU_ATA_SMART_ATTRIBUTE_UNIT_UNKNOWN:
- case GDU_ATA_SMART_ATTRIBUTE_UNIT_NONE:
- case GDU_ATA_SMART_ATTRIBUTE_UNIT_SECTORS:
- sample.value = (gdouble) raw;
- raw_unit = GDU_CURVE_UNIT_INTEGER;
- break;
- }
+ if (a->warn)
+ markup = g_strdup_printf ("<span foreground='red'>%s</span>", assessment);
+ else
+ markup = g_strdup_printf ("%s", assessment);
- g_array_append_val (raw_samples, sample);
+ g_object_set (renderer,
+ "markup", markup,
+ NULL);
- g_object_unref (attr);
- }
+ _gdu_sk_attr_free (a);
+ g_free (markup);
+}
+
+static void
+pixbuf_assessment (GtkCellLayout *cell_layout,
+ GtkCellRenderer *renderer,
+ GtkTreeModel *tree_model,
+ GtkTreeIter *iter,
+ gpointer user_data)
+{
+ SkSmartAttributeParsedData *a;
+ const gchar *icon_name;
+
+ gtk_tree_model_get (tree_model,
+ iter,
+ SK_ATTR_COLUMN, &a,
+ -1);
+
+ if (a->warn) {
+ icon_name = "gdu-smart-failing";
+ } else {
+ if (a->good_now_valid)
+ icon_name = "gdu-smart-healthy";
+ else
+ icon_name = "gdu-smart-unknown";
+ }
+
+ g_object_set (renderer,
+ "icon-name", icon_name,
+ "stock-size", GTK_ICON_SIZE_MENU,
+ NULL);
+
+ _gdu_sk_attr_free (a);
+}
+
+/* ---------------------------------------------------------------------------------------------------- */
+
+static void
+refresh_cb (GduDevice *device,
+ GError *error,
+ gpointer user_data)
+{
+ GduAtaSmartDialog *dialog = GDU_ATA_SMART_DIALOG (user_data);
+
+ /* TODO: maybe show error dialog */
+ if (error != NULL)
+ g_error_free (error);
+
+ dialog->priv->is_updating = FALSE;
+ update_dialog (dialog);
+}
+
+
+static void
+on_activate_link_update_smart_data (GtkLabel *label,
+ const gchar *uri,
+ gpointer user_data)
+{
+ GduAtaSmartDialog *dialog = GDU_ATA_SMART_DIALOG (user_data);
- /* draw a band if there's a discontinuity; e.g. no samples for an hour or more */
- if (last_age - age >= tolerance) {
- sample.time_usec = (now - last_age + tolerance) * 1000 * 1000;
- sample.value = 1.0;
- g_array_append_val (band_samples, sample);
+ gdu_device_drive_ata_smart_refresh_data (dialog->priv->device,
+ refresh_cb,
+ dialog);
- sample.time_usec = (now - age - tolerance) * 1000 * 1000;
- sample.value = 1.0;
- g_array_append_val (band_samples, sample);
+ g_signal_stop_emission_by_name (label, "activate-link");
+
+ dialog->priv->is_updating = TRUE;
+ update_dialog (dialog);
+}
+
+/* ---------------------------------------------------------------------------------------------------- */
+
+static void
+cancel_self_test_cb (GduDevice *device,
+ GError *error,
+ gpointer user_data)
+{
+ /* TODO: maybe show error dialog */
+ if (error != NULL)
+ g_error_free (error);
+}
+
+
+static void
+on_activate_link_cancel_self_test (GtkLabel *link_label,
+ const gchar *uri,
+ gpointer user_data)
+{
+ GduAtaSmartDialog *dialog = GDU_ATA_SMART_DIALOG (user_data);
+
+ g_signal_stop_emission_by_name (link_label, "activate-link");
+
+ gdu_device_op_cancel_job (dialog->priv->device,
+ cancel_self_test_cb,
+ dialog);
+}
+
+/* ---------------------------------------------------------------------------------------------------- */
+
+static void
+run_self_test_cb (GduDevice *device,
+ GError *error,
+ gpointer user_data)
+{
+ /* TODO: maybe show error dialog */
+ if (error != NULL)
+ g_error_free (error);
+}
+
+
+static void
+on_activate_link_run_self_test (GtkLabel *link_label,
+ const gchar *uri,
+ gpointer user_data)
+{
+ GduAtaSmartDialog *dialog = GDU_ATA_SMART_DIALOG (user_data);
+ GtkWidget *test_dialog;
+ GtkWidget *hbox;
+ GtkWidget *image;
+ GtkWidget *main_vbox;
+ GtkWidget *label;
+ GtkWidget *radio0;
+ GtkWidget *radio1;
+ GtkWidget *radio2;
+ gchar *s;
+ gint response;
+ const gchar *test;
+
+ g_signal_stop_emission_by_name (link_label, "activate-link");
+
+ test_dialog = gtk_dialog_new_with_buttons (NULL,
+ GTK_WINDOW (dialog),
+ GTK_DIALOG_MODAL|GTK_DIALOG_DESTROY_WITH_PARENT|GTK_DIALOG_NO_SEPARATOR,
+ NULL);
+ gtk_window_set_title (GTK_WINDOW (test_dialog), "");
+
+ gtk_container_set_border_width (GTK_CONTAINER (test_dialog), 6);
+ gtk_box_set_spacing (GTK_BOX (GTK_DIALOG (test_dialog)->vbox), 2);
+ gtk_container_set_border_width (GTK_CONTAINER (GTK_DIALOG (test_dialog)->action_area), 5);
+ gtk_box_set_spacing (GTK_BOX (GTK_DIALOG (test_dialog)->action_area), 6);
+ gtk_window_set_resizable (GTK_WINDOW (test_dialog), FALSE);
+
+ hbox = gtk_hbox_new (FALSE, 12);
+ gtk_container_set_border_width (GTK_CONTAINER (hbox), 5);
+ gtk_box_pack_start (GTK_BOX (GTK_DIALOG (test_dialog)->vbox), hbox, TRUE, TRUE, 0);
+
+ image = gtk_image_new_from_stock (GTK_STOCK_DIALOG_QUESTION, GTK_ICON_SIZE_DIALOG);
+ gtk_misc_set_alignment (GTK_MISC (image), 0.5, 0.0);
+ gtk_box_pack_start (GTK_BOX (hbox), image, FALSE, FALSE, 0);
+
+ main_vbox = gtk_vbox_new (FALSE, 10);
+ gtk_box_pack_start (GTK_BOX (hbox), main_vbox, TRUE, TRUE, 0);
+
+ label = gtk_label_new (NULL);
+ s = g_strconcat ("<big><b>",
+ /* Translators: Shown in the "Run self-test" dialog */
+ _("Select what SMART self test to run"),
+ "</b></big>",
+ NULL);
+ gtk_label_set_markup (GTK_LABEL (label), s);
+ g_free (s);
+ 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);
+
+ label = gtk_label_new (NULL);
+ /* Translators: Shown in the "Run self-test" dialog */
+ gtk_label_set_markup (GTK_LABEL (label), _("The tests may take a very long time to complete depending "
+ "on the speed and size of the disk. You can continue using "
+ "your system while the test is running."));
+ 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);
+
+ radio0 = gtk_radio_button_new_with_mnemonic_from_widget (NULL,
+ /* Translators: Radio button for short test */
+ _("_Short (usually less than ten minutes)"));
+ radio1 = gtk_radio_button_new_with_mnemonic_from_widget (GTK_RADIO_BUTTON (radio0),
+ /* Translators: Radio button for extended test */
+ _("_Extended (usually tens of minutes)"));
+ radio2 = gtk_radio_button_new_with_mnemonic_from_widget (GTK_RADIO_BUTTON (radio0),
+ /* Translators: Radio button for conveyance test */
+ _("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 (test_dialog), GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL);
+ /* Translators: Button in "Run self-test dialog" */
+ gtk_dialog_add_button (GTK_DIALOG (test_dialog), _("_Initiate Self Test"), 0);
+ gtk_dialog_set_default_response (GTK_DIALOG (test_dialog), 0);
+
+ gtk_widget_show_all (test_dialog);
+ response = gtk_dialog_run (GTK_DIALOG (test_dialog));
+
+ if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (radio0))) {
+ test = "short";
+ } else if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (radio1))) {
+ test = "extended";
+ } else if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (radio2))) {
+ test = "conveyance";
+ }
+
+ gtk_widget_destroy (test_dialog);
+ if (response != 0)
+ goto out;
+
+ gdu_device_op_drive_ata_smart_initiate_selftest (dialog->priv->device,
+ test,
+ run_self_test_cb,
+ dialog);
+
+ out:
+ ;
+}
+
+/* ---------------------------------------------------------------------------------------------------- */
+
+static void
+disk_name_data_func (GtkCellLayout *cell_layout,
+ GtkCellRenderer *renderer,
+ GtkTreeModel *tree_model,
+ GtkTreeIter *iter,
+ gpointer user_data)
+{
+ gchar *name;
+ gchar *vpd_name;
+ gchar *markup;
+ gchar *desc;
+ GduPresentable *p;
+ GduDevice *d;
+ gboolean sensitive;
+ gchar *s;
+
+ gtk_tree_model_get (tree_model,
+ iter,
+ GDU_POOL_TREE_MODEL_COLUMN_NAME, &name,
+ GDU_POOL_TREE_MODEL_COLUMN_VPD_NAME, &vpd_name,
+ GDU_POOL_TREE_MODEL_COLUMN_PRESENTABLE, &p,
+ -1);
- /* close the segment */
- sample.time_usec = G_MAXINT64;
- sample.value = G_MAXDOUBLE;
- g_array_append_val (band_samples, sample);
+ d = gdu_presentable_get_device (p);
+
+ desc = NULL;
+ sensitive = FALSE;
+ if (d != NULL) {
+ if (gdu_device_drive_ata_smart_get_is_available (d) &&
+ gdu_device_drive_ata_smart_get_time_collected (d) > 0) {
+ const gchar *status;
+ gboolean highlight;
+
+ sensitive = TRUE;
+
+ status = gdu_device_drive_ata_smart_get_status (d);
+ if (status != NULL && strlen (status) > 0) {
+ desc = gdu_util_ata_smart_status_to_desc (status, &highlight, NULL, NULL);
+ if (highlight) {
+ s = g_strdup_printf ("<span fgcolor=\"red\"><b>%s</b></span>", desc);
+ g_free (desc);
+ desc = s;
+ }
+ } else if (gdu_device_drive_ata_smart_get_is_available (d) &&
+ gdu_device_drive_ata_smart_get_time_collected (d) > 0) {
+ /* Translators: Used in the drive combo-box to indicate the health status is unknown */
+ desc = g_strdup (_("Health status is unknown"));
+ }
+ } else {
+ if (gdu_device_drive_ata_smart_get_is_available (d)) {
+ /* Translators: Used in the drive combo-box to indicate SMART is not enabled */
+ desc = g_strdup (_("SMART is not enabled"));
+ } else {
+ /* Translators: Used in the drive combo-box to indicate SMART is not available */
+ desc = g_strdup (_("SMART is not available"));
}
}
+ }
- last_age = age;
+ if (desc != NULL) {
+ markup = g_strdup_printf ("<b>%s</b> â?? %s\n"
+ "<small>%s</small>",
+ name,
+ vpd_name,
+ desc);
+ } else {
+ markup = g_strdup_printf ("<b>%s</b> â?? %s\n"
+ "<small> </small>",
+ name,
+ vpd_name);
}
-#define GDU_COLOR_FROM_HEX(argb_hex, alpha) \
- { \
- (((argb_hex) >> 16)&0xff) / 255.0, \
- (((argb_hex) >> 8)&0xff) / 255.0, \
- (((argb_hex) >> 0)&0xff) / 255.0, \
- alpha / 255.0 \
+ g_object_set (renderer,
+ "markup", markup,
+ "sensitive", sensitive,
+ NULL);
+
+ g_free (name);
+ g_free (vpd_name);
+ g_free (markup);
+ g_free (desc);
+ g_object_unref (p);
+ if (d != NULL)
+ g_object_unref (d);
+}
+
+static void
+disk_name_gicon_func (GtkCellLayout *cell_layout,
+ GtkCellRenderer *renderer,
+ GtkTreeModel *tree_model,
+ GtkTreeIter *iter,
+ gpointer user_data)
+{
+ GIcon *icon;
+ GduPresentable *p;
+ GduDevice *d;
+ gboolean sensitive;
+
+ gtk_tree_model_get (tree_model,
+ iter,
+ GDU_POOL_TREE_MODEL_COLUMN_ICON, &icon,
+ GDU_POOL_TREE_MODEL_COLUMN_PRESENTABLE, &p,
+ -1);
+
+ d = gdu_presentable_get_device (p);
+ sensitive = FALSE;
+ if (d != NULL) {
+ if (gdu_device_drive_ata_smart_get_is_available (d) &&
+ gdu_device_drive_ata_smart_get_time_collected (d) > 0)
+ sensitive = TRUE;
}
- /* see http://tango.freedesktop.org/Tango_Icon_Theme_Guidelines for colors
- */
- GduColor raw_color = GDU_COLOR_FROM_HEX (0xfcaf3e, 255.0); /* orange */
- GduColor raw_fill_color = GDU_COLOR_FROM_HEX (0xfcaf3e, 128.0); /* orange */
- GduColor cur_color = GDU_COLOR_FROM_HEX (0x729fcf, 255.0); /* sky blue */
- GduColor worst_color = GDU_COLOR_FROM_HEX (0xad7fa8, 255.0); /* plum */
- GduColor threshold_color = GDU_COLOR_FROM_HEX (0xef2929, 255.0); /* scarlet red */
- GduColor band_color = { 0.00, 0.00, 0.00, 0.0 };
- GduColor band_fill_color = { 0.85, 0.85, 0.85, 0.5 };
- GduCurve *c;
-
- /* add graphs in order */
- gint z_order = 0;
-
- /* bands representing no data */
- c = gdu_curve_new ();
- gdu_curve_set_legend (c, _("No data"));
- gdu_curve_set_z_order (c, z_order++);
- gdu_curve_set_samples (c, band_samples);
- gdu_curve_set_color (c, &band_color);
- gdu_curve_set_fill_color (c, &band_fill_color);
- gdu_curve_set_flags (c, GDU_CURVE_FLAGS_FILLED | GDU_CURVE_FLAGS_FADE_EDGES);
- gdu_graph_add_curve (GDU_GRAPH (dialog->priv->graph),
- "band",
- c);
- g_object_unref (c);
-
- /* worst */
- c = gdu_curve_new ();
- gdu_curve_set_legend (c, _("Worst"));
- gdu_curve_set_z_order (c, z_order++);
- gdu_curve_set_samples (c, worst_samples);
- gdu_curve_set_color (c, &worst_color);
- gdu_curve_set_width (c, 1.0);
- gdu_graph_add_curve (GDU_GRAPH (dialog->priv->graph),
- "worst",
- c);
- g_object_unref (c);
-
- /* threshold */
- c = gdu_curve_new ();
- gdu_curve_set_legend (c, _("Treshold"));
- gdu_curve_set_z_order (c, z_order++);
- gdu_curve_set_samples (c, threshold_samples);
- gdu_curve_set_color (c, &threshold_color);
- gdu_curve_set_width (c, 1.0);
- gdu_graph_add_curve (GDU_GRAPH (dialog->priv->graph),
- "threshold",
- c);
- g_object_unref (c);
-
- /* current */
- c = gdu_curve_new ();
- gdu_curve_set_legend (c, _("Current"));
- gdu_curve_set_z_order (c, z_order++);
- gdu_curve_set_samples (c, cur_samples);
- gdu_curve_set_color (c, &cur_color);
- gdu_curve_set_width (c, 2.0);
- gdu_graph_add_curve (GDU_GRAPH (dialog->priv->graph),
- "current",
- c);
- g_object_unref (c);
-
-
- /* raw */
- c = gdu_curve_new ();
- gdu_curve_set_legend (c, _("Raw")); /* TODO: units? */
- gdu_curve_set_z_order (c, z_order++);
- gdu_curve_set_samples (c, raw_samples);
- gdu_curve_set_unit (c, raw_unit);
- gdu_curve_set_color (c, &raw_color);
- gdu_curve_set_fill_color (c, &raw_fill_color);
- gdu_curve_set_width (c, 2.0);
- gdu_curve_set_flags (c,
- GDU_CURVE_FLAGS_AXIS_MARKERS_LEFT |
- GDU_CURVE_FLAGS_FILLED |
- GDU_CURVE_FLAGS_NORMALIZE);
- gdu_graph_add_curve (GDU_GRAPH (dialog->priv->graph),
- "raw",
- c);
- g_object_unref (c);
-
- g_array_unref (cur_samples);
- g_array_unref (worst_samples);
- g_array_unref (threshold_samples);
- g_array_unref (raw_samples);
- g_array_unref (band_samples);
+ g_object_set (renderer,
+ "gicon", icon,
+ "sensitive", sensitive,
+ NULL);
- out:
- g_free (attr_name);
+ g_object_unref (icon);
+ g_object_unref (p);
+ if (d != NULL)
+ g_object_unref (d);
}
+/* ---------------------------------------------------------------------------------------------------- */
+
static void
-on_period_scale_changed (GtkRange *range,
- gpointer user_data)
+on_drive_combo_box_changed (GtkComboBox *combo_box,
+ gpointer user_data)
{
- gdouble value;
GduAtaSmartDialog *dialog = GDU_ATA_SMART_DIALOG (user_data);
+ GtkTreeIter iter = {0};
- value = gtk_range_get_value (range);
+ if (gtk_combo_box_get_active_iter (combo_box, &iter)) {
+ GduPresentable *p;
- gdu_graph_set_window_size_usec (GDU_GRAPH (dialog->priv->graph),
- value * 60 * 60 * G_USEC_PER_SEC);
+ gtk_tree_model_get (GTK_TREE_MODEL (dialog->priv->pool_tree_model),
+ &iter,
+ GDU_POOL_TREE_MODEL_COLUMN_PRESENTABLE, &p,
+ -1);
+
+ g_object_set (dialog,
+ "drive", GDU_DRIVE (p),
+ NULL);
+
+ g_object_unref (p);
+ } else {
+ g_object_set (dialog,
+ "drive", NULL,
+ NULL);
+ }
}
+/* ---------------------------------------------------------------------------------------------------- */
+
static void
-on_end_scale_changed (GtkRange *range,
- gpointer user_data)
+on_no_warn_check_button_toggled (GtkToggleButton *toggle_button,
+ gpointer user_data)
{
- gdouble value;
GduAtaSmartDialog *dialog = GDU_ATA_SMART_DIALOG (user_data);
- gint64 now_usec;
+ gboolean is_active;
- now_usec = time (NULL) * G_USEC_PER_SEC;
+ is_active = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (dialog->priv->no_warn_check_button));
- value = gtk_range_get_value (range);
- if (value < 1.0) {
- gdu_graph_set_window_end_usec (GDU_GRAPH (dialog->priv->graph),
- G_MAXINT64);
- } else {
- gdu_graph_set_window_end_usec (GDU_GRAPH (dialog->priv->graph),
- now_usec - value * 60 * 60 * G_USEC_PER_SEC);
+ if (dialog->priv->device == NULL)
+ goto out;
+
+ if (get_ata_smart_no_warn (dialog->priv->device) != is_active) {
+ set_ata_smart_no_warn (dialog->priv->device, is_active);
+ update_dialog (dialog);
}
+
+ out:
+ ;
}
+/* ---------------------------------------------------------------------------------------------------- */
+
static void
gdu_ata_smart_dialog_constructed (GObject *object)
{
@@ -428,217 +1478,501 @@ gdu_ata_smart_dialog_constructed (GObject *object)
GtkWidget *content_area;
GtkWidget *align;
GtkWidget *vbox;
+ GtkWidget *vbox2;
GtkWidget *hbox;
+ GtkWidget *image;
GtkWidget *table;
GtkWidget *label;
GtkWidget *tree_view;
GtkWidget *scrolled_window;
- GtkWidget *graph;
+ GtkWidget *spinner;
+ GtkWidget *progress_bar;
+ GtkWidget *check_button;
GtkCellRenderer *renderer;
GtkTreeViewColumn *column;
gint row;
- GduPresentable *drive;
- GduPool *pool;
- gchar *title;
- gchar *drive_name;
GtkTreeSelection *selection;
+ gchar *s;
+ GtkWidget *combo_box;
+ GduPool *pool;
+ GtkTreeIter iter = {0};
+ const gchar *tooltip_markup;
+ gboolean rtl;
- gtk_dialog_set_has_separator (GTK_DIALOG (dialog), FALSE);
+ rtl = (gtk_widget_get_direction (GTK_WIDGET (dialog)) == GTK_TEXT_DIR_RTL);
- pool = gdu_device_get_pool (dialog->priv->device);
- drive = gdu_pool_get_drive_by_device (pool, dialog->priv->device);
- drive_name = gdu_presentable_get_name (drive);
- /* Translators: %s is the drive name */
- title = g_strdup_printf (_("ATA SMART data for %s"), drive_name);
- gtk_window_set_title (GTK_WINDOW (dialog), title);
- g_object_unref (pool);
- g_object_unref (drive);
- g_free (title);
- g_free (drive_name);
+ /* Translators: Title of the SMART dialog */
+ gtk_window_set_title (GTK_WINDOW (dialog), _("SMART Data"));
+ gtk_dialog_set_has_separator (GTK_DIALOG (dialog), FALSE);
content_area = gtk_dialog_get_content_area (GTK_DIALOG (dialog));
- //gtk_dialog_add_button (GTK_DIALOG (dialog),
- // GTK_STOCK_CLOSE,
- // GTK_RESPONSE_CLOSE);
align = gtk_alignment_new (0.5, 0.5, 1.0, 1.0);
gtk_alignment_set_padding (GTK_ALIGNMENT (align), 12, 12, 12, 12);
gtk_box_pack_start (GTK_BOX (content_area), align, TRUE, TRUE, 0);
- vbox = gtk_vbox_new (FALSE, 6);
+ vbox = gtk_vbox_new (FALSE, 12);
gtk_container_add (GTK_CONTAINER (align), vbox);
- hbox = gtk_hbox_new (FALSE, 6);
- gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, FALSE, 0);
+ /* ---------------------------------------------------------------------------------------------------- */
+
+ pool = gdu_device_get_pool (dialog->priv->device);
+ dialog->priv->pool_tree_model = gdu_pool_tree_model_new (pool,
+ GDU_POOL_TREE_MODEL_FLAGS_NO_VOLUMES);
+ g_object_unref (pool);
table = gtk_table_new (4, 2, FALSE);
gtk_table_set_col_spacings (GTK_TABLE (table), 12);
- gtk_table_set_row_spacings (GTK_TABLE (table), 4);
- gtk_box_pack_start (GTK_BOX (hbox), table, FALSE, FALSE, 0);
-
- graph = gdu_graph_new ();
- dialog->priv->graph = graph;
- gtk_widget_set_size_request (graph, 480, 350);
- gtk_box_pack_start (GTK_BOX (hbox), graph, TRUE, TRUE, 0);
-
-#if 0
- const gchar *time_axis[7];
- time_axis[0] = C_("ATA SMART graph label", "five days ago");
- time_axis[1] = C_("ATA SMART graph label", "four days ago");
- time_axis[2] = C_("ATA SMART graph label", "three days ago");
- time_axis[3] = C_("ATA SMART graph label", "two days ago");
- time_axis[4] = C_("ATA SMART graph label", "one day ago");
- time_axis[5] = C_("ATA SMART graph label", "now");
- time_axis[6] = NULL;
- gdu_graph_set_x_markers (GDU_GRAPH (graph), time_axis);
-
- const gchar *y_axis_right[6];
- y_axis_right[0] = C_("ATA SMART graph label", "0");
- y_axis_right[1] = C_("ATA SMART graph label", "64");
- y_axis_right[2] = C_("ATA SMART graph label", "128");
- y_axis_right[3] = C_("ATA SMART graph label", "192");
- y_axis_right[4] = C_("ATA SMART graph label", "255");
- y_axis_right[5] = NULL;
- gdu_graph_set_y_markers_right (GDU_GRAPH (graph), y_axis_right);
-#endif
+ gtk_table_set_row_spacings (GTK_TABLE (table), 0);
+ gtk_box_pack_start (GTK_BOX (vbox), table, FALSE, FALSE, 0);
row = 0;
- /* power on hours */
+ /* ------------------------------ */
+
label = gtk_label_new (NULL);
- gtk_misc_set_alignment (GTK_MISC (label), 1.0, 0.5);
- gtk_label_set_markup_with_mnemonic (GTK_LABEL (label), _("<b>Powered On:</b>"));
+ gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
+ /* Translators: Label used before the drive combo box */
+ gtk_label_set_markup_with_mnemonic (GTK_LABEL (label), _("_Drive:"));
gtk_table_attach (GTK_TABLE (table), label, 0, 1, row, row + 1,
GTK_FILL, GTK_FILL, 0, 0);
+ combo_box = gtk_combo_box_new_with_model (GTK_TREE_MODEL (dialog->priv->pool_tree_model));
+ gtk_table_attach (GTK_TABLE (table), combo_box, 1, 2, row, row + 1,
+ GTK_FILL | GTK_EXPAND, GTK_FILL, 0, 0);
+ dialog->priv->drive_combo_box = combo_box;
+ gtk_label_set_mnemonic_widget (GTK_LABEL (label), combo_box);
+ g_signal_connect (combo_box,
+ "changed",
+ G_CALLBACK (on_drive_combo_box_changed),
+ dialog);
+
+ renderer = gtk_cell_renderer_pixbuf_new ();
+ gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (combo_box), renderer, FALSE);
+ gtk_cell_layout_set_cell_data_func (GTK_CELL_LAYOUT (combo_box),
+ renderer,
+ disk_name_gicon_func,
+ dialog,
+ NULL);
+ g_object_set (renderer,
+ "stock-size", GTK_ICON_SIZE_SMALL_TOOLBAR,
+ NULL);
+
+ renderer = gtk_cell_renderer_text_new ();
+ gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (combo_box), renderer, TRUE);
+ gtk_cell_layout_set_cell_data_func (GTK_CELL_LAYOUT (combo_box),
+ renderer,
+ disk_name_data_func,
+ dialog,
+ NULL);
+
+ row++;
+
+ if (dialog->priv->drive != NULL) {
+ if (gdu_pool_tree_model_get_iter_for_presentable (dialog->priv->pool_tree_model,
+ GDU_PRESENTABLE (dialog->priv->drive),
+ &iter)) {
+ gtk_combo_box_set_active_iter (GTK_COMBO_BOX (dialog->priv->drive_combo_box), &iter);
+ }
+ }
+
+ /* ---------------------------------------------------------------------------------------------------- */
+
label = gtk_label_new (NULL);
gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
- dialog->priv->power_on_hours_label = label;
+ /* Translators: Heading used in the main dialog for the SMART status */
+ s = g_strconcat ("<b>", _("Status"), "</b>", NULL);
+ gtk_label_set_markup (GTK_LABEL (label), s);
+ g_free (s);
+ gtk_box_pack_start (GTK_BOX (vbox), label, FALSE, FALSE, 0);
- gtk_table_attach (GTK_TABLE (table), label, 1, 2, row, row + 1,
+ align = gtk_alignment_new (0.5, 0.5, 1.0, 1.0);
+ gtk_alignment_set_padding (GTK_ALIGNMENT (align), 0, 0, 12, 0);
+ gtk_box_pack_start (GTK_BOX (vbox), align, FALSE, FALSE, 0);
+
+ vbox2 = gtk_vbox_new (FALSE, 6);
+ gtk_container_add (GTK_CONTAINER (align), vbox2);
+
+ table = gtk_table_new (4, 2, FALSE);
+ gtk_table_set_col_spacings (GTK_TABLE (table), 12);
+ gtk_table_set_row_spacings (GTK_TABLE (table), 6);
+ gtk_box_pack_start (GTK_BOX (vbox2), table, FALSE, FALSE, 0);
+
+ row = 0;
+
+ /* ------------------------------ */
+ /* updated */
+
+ /* Translators: Tooltip for the Updated item in the status table */
+ tooltip_markup = _("Time since SMART data was last read â?? SMART data is updated every 30 minutes unless "
+ "the disk is sleeping");
+
+ label = gtk_label_new (NULL);
+ gtk_widget_set_tooltip_markup (label, tooltip_markup);
+ gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
+ /* Translators: Item name in the status table */
+ gtk_label_set_markup (GTK_LABEL (label), _("Updated:"));
+ gtk_table_attach (GTK_TABLE (table), label, 0, 1, row, row + 1,
GTK_FILL, GTK_FILL, 0, 0);
+ hbox = gtk_hbox_new (FALSE, 0);
+
+ /* Translators: Used in the status table when data is currently being updated */
+ label = gtk_label_new (_("Updating..."));
+ gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 0);
+ dialog->priv->updating_label = label;
+
+ spinner = gdu_spinner_new ();
+ gtk_box_pack_start (GTK_BOX (hbox), spinner, FALSE, FALSE, 6);
+ dialog->priv->updating_spinner = spinner;
+
+ label = gdu_time_label_new (NULL);
+ gtk_widget_set_tooltip_markup (label, tooltip_markup);
+ gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
+ dialog->priv->updated_label = label;
+ gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 0);
+
+
+ label = gtk_label_new (NULL);
+ s = g_strdup_printf (rtl ? "<a href=\"update-now\" title=\"%s\">%s</a> â?? " :
+ " â?? <a href=\"update-now\" title=\"%s\">%s</a>",
+ /* Translators: Tooltip for the "Update Now" hyperlink */
+ _("Reads SMART data from the disk, waking it up if necessary"),
+ /* Translators: Text used in the hyperlink in the status table to update the SMART status */
+ _("Update now"));
+ gtk_label_set_track_visited_links (GTK_LABEL (label), FALSE);
+ gtk_label_set_markup (GTK_LABEL (label), s);
+ g_free (s);
+ gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
+ dialog->priv->update_link_label = label;
+ gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 0);
+ g_signal_connect (label,
+ "activate-link",
+ G_CALLBACK (on_activate_link_update_smart_data),
+ dialog);
+
+ gtk_table_attach (GTK_TABLE (table), hbox, 1, 2, row, row + 1,
+ GTK_FILL, GTK_FILL, 0, 0);
row++;
- /* temperature */
+ /* control visibility (see update_dialog()) */
+ gtk_widget_set_no_show_all (dialog->priv->updated_label, TRUE);
+ gtk_widget_set_no_show_all (dialog->priv->updating_label, TRUE);
+ gtk_widget_set_no_show_all (dialog->priv->updating_spinner, TRUE);
+ gtk_widget_set_no_show_all (dialog->priv->update_link_label, TRUE);
+
+ /* ------------------------------ */
+ /* self-tests */
+
+ /* Translators: Tooltip for the Self-tests item in the status table */
+ tooltip_markup = _("The result of the last self-test that ran on the disk");
+
label = gtk_label_new (NULL);
- gtk_misc_set_alignment (GTK_MISC (label), 1.0, 0.5);
- gtk_label_set_markup_with_mnemonic (GTK_LABEL (label), _("<b>Temperature:</b>"));
+ gtk_widget_set_tooltip_markup (label, tooltip_markup);
+ gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
+ /* Translators: Item name in the status table */
+ gtk_label_set_markup (GTK_LABEL (label), _("Self-tests:"));
gtk_table_attach (GTK_TABLE (table), label, 0, 1, row, row + 1,
GTK_FILL, GTK_FILL, 0, 0);
+ hbox = gtk_hbox_new (FALSE, 0);
+
label = gtk_label_new (NULL);
+ gtk_widget_set_tooltip_markup (label, tooltip_markup);
gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
- dialog->priv->temperature_label = label;
+ gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 0);
+ dialog->priv->self_test_result_label = label;
+
+
+ progress_bar = gtk_progress_bar_new ();
+ gtk_box_pack_start (GTK_BOX (hbox), progress_bar, FALSE, FALSE, 0);
+ dialog->priv->self_test_progress_bar = progress_bar;
+
+ label = gtk_label_new (NULL);
+ s = g_strdup_printf (rtl ? "<a href=\"run-self-test\" title=\"%s\">%s</a> â?? " :
+ " â?? <a href=\"run-self-test\" title=\"%s\">%s</a>",
+ /* Translators: Tooltip for the "Run self-test" hyperlink */
+ _("Initiates a self-test on the drive"),
+ /* Translators: Text used in the hyperlink in the status table to run a self-test */
+ _("Run self-test"));
+ gtk_label_set_track_visited_links (GTK_LABEL (label), FALSE);
+ gtk_label_set_markup (GTK_LABEL (label), s);
+ g_free (s);
+ gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
+ gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 0);
+ dialog->priv->self_test_run_link_label = label;
+ g_signal_connect (label,
+ "activate-link",
+ G_CALLBACK (on_activate_link_run_self_test),
+ dialog);
+
+ label = gtk_label_new (NULL);
+ gtk_label_set_track_visited_links (GTK_LABEL (label), FALSE);
+ s = g_strdup_printf (rtl ? "<a href=\"cancel-self-test\" title=\"%s\">%s</a> â?? " :
+ " â?? <a href=\"cancel-self-test\" title=\"%s\">%s</a>",
+ /* Translators: Tooptip for the "Cancel" hyperlink */
+ _("Cancels the currently running test"),
+ /* Translators: Text used in the hyperlink in the status table to cancel a self-test */
+ _("Cancel"));
+ gtk_label_set_markup (GTK_LABEL (label), s);
+ g_free (s);
+ gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
+ gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 0);
+ dialog->priv->self_test_cancel_link_label = label;
+ g_signal_connect (label,
+ "activate-link",
+ G_CALLBACK (on_activate_link_cancel_self_test),
+ dialog);
+
+ gtk_table_attach (GTK_TABLE (table), hbox, 1, 2, row, row + 1,
+ GTK_FILL, GTK_FILL, 0, 0);
+
+ row++;
+
+ /* control visibility (see update_dialog()) */
+ gtk_widget_set_no_show_all (dialog->priv->self_test_result_label, TRUE);
+ gtk_widget_set_no_show_all (dialog->priv->self_test_progress_bar, TRUE);
+ gtk_widget_set_no_show_all (dialog->priv->self_test_run_link_label, TRUE);
+ gtk_widget_set_no_show_all (dialog->priv->self_test_cancel_link_label, TRUE);
+
+ /* ------------------------------ */
+ /* model */
+
+ /* Translators: Tooltip for the "Model Name:" item in the status table */
+ tooltip_markup = _("The name of the model of the disk");
+
+ label = gtk_label_new (NULL);
+ gtk_widget_set_tooltip_markup (label, tooltip_markup);
+ gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
+ /* Translators: Item name in the status table */
+ gtk_label_set_markup (GTK_LABEL (label), _("Model Name:"));
+ gtk_table_attach (GTK_TABLE (table), label, 0, 1, row, row + 1,
+ GTK_FILL, GTK_FILL, 0, 0);
+
+ label = gtk_label_new (NULL);
+ gtk_widget_set_tooltip_markup (label, tooltip_markup);
+ gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
+ dialog->priv->model_label = label;
gtk_table_attach (GTK_TABLE (table), label, 1, 2, row, row + 1,
GTK_FILL, GTK_FILL, 0, 0);
row++;
- /* last test */
+ /* ------------------------------ */
+ /* firmware */
+
+ /* Translators: Tooltip for the "Firmware Version:" item in the status table */
+ tooltip_markup = _("The firmware version of the disk");
+
label = gtk_label_new (NULL);
- gtk_misc_set_alignment (GTK_MISC (label), 1.0, 0.5);
- gtk_label_set_markup_with_mnemonic (GTK_LABEL (label), _("<b>Last Test:</b>"));
+ gtk_widget_set_tooltip_markup (label, tooltip_markup);
+ gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
+ /* Translators: Item name in the status table */
+ gtk_label_set_markup (GTK_LABEL (label), _("Firmware Version:"));
gtk_table_attach (GTK_TABLE (table), label, 0, 1, row, row + 1,
GTK_FILL, GTK_FILL, 0, 0);
label = gtk_label_new (NULL);
+ gtk_widget_set_tooltip_markup (label, tooltip_markup);
gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
- dialog->priv->last_self_test_result_label = label;
+ dialog->priv->firmware_label = label;
gtk_table_attach (GTK_TABLE (table), label, 1, 2, row, row + 1,
GTK_FILL, GTK_FILL, 0, 0);
row++;
- /* updated */
+ /* ------------------------------ */
+ /* serial */
+
+ /* Translators: Tooltip for the "Serial:" item in the status table */
+ tooltip_markup = _("The serial number of the disk");
+
label = gtk_label_new (NULL);
- gtk_misc_set_alignment (GTK_MISC (label), 1.0, 0.5);
- gtk_label_set_markup_with_mnemonic (GTK_LABEL (label), _("<b>Updated:</b>"));
+ gtk_widget_set_tooltip_markup (label, tooltip_markup);
+ gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
+ /* Translators: Item name in the status table */
+ gtk_label_set_markup (GTK_LABEL (label), _("Serial Number:"));
gtk_table_attach (GTK_TABLE (table), label, 0, 1, row, row + 1,
GTK_FILL, GTK_FILL, 0, 0);
- label = gdu_time_label_new (NULL);
+ label = gtk_label_new (NULL);
+ gtk_widget_set_tooltip_markup (label, tooltip_markup);
gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
- dialog->priv->updated_label = label;
+ dialog->priv->serial_label = label;
gtk_table_attach (GTK_TABLE (table), label, 1, 2, row, row + 1,
GTK_FILL, GTK_FILL, 0, 0);
row++;
- /* bad sectors */
+ /* ------------------------------ */
+ /* power on hours */
+
+ /* Translators: Tooltip for the "Powered On:" item in the status table */
+ tooltip_markup = _("The amount of elapsed time the disk has been in a powered-up state");
+
label = gtk_label_new (NULL);
- gtk_misc_set_alignment (GTK_MISC (label), 1.0, 0.5);
- gtk_label_set_markup_with_mnemonic (GTK_LABEL (label), _("<b>Sectors:</b>"));
+ gtk_widget_set_tooltip_markup (label, tooltip_markup);
+ gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
+ /* Translators: Item name in the status table */
+ gtk_label_set_markup (GTK_LABEL (label), _("Powered On:"));
gtk_table_attach (GTK_TABLE (table), label, 0, 1, row, row + 1,
GTK_FILL, GTK_FILL, 0, 0);
label = gtk_label_new (NULL);
+ gtk_widget_set_tooltip_markup (label, tooltip_markup);
gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
- dialog->priv->sectors_label = label;
+ dialog->priv->power_on_hours_label = label;
gtk_table_attach (GTK_TABLE (table), label, 1, 2, row, row + 1,
GTK_FILL, GTK_FILL, 0, 0);
row++;
- /* attributes */
+ /* ------------------------------ */
+ /* temperature */
+
+ /* Translators: Tooltip for the "Temperature:" item in the status table */
+ tooltip_markup = _("The temperature of the disk");
+
label = gtk_label_new (NULL);
- gtk_misc_set_alignment (GTK_MISC (label), 1.0, 0.5);
- gtk_label_set_markup_with_mnemonic (GTK_LABEL (label), _("<b>Attributes:</b>"));
+ gtk_widget_set_tooltip_markup (label, tooltip_markup);
+ gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
+ /* Translators: Item name in the status table */
+ gtk_label_set_markup (GTK_LABEL (label), _("Temperature:"));
gtk_table_attach (GTK_TABLE (table), label, 0, 1, row, row + 1,
GTK_FILL, GTK_FILL, 0, 0);
label = gtk_label_new (NULL);
+ gtk_widget_set_tooltip_markup (label, tooltip_markup);
gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
- dialog->priv->attributes_label = label;
+ dialog->priv->temperature_label = label;
gtk_table_attach (GTK_TABLE (table), label, 1, 2, row, row + 1,
GTK_FILL, GTK_FILL, 0, 0);
row++;
- /* assessment */
+ /* ------------------------------ */
+ /* bad sectors */
+
+ /* Translators: Tooltip for the "Bad Sectors" item in the status table */
+ tooltip_markup = _("The sum of pending and reallocated bad sectors");
+
label = gtk_label_new (NULL);
- gtk_misc_set_alignment (GTK_MISC (label), 1.0, 0.5);
- gtk_label_set_markup_with_mnemonic (GTK_LABEL (label), _("<b>Assessment:</b>"));
+ gtk_widget_set_tooltip_markup (label, tooltip_markup);
+ gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
+ /* Translators: Item name in the status table */
+ gtk_label_set_markup (GTK_LABEL (label), _("Bad Sectors:"));
gtk_table_attach (GTK_TABLE (table), label, 0, 1, row, row + 1,
GTK_FILL, GTK_FILL, 0, 0);
label = gtk_label_new (NULL);
+ gtk_widget_set_tooltip_markup (label, tooltip_markup);
+ gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
+ dialog->priv->sectors_label = label;
+ gtk_table_attach (GTK_TABLE (table), label, 1, 2, row, row + 1,
+ GTK_FILL, GTK_FILL, 0, 0);
+ row++;
+
+ /* ------------------------------ */
+ /* self assessment */
+
+ /* Translators: Tooltip for the "Self Assessment" item in the status table */
+ tooltip_markup = _("The assessment from the disk itself whether it is about to fail");
+
+ label = gtk_label_new (NULL);
+ gtk_widget_set_tooltip_markup (label, tooltip_markup);
gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
- dialog->priv->assessment_label = label;
+ /* Translators: Item name in the status table */
+ gtk_label_set_markup (GTK_LABEL (label), _("Self Assessment:"));
+ gtk_table_attach (GTK_TABLE (table), label, 0, 1, row, row + 1,
+ GTK_FILL, GTK_FILL, 0, 0);
+ label = gtk_label_new (NULL);
+ gtk_widget_set_tooltip_markup (label, tooltip_markup);
+ gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
+ dialog->priv->self_assessment_label = label;
gtk_table_attach (GTK_TABLE (table), label, 1, 2, row, row + 1,
GTK_FILL, GTK_FILL, 0, 0);
+ row++;
+
+ /* ------------------------------ */
+ /* overall assessment */
+
+ /* Translators: Tooltip for the "Overall Assessment" in the status table */
+ tooltip_markup = _("An overall assessment of the health of the disk");
+
+ label = gtk_label_new (NULL);
+ gtk_widget_set_tooltip_markup (label, tooltip_markup);
+ gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.0);
+ /* Translators: Item name in the status table */
+ gtk_label_set_markup (GTK_LABEL (label), _("Overall Assessment:"));
+ gtk_table_attach (GTK_TABLE (table), label, 0, 1, row, row + 1,
+ GTK_FILL, GTK_FILL, 0, 0);
+
+ hbox = gtk_hbox_new (FALSE, 2);
+ image = gtk_image_new_from_icon_name ("gdu-smart-unknown",
+ GTK_ICON_SIZE_MENU);
+ gtk_widget_set_tooltip_markup (image, tooltip_markup);
+ gtk_box_pack_start (GTK_BOX (hbox), image, FALSE, FALSE, 0);
+ dialog->priv->overall_assessment_image = image;
+
+ label = gtk_label_new (NULL);
+ gtk_widget_set_tooltip_markup (label, tooltip_markup);
+ gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.0);
+ dialog->priv->overall_assessment_label = label;
+ gtk_box_pack_start (GTK_BOX (hbox), label, TRUE, TRUE, 0);
+ gtk_table_attach (GTK_TABLE (table), hbox, 1, 2, row, row + 1,
+ GTK_FILL, GTK_FILL, 0, 0);
row++;
+ /* ------------------------------ */
+
+ /* Translators: Tooltip for the "Do not warn if disk is failing" check button */
+ tooltip_markup = _("Leave unchecked to get notified if the disk starts failing");
+
+ /* Translators: Check button in the status table */
+ check_button = gtk_check_button_new_with_mnemonic (_("Don't _warn me if the disk is failing"));
+ gtk_widget_set_tooltip_markup (check_button, tooltip_markup);
+ gtk_box_pack_start (GTK_BOX (vbox2), check_button, FALSE, FALSE, 0);
+ dialog->priv->no_warn_check_button = check_button;
+ g_signal_connect (check_button,
+ "toggled",
+ G_CALLBACK (on_no_warn_check_button_toggled),
+ dialog);
+
/* ---------------------------------------------------------------------------------------------------- */
/* attributes in a tree view */
- dialog->priv->attr_list_store = gtk_list_store_new (ATTR_N_COLUMNS,
- G_TYPE_STRING,
- G_TYPE_INT,
- G_TYPE_STRING,
- G_TYPE_STRING,
- G_TYPE_STRING,
- G_TYPE_STRING,
- G_TYPE_STRING,
- G_TYPE_STRING,
- GDK_TYPE_PIXBUF,
- G_TYPE_STRING,
- G_TYPE_STRING,
- G_TYPE_STRING,
- G_TYPE_STRING);
+ label = gtk_label_new (NULL);
+ gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
+ /* Translators: Heading used in the main dialog for SMART attributes*/
+ s = g_strconcat ("<b>", _("_Attributes"), "</b>", NULL);
+ gtk_label_set_markup_with_mnemonic (GTK_LABEL (label), s);
+ g_free (s);
+ gtk_box_pack_start (GTK_BOX (vbox), label, FALSE, FALSE, 0);
+
+ align = gtk_alignment_new (0.5, 0.5, 1.0, 1.0);
+ gtk_alignment_set_padding (GTK_ALIGNMENT (align), 0, 0, 12, 0);
+ gtk_box_pack_start (GTK_BOX (vbox), align, TRUE, TRUE, 0);
+
+ dialog->priv->attr_list_store = gtk_list_store_new (N_COLUMNS,
+ G_TYPE_INT, /* id */
+ G_TYPE_STRING, /* name */
+ G_TYPE_STRING, /* value */
+ G_TYPE_STRING, /* tooltip */
+ _GDU_TYPE_SK_ATTR); /* SkSmartAttributeParsedData pointer */
tree_view = gtk_tree_view_new_with_model (GTK_TREE_MODEL (dialog->priv->attr_list_store));
+ gtk_label_set_mnemonic_widget (GTK_LABEL (label), tree_view);
gtk_tree_view_set_rules_hint (GTK_TREE_VIEW (tree_view), TRUE);
- gtk_tree_view_set_tooltip_column (GTK_TREE_VIEW (tree_view), ATTR_TOOLTIP_COLUMN);
+ gtk_tree_view_set_tooltip_column (GTK_TREE_VIEW (tree_view), TOOLTIP_COLUMN);
gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (dialog->priv->attr_list_store),
- ATTR_ID_INT_COLUMN,
+ ID_COLUMN,
GTK_SORT_ASCENDING);
dialog->priv->tree_view = tree_view;
@@ -649,98 +1983,71 @@ gdu_ata_smart_dialog_constructed (GObject *object)
dialog);
column = gtk_tree_view_column_new ();
- gtk_tree_view_column_set_title (column, "ID");
- renderer = gtk_cell_renderer_text_new ();
- gtk_tree_view_column_pack_start (column, renderer, TRUE);
- gtk_tree_view_column_set_attributes (column, renderer,
- "text", ATTR_ID_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, "Attribute");
+ /* Translators: This string is used as the column title in the treeview for the Attribute ID (0-255) */
+ gtk_tree_view_column_set_title (column, _("ID"));
renderer = gtk_cell_renderer_text_new ();
gtk_tree_view_column_pack_start (column, renderer, TRUE);
- gtk_tree_view_column_set_attributes (column, renderer,
- "text", ATTR_DESC_COLUMN,
- NULL);
- gtk_tree_view_append_column (GTK_TREE_VIEW (tree_view), column);
+ gtk_cell_layout_set_cell_data_func (GTK_CELL_LAYOUT (column),
+ renderer,
+ format_markup_id,
+ dialog,
+ NULL);
column = gtk_tree_view_column_new ();
- 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_CURRENT_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, "Worst");
+ /* Translators: This string is used as the column title in the treeview for the attribute name and description */
+ gtk_tree_view_column_set_title (column, _("Attribute"));
+ gtk_tree_view_column_set_expand (column, TRUE);
renderer = gtk_cell_renderer_text_new ();
- g_object_set (renderer, "xalign", 1.0, NULL);
+ g_object_set (renderer,
+ "wrap-width", 300,
+ "wrap-mode", PANGO_WRAP_WORD_CHAR,
+ NULL);
gtk_tree_view_column_pack_start (column, renderer, TRUE);
- gtk_tree_view_column_set_attributes (column, renderer,
- "text", ATTR_WORST_COLUMN,
- NULL);
- gtk_tree_view_append_column (GTK_TREE_VIEW (tree_view), column);
-
+ gtk_cell_layout_set_cell_data_func (GTK_CELL_LAYOUT (column),
+ renderer,
+ format_markup_name,
+ dialog,
+ NULL);
column = gtk_tree_view_column_new ();
- gtk_tree_view_column_set_title (column, "Threshold");
- 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_THRESHOLD_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, "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_VALUE_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, "Status");
+ /* Translators: This string is used as the column title in the treeview for the assessment of the attribute */
+ gtk_tree_view_column_set_title (column, _("Assessment"));
renderer = gtk_cell_renderer_pixbuf_new ();
gtk_tree_view_column_pack_start (column, renderer, FALSE);
- gtk_tree_view_column_set_attributes (column, renderer,
- "pixbuf", ATTR_STATUS_PIXBUF_COLUMN,
- NULL);
+ gtk_cell_layout_set_cell_data_func (GTK_CELL_LAYOUT (column),
+ renderer,
+ pixbuf_assessment,
+ dialog,
+ NULL);
renderer = gtk_cell_renderer_text_new ();
- gtk_tree_view_column_pack_start (column, renderer, TRUE);
- gtk_tree_view_column_set_attributes (column, renderer,
- "markup", ATTR_STATUS_TEXT_COLUMN,
- NULL);
- gtk_tree_view_append_column (GTK_TREE_VIEW (tree_view), column);
+ gtk_tree_view_column_pack_start (column, renderer, FALSE);
+ gtk_cell_layout_set_cell_data_func (GTK_CELL_LAYOUT (column),
+ renderer,
+ format_markup_assessment,
+ dialog,
+ NULL);
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");
+ /* Translators: This string is used as the column title in the treeview for the value of the attribute */
+ 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_UPDATES_COLUMN,
- NULL);
- gtk_tree_view_append_column (GTK_TREE_VIEW (tree_view), column);
-
+ gtk_tree_view_column_pack_start (column, renderer, FALSE);
+ gtk_cell_layout_set_cell_data_func (GTK_CELL_LAYOUT (column),
+ renderer,
+ format_markup_value_headings,
+ dialog,
+ NULL);
+ renderer = gtk_cell_renderer_text_new ();
+ gtk_tree_view_column_pack_start (column, renderer, FALSE);
+ gtk_cell_layout_set_cell_data_func (GTK_CELL_LAYOUT (column),
+ renderer,
+ format_markup_value,
+ dialog,
+ NULL);
scrolled_window = gtk_scrolled_window_new (NULL, NULL);
gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled_window),
@@ -749,39 +2056,17 @@ gdu_ata_smart_dialog_constructed (GObject *object)
GTK_SHADOW_IN);
gtk_container_add (GTK_CONTAINER (scrolled_window), tree_view);
- gtk_box_pack_start (GTK_BOX (vbox), scrolled_window, TRUE, TRUE, 0);
+ gtk_container_add (GTK_CONTAINER (align), scrolled_window);
- gtk_window_set_default_size (GTK_WINDOW (dialog), 500, 500);
+ /* ---------------------------------------------------------------------------------------------------- */
- update_dialog (dialog);
+ gtk_window_set_default_size (GTK_WINDOW (dialog), 700, 600);
- dialog->priv->device_changed_signal_handler_id = g_signal_connect (dialog->priv->device,
- "changed",
- G_CALLBACK (device_changed),
- dialog);
-
- GtkWidget *scale;
- scale = gtk_hscale_new_with_range (2.0,
- 365 * 24.0,
- 1.0);
- gtk_scale_set_digits (GTK_SCALE (scale), 0);
- gtk_scale_set_draw_value (GTK_SCALE (scale), TRUE);
- gtk_box_pack_start (GTK_BOX (vbox), scale, FALSE, FALSE, 0);
- g_signal_connect (scale,
- "value-changed",
- G_CALLBACK (on_period_scale_changed),
- dialog);
+ dialog->priv->has_been_constructed = TRUE;
+ update_dialog (dialog);
- scale = gtk_hscale_new_with_range (0.0,
- 365 * 24.0,
- 1.0);
- gtk_scale_set_digits (GTK_SCALE (scale), 0);
- gtk_scale_set_draw_value (GTK_SCALE (scale), TRUE);
- gtk_box_pack_start (GTK_BOX (vbox), scale, FALSE, FALSE, 0);
- g_signal_connect (scale,
- "value-changed",
- G_CALLBACK (on_end_scale_changed),
- dialog);
+ /* Focus the first attribute view */
+ gtk_widget_grab_focus (dialog->priv->tree_view);
if (G_OBJECT_CLASS (gdu_ata_smart_dialog_parent_class)->constructed != NULL)
G_OBJECT_CLASS (gdu_ata_smart_dialog_parent_class)->constructed (object);
@@ -800,14 +2085,14 @@ gdu_ata_smart_dialog_class_init (GduAtaSmartDialogClass *klass)
object_class->finalize = gdu_ata_smart_dialog_finalize;
g_object_class_install_property (object_class,
- PROP_DEVICE,
- g_param_spec_object ("device",
- _("Device"),
- _("The device to show ATA SMART data for"),
- GDU_TYPE_DEVICE,
+ PROP_DRIVE,
+ g_param_spec_object ("drive",
+ NULL,
+ NULL,
+ GDU_TYPE_DRIVE,
G_PARAM_READABLE |
G_PARAM_WRITABLE |
- G_PARAM_CONSTRUCT_ONLY));
+ G_PARAM_CONSTRUCT));
}
static void
@@ -818,20 +2103,19 @@ gdu_ata_smart_dialog_init (GduAtaSmartDialog *dialog)
GtkWidget *
gdu_ata_smart_dialog_new (GtkWindow *parent,
- GduDevice *device)
+ GduDrive *drive)
{
return GTK_WIDGET (g_object_new (GDU_TYPE_ATA_SMART_DIALOG,
"transient-for", parent,
- "device", device,
+ "drive", drive,
NULL));
}
/* ---------------------------------------------------------------------------------------------------- */
static gchar *
-pretty_to_string (guint64 pretty_value,
- GduAtaSmartAttributeUnit pretty_unit,
- gboolean long_string)
+pretty_to_string (uint64_t pretty_value,
+ SkSmartAttributeUnit pretty_unit)
{
gchar *ret;
gdouble celcius;
@@ -839,63 +2123,62 @@ pretty_to_string (guint64 pretty_value,
switch (pretty_unit) {
- case GDU_ATA_SMART_ATTRIBUTE_UNIT_MSECONDS:
- if (long_string) {
- if (pretty_value > 1000 * 60 * 60 * 24) {
- ret = g_strdup_printf (_("%.3f days"), pretty_value / 1000.0 / 60.0 / 60.0 / 24.0);
- } else if (pretty_value > 1000 * 60 * 60) {
- ret = g_strdup_printf (_("%.3f hours"), pretty_value / 1000.0 / 60.0 / 60.0);
- } else if (pretty_value > 1000 * 60) {
- ret = g_strdup_printf (_("%.3f minutes"), pretty_value / 1000.0 / 60.0);
- } else if (pretty_value > 1000) {
- ret = g_strdup_printf (_("%.3f seconds"), pretty_value / 1000.0);
- } else {
- ret = g_strdup_printf (_("%" G_GUINT64_FORMAT " msec"), pretty_value);
- }
+ case SK_SMART_ATTRIBUTE_UNIT_MSECONDS:
+ if (pretty_value > 1000 * 60 * 60 * 24 * 365.25) {
+ /* Translators: Used in the treeview for the pretty/interpreted value of an attribute
+ * for a time-based unit that exceed one year */
+ ret = g_strdup_printf (_("%.1f years"), pretty_value / 1000.0 / 60.0 / 60.0 / 24.0 / 365.25);
+ } else if (pretty_value > 1000 * 60 * 60 * 24) {
+ /* Translators: Used in the treeview for the pretty/interpreted value of an attribute
+ * for a time-based unit that exceed one day */
+ ret = g_strdup_printf (_("%.1f days"), pretty_value / 1000.0 / 60.0 / 60.0 / 24.0);
+ } else if (pretty_value > 1000 * 60 * 60) {
+ /* Translators: Used in the treeview for the pretty/interpreted value of an attribute
+ * for a time-based unit that exceed one hour */
+ ret = g_strdup_printf (_("%.1f hours"), pretty_value / 1000.0 / 60.0 / 60.0);
+ } else if (pretty_value > 1000 * 60) {
+ /* Translators: Used in the treeview for the pretty/interpreted value of an attribute
+ * for a time-based unit that exceed one minute */
+ ret = g_strdup_printf (_("%.1f minutes"), pretty_value / 1000.0 / 60.0);
+ } else if (pretty_value > 1000) {
+ /* Translators: Used in the treeview for the pretty/interpreted value of an attribute
+ * for a time-based unit that exceed one second */
+ ret = g_strdup_printf (_("%.1f seconds"), pretty_value / 1000.0);
} else {
- if (pretty_value > 1000 * 60 * 60 * 24) {
- ret = g_strdup_printf (_("%.0f d"), pretty_value / 1000.0 / 60.0 / 60.0 / 24.0);
- } else if (pretty_value > 1000 * 60 * 60) {
- ret = g_strdup_printf (_("%.0f h"), pretty_value / 1000.0 / 60.0 / 60.0);
- } else if (pretty_value > 1000 * 60) {
- ret = g_strdup_printf (_("%.0f m"), pretty_value / 1000.0 / 60.0);
- } else if (pretty_value > 1000) {
- ret = g_strdup_printf (_("%.0f s"), pretty_value / 1000.0);
- } else {
- ret = g_strdup_printf (_("%" G_GUINT64_FORMAT " msec"), pretty_value);
- }
+ /* Translators: Used in the treeview for the pretty/interpreted value of an attribute
+ * for a time-based unit that is counted in milliseconds */
+ ret = g_strdup_printf (_("%" G_GUINT64_FORMAT " msec"), pretty_value);
}
break;
- case GDU_ATA_SMART_ATTRIBUTE_UNIT_SECTORS:
- if (long_string) {
- if (pretty_value == 1)
- ret = g_strdup (_("1 Sector"));
- else
- ret = g_strdup_printf (_("%" G_GUINT64_FORMAT " Sectors"), pretty_value);
- } else {
- ret = g_strdup_printf (_("%" G_GUINT64_FORMAT), pretty_value);
- }
+ case SK_SMART_ATTRIBUTE_UNIT_SECTORS:
+ /* Translators: Used in the treeview for the pretty/interpreted value of an attribute
+ * for a sector-based unit */
+ ret = g_strdup_printf (dngettext (GETTEXT_PACKAGE,
+ "%d sector",
+ "%d sectors",
+ (gint) pretty_value),
+ (gint) pretty_value);
break;
- case GDU_ATA_SMART_ATTRIBUTE_UNIT_MKELVIN:
- if (long_string) {
- celcius = pretty_value / 1000.0 - 273.15;
- fahrenheit = 9.0 * celcius / 5.0 + 32.0;
- ret = g_strdup_printf (_("%.3f\302\260 C / %.3f\302\260 F"), celcius, fahrenheit);
- } else {
- /* We could choose kelvin here to treat C and F camps equally. But
- * that would be lame.
- */
- celcius = pretty_value / 1000.0 - 273.15;
- ret = g_strdup_printf (_("%.0f\302\260 C"), celcius);
- }
+ case SK_SMART_ATTRIBUTE_UNIT_MKELVIN:
+ celcius = pretty_value / 1000.0 - 273.15;
+ fahrenheit = 9.0 * celcius / 5.0 + 32.0;
+ /* Translators: Used in the treeview for the pretty/interpreted value of an attribute
+ * for a temperature-based unit - first %f is the temperature in degrees Celcius, second %f
+ * is the temperature in degrees Fahrenheit */
+ ret = g_strdup_printf (_("%.0f° C / %.0f° F"), celcius, fahrenheit);
+ break;
+
+ case SK_SMART_ATTRIBUTE_UNIT_NONE:
+ ret = g_strdup_printf ("%" G_GUINT64_FORMAT, pretty_value);
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);
+ case SK_SMART_ATTRIBUTE_UNIT_UNKNOWN:
+ /* Translators: Used in the treeview for the pretty/interpreted value of an attribute
+ * where the value cannot be interpreted */
+ ret = g_strdup (_("N/A"));
break;
}
@@ -904,318 +2187,606 @@ pretty_to_string (guint64 pretty_value,
/* ---------------------------------------------------------------------------------------------------- */
+static gboolean
+find_row_with_name (GtkListStore *list_store,
+ const gchar *name,
+ GtkTreeIter *out_iter)
+{
+ GtkTreeIter iter;
+ gboolean ret;
+
+ ret = FALSE;
+
+ if (gtk_tree_model_get_iter_first (GTK_TREE_MODEL (list_store), &iter)) {
+ do {
+ gchar *row_name;
+
+ gtk_tree_model_get (GTK_TREE_MODEL (list_store),
+ &iter,
+ NAME_COLUMN, &row_name,
+ -1);
+ if (g_strcmp0 (name, row_name) == 0) {
+ g_free (row_name);
+ ret = TRUE;
+ if (out_iter != NULL)
+ *out_iter = iter;
+ goto out;
+ }
+ g_free (row_name);
+ } while (gtk_tree_model_iter_next (GTK_TREE_MODEL (list_store), &iter));
+ }
+
+ out:
+ return ret;
+}
+
static void
-get_historical_data_cb (GduDevice *device,
- GList *smart_data,
- GError *error,
- gpointer user_data)
+attr_foreach_add_cb (SkDisk *d,
+ const SkSmartAttributeParsedData *a,
+ void *user_data)
{
GduAtaSmartDialog *dialog = GDU_ATA_SMART_DIALOG (user_data);
+ GtkTreeIter iter;
+ gchar *pretty_str;
+ gchar *tooltip_str;
+ const gchar *tip_type_str;
+ const gchar *tip_updates_str;
+
+ if (a->prefailure) {
+ /* Translators: Used in the tooltip for a row in the attribute treeview - please keep
+ * "(Pre-Fail)" in English */
+ tip_type_str = _("Failure is a sign of imminent disk failure (Pre-Fail)");
+ } else {
+ /* Translators: Used in the tooltip for a row in the attribute treeview - please keep
+ * "(Old-Age)" in English */
+ tip_type_str = _("Failure is a sign of old age (Old-Age)");
+ }
- if (error != NULL) {
- g_warning ("Error getting historical data: %s", error->message);
- g_error_free (error);
+ if (a->online) {
+ /* Translators: Used in the tooltip for a row in the attribute treeview - please keep
+ * "(Online)" in English */
+ tip_updates_str = _("Every time data is collected (Online)");
} else {
- if (dialog->priv->historical_data != NULL) {
- g_list_foreach (dialog->priv->historical_data, (GFunc) g_object_unref, NULL);
- g_list_free (dialog->priv->historical_data);
- }
- dialog->priv->historical_data = smart_data;
+ /* Translators: Used in the tooltip for a row in the attribute treeview - please keep
+ * "(Not Online)" in English */
+ tip_updates_str = _("Only during off-line activities (Not Online)");
+ }
- g_debug ("got historical data (%d elems)", g_list_length (smart_data));
+ /* Translators: Used in the tooltip for a row in the attribute treeview.
+ * First %s is the type of the attribute (Pre-Fail or Old-Age).
+ * Second %s is the update type (Online or Not Online).
+ * The six %x is the raw data of the attribute.
+ */
+ tooltip_str = g_strdup_printf (_("Type: %s\n"
+ "Updates: %s\n"
+ "Raw: 0x%02x%02x%02x%02x%02x%02x"),
+ tip_type_str,
+ tip_updates_str,
+ a->raw[0], a->raw[1], a->raw[2], a->raw[3], a->raw[4], a->raw[5]);
+
+ pretty_str = pretty_to_string (a->pretty_value, a->pretty_unit);
+
+ gtk_list_store_append (dialog->priv->attr_list_store, &iter);
+ gtk_list_store_set (dialog->priv->attr_list_store, &iter,
+ ID_COLUMN, a->id,
+ NAME_COLUMN, a->name,
+ VALUE_COLUMN, pretty_str,
+ TOOLTIP_COLUMN, tooltip_str,
+ SK_ATTR_COLUMN, a,
+ -1);
+ g_free (pretty_str);
+ g_free (tooltip_str);
+}
- update_dialog (dialog);
+static gboolean
+is_self_test_running (GduDevice *device,
+ SkSmartSelfTest *out_test_type)
+{
+ gboolean ret;
+
+ ret = FALSE;
+
+ if (!gdu_device_job_in_progress (device))
+ goto out;
+
+ if (g_strcmp0 (gdu_device_job_get_id (device), "DriveAtaSmartSelftestShort") == 0) {
+ ret = TRUE;
+ if (out_test_type != NULL)
+ *out_test_type = SK_SMART_SELF_TEST_SHORT;
+ } else if (g_strcmp0 (gdu_device_job_get_id (device), "DriveAtaSmartSelftestExtended") == 0) {
+ ret = TRUE;
+ if (out_test_type != NULL)
+ *out_test_type = SK_SMART_SELF_TEST_EXTENDED;
+ } else if (g_strcmp0 (gdu_device_job_get_id (device), "DriveAtaSmartSelftestConveyance") == 0) {
+ ret = TRUE;
+ if (out_test_type != NULL)
+ *out_test_type = SK_SMART_SELF_TEST_CONVEYANCE;
+ }
+
+ out:
+ return ret;
+}
+
+/* ---------------------------------------------------------------------------------------------------- */
+
+/* TODO: in the future we probably want to get/set this via the daemon - e.g. so the preference also
+ * takes effect system-wide */
+
+/* TODO: keep in sync with src/notification/notification-main.c */
+static gboolean
+get_ata_smart_no_warn (GduDevice *device)
+{
+ gboolean ret;
+ gchar *path;
+ gchar *disk_id;
+ struct stat stat_buf;
+
+ ret = FALSE;
+
+ disk_id = g_strdup_printf ("%s-%s-%s-%s",
+ gdu_device_drive_get_vendor (device),
+ gdu_device_drive_get_model (device),
+ gdu_device_drive_get_revision (device),
+ gdu_device_drive_get_serial (device));
+
+ path = g_build_filename (g_get_user_config_dir (),
+ "gnome-disk-utility",
+ "ata-smart-ignore",
+ disk_id,
+ NULL);
+
+ if (g_stat (path, &stat_buf) == 0) {
+ ret = TRUE;
}
- g_object_unref (dialog);
+ g_free (path);
+ g_free (disk_id);
+
+ return ret;
}
+static gboolean
+set_ata_smart_no_warn (GduDevice *device,
+ gboolean no_warn)
+{
+ gboolean ret;
+ gchar *path;
+ gchar *dir_path;
+ gchar *disk_id;
+ gint fd;
+
+ disk_id = NULL;
+ dir_path = NULL;
+ path = NULL;
+ ret = FALSE;
+
+ disk_id = g_strdup_printf ("%s-%s-%s-%s",
+ gdu_device_drive_get_vendor (device),
+ gdu_device_drive_get_model (device),
+ gdu_device_drive_get_revision (device),
+ gdu_device_drive_get_serial (device));
+
+ dir_path = g_build_filename (g_get_user_config_dir (),
+ "gnome-disk-utility",
+ "ata-smart-ignore",
+ NULL);
+
+ path = g_build_filename (dir_path,
+ disk_id,
+ NULL);
+
+ if (g_mkdir_with_parents (dir_path, 0755) != 0) {
+ g_warning ("Error creating directory `%s': %s",
+ dir_path,
+ g_strerror (errno));
+ goto out;
+ }
+
+ if (no_warn) {
+ fd = g_creat (path, 0644);
+ if (fd == -1) {
+ g_warning ("Error creating file `%s': %s",
+ path,
+ g_strerror (errno));
+ }
+ close (fd);
+ } else {
+ if (g_unlink (path) != 0) {
+ g_warning ("Error unlinking `%s': %s",
+ path,
+ g_strerror (errno));
+ goto out;
+ }
+ }
+
+ ret = TRUE;
+
+ out:
+ g_free (path);
+ g_free (dir_path);
+ g_free (disk_id);
+
+ return ret;
+}
+
+/* ---------------------------------------------------------------------------------------------------- */
static void
update_dialog (GduAtaSmartDialog *dialog)
{
- gchar *assessment_text;
+ gchar *self_assessment_text;
+ gchar *overall_assessment_text;
gchar *bad_sectors_text;
- gchar *attributes_text;
gchar *powered_on_text;
+ gchar *model_text;
+ gchar *firmware_text;
+ gchar *serial_text;
gchar *temperature_text;
gchar *selftest_text;
- guint64 temperature_mkelvin;
- guint64 power_on_msec;
+ gchar *action_text;
+ gboolean highlight;
GTimeVal updated;
- gboolean is_failing;
- gboolean is_failing_valid;
- gboolean has_bad_sectors;
- gboolean has_bad_attributes;
- GduAtaSmartSelfTestExecutionStatus self_test_status;
- GList *attributes;
- GList *l;
-
- if (!gdu_device_drive_ata_smart_get_is_available (dialog->priv->device)) {
- assessment_text = g_strdup (_("ATA SMART Not Supported"));
- bad_sectors_text = g_strdup ("-");
- attributes_text = g_strdup ("-");
- powered_on_text = g_strdup ("-");
- temperature_text = g_strdup ("-");
- selftest_text = g_strdup ("-");
-
- updated.tv_sec = 0;
-
- attributes = NULL;
-
- //polkit_gnome_action_set_sensitive (dialog->priv->refresh_action, FALSE);
- //polkit_gnome_action_set_sensitive (dialog->priv->details_action, FALSE);
- //polkit_gnome_action_set_sensitive (dialog->priv->selftest_action, FALSE);
- dialog->priv->last_updated = 0;
+ gconstpointer blob;
+ gsize blob_size;
+ GIcon *status_icon;
+ gchar *s;
+ SkBool self_assessment_good;
+ uint64_t num_bad_sectors;
+ uint64_t power_on_msec;
+ uint64_t temperature_mkelvin;
+ SkSmartSelfTest test_type;
+ SkDisk *sk_disk;
+ const SkSmartParsedData *parsed_data;
+ const SkIdentifyParsedData *parsed_identify_data;
+ gboolean no_warn;
+
+ self_assessment_text = NULL;
+ overall_assessment_text = NULL;
+ bad_sectors_text = NULL;
+ model_text = NULL;
+ firmware_text = NULL;
+ serial_text = NULL;
+ powered_on_text = NULL;
+ temperature_text = NULL;
+ selftest_text = NULL;
+ action_text = NULL;
+ updated.tv_sec = 0;
+ dialog->priv->last_updated = 0;
+ status_icon = NULL;
+ sk_disk = NULL;
+
+ /* avoid updating anything if the widgets hasn't been constsructed */
+ if (!dialog->priv->has_been_constructed)
goto out;
- }
- attributes = gdu_device_drive_ata_smart_get_attributes (dialog->priv->device);
+ if (dialog->priv->device == NULL) {
+ /* Translators: Shown in the "Overall Assessment" item in the status table
+ * when no drive is currently selected */
+ overall_assessment_text = g_strdup (_("No drive selected"));
+ goto has_data;
+ }
- is_failing = gdu_device_drive_ata_smart_get_is_failing (dialog->priv->device);
- is_failing_valid = gdu_device_drive_ata_smart_get_is_failing_valid (dialog->priv->device);
+ if (!gdu_device_drive_ata_smart_get_is_available (dialog->priv->device)) {
+ /* Translators: Shown in the "Overall Assessment" item in the status table
+ * when SMART is not available */
+ overall_assessment_text = g_strdup (_("SMART not supported"));
+ goto has_data;
+ }
- self_test_status = gdu_device_drive_ata_smart_get_self_test_execution_status (dialog->priv->device);
+ blob = gdu_device_drive_ata_smart_get_blob (dialog->priv->device, &blob_size);
+ if (blob == NULL) {
+ /* Translators: Shown in the "Overall Assessment" item in the status table
+ * when SMART is supported but data was never collected */
+ overall_assessment_text = g_strdup (_("SMART data never collected"));
+ goto has_data;
+ }
- power_on_msec = 1000 * gdu_device_drive_ata_smart_get_power_on_seconds (dialog->priv->device);
- temperature_mkelvin = (guint64) (gdu_device_drive_ata_smart_get_temperature_kelvin (dialog->priv->device) * 1000.0);
+ if (sk_disk_open (NULL, &sk_disk) != 0) {
+ /* Translators: Shown in the "Overall Assessment" item in the status table
+ * when the SMART data is malformed */
+ overall_assessment_text = g_strdup (_("SMART data is malformed"));
+ goto has_data;
+ }
+ if (sk_disk_set_blob (sk_disk, blob, blob_size) != 0) {
+ /* Translators: Shown in the "Overall Assessment" item in the status table
+ * when the SMART data is malformed */
+ overall_assessment_text = g_strdup (_("SMART data is malformed"));
+ goto has_data;
+ }
- has_bad_sectors = gdu_device_drive_ata_smart_get_has_bad_sectors (dialog->priv->device);
- has_bad_attributes = gdu_device_drive_ata_smart_get_has_bad_attributes (dialog->priv->device);
+ dialog->priv->last_updated = updated.tv_sec = gdu_device_drive_ata_smart_get_time_collected (dialog->priv->device);
+ updated.tv_usec = 0;
- //polkit_gnome_action_set_sensitive (dialog->priv->refresh_action, TRUE);
- //polkit_gnome_action_set_sensitive (dialog->priv->details_action, TRUE);
- //polkit_gnome_action_set_sensitive (dialog->priv->selftest_action, TRUE);
+ s = gdu_util_ata_smart_status_to_desc (gdu_device_drive_ata_smart_get_status (dialog->priv->device),
+ &highlight,
+ &action_text,
+ &status_icon);
+ if (highlight) {
+ gchar *s2;
+ s2 = g_strdup_printf ("<span fgcolor=\"red\"><b>%s</b></span>", s);
+ g_free (s);
+ s = s2;
+ }
+ if (action_text != NULL) {
+ overall_assessment_text = g_strdup_printf ("%s\n"
+ "<small>%s</small>",
+ s,
+ action_text);
+ g_free (action_text);
+ } else {
+ overall_assessment_text = s;
+ s = NULL;
+ }
- if (is_failing_valid) {
- if (!is_failing) {
- assessment_text = g_strdup (_("Passed"));
+ if (sk_disk_smart_status (sk_disk, &self_assessment_good) != 0) {
+ /* Translators: Shown in the "Self-assessment" item in the status table
+ * when the self-assessment of the drive is unknown */
+ self_assessment_text = g_strdup (_("Unknown"));
+ } else {
+ if (self_assessment_good) {
+ /* Translators: Shown in the "Self-assessment" item in the status table
+ * when the self-assessment of the drive is PASSED */
+ self_assessment_text = g_strdup (_("Passed"));
} else {
- assessment_text = g_strdup (_("<span foreground='red'><b>FAILING</b></span>"));
+ self_assessment_text = g_strdup_printf ("<span foreground='red'><b>%s</b></span>",
+ /* Translators: Shown in the "Self-assessment" item in
+ * the status table when the self-assessment of the
+ * drive is FAILING */
+ _("FAILING"));
}
- } else {
- assessment_text = g_strdup (_("Unknown"));
}
- if (has_bad_sectors)
- bad_sectors_text = g_strdup (_("<span foreground='red'><b>BAD SECTORS DETECTED</b></span>"));
- else
- bad_sectors_text = g_strdup (_("No bad sectors detected"));
-
- if (has_bad_attributes)
- attributes_text = g_strdup (_("<span foreground='red'><b>EXCEEDS THRESHOLD</b></span>"));
- else
- attributes_text = g_strdup (_("Within threshold"));
+ if (sk_disk_smart_get_bad (sk_disk, &num_bad_sectors) != 0) {
+ /* Translators: Shown in the "Bad Sectors" item in the status table
+ * when we don't know if the disk has bad sectors */
+ bad_sectors_text = g_strdup (_("Unknown"));
+ } else {
+ if (num_bad_sectors == 0) {
+ /* Translators: Shown in the "Bad Sectors" item in the status table
+ * when we the disk has no bad sectors */
+ bad_sectors_text = g_strdup (_("None"));
+ } else {
+ /* Translators: Shown in the "Bad Sectors" item in the status table
+ * when we the disk has one or more bad sectors */
+ bad_sectors_text = g_strdup_printf (dngettext (GETTEXT_PACKAGE,
+ "%d bad sector",
+ "%d bad sectors",
+ (gint) num_bad_sectors),
+ (gint) num_bad_sectors);
+ }
+ }
- if (power_on_msec == 0) {
+ if (sk_disk_smart_get_power_on (sk_disk, &power_on_msec) != 0) {
+ /* Translators: Shown in the "Powered On" item in the status table when we don't know
+ * the amount of time the disk has been powered on */
powered_on_text = g_strdup (_("Unknown"));
} else {
- powered_on_text = pretty_to_string (power_on_msec, GDU_ATA_SMART_ATTRIBUTE_UNIT_MSECONDS, TRUE);
+ powered_on_text = pretty_to_string (power_on_msec, SK_SMART_ATTRIBUTE_UNIT_MSECONDS);
}
- if (temperature_mkelvin == 0) {
+ if (sk_disk_smart_get_temperature (sk_disk, &temperature_mkelvin) != 0) {
+ /* Translators: Shown in the "Temperature" item in the status table when we don't know
+ * the temperature of the disk
+ */
temperature_text = g_strdup (_("Unknown"));
} else {
- temperature_text = pretty_to_string (temperature_mkelvin, GDU_ATA_SMART_ATTRIBUTE_UNIT_MKELVIN, TRUE);
+ temperature_text = pretty_to_string (temperature_mkelvin, SK_SMART_ATTRIBUTE_UNIT_MKELVIN);
}
- dialog->priv->last_updated = updated.tv_sec = gdu_device_drive_ata_smart_get_time_collected (dialog->priv->device);
- updated.tv_usec = 0;
+ if (sk_disk_identify_parse (sk_disk, &parsed_identify_data) == 0) {
+ model_text = g_strdup (parsed_identify_data->model);
+ firmware_text = g_strdup (parsed_identify_data->firmware);
+ serial_text = g_strdup (parsed_identify_data->serial);
+ }
- switch (self_test_status) {
- case GDU_ATA_SMART_SELF_TEST_EXECUTION_STATUS_SUCCESS_OR_NEVER:
- selftest_text = g_strdup (_("Completed OK"));
- break;
- case GDU_ATA_SMART_SELF_TEST_EXECUTION_STATUS_ABORTED:
- selftest_text = g_strdup (_("Cancelled"));
- break;
- case GDU_ATA_SMART_SELF_TEST_EXECUTION_STATUS_INTERRUPTED:
- selftest_text = g_strdup (_("Cancelled (with hard or soft reset)"));
- break;
- case GDU_ATA_SMART_SELF_TEST_EXECUTION_STATUS_FATAL:
- selftest_text = g_strdup (_("Not completed (a fatal error might have occured)"));
- break;
- case GDU_ATA_SMART_SELF_TEST_EXECUTION_STATUS_ERROR_ELECTRICAL:
- selftest_text = g_strdup (_("<span foreground='red'><b>FAILED</b></span> (Electrical)"));
- break;
- case GDU_ATA_SMART_SELF_TEST_EXECUTION_STATUS_ERROR_SERVO:
- selftest_text = g_strdup (_("<span foreground='red'><b>FAILED</b></span> (Servo)"));
- break;
- case GDU_ATA_SMART_SELF_TEST_EXECUTION_STATUS_ERROR_READ:
- selftest_text = g_strdup (_("<span foreground='red'><b>FAILED</b></span> (Read)"));
- break;
- case GDU_ATA_SMART_SELF_TEST_EXECUTION_STATUS_ERROR_HANDLING:
- selftest_text = g_strdup (_("<span foreground='red'><b>FAILED</b></span> (Suspected of having handled damage"));
- break;
- case GDU_ATA_SMART_SELF_TEST_EXECUTION_STATUS_INPROGRESS:
- selftest_text = g_strdup (_("In progress"));
- break;
+ if (sk_disk_smart_parse (sk_disk, &parsed_data) == 0) {
+ const gchar *self_text;
+ gboolean highlight;
+
+ highlight = FALSE;
+ switch (parsed_data->self_test_execution_status) {
+ case SK_SMART_SELF_TEST_EXECUTION_STATUS_SUCCESS_OR_NEVER:
+ /* Translators: Shown in the "Self-tests" item in the status table */
+ self_text = _("Last self-test completed OK");
+ break;
+ case SK_SMART_SELF_TEST_EXECUTION_STATUS_ABORTED:
+ /* Translators: Shown in the "Self-tests" item in the status table */
+ self_text = _("Last self-test was cancelled");
+ break;
+ case SK_SMART_SELF_TEST_EXECUTION_STATUS_INTERRUPTED:
+ /* Translators: Shown in the "Self-tests" item in the status table */
+ self_text = _("Last self-test was cancelled (with hard or soft reset)");
+ break;
+ case SK_SMART_SELF_TEST_EXECUTION_STATUS_FATAL:
+ /* Translators: Shown in the "Self-tests" item in the status table */
+ self_text = _("Last self-test not completed (a fatal error might have occured)");
+ break;
+ case SK_SMART_SELF_TEST_EXECUTION_STATUS_ERROR_ELECTRICAL:
+ /* Translators: Shown in the "Self-tests" item in the status table */
+ self_text = _("Last self-test FAILED (Electrical)");
+ highlight = TRUE;
+ break;
+ case SK_SMART_SELF_TEST_EXECUTION_STATUS_ERROR_SERVO:
+ /* Translators: Shown in the "Self-tests" item in the status table */
+ self_text = _("Last self-test FAILED (Servo)");
+ highlight = TRUE;
+ break;
+ case SK_SMART_SELF_TEST_EXECUTION_STATUS_ERROR_READ:
+ /* Translators: Shown in the "Self-tests" item in the status table */
+ self_text = _("Last self-test FAILED (Read)");
+ highlight = TRUE;
+ break;
+ case SK_SMART_SELF_TEST_EXECUTION_STATUS_ERROR_HANDLING:
+ /* Translators: Shown in the "Self-tests" item in the status table */
+ self_text = _("Last self-test FAILED (Suspected of having handled damage)");
+ highlight = TRUE;
+ break;
+ case SK_SMART_SELF_TEST_EXECUTION_STATUS_INPROGRESS:
+ /* Translators: Shown in the "Self-tests" item in the status table */
+ self_text = _("Self-test is in progress");
+ highlight = TRUE;
+ break;
+
+ default:
+ case SK_SMART_SELF_TEST_EXECUTION_STATUS_ERROR_UNKNOWN:
+ /* Translators: Shown in the "Self-tests" item in the status table */
+ self_text = _("Unknown");
+ break;
+ }
- default:
- case GDU_ATA_SMART_SELF_TEST_EXECUTION_STATUS_ERROR_UNKNOWN:
- selftest_text = g_strdup (_("Unknown"));
- break;
+ if (highlight)
+ selftest_text = g_strdup_printf ("<span foreground='red'><b>%s</b></span>", self_text);
+ else
+ selftest_text = g_strdup (self_text);
}
- out:
- gtk_label_set_markup (GTK_LABEL (dialog->priv->assessment_label), assessment_text);
- gtk_label_set_markup (GTK_LABEL (dialog->priv->sectors_label), bad_sectors_text);
- gtk_label_set_markup (GTK_LABEL (dialog->priv->attributes_label), attributes_text);
- gtk_label_set_markup (GTK_LABEL (dialog->priv->power_on_hours_label), powered_on_text);
- gtk_label_set_markup (GTK_LABEL (dialog->priv->temperature_label), temperature_text);
+ has_data:
+
+ if (status_icon == NULL)
+ status_icon = g_themed_icon_new ("gdu-smart-unknown");
+ gtk_image_set_from_gicon (GTK_IMAGE (dialog->priv->overall_assessment_image),
+ status_icon,
+ GTK_ICON_SIZE_MENU);
+
+ gtk_label_set_markup (GTK_LABEL (dialog->priv->self_assessment_label), self_assessment_text != NULL ? self_assessment_text : "-");
+ gtk_label_set_markup (GTK_LABEL (dialog->priv->overall_assessment_label), overall_assessment_text != NULL ? overall_assessment_text : "-");
+ gtk_label_set_markup (GTK_LABEL (dialog->priv->sectors_label), bad_sectors_text != NULL ? bad_sectors_text : "-");
+ gtk_label_set_markup (GTK_LABEL (dialog->priv->power_on_hours_label), powered_on_text != NULL ? powered_on_text : "-");
+ gtk_label_set_markup (GTK_LABEL (dialog->priv->temperature_label), temperature_text != NULL ? temperature_text : "-");
+ gtk_label_set_markup (GTK_LABEL (dialog->priv->model_label), model_text != NULL ? model_text : "-");
+ gtk_label_set_markup (GTK_LABEL (dialog->priv->firmware_label), firmware_text != NULL ? firmware_text : "-");
+ gtk_label_set_markup (GTK_LABEL (dialog->priv->serial_label), serial_text != NULL ? serial_text : "-");
if (updated.tv_sec == 0) {
gdu_time_label_set_time (GDU_TIME_LABEL (dialog->priv->updated_label), NULL);
gtk_label_set_markup (GTK_LABEL (dialog->priv->updated_label), "-");
} else {
gdu_time_label_set_time (GDU_TIME_LABEL (dialog->priv->updated_label), &updated);
}
- gtk_label_set_markup (GTK_LABEL (dialog->priv->last_self_test_result_label), selftest_text);
+ gtk_label_set_markup (GTK_LABEL (dialog->priv->self_test_result_label), selftest_text != NULL ? selftest_text : "-");
- gtk_list_store_clear (dialog->priv->attr_list_store);
- for (l = attributes; l != NULL; l = l->next) {
- GduAtaSmartAttribute *a = GDU_ATA_SMART_ATTRIBUTE (l->data);
+ if (sk_disk == NULL) {
+ gtk_list_store_clear (dialog->priv->attr_list_store);
+ } else {
GtkTreeIter iter;
- char *col_str;
- char *name_str;
- char *current_str;
- char *worst_str;
- char *threshold_str;
- char *pretty_str;
- char *status_str;
- GdkPixbuf *status_pixbuf;
- char *tooltip_str;
- int icon_width, icon_height;
- char *desc_str;
- const gchar *type_str;
- const gchar *updates_str;
- const gchar *tip_type_str;
- const gchar *tip_updates_str;
- gboolean is_good;
- gboolean is_good_valid;
- guint64 pretty_value;
- GduAtaSmartAttributeUnit pretty_unit;
-
- col_str = g_strdup_printf ("%d", gdu_ata_smart_attribute_get_id (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_ata_smart_attribute_get_id (a));
+ gchar *name_selected;
+
+ /* keep selected row if it exists after the refresh (disk may have changed) */
+ name_selected = NULL;
+ if (gtk_tree_selection_get_selected (gtk_tree_view_get_selection (GTK_TREE_VIEW (dialog->priv->tree_view)),
+ NULL,
+ &iter)) {
+ gtk_tree_model_get (GTK_TREE_MODEL (dialog->priv->attr_list_store),
+ &iter,
+ NAME_COLUMN, &name_selected,
+ -1);
}
- if (gdu_ata_smart_attribute_get_flags (a) & 0x0001) {
- tip_type_str = _("Failure is a sign of imminent disk failure.");
+ gtk_list_store_clear (dialog->priv->attr_list_store);
+ sk_disk_smart_parse_attributes (sk_disk,
+ attr_foreach_add_cb,
+ dialog);
+
+ if (name_selected != NULL) {
+ if (!find_row_with_name (dialog->priv->attr_list_store, name_selected, &iter))
+ gtk_tree_model_get_iter_first (GTK_TREE_MODEL (dialog->priv->attr_list_store), &iter);
+ g_free (name_selected);
} else {
- tip_type_str = _("Failure is a sign of old age.");
+ gtk_tree_model_get_iter_first (GTK_TREE_MODEL (dialog->priv->attr_list_store), &iter);
}
+ gtk_tree_selection_select_iter (gtk_tree_view_get_selection (GTK_TREE_VIEW (dialog->priv->tree_view)),
+ &iter);
+ }
- if (gdu_ata_smart_attribute_get_flags (a) & 0x0002) {
- tip_updates_str = _("Every time data is collected.");
+ /* update "no warning" check button */
+ no_warn = FALSE;
+ if (dialog->priv->device != NULL)
+ no_warn = get_ata_smart_no_warn (dialog->priv->device);
+ gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (dialog->priv->no_warn_check_button), no_warn);
+
+ /* control visility of update widgets */
+ if (dialog->priv->is_updating) {
+ gtk_widget_hide (dialog->priv->updated_label);
+ gtk_widget_hide (dialog->priv->update_link_label);
+ gtk_widget_show (dialog->priv->updating_spinner);
+ gtk_widget_show (dialog->priv->updating_label);
+ gdu_spinner_start (GDU_SPINNER (dialog->priv->updating_spinner));
+ } else {
+ gtk_widget_hide (dialog->priv->updating_spinner);
+ gdu_spinner_stop (GDU_SPINNER (dialog->priv->updating_spinner));
+ gtk_widget_hide (dialog->priv->updating_label);
+ gtk_widget_show (dialog->priv->updated_label);
+ if (dialog->priv->device == NULL) {
+ gtk_widget_hide (dialog->priv->update_link_label);
} else {
- tip_updates_str = _("Only when performing a self-test.");
+ gtk_widget_show (dialog->priv->update_link_label);
}
+ }
- tooltip_str = g_strdup_printf (_("<b>Type:</b> %s\n"
- "<b>Updates:</b> %s\n"
- "<b>Description</b>: %s"),
- tip_type_str,
- tip_updates_str,
- desc_str);
-
- 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));
-
- if (gdu_ata_smart_attribute_get_flags (a) & 0x0002)
- updates_str = _("Online");
- else
- updates_str = _("Offline");
-
- if (gdu_ata_smart_attribute_get_flags (a) & 0x0001)
- type_str = _("Pre-fail");
+ /* control visibility of self-test widgets */
+ if (dialog->priv->device != NULL && is_self_test_running (dialog->priv->device, &test_type)) {
+ gdouble fraction;
+ const gchar *test_type_str;
+
+ fraction = gdu_device_job_get_percentage (dialog->priv->device) / 100.0;
+ if (fraction < 0.0)
+ fraction = 0.0;
+ if (fraction > 1.0)
+ fraction = 1.0;
+
+ gtk_widget_show (dialog->priv->self_test_result_label);
+ gtk_widget_hide (dialog->priv->self_test_run_link_label);
+ gtk_widget_show (dialog->priv->self_test_progress_bar);
+ if (gdu_device_job_is_cancellable (dialog->priv->device))
+ gtk_widget_show (dialog->priv->self_test_cancel_link_label);
else
- type_str = _("Old-age");
-
- 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, TRUE);
-
- 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 (!is_good_valid) {
- status_pixbuf = gtk_icon_theme_load_icon (gtk_icon_theme_get_default (),
- "gdu-smart-unknown",
- icon_height,
- GTK_ICON_LOOKUP_GENERIC_FALLBACK,
- NULL);
- status_str = g_strdup (_("N/A"));
+ gtk_widget_hide (dialog->priv->self_test_cancel_link_label);
+ gtk_progress_bar_set_fraction (GTK_PROGRESS_BAR (dialog->priv->self_test_progress_bar),
+ fraction);
+
+ switch (test_type) {
+ case SK_SMART_SELF_TEST_SHORT:
+ /* Translators: Shown in the "Self-tests" item in the status table when a test is underway */
+ test_type_str = _("Short self-test in progress: ");
+ break;
+ case SK_SMART_SELF_TEST_EXTENDED:
+ /* Translators: Shown in the "Self-tests" item in the status table when a test is underway */
+ test_type_str = _("Extended self-test in progress: ");
+ break;
+ case SK_SMART_SELF_TEST_CONVEYANCE:
+ /* Translators: Shown in the "Self-tests" item in the status table when a test is underway */
+ test_type_str = _("Conveyance self-test in progress: ");
+ break;
+ default:
+ g_assert_not_reached ();
+ break;
+ }
+ gtk_label_set_markup (GTK_LABEL (dialog->priv->self_test_result_label),
+ test_type_str);
+ } else {
+ gtk_widget_hide (dialog->priv->self_test_progress_bar);
+ gtk_widget_hide (dialog->priv->self_test_cancel_link_label);
+ gtk_widget_show (dialog->priv->self_test_result_label);
+ if (dialog->priv->device == NULL) {
+ gtk_widget_hide (dialog->priv->self_test_run_link_label);
} 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_widget_show (dialog->priv->self_test_run_link_label);
}
-
- gtk_list_store_append (dialog->priv->attr_list_store, &iter);
- gtk_list_store_set (dialog->priv->attr_list_store, &iter,
- ATTR_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_CURRENT_COLUMN, current_str,
- ATTR_WORST_COLUMN, worst_str,
- ATTR_THRESHOLD_COLUMN, threshold_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 (current_str);
- g_free (worst_str);
- g_free (threshold_str);
- g_free (pretty_str);
- g_object_unref (status_pixbuf);
- g_free (status_str);
- g_free (tooltip_str);
- g_free (desc_str);
-
}
- g_free (assessment_text);
+ if (sk_disk != NULL)
+ sk_disk_free (sk_disk);
+
+ out:
+ g_free (overall_assessment_text);
+ g_free (self_assessment_text);
g_free (powered_on_text);
+ g_free (model_text);
+ g_free (firmware_text);
+ g_free (serial_text);
g_free (temperature_text);
g_free (selftest_text);
-
- /* TODO: also fetch new data if current data is out of date */
- if (dialog->priv->historical_data == NULL) {
- gdu_device_drive_ata_smart_get_historical_data (dialog->priv->device,
- 0, /* since */
- 0, /* until */
- 0, /* spacing */
- get_historical_data_cb,
- g_object_ref (dialog));
- }
+ if (status_icon != NULL)
+ g_object_unref (status_icon);
}
static void
@@ -1229,3 +2800,12 @@ device_changed (GduDevice *device,
}
}
+
+static void
+device_job_changed (GduDevice *device,
+ gpointer user_data)
+{
+ GduAtaSmartDialog *dialog = GDU_ATA_SMART_DIALOG (user_data);
+
+ update_dialog (dialog);
+}
diff --git a/src/gdu-gtk/gdu-ata-smart-dialog.h b/src/gdu-gtk/gdu-ata-smart-dialog.h
index d441c9c..a2f9d10 100644
--- a/src/gdu-gtk/gdu-ata-smart-dialog.h
+++ b/src/gdu-gtk/gdu-ata-smart-dialog.h
@@ -55,7 +55,7 @@ struct GduAtaSmartDialogClass
GType gdu_ata_smart_dialog_get_type (void) G_GNUC_CONST;
GtkWidget* gdu_ata_smart_dialog_new (GtkWindow *parent,
- GduDevice *device);
+ GduDrive *drive);
G_END_DECLS
diff --git a/src/gdu-gtk/gdu-gtk-enums.h b/src/gdu-gtk/gdu-gtk-enums.h
index 844a632..938f36c 100644
--- a/src/gdu-gtk/gdu-gtk-enums.h
+++ b/src/gdu-gtk/gdu-gtk-enums.h
@@ -28,30 +28,6 @@
#include <glib-object.h>
-typedef enum {
- GDU_CURVE_FLAGS_NONE = 0,
- GDU_CURVE_FLAGS_FILLED = (1 << 0),
- GDU_CURVE_FLAGS_FADE_EDGES = (1 << 1),
- GDU_CURVE_FLAGS_AXIS_MARKERS_LEFT = (1 << 2),
- GDU_CURVE_FLAGS_AXIS_MARKERS_RIGHT = (1 << 3),
- GDU_CURVE_FLAGS_NORMALIZE = (1 << 4),
-} GduCurveFlags;
-
-/**
- * GduCurveUnit:
- * @GDU_CURVE_UNIT_FLOATING: Value is a floating point number.
- * @GDU_CURVE_UNIT_INTEGER: Value is an integer number, such as a count of some sort.
- * @GDU_CURVE_UNIT_TIME_SECONDS: Value is a measure of time, in seconds.
- * @GDU_CURVE_UNIT_TEMPERATURE_KELVIN: Value is a measure of temperature, in degrees Kelvin.
- *
- */
-typedef enum {
- GDU_CURVE_UNIT_FLOATING = 0,
- GDU_CURVE_UNIT_INTEGER = 1,
- GDU_CURVE_UNIT_TIME_SECONDS = 2,
- GDU_CURVE_UNIT_TEMPERATURE_KELVIN = 3
-} GduCurveUnit;
-
/**
* GduPoolTreeModelColumn:
* @GDU_POOL_TREE_MODEL_COLUMN_ICON: The #GIcon for the presentable.
diff --git a/src/gdu-gtk/gdu-gtk-enumtypes.h b/src/gdu-gtk/gdu-gtk-enumtypes.h
index 5df9d8b..35aa1c6 100644
--- a/src/gdu-gtk/gdu-gtk-enumtypes.h
+++ b/src/gdu-gtk/gdu-gtk-enumtypes.h
@@ -9,10 +9,6 @@
G_BEGIN_DECLS
/* enumerations from "gdu-gtk-enums.h" */
-GType gdu_curve_flags_get_type (void) G_GNUC_CONST;
-#define GDU_TYPE_CURVE_FLAGS (gdu_curve_flags_get_type ())
-GType gdu_curve_unit_get_type (void) G_GNUC_CONST;
-#define GDU_TYPE_CURVE_UNIT (gdu_curve_unit_get_type ())
GType gdu_pool_tree_model_column_get_type (void) G_GNUC_CONST;
#define GDU_TYPE_POOL_TREE_MODEL_COLUMN (gdu_pool_tree_model_column_get_type ())
GType gdu_pool_tree_view_flags_get_type (void) G_GNUC_CONST;
diff --git a/src/gdu-gtk/gdu-gtk-types.h b/src/gdu-gtk/gdu-gtk-types.h
index 34465da..fca5641 100644
--- a/src/gdu-gtk/gdu-gtk-types.h
+++ b/src/gdu-gtk/gdu-gtk-types.h
@@ -39,6 +39,7 @@ typedef struct GduCurve GduCurve;
typedef struct GduGraph GduGraph;
typedef struct GduTimeLabel GduTimeLabel;
typedef struct GduAtaSmartDialog GduAtaSmartDialog;
+typedef struct GduSpinner GduSpinner;
struct GduPoolTreeModel;
typedef struct GduPoolTreeModel GduPoolTreeModel;
diff --git a/src/gdu-gtk/gdu-gtk.h b/src/gdu-gtk/gdu-gtk.h
index 750e496..dccb785 100644
--- a/src/gdu-gtk/gdu-gtk.h
+++ b/src/gdu-gtk/gdu-gtk.h
@@ -34,9 +34,8 @@
#include <gdu-gtk/gdu-pool-tree-model.h>
#include <gdu-gtk/gdu-size-widget.h>
#include <gdu-gtk/gdu-create-linux-md-dialog.h>
-#include <gdu-gtk/gdu-curve.h>
-#include <gdu-gtk/gdu-graph.h>
#include <gdu-gtk/gdu-ata-smart-dialog.h>
+#include <gdu-gtk/gdu-spinner.h>
#undef __GDU_GTK_INSIDE_GDU_GTK_H
G_BEGIN_DECLS
diff --git a/src/gdu-gtk/gdu-pool-tree-view.c b/src/gdu-gtk/gdu-pool-tree-view.c
index 1cab240..05ec317 100644
--- a/src/gdu-gtk/gdu-pool-tree-view.c
+++ b/src/gdu-gtk/gdu-pool-tree-view.c
@@ -226,7 +226,7 @@ pixbuf_data_func (GtkCellLayout *cell_layout,
GtkTreeIter *iter,
gpointer user_data)
{
- GduPoolTreeView *view = GDU_POOL_TREE_VIEW (user_data);
+ //GduPoolTreeView *view = GDU_POOL_TREE_VIEW (user_data);
GduPresentable *p;
GIcon *icon;
diff --git a/src/gdu/Makefile.am b/src/gdu/Makefile.am
index ed890d3..b81700a 100644
--- a/src/gdu/Makefile.am
+++ b/src/gdu/Makefile.am
@@ -32,8 +32,6 @@ libgduinclude_HEADERS = \
gdu-pool.h \
gdu-presentable.h \
gdu-process.h \
- gdu-ata-smart-attribute.h \
- gdu-ata-smart-historical-data.h \
gdu-util.h \
gdu-volume.h \
gdu-volume-hole.h
@@ -44,8 +42,6 @@ libgdu_la_SOURCES = \
gdu-callbacks.h \
gdu-util.h gdu-util.c \
gdu-pool.c gdu-pool.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-callbacks.h b/src/gdu/gdu-callbacks.h
index 8f8057e..31bc81a 100644
--- a/src/gdu/gdu-callbacks.h
+++ b/src/gdu/gdu-callbacks.h
@@ -122,11 +122,6 @@ typedef void (*GduDeviceCancelJobCompletedFunc) (GduDevice *device,
GError *error,
gpointer user_data);
-typedef void (*GduDeviceDriveAtaSmartGetHistoricalDataCompletedFunc) (GduDevice *device,
- GList *smart_data,
- GError *error,
- gpointer user_data);
-
typedef void (*GduDeviceFilesystemListOpenFilesCompletedFunc) (GduDevice *device,
GList *processes,
GError *error,
diff --git a/src/gdu/gdu-device.c b/src/gdu/gdu-device.c
index ab3736d..a38b08b 100644
--- a/src/gdu/gdu-device.c
+++ b/src/gdu/gdu-device.c
@@ -31,7 +31,6 @@
#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 --- */
@@ -130,25 +129,10 @@ typedef struct
guint optical_disc_num_sessions;
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;
+ gchar *drive_ata_smart_status;
+ gchar *drive_ata_smart_blob;
+ gsize drive_ata_smart_blob_size;
char *linux_md_component_level;
int linux_md_component_num_raid_devices;
@@ -340,44 +324,15 @@ collect_props (const char *key, const GValue *value, DeviceProperties *props)
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, "drive-ata-smart-status") == 0)
+ props->drive_ata_smart_status = g_strdup (g_value_get_string (value));
+ else if (strcmp (key, "drive-ata-smart-blob") == 0) {
+ GArray *a = g_value_get_boxed (value);
+ g_free (props->drive_ata_smart_blob);
+ props->drive_ata_smart_blob = g_memdup (a->data, a->len);
+ props->drive_ata_smart_blob_size = a->len;
}
else if (strcmp (key, "linux-md-component-level") == 0)
@@ -470,7 +425,8 @@ device_properties_free (DeviceProperties *props)
g_strfreev (props->drive_media_compatibility);
g_free (props->drive_media);
- g_value_unset (&(props->drive_ata_smart_attributes));
+ g_free (props->drive_ata_smart_status);
+ g_free (props->drive_ata_smart_blob);
g_free (props->linux_md_component_level);
g_free (props->linux_md_component_uuid);
@@ -502,8 +458,6 @@ device_properties_get (DBusGConnection *bus,
const char *ifname = "org.freedesktop.DeviceKit.Disks.Device";
props = g_new0 (DeviceProperties, 1);
- 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",
@@ -1297,149 +1251,26 @@ 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)
+const gchar *
+gdu_device_drive_ata_smart_get_status (GduDevice *device)
{
- return device->priv->props->drive_ata_smart_conveyance_self_test_polling_minutes;
+ return device->priv->props->drive_ata_smart_status;
}
-GList *
-gdu_device_drive_ata_smart_get_attributes (GduDevice *device)
+gconstpointer
+gdu_device_drive_ata_smart_get_blob (GduDevice *device, gsize *out_size)
{
- GList *ret;
- GPtrArray *p;
- guint n;
+ gconstpointer ret;
- 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);
+ ret = device->priv->props->drive_ata_smart_blob;
+ if (out_size != NULL)
+ *out_size = device->priv->props->drive_ata_smart_blob_size;
return ret;
}
@@ -2394,94 +2225,6 @@ gdu_device_op_cancel_job (GduDevice *device, GduDeviceCancelJobCompletedFunc cal
typedef struct {
GduDevice *device;
- GduDeviceDriveAtaSmartGetHistoricalDataCompletedFunc callback;
- gpointer user_data;
-} DriveAtaSmartGetHistoricalDataData;
-
-static GList *
-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_ata_smart_historical_data_new (historical_data->pdata[n]));
- }
- ret = g_list_reverse (ret);
- return ret;
-}
-
-static void
-op_ata_smart_historical_data_cb (DBusGProxy *proxy, GPtrArray *historical_data, GError *error, gpointer user_data)
-{
- DriveAtaSmartGetHistoricalDataData *data = user_data;
- GList *ret;
-
- _gdu_error_fixup (error);
-
- ret = NULL;
- if (historical_data != NULL && error == NULL)
- ret = op_ata_smart_historical_data_compute_ret (historical_data);
-
- if (data->callback != NULL)
- data->callback (data->device, ret, error, data->user_data);
-
- g_object_unref (data->device);
- g_free (data);
-}
-
-void
-gdu_device_drive_ata_smart_get_historical_data (GduDevice *device,
- guint64 since,
- guint64 until,
- guint64 spacing,
- GduDeviceDriveAtaSmartGetHistoricalDataCompletedFunc callback,
- gpointer user_data)
-{
- DriveAtaSmartGetHistoricalDataData *data;
-
- data = g_new0 (DriveAtaSmartGetHistoricalDataData, 1);
- data->device = g_object_ref (device);
- data->callback = callback;
- data->user_data = user_data;
-
- org_freedesktop_DeviceKit_Disks_Device_drive_ata_smart_get_historical_data_async (device->priv->proxy,
- since,
- until,
- spacing,
- op_ata_smart_historical_data_cb,
- data);
-}
-
-GList *
-gdu_device_drive_ata_smart_get_historical_data_sync (GduDevice *device,
- guint64 since,
- guint64 until,
- guint64 spacing,
- GError **error)
-{
- GList *ret;
- GPtrArray *historical_data;
-
- ret = NULL;
- if (!org_freedesktop_DeviceKit_Disks_Device_drive_ata_smart_get_historical_data (device->priv->proxy,
- since,
- until,
- spacing,
- &historical_data,
- error))
- goto out;
-
- ret = op_ata_smart_historical_data_compute_ret (historical_data);
-out:
- return ret;
-}
-
-/* -------------------------------------------------------------------------------- */
-
-typedef struct {
- GduDevice *device;
GduDeviceDriveEjectCompletedFunc callback;
gpointer user_data;
} DriveEjectData;
diff --git a/src/gdu/gdu-device.h b/src/gdu/gdu-device.h
index 0ef276b..8b9fddf 100644
--- a/src/gdu/gdu-device.h
+++ b/src/gdu/gdu-device.h
@@ -171,50 +171,11 @@ 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);
+
+gboolean gdu_device_drive_ata_smart_get_is_available (GduDevice *device);
+guint64 gdu_device_drive_ata_smart_get_time_collected (GduDevice *device);
+const gchar *gdu_device_drive_ata_smart_get_status (GduDevice *device);
+gconstpointer gdu_device_drive_ata_smart_get_blob (GduDevice *device, gsize *out_size);
/* ---------------------------------------------------------------------------------------------------- */
@@ -358,21 +319,6 @@ void gdu_device_op_cancel_job (GduDevice *device,
/* ---------------------------------------------------------------------------------------------------- */
-void gdu_device_drive_ata_smart_get_historical_data (GduDevice *device,
- guint64 since,
- guint64 until,
- guint64 spacing,
- GduDeviceDriveAtaSmartGetHistoricalDataCompletedFunc callback,
- gpointer user_data);
-
-GList *gdu_device_drive_ata_smart_get_historical_data_sync (GduDevice *device,
- guint64 since,
- guint64 until,
- guint64 spacing,
- GError **error);
-
-/* ---------------------------------------------------------------------------------------------------- */
-
void gdu_device_filesystem_list_open_files (GduDevice *device,
GduDeviceFilesystemListOpenFilesCompletedFunc callback,
gpointer user_data);
diff --git a/src/gdu/gdu-private.h b/src/gdu/gdu-private.h
index fe94862..6cb82d5 100644
--- a/src/gdu/gdu-private.h
+++ b/src/gdu/gdu-private.h
@@ -75,10 +75,6 @@
G_TYPE_STRING, \
G_TYPE_INVALID))
-GduAtaSmartAttribute *_gdu_ata_smart_attribute_new (gpointer data);
-
-GduAtaSmartHistoricalData * _gdu_ata_smart_historical_data_new (gpointer data);
-
GduKnownFilesystem *_gdu_known_filesystem_new (gpointer data);
GduProcess * _gdu_process_new (gpointer data);
diff --git a/src/gdu/gdu-types.h b/src/gdu/gdu-types.h
index 8e3c826..de1a929 100644
--- a/src/gdu/gdu-types.h
+++ b/src/gdu/gdu-types.h
@@ -43,8 +43,6 @@ 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-util.c b/src/gdu/gdu-util.c
index 27ccffc..7bf22d5 100644
--- a/src/gdu/gdu-util.c
+++ b/src/gdu/gdu-util.c
@@ -357,8 +357,12 @@ gdu_get_job_description (const char *job_id)
s = g_strdup (_("Checking RAID Array"));
} else if (strcmp (job_id, "LinuxMdRepair") == 0) {
s = g_strdup (_("Repairing RAID Array"));
- } else if (strcmp (job_id, "DriveAtaSmartInitiateSelftest") == 0) {
- s = g_strdup (_("Running S.M.A.R.T. Self Test"));
+ } else if (strcmp (job_id, "DriveAtaSmartSelftestShort") == 0) {
+ s = g_strdup (_("Running Short SMART Self-Test"));
+ } else if (strcmp (job_id, "DriveAtaSmartSelftestExtended") == 0) {
+ s = g_strdup (_("Running Extended SMART Self-Test"));
+ } else if (strcmp (job_id, "DriveAtaSmartSelftestConveyance") == 0) {
+ s = g_strdup (_("Running Conveyance SMART Self-Test"));
} else if (strcmp (job_id, "DriveEject") == 0) {
s = g_strdup (_("Ejecting Media"));
} else if (strcmp (job_id, "DriveDetach") == 0) {
@@ -915,3 +919,86 @@ gdu_linux_md_get_raid_level_description (const gchar *linux_md_raid_level)
/* ---------------------------------------------------------------------------------------------------- */
+/**
+ * gdu_util_ata_smart_status_to_desc:
+ * @status: Status from libatasmart, e.g. <quote>BAD_STATUS</quote>.
+ * @out_highlight: Return value (or %NULL) for suggesting whether the status should be highlighted.
+ * @out_action_text: Return value (or %NULL) for suggested action. Free with g_free().
+ * @out_icon: Return value (or %NULL) for icon to show. Free with g_object_unref().
+ *
+ * Gets a human readable representation of @status.
+ *
+ * Returns: The human readable status. Free with g_free().
+ */
+gchar *
+gdu_util_ata_smart_status_to_desc (const gchar *status,
+ gboolean *out_highlight,
+ gchar **out_action_text,
+ GIcon **out_icon)
+{
+ const gchar *desc;
+ const gchar *action_text;
+ gchar *ret;
+ gboolean highlight;
+ GIcon *icon;
+
+ highlight = FALSE;
+ action_text = NULL;
+ if (g_strcmp0 (status, "GOOD") == 0) {
+ /* Translators: Overall description of the GOOD status */
+ desc = _("Disk is healthy");
+ icon = g_themed_icon_new ("gdu-smart-healthy");
+ } else if (g_strcmp0 (status, "BAD_ATTRIBUTE_IN_THE_PAST") == 0) {
+ /* Translators: Overall description of the BAD_ATTRIBUTE_IN_THE_PAST status */
+ desc = _("Disk was used outside of design parameters in the past");
+ icon = g_themed_icon_new ("gdu-smart-healthy");
+ } else if (g_strcmp0 (status, "BAD_SECTOR") == 0) {
+ /* Translators: Overall description of the BAD_SECTOR status */
+ desc = _("Disk has a few bad sectors");
+ icon = g_themed_icon_new ("gdu-smart-healthy");
+ } else if (g_strcmp0 (status, "BAD_ATTRIBUTE_NOW") == 0) {
+ /* Translators: Overall description of the BAD_ATTRIBUTE_NOW status */
+ desc = _("DISK IS BEING USED OUTSIDE DESIGN PARAMETERS");
+ /* Translators: Suggested action for the BAD_ATTRIBUTE_NOW status */
+ action_text = _("Backup all data and replace the disk");
+ highlight = TRUE;
+ icon = g_themed_icon_new ("gdu-smart-threshold");
+ } else if (g_strcmp0 (status, "BAD_SECTOR_MANY") == 0) {
+ /* Translators: Overall description of the BAD_SECTOR_MANY status */
+ desc = _("DISK HAS MANY BAD SECTORS");
+ highlight = TRUE;
+ /* Translators: Suggested action for the BAD_SECTOR_MANY status */
+ action_text = _("Backup all data and replace the disk");
+ icon = g_themed_icon_new ("gdu-smart-threshold");
+ } else if (g_strcmp0 (status, "BAD_STATUS") == 0) {
+ /* Translators: Overall description of the BAD_STATUS status */
+ desc = _("DISK FAILURE IS IMMINENT");
+ /* Translators: Suggested action for the BAD_STATUS status */
+ action_text = _("Backup all data and replace the disk");
+ highlight = TRUE;
+ icon = g_themed_icon_new ("gdu-smart-failing");
+ } else if (status == NULL || strlen (status) == 0) {
+ /* Translators: Description when the overall SMART status is unknown */
+ desc = _("Unknown");
+ icon = g_themed_icon_new ("gdu-smart-unknown");
+ } else {
+ desc = status;
+ icon = g_themed_icon_new ("gdu-smart-unknown");
+ }
+
+ if (out_highlight != NULL)
+ *out_highlight = highlight;
+
+ if (out_action_text != NULL)
+ *out_action_text = g_strdup (action_text);
+
+ if (out_icon != NULL)
+ *out_icon = g_object_ref (icon);
+ g_object_unref (icon);
+
+ ret = g_strdup (desc);
+
+ return ret;
+}
+
+/* ---------------------------------------------------------------------------------------------------- */
diff --git a/src/gdu/gdu-util.h b/src/gdu/gdu-util.h
index 2c1adb1..4305a98 100644
--- a/src/gdu/gdu-util.h
+++ b/src/gdu/gdu-util.h
@@ -50,6 +50,11 @@ char *gdu_linux_md_get_raid_level_for_display (const gchar *linux_md_raid_level,
char *gdu_linux_md_get_raid_level_description (const gchar *linux_md_raid_level);
+gchar *gdu_util_ata_smart_status_to_desc (const gchar *status,
+ gboolean *out_highlight,
+ gchar **out_action_text,
+ GIcon **out_icon);
+
typedef void (*GduUtilPartTypeForeachFunc) (const char *scheme,
const char *type,
const char *name,
diff --git a/src/gdu/gdu.h b/src/gdu/gdu.h
index 67aa4a2..5588b97 100644
--- a/src/gdu/gdu.h
+++ b/src/gdu/gdu.h
@@ -37,8 +37,6 @@
#include <gdu/gdu-pool.h>
#include <gdu/gdu-presentable.h>
#include <gdu/gdu-process.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/notification/notification-main.c b/src/notification/notification-main.c
index 609f9ff..5f13e38 100644
--- a/src/notification/notification-main.c
+++ b/src/notification/notification-main.c
@@ -24,6 +24,8 @@
#include <gtk/gtk.h>
#include <glib/gi18n.h>
#include <stdlib.h>
+#include <glib/gstdio.h>
+#include <errno.h>
#include <gdu/gdu.h>
#include <gdu-gtk/gdu-gtk.h>
@@ -49,6 +51,8 @@ typedef struct
NotifyNotification *ata_smart_notification;
+ GFileMonitor *ata_smart_ignore_monitor;
+
} NotificationData;
/* ---------------------------------------------------------------------------------------------------- */
@@ -132,10 +136,25 @@ on_status_icon_popup_menu (GtkStatusIcon *status_icon,
show_menu_for_status_icon (data);
}
+static void
+on_ata_smart_ignore_monitor_changed (GFileMonitor *monitor,
+ GFile *file,
+ GFile *other_file,
+ GFileMonitorEvent event_type,
+ gpointer user_data)
+{
+ NotificationData *data = user_data;
+ update_all (data);
+}
+
static NotificationData *
notification_data_new (void)
{
NotificationData *data;
+ GFile *file;
+ gchar *dir_path;
+ GError *error;
+ struct stat stat_buf;
data = g_new0 (NotificationData, 1);
@@ -152,6 +171,37 @@ notification_data_new (void)
g_signal_connect (data->status_icon, "activate", G_CALLBACK (on_status_icon_activate), data);
g_signal_connect (data->status_icon, "popup-menu", G_CALLBACK (on_status_icon_popup_menu), data);
+ dir_path = g_build_filename (g_get_user_config_dir (),
+ "gnome-disk-utility",
+ "ata-smart-ignore",
+ NULL);
+ if (g_stat (dir_path, &stat_buf) != 0) {
+ if (g_mkdir_with_parents (dir_path, 0755) != 0) {
+ g_warning ("Error creating directory `%s': %s",
+ dir_path,
+ g_strerror (errno));
+ }
+ }
+
+ file = g_file_new_for_path (dir_path);
+
+ error = NULL;
+ data->ata_smart_ignore_monitor = g_file_monitor_directory (file,
+ G_FILE_MONITOR_NONE,
+ NULL,
+ &error);
+ if (data->ata_smart_ignore_monitor != NULL) {
+ g_signal_connect (data->ata_smart_ignore_monitor,
+ "changed",
+ G_CALLBACK (on_ata_smart_ignore_monitor_changed),
+ data);
+ } else {
+ g_warning ("Error monitoring directory `%s': %s", dir_path, error->message);
+ g_error_free (error);
+ }
+ g_free (dir_path);
+ g_object_unref (file);
+
return data;
}
@@ -172,6 +222,11 @@ notification_data_free (NotificationData *data)
g_list_free (data->devices_being_unmounted);
g_list_foreach (data->ata_smart_failures, (GFunc) g_object_unref, NULL);
g_list_free (data->ata_smart_failures);
+
+ if (data->ata_smart_ignore_monitor != NULL) {
+ g_object_unref (data->ata_smart_ignore_monitor);
+ }
+
g_free (data);
}
@@ -323,6 +378,39 @@ update_unmount_dialogs (NotificationData *data)
/* ---------------------------------------------------------------------------------------------------- */
+/* TODO: keep in sync with src/gdu-gtk/gdu-ata-smart-dialog.c */
+static gboolean
+get_ata_smart_no_warn (GduDevice *device)
+{
+ gboolean ret;
+ gchar *path;
+ gchar *disk_id;
+ struct stat stat_buf;
+
+ ret = FALSE;
+
+ disk_id = g_strdup_printf ("%s-%s-%s-%s",
+ gdu_device_drive_get_vendor (device),
+ gdu_device_drive_get_model (device),
+ gdu_device_drive_get_revision (device),
+ gdu_device_drive_get_serial (device));
+
+ path = g_build_filename (g_get_user_config_dir (),
+ "gnome-disk-utility",
+ "ata-smart-ignore",
+ disk_id,
+ NULL);
+
+ if (g_stat (path, &stat_buf) == 0) {
+ ret = TRUE;
+ }
+
+ g_free (path);
+ g_free (disk_id);
+
+ return ret;
+}
+
static void
update_ata_smart_failures (NotificationData *data)
{
@@ -338,14 +426,24 @@ update_ata_smart_failures (NotificationData *data)
for (l = devices; l != NULL; l = l->next) {
GduDevice *device = GDU_DEVICE (l->data);
+ gboolean available;
+ const gchar *status;
+ guint64 time_collected;
+
+ available = gdu_device_drive_ata_smart_get_is_available (device);
+ time_collected = gdu_device_drive_ata_smart_get_time_collected (device);
+ status = gdu_device_drive_ata_smart_get_status (device);
- if (!gdu_device_drive_ata_smart_get_is_available (device))
+ if (!available || time_collected == 0)
continue;
- if (!((gdu_device_drive_ata_smart_get_is_failing (device) &&
- gdu_device_drive_ata_smart_get_is_failing_valid (device)) ||
- gdu_device_drive_ata_smart_get_has_bad_sectors (device) ||
- gdu_device_drive_ata_smart_get_has_bad_attributes (device)))
+ /* only warn on these statuses.. */
+ if (!((g_strcmp0 (status, "BAD_SECTOR_MANY") == 0) ||
+ (g_strcmp0 (status, "BAD_ATTRIBUTE_NOW") == 0) ||
+ (g_strcmp0 (status, "BAD_STATUS") == 0)))
+ continue;
+
+ if (get_ata_smart_no_warn (device))
continue;
current = g_list_prepend (current, device);
@@ -432,11 +530,13 @@ update_status_icon (NotificationData *data)
/* we've started showing the icon for ATA RAID failures; pop up a libnotify notification */
if (old_show_icon_for_ata_smart_failures != data->show_icon_for_ata_smart_failures) {
- data->ata_smart_notification = notify_notification_new
- (_("A hard disk is failing"),
- _("One or more hard disks report health problems. Click the icon to get more information."),
- "gtk-dialog-warning",
- NULL);
+ data->ata_smart_notification = notify_notification_new (
+ /* Translators: This is used as the title of the notification */
+ _("A hard disk may be failing"),
+ /* Translators: This is used as the text of the notification*/
+ _("One or more hard disks report health problems. Click the icon to get more information."),
+ "gtk-dialog-warning",
+ NULL);
notify_notification_attach_to_status_icon (data->ata_smart_notification,
data->status_icon);
notify_notification_set_urgency (data->ata_smart_notification, NOTIFY_URGENCY_CRITICAL);
@@ -502,18 +602,42 @@ show_menu_for_status_icon (NotificationData *data)
for (l = data->ata_smart_failures; l != NULL; l = l->next) {
GduDevice *device = GDU_DEVICE (l->data);
GduPresentable *presentable;
- gchar *device_name;
+ gchar *name;
+ gchar *vpd_name;
+ const gchar *status;
+ gchar *status_desc;
+ gboolean highlight;
GdkPixbuf *pixbuf;
GtkWidget *image;
GtkWidget *menu_item;
+ gchar *s;
presentable = gdu_pool_get_drive_by_device (data->pool, device);
- device_name = gdu_presentable_get_name (presentable);
+ name = gdu_presentable_get_name (presentable);
+ vpd_name = gdu_presentable_get_vpd_name (presentable);
+
+ status = gdu_device_drive_ata_smart_get_status (device);
+ status_desc = gdu_util_ata_smart_status_to_desc (status, &highlight, NULL, NULL);
+
+ if (highlight) {
+ s = g_strdup_printf ("<span fgcolor=\"red\"><b>%s</b></span>", status_desc);
+ g_free (status_desc);
+ status_desc = s;
+ }
+
+ s = g_strdup_printf ("<b>%s</b> â?? %s\n"
+ "<small>%s</small>",
+ name,
+ vpd_name,
+ status_desc);
+
+ menu_item = gtk_image_menu_item_new_with_label (s);
+ gtk_label_set_use_markup (GTK_LABEL (gtk_bin_get_child (GTK_BIN (menu_item))), TRUE);
+ gtk_image_menu_item_set_always_show_image (GTK_IMAGE_MENU_ITEM (menu_item), TRUE);
- menu_item = gtk_image_menu_item_new_with_label (device_name);
g_object_set_data_full (G_OBJECT (menu_item), "gdu-device", g_object_ref (device), g_object_unref);
- pixbuf = gdu_util_get_pixbuf_for_presentable (presentable, GTK_ICON_SIZE_MENU);
+ pixbuf = gdu_util_get_pixbuf_for_presentable (presentable, GTK_ICON_SIZE_SMALL_TOOLBAR);
image = gtk_image_new_from_pixbuf (pixbuf);
g_object_unref (pixbuf);
gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (menu_item), image);
@@ -525,7 +649,10 @@ show_menu_for_status_icon (NotificationData *data)
gtk_menu_shell_append (GTK_MENU_SHELL (menu), menu_item);
- g_free (device_name);
+ g_free (name);
+ g_free (vpd_name);
+ g_free (status_desc);
+ g_free (s);
g_object_unref (presentable);
}
gtk_widget_show_all (menu);
diff --git a/src/palimpsest/Makefile.am b/src/palimpsest/Makefile.am
index a59f258..42c8bdc 100644
--- a/src/palimpsest/Makefile.am
+++ b/src/palimpsest/Makefile.am
@@ -9,7 +9,6 @@ palimpsest_SOURCES = \
gdu-main.c \
gdu-shell.h gdu-shell.c \
gdu-section.h gdu-section.c \
- gdu-section-health.h gdu-section-health.c \
gdu-section-create-partition-table.h gdu-section-create-partition-table.c \
gdu-section-partition.h gdu-section-partition.c \
gdu-section-unallocated.h gdu-section-unallocated.c \
diff --git a/src/palimpsest/gdu-shell.c b/src/palimpsest/gdu-shell.c
index a397f70..fcb628f 100644
--- a/src/palimpsest/gdu-shell.c
+++ b/src/palimpsest/gdu-shell.c
@@ -34,7 +34,6 @@
#include "gdu-shell.h"
-#include "gdu-section-health.h"
#include "gdu-section-partition.h"
#include "gdu-section-create-partition-table.h"
#include "gdu-section-unallocated.h"
@@ -273,13 +272,43 @@ details_update (GduShell *shell)
g_ptr_array_add (details,
g_strdup (_("Linux Software RAID")));
} else {
- s = gdu_util_get_connection_for_display (
- gdu_device_drive_get_connection_interface (device),
- gdu_device_drive_get_connection_speed (device));
- g_ptr_array_add (details,
- /* Translators: %s is the name of a connection, like 'USB at 2 MB/s' */
- g_strdup_printf (_("Connected via %s"), s));
- g_free (s);
+ if (gdu_device_drive_ata_smart_get_is_available (device) &&
+ gdu_device_drive_ata_smart_get_time_collected (device) > 0) {
+ gchar *smart_status;
+ gchar *status_desc;
+ gboolean highlight;
+ gboolean rtl;
+
+ rtl = (gtk_widget_get_direction (GTK_WIDGET (shell->priv->app_window)) == GTK_TEXT_DIR_RTL);
+
+ status_desc = gdu_util_ata_smart_status_to_desc (gdu_device_drive_ata_smart_get_status (device),
+ &highlight,
+ NULL,
+ NULL);
+ /* Translators: the %s is the SMART status of the disk e.g. 'Healthy' */
+ if (highlight) {
+ s = g_strdup_printf ("<span fgcolor=\"red\"><b>%s</b></span>", status_desc);
+ g_free (status_desc);
+ status_desc = s;
+ }
+ smart_status = g_strdup_printf (_("SMART status: %s"),
+ status_desc);
+ g_free (status_desc);
+
+ s = g_strdup_printf (rtl ? "<a href=\"gnome-disk-utility://show-smart\" title=\"%2$s\">%3$s</a> â?? %1$s" :
+ "%s â?? <a href=\"gnome-disk-utility://show-smart\" title=\"%s\">%s</a>",
+ smart_status,
+ /* Translators: this the SMART hyperlink tooltip */
+ _("View details about SMART for this disk"),
+ /* Translators: this is the text for the SMART hyperlink */
+ _("More Information"));
+ g_free (smart_status);
+
+ g_ptr_array_add (details, s);
+
+ } else {
+ g_ptr_array_add (details, g_strdup (_("SMART is not available")));
+ }
}
if (device_file != NULL) {
@@ -425,6 +454,7 @@ details_update (GduShell *shell)
s = g_strdup_printf ("<span foreground='%s'>%s</span>", detail_color, detail_str);
gtk_label_set_markup (GTK_LABEL (label), s);
+ gtk_label_set_track_visited_links (GTK_LABEL (label), FALSE);
g_free (s);
}
@@ -484,13 +514,6 @@ compute_sections_to_show (GduShell *shell)
sections_to_show = g_list_append (sections_to_show, (gpointer) GDU_TYPE_SECTION_NO_MEDIA);
- } else {
-
- if (gdu_device_drive_ata_smart_get_is_available (device)) {
- sections_to_show = g_list_append (sections_to_show,
- (gpointer) GDU_TYPE_SECTION_HEALTH);
- }
-
}
} else if (GDU_IS_VOLUME (shell->priv->presentable_now_showing) && device != NULL) {
@@ -2120,6 +2143,33 @@ gdu_shell_raise_error (GduShell *shell,
}
static void
+on_activate_link_for_details_label (GtkLabel *label,
+ const gchar *uri,
+ gpointer user_data)
+{
+ GduShell *shell = GDU_SHELL (user_data);
+
+ if (g_str_has_prefix (uri, "gnome-disk-utility://")) {
+
+ if (g_strcmp0 (uri, "gnome-disk-utility://show-smart") == 0) {
+ if (GDU_IS_DRIVE (shell->priv->presentable_now_showing)) {
+ GtkWidget *dialog;
+
+ dialog = gdu_ata_smart_dialog_new (GTK_WINDOW (shell->priv->app_window),
+ GDU_DRIVE (shell->priv->presentable_now_showing));
+ gtk_widget_show_all (dialog);
+ gtk_dialog_run (GTK_DIALOG (dialog));
+ gtk_widget_destroy (dialog);
+ } else {
+ g_warning ("Trying to show ATA SMART dialog for presentable that is not a drive");
+ }
+ }
+
+ g_signal_stop_emission_by_name (label, "activate-link");
+ }
+}
+
+static void
create_window (GduShell *shell)
{
GtkWidget *vbox;
@@ -2236,21 +2286,37 @@ create_window (GduShell *shell)
label = gtk_label_new (NULL);
gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
gtk_box_pack_start (GTK_BOX (vbox3), label, FALSE, TRUE, 0);
+ g_signal_connect (label,
+ "activate-link",
+ G_CALLBACK (on_activate_link_for_details_label),
+ shell);
shell->priv->details0_label = label;
label = gtk_label_new (NULL);
gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
gtk_box_pack_start (GTK_BOX (vbox3), label, FALSE, TRUE, 0);
+ g_signal_connect (label,
+ "activate-link",
+ G_CALLBACK (on_activate_link_for_details_label),
+ shell);
shell->priv->details1_label = label;
label = gtk_label_new (NULL);
gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
gtk_box_pack_start (GTK_BOX (vbox3), label, FALSE, TRUE, 0);
+ g_signal_connect (label,
+ "activate-link",
+ G_CALLBACK (on_activate_link_for_details_label),
+ shell);
shell->priv->details2_label = label;
label = gtk_label_new (NULL);
gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
gtk_box_pack_start (GTK_BOX (vbox3), label, FALSE, TRUE, 0);
+ g_signal_connect (label,
+ "activate-link",
+ G_CALLBACK (on_activate_link_for_details_label),
+ shell);
shell->priv->details3_label = label;
/* --- */
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]