Skip to content

Commit 3b9ee4a

Browse files
committed
ping sensor fixes #72
1 parent a112fe1 commit 3b9ee4a

8 files changed

Lines changed: 139 additions & 1 deletion

File tree

extension.js

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ var VitalsMenuButton = GObject.registerClass({
3939
'network' : { 'icon': 'network-symbolic.svg',
4040
'icon-rx': 'network-download-symbolic.svg',
4141
'icon-tx': 'network-upload-symbolic.svg',
42+
'icon-ping': 'network-ping-symbolic.svg',
4243
'icon-ad': '../flags/1x1/ad.svg',
4344
'icon-ae': '../flags/1x1/ae.svg',
4445
'icon-af': '../flags/1x1/af.svg',
@@ -335,7 +336,8 @@ var VitalsMenuButton = GObject.registerClass({
335336
'fixed-widths', 'hide-icons', 'unit',
336337
'memory-measurement', 'include-public-ip', 'network-public-ip-interval',
337338
'network-public-ip-show-flag', 'network-speed-format', 'storage-measurement',
338-
'include-static-info', 'include-static-gpu-info' ];
339+
'include-static-info', 'include-static-gpu-info',
340+
'network-ping-host' ];
339341

340342
for (let setting of Object.values(settings))
341343
this._addSettingChangedSignal(setting, this._redrawMenu.bind(this));
Lines changed: 8 additions & 0 deletions
Loading
Lines changed: 1 addition & 0 deletions
Loading

prefs.js

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,24 @@ const Settings = new GObject.Class({
7878
this._settings.bind('network-public-ip-interval', this.builder.get_object('network-public-ip-interval'),
7979
'value', Gio.SettingsBindFlags.DEFAULT);
8080

81+
let pingHostEntry = this.builder.get_object('network-ping-host');
82+
let pingHostSave = this.builder.get_object('network-ping-host-save');
83+
let getSavedPingHost = () => this._settings.get_string('network-ping-host');
84+
let savePingHost = () => {
85+
if (pingHostEntry.get_text() === getSavedPingHost())
86+
return;
87+
88+
this._settings.set_string('network-ping-host', pingHostEntry.get_text());
89+
pingHostSave.set_sensitive(false);
90+
};
91+
92+
pingHostEntry.set_text(getSavedPingHost());
93+
pingHostEntry.connect('changed', (widget) => {
94+
pingHostSave.set_sensitive(widget.get_text() !== getSavedPingHost());
95+
});
96+
pingHostEntry.connect('activate', () => savePingHost());
97+
pingHostSave.connect('clicked', () => savePingHost());
98+
8199
// process individual text entry sensor preferences
82100
sensors = [ 'storage-path', 'monitor-cmd' ];
83101
for (let key in sensors) {

prefs.ui

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -147,6 +147,47 @@
147147
</property>
148148
</object>
149149
</child>
150+
<child>
151+
<object class="GtkListBoxRow">
152+
<property name="width_request">100</property>
153+
<property name="hexpand">1</property>
154+
<property name="selectable">0</property>
155+
<property name="child">
156+
<object class="GtkBox">
157+
<property name="can_focus">1</property>
158+
<property name="margin_top">6</property>
159+
<property name="margin_bottom">6</property>
160+
<property name="margin_start">6</property>
161+
<property name="margin_end">6</property>
162+
<property name="spacing">12</property>
163+
<child>
164+
<object class="GtkLabel">
165+
<property name="hexpand">1</property>
166+
<property name="can_focus">0</property>
167+
<property name="halign">start</property>
168+
<property name="label" translatable="yes">Ping host</property>
169+
</object>
170+
</child>
171+
<child>
172+
<object class="GtkEntry" id="network-ping-host">
173+
<property name="placeholder_text" translatable="no">e.g. 1.1.1.1</property>
174+
<property name="can_focus">1</property>
175+
<property name="editable">1</property>
176+
<property name="width_chars">18</property>
177+
</object>
178+
</child>
179+
<child>
180+
<object class="GtkButton" id="network-ping-host-save">
181+
<property name="can_focus">1</property>
182+
<property name="sensitive">0</property>
183+
<property name="tooltip_text" translatable="yes">Save ping host</property>
184+
<property name="icon_name">object-select-symbolic</property>
185+
</object>
186+
</child>
187+
</object>
188+
</property>
189+
</object>
190+
</child>
150191
</object>
151192
</property>
152193
</object>

schemas/gschemas.compiled

56 Bytes
Binary file not shown.

schemas/org.gnome.shell.extensions.vitals.gschema.xml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,11 @@
9494
<summary>Network speed format</summary>
9595
<description>Should speed display in bits or bytes?</description>
9696
</key>
97+
<key type="s" name="network-ping-host">
98+
<default>""</default>
99+
<summary>Ping target host</summary>
100+
<description>Hostname or IP address to ping for latency measurement</description>
101+
</key>
97102
<key type="s" name="storage-path">
98103
<default>"/"</default>
99104
<summary>Storage path</summary>

sensors.js

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
import GLib from 'gi://GLib';
2828
import GObject from 'gi://GObject';
2929
import * as SubProcessModule from './helpers/subprocess.js';
30+
import Gio from 'gi://Gio';
3031
import * as FileModule from './helpers/file.js';
3132
import { gettext as _ } from 'resource:///org/gnome/shell/extensions/extension.js';
3233
import NM from 'gi://NM';
@@ -46,6 +47,8 @@ export const Sensors = GObject.registerClass({
4647
this._settings = settings;
4748
this._sensorIcons = sensorIcons;
4849

50+
this._pingCancellable = null;
51+
4952
this.resetHistory();
5053

5154
this._last_processor = { 'core': {}, 'speed': [] };
@@ -54,6 +57,7 @@ export const Sensors = GObject.registerClass({
5457
this._addSettingChangedSignal('show-gpu', this._reconfigureNvidiaSmiProcess.bind(this));
5558
this._addSettingChangedSignal('update-time', this._reconfigureNvidiaSmiProcess.bind(this));
5659
this._addSettingChangedSignal('network-public-ip-interval', () => {this._lastPublicIPCheck = 0;});
60+
this._addSettingChangedSignal('network-ping-host', () => this._pingCancellable?.cancel());
5761
//this._addSettingChangedSignal('include-static-gpu-info', this._reconfigureNvidiaSmiProcess.bind(this));
5862

5963
this._gpu_drm_vendors = null;
@@ -338,6 +342,63 @@ export const Sensors = GObject.registerClass({
338342
this._returnValue(callback, 'WiFi Signal Level', signal, 'network', 'string');
339343
}
340344
}).catch(err => { });
345+
346+
this._pollPing(value => {
347+
this._returnValue(callback, 'Ping', value, 'network-ping', 'string');
348+
});
349+
}
350+
351+
_pollPing(callback) {
352+
let host = this._settings.get_string('network-ping-host').trim();
353+
if (!host) return;
354+
355+
this._pingCancellable?.cancel();
356+
this._pingCancellable = new Gio.Cancellable();
357+
let cancellable = this._pingCancellable;
358+
359+
let subprocess;
360+
try {
361+
subprocess = new Gio.Subprocess({
362+
argv: ['ping', '-c', '1', '-W', '5', host],
363+
flags: Gio.SubprocessFlags.STDOUT_PIPE |
364+
Gio.SubprocessFlags.STDERR_PIPE,
365+
});
366+
subprocess.init(null);
367+
} catch (e) {
368+
callback('?? ms');
369+
return;
370+
}
371+
372+
cancellable.connect(() => subprocess.force_exit());
373+
374+
subprocess.communicate_utf8_async(null, cancellable, (proc, result) => {
375+
let value = this._parsePingResult(proc, result, cancellable);
376+
callback(value);
377+
});
378+
}
379+
380+
_parsePingResult(proc, result, cancellable) {
381+
let stdout, exitStatus;
382+
try {
383+
[, stdout] = proc.communicate_utf8_finish(result);
384+
exitStatus = proc.get_exit_status();
385+
} catch (e) {
386+
let cancelled = cancellable.is_cancelled();
387+
return cancelled ? this._pingTimeoutLabel() : '?? ms';
388+
}
389+
390+
if (exitStatus === 0 && stdout) {
391+
let match = /time[=<]([\d.]+)\s*ms/.exec(stdout);
392+
if (match)
393+
return `${parseFloat(match[1]).toFixed(1)} ms`;
394+
}
395+
396+
return exitStatus === 1 ? this._pingTimeoutLabel() : '?? ms';
397+
}
398+
399+
_pingTimeoutLabel() {
400+
let timeoutMs = Math.min(Math.max(this._settings.get_int('update-time'), 1), 5) * 1000;
401+
return `${timeoutMs}+ ms`;
341402
}
342403

343404
_queryStorage(callback, dwell) {
@@ -1066,11 +1127,13 @@ export const Sensors = GObject.registerClass({
10661127
this._frameMonitorLastTime = 0;
10671128
this._frameMonitorFrameCount = 0;
10681129
this._frameMonitorAccTime = 0;
1130+
this._pingCancellable?.cancel();
10691131
}
10701132

10711133
destroy() {
10721134
this._destroyFrameMonitor();
10731135
this._terminateNvidiaSmiProcess();
1136+
this._pingCancellable?.cancel();
10741137

10751138
for (let signal of Object.values(this._settingChangedSignals))
10761139
this._settings.disconnect(signal);

0 commit comments

Comments
 (0)