From c3c03c7841a418119823aaeaf43ed3ed2117798e Mon Sep 17 00:00:00 2001 From: Your Name Date: Tue, 10 Mar 2026 20:23:04 +0700 Subject: [PATCH 1/2] add multiple disks --- prefs.js | 68 ++++++++++++- schemas/gschemas.compiled | Bin 2084 -> 2084 bytes ....gnome.shell.extensions.vitals.gschema.xml | 4 +- sensors.js | 96 +++++++++++------- 4 files changed, 127 insertions(+), 41 deletions(-) diff --git a/prefs.js b/prefs.js index ce7885c..227dcbe 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' ]; + sensors = [ 'monitor-cmd' ]; + this._setup_storage_list(); + for (let key in sensors) { let sensor = sensors[key]; diff --git a/schemas/gschemas.compiled b/schemas/gschemas.compiled index e60cb0f1a650ca893c3a45db007e3a7cdee12b84..e4978b1169d166ce8c88dc42a5e3d5bbc3e1ba86 100644 GIT binary patch delta 51 zcmZ1?utZ>k1T*gkHU@@|RmSf)7#J8nY*uAH$}G&pppjUtnVXtds+*jeSCU$knzH#X Hn>r%^qMs0= delta 51 zcmZ1?utZ>k1T*hDHU@@|RmSf)7#JAdZB}JI$}G&FQLLGpnpdiuoSIjXT9lf?z_9r* Hn>r%^rJfKw 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) { From 393b24f20a219efd74a8f7661ea0aa3ac1937b5c Mon Sep 17 00:00:00 2001 From: Your Name Date: Tue, 10 Mar 2026 20:56:18 +0700 Subject: [PATCH 2/2] add multiple disks --- prefs.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/prefs.js b/prefs.js index 227dcbe..a27e92a 100644 --- a/prefs.js +++ b/prefs.js @@ -141,8 +141,8 @@ 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 = [ 'monitor-cmd' ]; this._setup_storage_list(); + sensors = [ 'monitor-cmd' ]; for (let key in sensors) { let sensor = sensors[key];