From c3c03c7841a418119823aaeaf43ed3ed2117798e Mon Sep 17 00:00:00 2001 From: Your Name Date: Tue, 10 Mar 2026 20:23:04 +0700 Subject: [PATCH 1/4] 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/4] 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]; From d4ae4c63beaafbc3274033ed028bf8920661e35f Mon Sep 17 00:00:00 2001 From: Your Name Date: Tue, 14 Apr 2026 14:10:51 +0700 Subject: [PATCH 3/4] drop changes to compiled schemas --- schemas/gschemas.compiled | Bin 2084 -> 1972 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/schemas/gschemas.compiled b/schemas/gschemas.compiled index e4978b1169d166ce8c88dc42a5e3d5bbc3e1ba86..936fdb3a506ffb8d2405e995628fbde747e729c0 100644 GIT binary patch literal 1972 zcmZWqUuYaf93C~bHEEh_`p>A<7EvzB+z~1|PRe;k)nKZ)azIzu)Zq z?zxxzEc6pA%IkjcbfK$vm)>3A8?_(D$$WNHoD%22eSJdgI3UCwTq`?ai08#B_;WyK z?OHq0v8tIsMNv(4tV&F%6H}WFtsfZ<7ovK^kr14l>k;<=m|Aek9{Qn)ff9q@J-}XI zAFv-dSmF?vd5n~J0Q}%K9EK(yF7e&@HwKu4%SX(L3Kky+j$U~B$$K$|x&r?c_yypn zM6J-L-VZ+jr$B40(WOs40RK(!Md0el(mDFneef@V7l6t9+8llA-SC&eE5K$=pX$(ti5XtbYf59$0-V_=`UEA@~d6 zMc|M5W3CR=gYZ|uUjVNi-xvltJq&*hH`jp=ZvQexpL!4cAHY8Y-!CoFa+>jQvA==* z!iO$jYWfv?v!x%5&!Y5MrNw_r> z1ojB_6rTSIa38>P&pyH)z@D)SV2@xAVm$0E>>)gU>_x*s5Vn*Io9JJ-aToG+K^m*G zGD!F?PUp|~N$)<;RvNTFof$7yvCg_)Zt#vLJkvF(qZetv<&DKKyj~Hrju-nK&l5vO zj)|&oiq(qO%XJu!G`1TRwPbzEXk@H>gN=z*+1i;KpT`=7)|qU^Ejq$&wJf5Lk<_;D Zqul5J`KW^Pu%7$q=2fN{9PZ1p{{VT+hkyV8 literal 2084 zcmZ8iL1-LR7=G2p)}(2+X>AiVn%FA4%Iq4d)uM=?#T+~oY^C%vo!x!e89Os?oHvu~ z#wvpCK@lu?DX63eMM2bf5JRQnMeIe0&=xOJ#7hvH)`K)TX#BqSW*g(e$M?-QfByI0 z|Ni;&+>2fscyT6*-w^nS)#Y0XZv*&p_1Ar5z8e!0;sp4~jY9O?A;cg6{|>AwJ*c4D%+Wib)aHhoeDB9)C?D*e4k~(++6S0|DgxZn*gT2y+9v$3$V37 z2|NgF2X+A1(oO7y-c^8S8wTzK?gH)s?kzA1UaGxxnCtLdePT*XfIZ+!e&8GW)V=T% za1Ok!-aJa5n(?oLPXT`%dgls#YQ~=ip8?97+$H+do8g}Ye+0a;Z)HDy>TU4n!RLW% z_b0vdsdvEt8T8dJE#`z+VCH-uV3> zed?|7FMxjpzI*kxKHe#H57!0%1LP;)Gxecnp3-foGcYpy$O`jN(=US^;EBcqW%|@S z*VEt$;M(l?W%|^NKLS1meE!U8jXpKcm4I{L@lXE>=u?|IgHHiJJ+<1VPrVEAXThHk zUzE<#r)K@k)i{R_PpEG;SeNp$rXCw9iV<#Vb zi1E}V_(R|kVDa47@6)Gdo`=DY0>`V%&(fzJhJO%z7-){yJM^h}u47;y_*@r`T;CCLWILK7$G@_<3-@2naI+Kx8yg(=-Fmr@+X9VE9;cpD!eBxZY{6#%%I$Q5V=^#Umogj7+FP5P_5AUn) zWtmJnjtFz5=nV1bi+EC*duJNd3VZC9L)1`tUS=fY+-b-do0Uy-wr)S7aTAG!^OQUN&pvH3 z6T8k|zv))$C8)jmyF6)nnRK!slI#!eKgXw1q%hCjEk@GQSP|Q@ui0CSx9y6LWc_R8 tx9@}XM{gy0aeUUr^ha?cj5oiokI?ROx8-#r(FT($jl8u@A_)6n=)ZP@s#X91 From 1ea0f64da8f8444920ca662ffda3f9e699a9ce1f Mon Sep 17 00:00:00 2001 From: Your Name Date: Tue, 14 Apr 2026 22:22:11 +0700 Subject: [PATCH 4/4] drop changes to compiled schemas --- schemas/gschemas.compiled | Bin 1972 -> 2084 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/schemas/gschemas.compiled b/schemas/gschemas.compiled index 936fdb3a506ffb8d2405e995628fbde747e729c0..b84716f2279c87ea5ad1ad1bc993508bb54a2564 100644 GIT binary patch literal 2084 zcmZWqO^g&p7%h|)++|rnz|3ZctD7KKz8yYyKmGSXB>PG*fsa$GRL8& ze*`=MJl)t=rccfFdf*tiIX8NZJ~iV{fZqkaeC}?IJ~h`n3qAvke{svFPfhmvMeq{v=gfY4Uetr|S%`hW*iX+M zV?6av_$BaOVC3XePtd2{0Dl~O5LmqU^~dz7?LL4ffaYj@nm#r2e--Qj-))~ePM>-; z{21H;2A78_^r@NuDex@t`hn$P`qabl&x7ZI^KW~1=u>ZnzW}}pEWNnwFoJQCb_O3f-+N3IUiVvuGQ}O(!a%NPb ziyJS>^@{QIloP5@C)2C=?l*Mgm~=W&m<3PS&qG==%D+dAAj2?mRuBA!8_Q zay-B7slXGcn;F?wu5j~A-9XExI~u}pBb83+q;}_ZG!{y`0 z+W0BX0(m;Ij1=;;|0Ourx=fM!v||Fj@}I-}We|I^u2O#{uYun9`AOM#TT3h!Cc(NX z>cXTlWnDxqZGD5P#6Do|?lJ{dfnp3*lsOH>-BZmXV~q3v4YoVi3S_&N2MRk@iA=ME z8TR~QvVX5Xi<>f4PU?q>^}+RJxGF`6eeb3iDrqnx63aicwiut6D=x`@KV#nf`#no< m$62v_?u*U7*lEVwr|ToM``%r*i4~5wrIS$hl0*>lVCX+*E3Ik( literal 1972 zcmZWqUuYaf93C~bHEEh_`p>A<7EvzB+z~1|PRe;k)nKZ)azIzu)Zq z?zxxzEc6pA%IkjcbfK$vm)>3A8?_(D$$WNHoD%22eSJdgI3UCwTq`?ai08#B_;WyK z?OHq0v8tIsMNv(4tV&F%6H}WFtsfZ<7ovK^kr14l>k;<=m|Aek9{Qn)ff9q@J-}XI zAFv-dSmF?vd5n~J0Q}%K9EK(yF7e&@HwKu4%SX(L3Kky+j$U~B$$K$|x&r?c_yypn zM6J-L-VZ+jr$B40(WOs40RK(!Md0el(mDFneef@V7l6t9+8llA-SC&eE5K$=pX$(ti5XtbYf59$0-V_=`UEA@~d6 zMc|M5W3CR=gYZ|uUjVNi-xvltJq&*hH`jp=ZvQexpL!4cAHY8Y-!CoFa+>jQvA==* z!iO$jYWfv?v!x%5&!Y5MrNw_r> z1ojB_6rTSIa38>P&pyH)z@D)SV2@xAVm$0E>>)gU>_x*s5Vn*Io9JJ-aToG+K^m*G zGD!F?PUp|~N$)<;RvNTFof$7yvCg_)Zt#vLJkvF(qZetv<&DKKyj~Hrju-nK&l5vO zj)|&oiq(qO%XJu!G`1TRwPbzEXk@H>gN=z*+1i;KpT`=7)|qU^Ejq$&wJf5Lk<_;D Zqul5J`KW^Pu%7$q=2fN{9PZ1p{{VT+hkyV8