diff --git a/prefs.js b/prefs.js
index ce7885c..a27e92a 100644
--- a/prefs.js
+++ b/prefs.js
@@ -38,6 +38,70 @@ const Settings = new GObject.Class({
this._bind_settings();
},
+ _setup_storage_list: function() {
+ let entryWidget = this.builder.get_object('storage-path');
+ let parentBox = entryWidget.get_parent();
+ parentBox.remove(entryWidget);
+
+ let listContainer = new Gtk.Box({ orientation: Gtk.Orientation.VERTICAL, spacing: 6 });
+ parentBox.append(listContainer);
+
+ let paths = this._settings.get_strv('storage-path');
+
+ let renderRows = () => {
+ let child = listContainer.get_first_child();
+ while (child) {
+ listContainer.remove(child);
+ child = listContainer.get_first_child();
+ }
+
+ let currentPaths = this._settings.get_strv('storage-path') || [];
+ currentPaths.forEach((path, index) => {
+ let row = new Gtk.Box({ spacing: 6 });
+ let entry = new Gtk.Entry({ text: path, hexpand: true });
+
+ entry.connect('activate', (w) => {
+ let p = this._settings.get_strv('storage-path');
+ p[index] = w.get_text();
+ this._settings.set_strv('storage-path', p);
+ });
+ let focusController = new Gtk.EventControllerFocus();
+ focusController.connect('leave', () => {
+ let p = this._settings.get_strv('storage-path');
+ let text = entry.get_text();
+ if (p[index] !== text) {
+ p[index] = text;
+ this._settings.set_strv('storage-path', p);
+ }
+ });
+ entry.add_controller(focusController);
+
+ let delBtn = new Gtk.Button({ icon_name: 'list-remove-symbolic' });
+ delBtn.connect('clicked', () => {
+ let p = this._settings.get_strv('storage-path') || [];
+ p.splice(index, 1);
+ this._settings.set_strv('storage-path', p);
+ renderRows();
+ });
+
+ row.append(entry);
+ row.append(delBtn);
+ listContainer.append(row);
+ });
+
+ let addBtn = new Gtk.Button({ label: _('Add Path'), icon_name: 'list-add-symbolic' });
+ addBtn.connect('clicked', () => {
+ let p = this._settings.get_strv('storage-path');
+ p.push('/');
+ this._settings.set_strv('storage-path', p);
+ renderRows();
+ });
+ listContainer.append(addBtn);
+ };
+
+ renderRows();
+ },
+
// Bind the gtk window to the schema settings
_bind_settings: function() {
let widget;
@@ -77,7 +141,9 @@ const Settings = new GObject.Class({
this._settings.bind('update-time', this.builder.get_object('update-time'), 'value', Gio.SettingsBindFlags.DEFAULT);
// process individual text entry sensor preferences
- sensors = [ 'storage-path', 'monitor-cmd' ];
+ this._setup_storage_list();
+ sensors = [ 'monitor-cmd' ];
+
for (let key in sensors) {
let sensor = sensors[key];
diff --git a/schemas/gschemas.compiled b/schemas/gschemas.compiled
index e60cb0f..e4978b1 100644
Binary files a/schemas/gschemas.compiled and b/schemas/gschemas.compiled differ
diff --git a/schemas/org.gnome.shell.extensions.vitals.gschema.xml b/schemas/org.gnome.shell.extensions.vitals.gschema.xml
index 72f8f40..3d28bd9 100644
--- a/schemas/org.gnome.shell.extensions.vitals.gschema.xml
+++ b/schemas/org.gnome.shell.extensions.vitals.gschema.xml
@@ -86,8 +86,8 @@
Network speed format
Should speed display in bits or bytes?
-
- "/"
+
+ ["/"]
Storage path
Storage path for monitoring
diff --git a/sensors.js b/sensors.js
index be8df5d..4b94b5a 100644
--- a/sensors.js
+++ b/sensors.js
@@ -72,8 +72,7 @@ export const Sensors = GObject.registerClass({
this._storageDevice = '';
this._findStorageDevice();
- this._lastRead = 0;
- this._lastWrite = 0;
+ this._storageHistory = {};
}
}
@@ -349,48 +348,69 @@ export const Sensors = GObject.registerClass({
this._returnValue(callback, 'ARC Current', current, 'storage', 'storage');
}).catch(err => { });
+ // skip rest of stats if gtop not available
+ if (!hasGTop) return;
+
+ let paths = this._settings.get_strv('storage-path') || [];
+ if (paths.length === 0) return;
+
// check disk performance stats
- new FileModule.File('/proc/diskstats').read("\n").then(lines => {
- for (let line of lines) {
- let loadArray = line.trim().split(/\s+/);
- if ('/dev/' + loadArray[2] == this._storageDevice) {
- var read = (loadArray[5] * 512);
- var write = (loadArray[9] * 512);
- this._returnValue(callback, 'Read total', read, 'storage', 'storage');
- this._returnValue(callback, 'Write total', write, 'storage', 'storage');
- this._returnValue(callback, 'Read rate', (read - this._lastRead) / dwell, 'storage', 'storage');
- this._returnValue(callback, 'Write rate', (write - this._lastWrite) / dwell, 'storage', 'storage');
- this._lastRead = read;
- this._lastWrite = write;
- break;
+ Promise.all([
+ new FileModule.File('/proc/mounts').read("\n"),
+ new FileModule.File('/proc/diskstats').read("\n")
+ ]).then(([mounts, stats]) => {
+ let pathDeviceMap = {};
+ for (let line of mounts) {
+ let parts = line.trim().split(/\s+/);
+ if (parts.length >= 2) pathDeviceMap[parts[1]] = parts[0].replace('/dev/', '');
+ }
+
+ let deviceData = {};
+ for (let line of stats) {
+ let parts = line.trim().split(/\s+/);
+ if (parts.length > 10) {
+ deviceData[parts[2]] = {
+ read: parseInt(parts[5]) * 512,
+ write: parseInt(parts[9]) * 512
+ };
}
}
- }).catch(err => { });
- // skip rest of stats if gtop not available
- if (!hasGTop) return;
+ paths.forEach(path => {
+ if (!path) return;
+
+ GTop.glibtop_get_fsusage(this.storage, path);
+ let total = this.storage.blocks * this.storage.block_size;
+ let avail = this.storage.bavail * this.storage.block_size;
+ let free = this.storage.bfree * this.storage.block_size;
+ let used = total - free;
+ let usedPct = Math.round((used / (used + avail)) * 100);
+
+ let suffix = ` (${path})`;
+ this._returnValue(callback, _('Used %') + suffix, usedPct + '%', 'storage', 'string');
+ this._returnValue(callback, _('Free') + suffix, avail, 'storage', 'storage');
+
+ let dev = pathDeviceMap[path];
+ if (dev && deviceData[dev]) {
+ let currentRead = deviceData[dev].read;
+ let currentWrite = deviceData[dev].write;
+
+ this._returnValue(callback, _('Read total') + suffix, currentRead, 'storage', 'storage');
+ this._returnValue(callback, _('Write total') + suffix, currentWrite, 'storage', 'storage');
+ if (this._storageHistory[dev]) {
+ let rRate = (currentRead - this._storageHistory[dev].read) / dwell;
+ let wRate = (currentWrite - this._storageHistory[dev].write) / dwell;
+ this._returnValue(callback, _('Read rate') + suffix, rRate, 'storage', 'storage');
+ this._returnValue(callback, _('Write rate') + suffix, wRate, 'storage', 'storage');
+ }
- GTop.glibtop_get_fsusage(this.storage, this._settings.get_string('storage-path'));
-
- let total = this.storage.blocks * this.storage.block_size;
- let avail = this.storage.bavail * this.storage.block_size;
- let free = this.storage.bfree * this.storage.block_size;
- let used = total - free;
- let reserved = (total - avail) - used;
- let freePercent = 0;
- let usedPercent = 0;
- if (total > 0) {
- freePercent = Math.round((free / total) * 100);
- usedPercent = Math.round((used / total) * 100);
- }
+ this._storageHistory[dev] = { read: currentRead, write: currentWrite };
+ }
- this._returnValue(callback, 'Total', total, 'storage', 'storage');
- this._returnValue(callback, 'Used', used, 'storage', 'storage');
- this._returnValue(callback, 'Reserved', reserved, 'storage', 'storage');
- this._returnValue(callback, 'Free', avail, 'storage', 'storage');
- this._returnValue(callback, 'Used %', usedPercent + '%', 'storage', 'string');
- this._returnValue(callback, 'Free %', freePercent + '%', 'storage', 'string');
- this._returnValue(callback, 'storage', avail, 'storage-group', 'storage');
+ if (path == paths[0])
+ this._returnValue(callback, 'storage', avail, 'storage-group', 'storage');
+ });
+ }).catch(err => { });
}
_queryBattery(callback) {