summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDavid Zeuthen <davidz@redhat.com>2009-04-11 21:18:06 -0400
committerDavid Zeuthen <davidz@redhat.com>2009-04-11 21:18:06 -0400
commitf6c622352767cdd7ffe94b78f58749b9e76ba71a (patch)
treefae12d4bae050b3d4afb942fe24a6c4b9257b212
parentc8bc2e5d25ec5a1a7fb882567e6c6b6dbc343798 (diff)
downloadgnome-disk-utility-f6c622352767cdd7ffe94b78f58749b9e76ba71a.tar.gz
gnome-disk-utility-f6c622352767cdd7ffe94b78f58749b9e76ba71a.tar.xz
gnome-disk-utility-f6c622352767cdd7ffe94b78f58749b9e76ba71a.zip
show an icon in the notification area if one or more disks are failing
Screenshot: http://people.freedesktop.org/~david/gdu-ata-smart-warning.png Bug: http://bugzilla.gnome.org/show_bug.cgi?id=575572
-rw-r--r--src/notification/Makefile.am2
-rw-r--r--src/notification/notification-main.c351
2 files changed, 292 insertions, 61 deletions
diff --git a/src/notification/Makefile.am b/src/notification/Makefile.am
index 4a30c21..0a978a3 100644
--- a/src/notification/Makefile.am
+++ b/src/notification/Makefile.am
@@ -11,7 +11,7 @@ gdu_notification_daemon_SOURCES = \
gdu_notification_daemon_CPPFLAGS = \
-I$(top_srcdir)/src/ \
-I$(top_builddir)/src/ \
- -DG_LOG_DOMAIN=\"Palimpsest\" \
+ -DG_LOG_DOMAIN=\"GduNotification\" \
-DGNOMELOCALEDIR=\""$(datadir)/locale"\" \
$(DISABLE_DEPRECATED) \
-DGDU_API_IS_SUBJECT_TO_CHANGE \
diff --git a/src/notification/notification-main.c b/src/notification/notification-main.c
index a5cb827..e4f19b2 100644
--- a/src/notification/notification-main.c
+++ b/src/notification/notification-main.c
@@ -31,6 +31,145 @@
/* ---------------------------------------------------------------------------------------------------- */
+typedef struct
+{
+ GduPool *pool;
+
+ GtkStatusIcon *status_icon;
+
+ /* List of GduDevice objects currently being unmounted */
+ GList *devices_being_unmounted;
+
+ /* List of GduDevice objects with ATA SMART failures */
+ GList *ata_smart_failures;
+} NotificationData;
+
+/* ---------------------------------------------------------------------------------------------------- */
+
+static void diff_sorted_lists (GList *list1,
+ GList *list2,
+ GCompareFunc compare,
+ GList **added,
+ GList **removed);
+
+static gint ptr_compare (gconstpointer a, gconstpointer b);
+
+static void update_unmount_dialogs (NotificationData *data);
+
+static void update_ata_smart_failures (NotificationData *data);
+
+static void update_status_icon (NotificationData *data);
+
+static void show_menu_for_status_icon (NotificationData *data);
+
+/* ---------------------------------------------------------------------------------------------------- */
+
+static void
+update_all (NotificationData *data)
+{
+ update_unmount_dialogs (data);
+ update_ata_smart_failures (data);
+}
+
+static void
+on_device_added (GduPool *pool,
+ GduDevice *device,
+ gpointer user_data)
+{
+ NotificationData *data = user_data;
+ update_all (data);
+}
+
+static void
+on_device_removed (GduPool *pool,
+ GduDevice *device,
+ gpointer user_data)
+{
+ NotificationData *data = user_data;
+ update_all (data);
+}
+
+static void
+on_device_changed (GduPool *pool,
+ GduDevice *device,
+ gpointer user_data)
+{
+ NotificationData *data = user_data;
+ update_all (data);
+}
+
+static void
+on_device_job_changed (GduPool *pool,
+ GduDevice *device,
+ gpointer user_data)
+{
+ NotificationData *data = user_data;
+ update_all (data);
+}
+
+static void
+on_status_icon_activate (GtkStatusIcon *status_icon,
+ gpointer user_data)
+{
+ NotificationData *data = user_data;
+ show_menu_for_status_icon (data);
+}
+
+static void
+on_status_icon_popup_menu (GtkStatusIcon *status_icon,
+ guint button,
+ guint activate_time,
+ gpointer user_data)
+{
+ NotificationData *data = user_data;
+ show_menu_for_status_icon (data);
+}
+
+static NotificationData *
+notification_data_new (void)
+{
+ NotificationData *data;
+
+ data = g_new0 (NotificationData, 1);
+
+ data->pool = gdu_pool_new ();
+ g_signal_connect (data->pool, "device-added", G_CALLBACK (on_device_added), data);
+ g_signal_connect (data->pool, "device-removed", G_CALLBACK (on_device_removed), data);
+ g_signal_connect (data->pool, "device-changed", G_CALLBACK (on_device_changed), data);
+ g_signal_connect (data->pool, "device-job-changed", G_CALLBACK (on_device_job_changed), data);
+
+ data->status_icon = gtk_status_icon_new ();
+ gtk_status_icon_set_visible (data->status_icon, FALSE);
+ gtk_status_icon_set_from_icon_name (data->status_icon, "gdu-warning");
+ gtk_status_icon_set_tooltip_markup (data->status_icon, _("One or more disks are failing"));
+ 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);
+
+ return data;
+}
+
+static void
+notification_data_free (NotificationData *data)
+{
+ g_signal_handlers_disconnect_by_func (data->status_icon, on_status_icon_activate, data);
+ g_signal_handlers_disconnect_by_func (data->status_icon, on_status_icon_popup_menu, data);
+ g_object_unref (data->status_icon);
+
+ g_signal_handlers_disconnect_by_func (data->pool, on_device_added, data);
+ g_signal_handlers_disconnect_by_func (data->pool, on_device_removed, data);
+ g_signal_handlers_disconnect_by_func (data->pool, on_device_changed, data);
+ g_signal_handlers_disconnect_by_func (data->pool, on_device_job_changed, data);
+ g_object_unref (data->pool);
+
+ g_list_foreach (data->devices_being_unmounted, (GFunc) g_object_unref, NULL);
+ 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);
+ g_free (data);
+}
+
+/* ---------------------------------------------------------------------------------------------------- */
+
static void
diff_sorted_lists (GList *list1,
GList *list2,
@@ -75,17 +214,6 @@ diff_sorted_lists (GList *list1,
}
}
-/* ---------------------------------------------------------------------------------------------------- */
-
-typedef struct
-{
- GduPool *pool;
-
- GList *devices_being_unmounted;
-} NotificationData;
-
-/* ---------------------------------------------------------------------------------------------------- */
-
static gint
ptr_compare (gconstpointer a, gconstpointer b)
{
@@ -97,13 +225,15 @@ ptr_compare (gconstpointer a, gconstpointer b)
return 0;
}
+/* ---------------------------------------------------------------------------------------------------- */
+
static gboolean
show_unmount_dialog (gpointer user_data)
{
GduDevice *device = GDU_DEVICE (user_data);
GtkWidget *dialog;
- g_debug ("show unmount dialog for %s", gdu_device_get_device_file (device));
+ //g_debug ("show unmount dialog for %s", gdu_device_get_device_file (device));
dialog = gdu_slow_unmount_dialog_new (NULL, device);
gtk_widget_show_all (GTK_WIDGET (dialog));
@@ -117,14 +247,14 @@ static void
update_unmount_dialogs (NotificationData *data)
{
GList *devices;
- GList *currently_being_unmounted;
+ GList *current;
GList *l;
GList *added;
GList *removed;
devices = gdu_pool_get_devices (data->pool);
- currently_being_unmounted = NULL;
+ current = NULL;
for (l = devices; l != NULL; l = l->next) {
GduDevice *device = GDU_DEVICE (l->data);
@@ -138,15 +268,15 @@ update_unmount_dialogs (NotificationData *data)
gdu_device_job_get_initiated_by_uid (device) == getuid ()))
continue;
- currently_being_unmounted = g_list_prepend (currently_being_unmounted, device);
+ current = g_list_prepend (current, device);
}
- currently_being_unmounted = g_list_sort (currently_being_unmounted, ptr_compare);
+ current = g_list_sort (current, ptr_compare);
data->devices_being_unmounted = g_list_sort (data->devices_being_unmounted, ptr_compare);
added = removed = NULL;
diff_sorted_lists (data->devices_being_unmounted,
- currently_being_unmounted,
+ current,
ptr_compare,
&added,
&removed);
@@ -187,65 +317,165 @@ update_unmount_dialogs (NotificationData *data)
/* ---------------------------------------------------------------------------------------------------- */
static void
-on_device_added (GduPool *pool,
- GduDevice *device,
- gpointer user_data)
+update_ata_smart_failures (NotificationData *data)
{
- NotificationData *data = user_data;
- update_unmount_dialogs (data);
-}
+ GList *devices;
+ GList *current;
+ GList *l;
+ GList *added;
+ GList *removed;
-static void
-on_device_removed (GduPool *pool,
- GduDevice *device,
- gpointer user_data)
-{
- NotificationData *data = user_data;
- update_unmount_dialogs (data);
+ devices = gdu_pool_get_devices (data->pool);
+
+ current = NULL;
+
+ for (l = devices; l != NULL; l = l->next) {
+ GduDevice *device = GDU_DEVICE (l->data);
+
+ if (!gdu_device_drive_ata_smart_get_is_available (device))
+ 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)))
+ continue;
+
+ current = g_list_prepend (current, device);
+ }
+
+ current = g_list_sort (current, ptr_compare);
+ data->ata_smart_failures = g_list_sort (data->ata_smart_failures, ptr_compare);
+
+ added = removed = NULL;
+ diff_sorted_lists (data->ata_smart_failures,
+ current,
+ ptr_compare,
+ &added,
+ &removed);
+
+ for (l = removed; l != NULL; l = l->next) {
+ GduDevice *device = GDU_DEVICE (l->data);
+
+ //g_debug ("%s is no longer failing", gdu_device_get_device_file (device));
+
+ data->ata_smart_failures = g_list_remove (data->ata_smart_failures, device);
+ g_object_unref (device);
+ }
+
+ for (l = added; l != NULL; l = l->next) {
+ GduDevice *device = GDU_DEVICE (l->data);
+ data->ata_smart_failures = g_list_prepend (data->ata_smart_failures, g_object_ref (device));
+
+ //g_debug ("%s is now failing", gdu_device_get_device_file (device));
+ }
+
+ g_list_foreach (devices, (GFunc) g_object_unref, NULL);
+ g_list_free (devices);
+
+ update_status_icon (data);
}
+/* ---------------------------------------------------------------------------------------------------- */
+
static void
-on_device_changed (GduPool *pool,
- GduDevice *device,
- gpointer user_data)
+update_status_icon (NotificationData *data)
{
- NotificationData *data = user_data;
- update_unmount_dialogs (data);
+ gboolean show_icon;
+
+ show_icon = FALSE;
+ if (g_list_length (data->ata_smart_failures) > 0)
+ show_icon = TRUE;
+
+ if (!show_icon) {
+ gtk_status_icon_set_visible (data->status_icon, FALSE);
+ goto out;
+ }
+
+ gtk_status_icon_set_visible (data->status_icon, TRUE);
+ out:
+ ;
}
+/* ---------------------------------------------------------------------------------------------------- */
+
static void
-on_device_job_changed (GduPool *pool,
- GduDevice *device,
- gpointer user_data)
+on_menu_item_activated (GtkMenuItem *menu_item,
+ gpointer user_data)
{
NotificationData *data = user_data;
- update_unmount_dialogs (data);
-}
+ GduDevice *device;
+ GdkScreen *screen;
+ gchar *command_line;
-static NotificationData *
-notification_data_new (void)
-{
- NotificationData *data;
- data = g_new0 (NotificationData, 1);
- data->pool = gdu_pool_new ();
- g_signal_connect (data->pool, "device-added", G_CALLBACK (on_device_added), data);
- g_signal_connect (data->pool, "device-removed", G_CALLBACK (on_device_removed), data);
- g_signal_connect (data->pool, "device-changed", G_CALLBACK (on_device_changed), data);
- g_signal_connect (data->pool, "device-job-changed", G_CALLBACK (on_device_job_changed), data);
- return data;
+ device = GDU_DEVICE (g_object_get_data (G_OBJECT (menu_item), "gdu-device"));
+
+ screen = gtk_status_icon_get_screen (data->status_icon);
+ command_line = g_strdup_printf ("palimpsest --show-drive=%s", gdu_device_get_device_file (device));
+ gdk_spawn_command_line_on_screen (screen, command_line, NULL);
+ g_free (command_line);
}
static void
-notification_data_free (NotificationData *data)
+show_menu_for_status_icon (NotificationData *data)
{
- g_signal_handlers_disconnect_by_func (data->pool, on_device_added, data);
- g_signal_handlers_disconnect_by_func (data->pool, on_device_removed, data);
- g_signal_handlers_disconnect_by_func (data->pool, on_device_changed, data);
- g_signal_handlers_disconnect_by_func (data->pool, on_device_job_changed, data);
- g_object_unref (data->pool);
- g_list_foreach (data->devices_being_unmounted, (GFunc) g_object_unref, NULL);
- g_list_free (data->devices_being_unmounted);
- g_free (data);
+ GtkWidget *menu;
+ GList *l;
+
+ /* TODO: it would be nice to display something like
+ *
+ * Select a disk to get more information...
+ * -----------------------------------------------
+ * [Icon] 80 GB ATA INTEL SSDSA2MH08
+ * [Icon] 250GB WD 2500JB External
+ *
+ * but unfortunately that would require fucking with gtk+'s
+ * internals the same way the display-settings applet does
+ * it; see e.g. line 951 of
+ *
+ * http://svn.gnome.org/viewvc/gnome-settings-daemon/trunk/plugins/xrandr/gsd-xrandr-manager.c?revision=810&view=markup
+ */
+
+ menu = gtk_menu_new ();
+ for (l = data->ata_smart_failures; l != NULL; l = l->next) {
+ GduDevice *device = GDU_DEVICE (l->data);
+ GduPresentable *presentable;
+ gchar *device_name;
+ GdkPixbuf *pixbuf;
+ GtkWidget *image;
+ GtkWidget *menu_item;
+
+ presentable = gdu_pool_get_drive_by_device (data->pool, device);
+ device_name = gdu_presentable_get_name (presentable);
+
+ 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);
+ image = gtk_image_new_from_pixbuf (pixbuf);
+ g_object_unref (pixbuf);
+ gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (menu_item), image);
+
+ g_signal_connect (menu_item,
+ "activate",
+ G_CALLBACK (on_menu_item_activated),
+ data);
+
+ gtk_menu_shell_append (GTK_MENU_SHELL (menu), menu_item);
+
+ g_free (device_name);
+ g_object_unref (presentable);
+ }
+ gtk_widget_show_all (menu);
+
+ gtk_menu_popup (GTK_MENU (menu),
+ NULL,
+ NULL,
+ gtk_status_icon_position_menu,
+ data->status_icon,
+ 0,
+ gtk_get_current_event_time ());
+
}
/* ---------------------------------------------------------------------------------------------------- */
@@ -264,6 +494,7 @@ main (int argc, char **argv)
gtk_window_set_default_icon_name ("palimpsest");
data = notification_data_new ();
+ update_all (data);
gtk_main ();