From fb31765cbe33890f325a87015507364156741321 Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Sun, 7 Apr 2024 19:59:44 +0200 Subject: Adding upstream version 42.0. Signed-off-by: Daniel Baumann --- src/disks.cpp | 491 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 491 insertions(+) create mode 100644 src/disks.cpp (limited to 'src/disks.cpp') diff --git a/src/disks.cpp b/src/disks.cpp new file mode 100644 index 0000000..fe79fae --- /dev/null +++ b/src/disks.cpp @@ -0,0 +1,491 @@ +/* -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +#include + +#include +#include +#include +#include + +#include "disks.h" +#include "application.h" +#include "util.h" +#include "settings-keys.h" +#include "legacy/treeview.h" + +enum DiskColumns +{ + /* string columns* */ + DISK_DEVICE, + DISK_DIR, + DISK_TYPE, + DISK_TOTAL, + DISK_FREE, + DISK_AVAIL, + /* USED has to be the last column */ + DISK_USED, + // then invisible columns + /* PixBuf column */ + DISK_ICON, + /* numeric columns */ + DISK_USED_PERCENTAGE, + DISK_N_COLUMNS +}; + +static void +cb_sort_changed (GtkTreeSortable *model, gpointer data) +{ + GsmApplication *app = (GsmApplication *) data; + + gsm_tree_view_save_state (GSM_TREE_VIEW (app->disk_list)); +} + +static void +fsusage_stats(const glibtop_fsusage *buf, + guint64 *bused, guint64 *bfree, guint64 *bavail, guint64 *btotal, + gint *percentage) +{ + guint64 total = buf->blocks * buf->block_size; + + if (!total) { + /* not a real device */ + *btotal = *bfree = *bavail = *bused = 0ULL; + *percentage = 0; + } else { + int percent; + *btotal = total; + *bfree = buf->bfree * buf->block_size; + *bavail = buf->bavail * buf->block_size; + *bused = *btotal - *bfree; + /* percent = 100.0f * *bused / *btotal; */ + percent = 100 * *bused / (*bused + *bavail); + *percentage = CLAMP(percent, 0, 100); + } +} + +static const char* get_icon_for_path(const char* path) +{ + GVolumeMonitor *monitor; + GList *mounts; + uint i; + GMount *mount; + GIcon *icon; + const char* name = ""; + + monitor = g_volume_monitor_get (); + mounts = g_volume_monitor_get_mounts (monitor); + + for (i = 0; i < g_list_length (mounts); i++) { + mount = G_MOUNT (g_list_nth_data(mounts, i)); + if (strcmp(g_mount_get_name(mount), path)) + continue; + + icon = g_mount_get_icon (mount); + + if (!icon) + continue; + name = g_icon_to_string (icon); + g_object_unref (icon); + } + + g_list_free_full (mounts, g_object_unref); + return name; + +} + +static GdkPixbuf* +get_icon_for_device(const char *mountpoint) +{ + const char* icon_name = get_icon_for_path(mountpoint); + if (!strcmp(icon_name, "")) + // FIXME: defaults to a safe value + icon_name = "drive-harddisk"; // get_icon_for_path("/"); + return gtk_icon_theme_load_icon (gtk_icon_theme_get_default (), icon_name, 24, GTK_ICON_LOOKUP_USE_BUILTIN, NULL); +} + + +static gboolean +find_disk_in_model(GtkTreeModel *model, const char *mountpoint, + GtkTreeIter *result) +{ + GtkTreeIter iter; + gboolean found = FALSE; + + if (gtk_tree_model_get_iter_first(model, &iter)) { + do { + char *dir; + + gtk_tree_model_get(model, &iter, + DISK_DIR, &dir, + -1); + + if (dir && !strcmp(dir, mountpoint)) { + *result = iter; + found = TRUE; + } + + g_free(dir); + + } while (!found && gtk_tree_model_iter_next(model, &iter)); + } + + return found; +} + + + +static void +remove_old_disks(GtkTreeModel *model, const glibtop_mountentry *entries, guint n) +{ + GtkTreeIter iter; + + if (!gtk_tree_model_get_iter_first(model, &iter)) + return; + + while (true) { + char *dir; + guint i; + gboolean found = FALSE; + + gtk_tree_model_get(model, &iter, + DISK_DIR, &dir, + -1); + + for (i = 0; i != n; ++i) { + if (!strcmp(dir, entries[i].mountdir)) { + found = TRUE; + break; + } + } + + g_free(dir); + + if (!found) { + if (!gtk_list_store_remove(GTK_LIST_STORE(model), &iter)) + break; + else + continue; + } + + if (!gtk_tree_model_iter_next(model, &iter)) + break; + } +} + + + +static void +add_disk(GtkListStore *list, const glibtop_mountentry *entry, bool show_all_fs) +{ + GdkPixbuf* pixbuf; + GtkTreeIter iter; + glibtop_fsusage usage; + guint64 bused, bfree, bavail, btotal; + gint percentage; + + glibtop_get_fsusage(&usage, entry->mountdir); + + if (not show_all_fs and usage.blocks == 0) { + if (find_disk_in_model(GTK_TREE_MODEL(list), entry->mountdir, &iter)) + gtk_list_store_remove(list, &iter); + return; + } + + fsusage_stats(&usage, &bused, &bfree, &bavail, &btotal, &percentage); + pixbuf = get_icon_for_device(entry->mountdir); + + /* if we can find a row with the same mountpoint, we get it but we + still need to update all the fields. + This makes selection persistent. + */ + if (!find_disk_in_model(GTK_TREE_MODEL(list), entry->mountdir, &iter)) + gtk_list_store_append(list, &iter); + + gtk_list_store_set(list, &iter, + DISK_ICON, pixbuf, + DISK_DEVICE, entry->devname, + DISK_DIR, entry->mountdir, + DISK_TYPE, entry->type, + DISK_USED_PERCENTAGE, percentage, + DISK_TOTAL, btotal, + DISK_FREE, bfree, + DISK_AVAIL, bavail, + DISK_USED, bused, + -1); +} + +static void +mount_changed (GVolumeMonitor *monitor, GMount *mount, GsmApplication *app) +{ + disks_update(app); +} + +static gboolean +cb_timeout (gpointer data) +{ + GsmApplication *app = (GsmApplication *) data; + disks_update (app); + + return G_SOURCE_CONTINUE; +} + +void +disks_update(GsmApplication *app) +{ + GtkListStore *list; + glibtop_mountentry * entries; + glibtop_mountlist mountlist; + guint i; + gboolean show_all_fs; + + list = GTK_LIST_STORE(gtk_tree_view_get_model(GTK_TREE_VIEW(app->disk_list))); + show_all_fs = app->settings->get_boolean (GSM_SETTING_SHOW_ALL_FS); + entries = glibtop_get_mountlist (&mountlist, show_all_fs); + + remove_old_disks(GTK_TREE_MODEL(list), entries, mountlist.number); + + for (i = 0; i < mountlist.number; i++) + add_disk(list, &entries[i], show_all_fs); + + g_free(entries); +} + +static void +init_volume_monitor (GsmApplication *app) +{ + GVolumeMonitor *monitor = g_volume_monitor_get (); + + g_signal_connect (monitor, "mount-added", G_CALLBACK (mount_changed), app); + g_signal_connect (monitor, "mount-changed", G_CALLBACK (mount_changed), app); + g_signal_connect (monitor, "mount-removed", G_CALLBACK (mount_changed), app); +} + +void +disks_freeze (GsmApplication *app) +{ + if (app->disk_timeout) { + g_source_remove (app->disk_timeout); + app->disk_timeout = 0; + } +} + +void +disks_thaw (GsmApplication *app) +{ + if (app->disk_timeout) + return; + + app->disk_timeout = g_timeout_add (app->config.disks_update_interval, + cb_timeout, + app); +} + +void +disks_reset_timeout (GsmApplication *app) +{ + disks_freeze (app); + disks_thaw (app); +} + +static void +cb_disk_columns_changed(GtkTreeView *treeview, gpointer data) +{ + gsm_tree_view_save_state (GSM_TREE_VIEW (treeview)); +} + + +static void open_dir(GtkTreeView *tree_view, + GtkTreePath *path, + GtkTreeViewColumn *column, + gpointer user_data) +{ + GtkTreeIter iter; + GtkTreeModel *model; + char *dir, *url; + + model = gtk_tree_view_get_model(tree_view); + + if (!gtk_tree_model_get_iter(model, &iter, path)) { + char *p; + p = gtk_tree_path_to_string(path); + g_warning("Cannot get iter for path '%s'\n", p); + g_free(p); + return; + } + + gtk_tree_model_get(model, &iter, DISK_DIR, &dir, -1); + + url = g_strdup_printf("file://%s", dir); + + GError* error = 0; + if (!g_app_info_launch_default_for_uri(url, NULL, &error)) { + g_warning("Cannot open '%s' : %s\n", url, error->message); + g_error_free(error); + } + + g_free(url); + g_free(dir); +} + +static void +cb_disk_list_destroying (GtkWidget *self, gpointer data) +{ + g_signal_handlers_disconnect_by_func(self, (gpointer) cb_disk_columns_changed, data); + + g_signal_handlers_disconnect_by_func (gtk_tree_view_get_model (GTK_TREE_VIEW(self)), + (gpointer) cb_sort_changed, + data); +} + + +void +create_disk_view(GsmApplication *app, GtkBuilder *builder) +{ + GtkScrolledWindow *scrolled; + GsmTreeView *disk_tree; + GtkListStore *model; + GtkTreeViewColumn *col; + GtkCellRenderer *cell; + PangoAttrList *attrs = NULL; + guint i; + + init_volume_monitor (app); + const gchar * const titles[] = { + N_("Device"), + N_("Directory"), + N_("Type"), + N_("Total"), + N_("Free"), + N_("Available"), + N_("Used") + }; + + scrolled = GTK_SCROLLED_WINDOW (gtk_builder_get_object (builder, "disks_scrolled")); + + model = gtk_list_store_new(DISK_N_COLUMNS, /* n columns */ + G_TYPE_STRING, /* DISK_DEVICE */ + G_TYPE_STRING, /* DISK_DIR */ + G_TYPE_STRING, /* DISK_TYPE */ + G_TYPE_UINT64, /* DISK_TOTAL */ + G_TYPE_UINT64, /* DISK_FREE */ + G_TYPE_UINT64, /* DISK_AVAIL */ + G_TYPE_UINT64, /* DISK_USED */ + GDK_TYPE_PIXBUF, /* DISK_ICON */ + G_TYPE_INT /* DISK_USED_PERCENTAGE */ + ); + disk_tree = gsm_tree_view_new (g_settings_get_child (app->settings->gobj(), GSM_SETTINGS_CHILD_DISKS), TRUE); + gtk_tree_view_set_model (GTK_TREE_VIEW (disk_tree), GTK_TREE_MODEL (model)); + + g_signal_connect(G_OBJECT(disk_tree), "row-activated", G_CALLBACK(open_dir), NULL); + app->disk_list = disk_tree; + gtk_container_add(GTK_CONTAINER(scrolled), GTK_WIDGET (disk_tree)); + g_object_unref(G_OBJECT(model)); + + /* icon + device */ + + col = gtk_tree_view_column_new(); + cell = gtk_cell_renderer_pixbuf_new(); + + gtk_tree_view_column_pack_start(col, cell, FALSE); + gtk_tree_view_column_set_min_width(col, 30); + gtk_tree_view_column_set_attributes(col, cell, "pixbuf", DISK_ICON, + NULL); + + cell = gtk_cell_renderer_text_new(); + gtk_tree_view_column_pack_start(col, cell, FALSE); + gtk_tree_view_column_set_attributes(col, cell, "text", DISK_DEVICE, + NULL); + gtk_tree_view_column_set_title(col, _(titles[DISK_DEVICE])); + gtk_tree_view_column_set_sort_column_id(col, DISK_DEVICE); + gtk_tree_view_column_set_reorderable(col, TRUE); + gtk_tree_view_column_set_resizable(col, TRUE); + gtk_tree_view_column_set_sizing(col, GTK_TREE_VIEW_COLUMN_FIXED); + gsm_tree_view_append_and_bind_column (GSM_TREE_VIEW (disk_tree), col); + + + /* sizes - used */ + + for (i = DISK_DIR; i <= DISK_AVAIL; i++) { + cell = gtk_cell_renderer_text_new(); + col = gtk_tree_view_column_new(); + gtk_tree_view_column_pack_start(col, cell, TRUE); + gtk_tree_view_column_set_title(col, _(titles[i])); + gtk_tree_view_column_set_resizable(col, TRUE); + gtk_tree_view_column_set_sort_column_id(col, i); + gtk_tree_view_column_set_reorderable(col, TRUE); + gtk_tree_view_column_set_min_width(col, i == DISK_TYPE ? 40 : 72); + gtk_tree_view_column_set_sizing(col, GTK_TREE_VIEW_COLUMN_FIXED); + gsm_tree_view_append_and_bind_column (GSM_TREE_VIEW (disk_tree), col); + switch (i) { + case DISK_TOTAL: + case DISK_FREE: + case DISK_AVAIL: + gtk_tree_view_column_set_cell_data_func(col, cell, + &procman::size_si_cell_data_func, + GUINT_TO_POINTER(i), + NULL); + + attrs = make_tnum_attr_list (); + g_object_set (cell, + "attributes", attrs, + "xalign", 1.0f, + NULL); + g_clear_pointer (&attrs, pango_attr_list_unref); + + break; + + default: + gtk_tree_view_column_set_attributes(col, cell, + "text", i, + NULL); + break; + } + } + + /* used + percentage */ + + col = gtk_tree_view_column_new(); + cell = gtk_cell_renderer_text_new(); + + attrs = make_tnum_attr_list (); + g_object_set (cell, + "attributes", attrs, + "xalign", 1.0f, + NULL); + g_clear_pointer (&attrs, pango_attr_list_unref); + + gtk_tree_view_column_set_min_width(col, 72); + gtk_tree_view_column_set_sizing(col, GTK_TREE_VIEW_COLUMN_FIXED); + gtk_tree_view_column_pack_start(col, cell, FALSE); + gtk_tree_view_column_set_cell_data_func(col, cell, + &procman::size_si_cell_data_func, + GUINT_TO_POINTER(DISK_USED), + NULL); + gtk_tree_view_column_set_title(col, _(titles[DISK_USED])); + + cell = gtk_cell_renderer_progress_new(); + gtk_cell_renderer_set_padding(cell, 4.0f, 4.0f); + gtk_tree_view_column_pack_start(col, cell, TRUE); + gtk_tree_view_column_set_attributes(col, cell, "value", + DISK_USED_PERCENTAGE, NULL); + gtk_tree_view_column_set_resizable(col, TRUE); + gtk_tree_view_column_set_sort_column_id(col, DISK_USED); + gtk_tree_view_column_set_reorderable(col, TRUE); + gsm_tree_view_append_and_bind_column (GSM_TREE_VIEW (disk_tree), col); + + /* numeric sort */ + + gsm_tree_view_load_state (GSM_TREE_VIEW (disk_tree)); + g_signal_connect (G_OBJECT(disk_tree), "destroy", + G_CALLBACK(cb_disk_list_destroying), + app); + + g_signal_connect (G_OBJECT(disk_tree), "columns-changed", + G_CALLBACK(cb_disk_columns_changed), app); + + g_signal_connect (G_OBJECT (model), "sort-column-changed", + G_CALLBACK (cb_sort_changed), app); + + app->settings->signal_changed(GSM_SETTING_SHOW_ALL_FS).connect ([app](const Glib::ustring&) { disks_update (app); disks_reset_timeout (app); }); + + gtk_widget_show (GTK_WIDGET (disk_tree)); +} -- cgit v1.2.3