[gnome] Update extensions for v46
@ -40,15 +40,23 @@ var VitalsMenuButton = GObject.registerClass({
|
||||
'icon-rx': 'network-download-symbolic.svg',
|
||||
'icon-tx': 'network-upload-symbolic.svg' },
|
||||
'storage' : { 'icon': 'storage-symbolic.svg' },
|
||||
'battery' : { 'icon': 'battery-symbolic.svg' }
|
||||
'battery' : { 'icon': 'battery-symbolic.svg' },
|
||||
'gpu' : { 'icon': 'gpu-symbolic.svg' }
|
||||
}
|
||||
|
||||
// list with the prefixes for the according themes, the index of each
|
||||
// item must match the index on the combo box
|
||||
this._sensorsIconPathPrefix = ['/icons/original/', '/icons/gnome/'];
|
||||
|
||||
this._warnings = [];
|
||||
this._sensorMenuItems = {};
|
||||
this._hotLabels = {};
|
||||
this._hotIcons = {};
|
||||
this._groups = {};
|
||||
this._widths = {};
|
||||
this._numGpus = 1;
|
||||
this._newGpuDetected = false;
|
||||
this._newGpuDetectedCount = 0;
|
||||
this._last_query = new Date().getTime();
|
||||
|
||||
this._sensors = new Sensors.Sensors(this._settings, this._sensorIcons);
|
||||
@ -64,15 +72,16 @@ var VitalsMenuButton = GObject.registerClass({
|
||||
});
|
||||
|
||||
this._drawMenu();
|
||||
this.add_actor(this._menuLayout);
|
||||
this.add_child(this._menuLayout);
|
||||
this._settingChangedSignals = [];
|
||||
this._refreshTimeoutId = null;
|
||||
|
||||
this._addSettingChangedSignal('update-time', this._updateTimeChanged.bind(this));
|
||||
this._addSettingChangedSignal('position-in-panel', this._positionInPanelChanged.bind(this));
|
||||
this._addSettingChangedSignal('menu-centered', this._positionInPanelChanged.bind(this));
|
||||
this._addSettingChangedSignal('icon-style', this._iconStyleChanged.bind(this));
|
||||
|
||||
let settings = [ 'use-higher-precision', 'alphabetize', 'hide-zeros', 'fixed-widths', 'hide-icons', 'unit', 'memory-measurement', 'include-public-ip', 'network-speed-format', 'storage-measurement', 'include-static-info' ];
|
||||
let settings = [ 'use-higher-precision', 'alphabetize', 'hide-zeros', 'fixed-widths', 'hide-icons', 'unit', 'memory-measurement', 'include-public-ip', 'network-speed-format', 'storage-measurement', 'include-static-info', 'include-static-gpu-info' ];
|
||||
for (let setting of Object.values(settings))
|
||||
this._addSettingChangedSignal(setting, this._redrawMenu.bind(this));
|
||||
|
||||
@ -95,21 +104,14 @@ var VitalsMenuButton = GObject.registerClass({
|
||||
// groups associated sensors under accordion menu
|
||||
if (sensor in this._groups) continue;
|
||||
|
||||
this._groups[sensor] = new PopupMenu.PopupSubMenuMenuItem(_(this._ucFirst(sensor)), true);
|
||||
this._groups[sensor].icon.gicon = Gio.icon_new_for_string(this._extensionObject.path + '/icons/' + this._sensorIcons[sensor]['icon']);
|
||||
//handle gpus separately.
|
||||
if (sensor === 'gpu') continue;
|
||||
|
||||
// hide menu items that user has requested to not include
|
||||
if (!this._settings.get_boolean('show-' + sensor))
|
||||
this._groups[sensor].actor.hide();
|
||||
|
||||
if (!this._groups[sensor].status) {
|
||||
this._groups[sensor].status = this._defaultLabel();
|
||||
this._groups[sensor].actor.insert_child_at_index(this._groups[sensor].status, 4);
|
||||
this._groups[sensor].status.text = _('No Data');
|
||||
}
|
||||
|
||||
this.menu.addMenuItem(this._groups[sensor]);
|
||||
this._initializeMenuGroup(sensor, sensor);
|
||||
}
|
||||
|
||||
for (let i = 1; i <= this._numGpus; i++)
|
||||
this._initializeMenuGroup('gpu#' + i, 'gpu', (this._numGpus > 1 ? ' ' + i : ''));
|
||||
|
||||
// add separator
|
||||
this.menu.addMenuItem(new PopupMenu.PopupSeparatorMenuItem());
|
||||
@ -135,7 +137,7 @@ var VitalsMenuButton = GObject.registerClass({
|
||||
refreshButton.connect('clicked', (self) => {
|
||||
// force refresh by clearing history
|
||||
this._sensors.resetHistory();
|
||||
this._values.resetHistory();
|
||||
this._values.resetHistory(this._numGpus);
|
||||
|
||||
// make sure timer fires at next full interval
|
||||
this._updateTimeChanged();
|
||||
@ -143,7 +145,7 @@ var VitalsMenuButton = GObject.registerClass({
|
||||
// refresh sensors now
|
||||
this._querySensors();
|
||||
});
|
||||
customButtonBox.add_actor(refreshButton);
|
||||
customButtonBox.add_child(refreshButton);
|
||||
|
||||
// custom round monitor button
|
||||
let monitorButton = this._createRoundButton('org.gnome.SystemMonitor-symbolic', _('System Monitor'));
|
||||
@ -151,7 +153,7 @@ var VitalsMenuButton = GObject.registerClass({
|
||||
this.menu._getTopMenu().close();
|
||||
Util.spawn(this._settings.get_string('monitor-cmd').split(" "));
|
||||
});
|
||||
customButtonBox.add_actor(monitorButton);
|
||||
customButtonBox.add_child(monitorButton);
|
||||
|
||||
// custom round preferences button
|
||||
let prefsButton = this._createRoundButton('preferences-system-symbolic', _('Preferences'));
|
||||
@ -159,10 +161,10 @@ var VitalsMenuButton = GObject.registerClass({
|
||||
this.menu._getTopMenu().close();
|
||||
this._extensionObject.openPreferences();
|
||||
});
|
||||
customButtonBox.add_actor(prefsButton);
|
||||
customButtonBox.add_child(prefsButton);
|
||||
|
||||
// now add the buttons to the top bar
|
||||
item.actor.add_actor(customButtonBox);
|
||||
item.actor.add_child(customButtonBox);
|
||||
|
||||
// add buttons
|
||||
this.menu.addMenuItem(item);
|
||||
@ -179,6 +181,24 @@ var VitalsMenuButton = GObject.registerClass({
|
||||
});
|
||||
}
|
||||
|
||||
_initializeMenuGroup(groupName, optionName, menuSuffix = '', position = -1) {
|
||||
this._groups[groupName] = new PopupMenu.PopupSubMenuMenuItem(_(this._ucFirst(groupName) + menuSuffix), true);
|
||||
this._groups[groupName].icon.gicon = Gio.icon_new_for_string(this._sensorIconPath(groupName));
|
||||
|
||||
// hide menu items that user has requested to not include
|
||||
if (!this._settings.get_boolean('show-' + optionName))
|
||||
this._groups[groupName].actor.hide();
|
||||
|
||||
if (!this._groups[groupName].status) {
|
||||
this._groups[groupName].status = this._defaultLabel();
|
||||
this._groups[groupName].actor.insert_child_at_index(this._groups[groupName].status, 4);
|
||||
this._groups[groupName].status.text = _('No Data');
|
||||
}
|
||||
|
||||
if(position == -1) this.menu.addMenuItem(this._groups[groupName]);
|
||||
else this.menu.addMenuItem(this._groups[groupName], position);
|
||||
}
|
||||
|
||||
_createRoundButton(iconName) {
|
||||
let button = new St.Button({
|
||||
style_class: 'message-list-clear-button button vitals-button-action'
|
||||
@ -239,7 +259,7 @@ var VitalsMenuButton = GObject.registerClass({
|
||||
_createHotItem(key, value) {
|
||||
let icon = this._defaultIcon(key);
|
||||
this._hotIcons[key] = icon;
|
||||
this._menuLayout.add_actor(icon)
|
||||
this._menuLayout.add_child(icon)
|
||||
|
||||
// don't add a label when no sensors are in the panel
|
||||
if (key == '_default_icon_') return;
|
||||
@ -248,7 +268,7 @@ var VitalsMenuButton = GObject.registerClass({
|
||||
style_class: 'vitals-panel-label',
|
||||
text: (value)?value:'\u2026', // ...
|
||||
y_expand: true,
|
||||
y_align: Clutter.ActorAlign.START
|
||||
y_align: Clutter.ActorAlign.CENTER
|
||||
});
|
||||
|
||||
// attempt to prevent ellipsizes
|
||||
@ -258,7 +278,7 @@ var VitalsMenuButton = GObject.registerClass({
|
||||
this._hotLabels[key] = label;
|
||||
|
||||
// prevent "called on the widget" "which is not in the stage" errors by adding before width below
|
||||
this._menuLayout.add_actor(label);
|
||||
this._menuLayout.add_child(label);
|
||||
|
||||
// support for fixed widths #55, save label (text) width
|
||||
this._widths[key] = label.width;
|
||||
@ -266,11 +286,17 @@ var VitalsMenuButton = GObject.registerClass({
|
||||
|
||||
_showHideSensorsChanged(self, sensor) {
|
||||
this._sensors.resetHistory();
|
||||
this._groups[sensor.substr(5)].visible = this._settings.get_boolean(sensor);
|
||||
|
||||
const sensorName = sensor.substr(5);
|
||||
if(sensorName === 'gpu') {
|
||||
for(let i = 1; i <= this._numGpus; i++)
|
||||
this._groups[sensorName + '#' + i].visible = this._settings.get_boolean(sensor);
|
||||
} else
|
||||
this._groups[sensorName].visible = this._settings.get_boolean(sensor);
|
||||
}
|
||||
|
||||
_positionInPanelChanged() {
|
||||
this.container.get_parent().remove_actor(this.container);
|
||||
this.container.get_parent().remove_child(this.container);
|
||||
let position = this._positionInPanel();
|
||||
|
||||
// allows easily addressable boxes
|
||||
@ -284,6 +310,27 @@ var VitalsMenuButton = GObject.registerClass({
|
||||
boxes[position[0]].insert_child_at_index(this.container, position[1]);
|
||||
}
|
||||
|
||||
_redrawDetailsMenuIcons() {
|
||||
// updates the icons on the 'details' menu, the one
|
||||
// you have to click to appear
|
||||
this._sensors.resetHistory();
|
||||
for (const sensor in this._sensorIcons) {
|
||||
if (sensor == "gpu") continue;
|
||||
this._groups[sensor].icon.gicon = Gio.icon_new_for_string(this._sensorIconPath(sensor));
|
||||
}
|
||||
|
||||
// gpu's are indexed differently, handle them here
|
||||
const gpuKeys = Object.keys(this._groups).filter(key => key.startsWith("gpu#"));
|
||||
gpuKeys.forEach((gpuKey) => {
|
||||
this._groups[gpuKey].icon.gicon = Gio.icon_new_for_string(this._sensorIconPath("gpu"));
|
||||
});
|
||||
}
|
||||
|
||||
_iconStyleChanged() {
|
||||
this._redrawDetailsMenuIcons();
|
||||
this._redrawMenu();
|
||||
}
|
||||
|
||||
_removeHotLabel(key) {
|
||||
if (key in this._hotLabels) {
|
||||
let label = this._hotLabels[key];
|
||||
@ -322,7 +369,7 @@ var VitalsMenuButton = GObject.registerClass({
|
||||
|
||||
this._drawMenu();
|
||||
this._sensors.resetHistory();
|
||||
this._values.resetHistory();
|
||||
this._values.resetHistory(this._numGpus);
|
||||
this._querySensors();
|
||||
}
|
||||
|
||||
@ -370,7 +417,8 @@ var VitalsMenuButton = GObject.registerClass({
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(key === "_gpu#1_domain_number_")
|
||||
console.error('UPDATING: ', key);
|
||||
// have we added this sensor before?
|
||||
let item = this._sensorMenuItems[key];
|
||||
if (item) {
|
||||
@ -394,7 +442,7 @@ var VitalsMenuButton = GObject.registerClass({
|
||||
let split = sensor.type.split('-');
|
||||
let type = split[0];
|
||||
let icon = (split.length == 2)?'icon-' + split[1]:'icon';
|
||||
let gicon = Gio.icon_new_for_string(this._extensionObject.path + '/icons/' + this._sensorIcons[type][icon]);
|
||||
let gicon = Gio.icon_new_for_string(this._sensorIconPath(type, icon));
|
||||
|
||||
let item = new MenuItem.MenuItem(gicon, key, sensor.label, sensor.value, this._hotLabels[key]);
|
||||
item.connect('toggle', (self) => {
|
||||
@ -460,17 +508,28 @@ var VitalsMenuButton = GObject.registerClass({
|
||||
});
|
||||
|
||||
// second condition prevents crash due to issue #225, which started when _max_ was moved to the end
|
||||
if (type == 'default' || !(type in this._sensorIcons)) {
|
||||
icon.gicon = Gio.icon_new_for_string(this._extensionObject.path + '/icons/' + this._sensorIcons['system']['icon']);
|
||||
// don't use the default system icon if the type is a gpu; use the universal gpu icon instead
|
||||
if (type == 'default' || (!(type in this._sensorIcons) && !type.startsWith('gpu'))) {
|
||||
icon.gicon = Gio.icon_new_for_string(this._sensorIconPath('system'));
|
||||
} else if (!this._settings.get_boolean('hide-icons')) { // support for hide icons #80
|
||||
let iconObj = (split.length == 2)?'icon-' + split[1]:'icon';
|
||||
icon.gicon = Gio.icon_new_for_string(this._extensionObject.path + '/icons/' + this._sensorIcons[type][iconObj]);
|
||||
icon.gicon = Gio.icon_new_for_string(this._sensorIconPath(type, iconObj));
|
||||
}
|
||||
|
||||
return icon;
|
||||
}
|
||||
|
||||
_sensorIconPath(sensor, icon = 'icon') {
|
||||
// If the sensor is a numbered gpu, use the gpu icon. Otherwise use whatever icon associated with the sensor name.
|
||||
let sensorKey = sensor;
|
||||
if(sensor.startsWith('gpu')) sensorKey = 'gpu';
|
||||
|
||||
const iconPathPrefixIndex = this._settings.get_int('icon-style');
|
||||
return this._extensionObject.path + this._sensorsIconPathPrefix[iconPathPrefixIndex] + this._sensorIcons[sensorKey][icon];
|
||||
}
|
||||
|
||||
_ucFirst(string) {
|
||||
if(string.startsWith('gpu')) return 'Graphics';
|
||||
return string.charAt(0).toUpperCase() + string.slice(1);
|
||||
}
|
||||
|
||||
@ -524,7 +583,8 @@ var VitalsMenuButton = GObject.registerClass({
|
||||
this._last_query = now;
|
||||
|
||||
this._sensors.query((label, value, type, format) => {
|
||||
let key = '_' + type.replace('-group', '') + '_' + label.replace(' ', '_').toLowerCase() + '_';
|
||||
const typeKey = type.replace('-group', '');
|
||||
let key = '_' + typeKey + '_' + label.replace(' ', '_').toLowerCase() + '_';
|
||||
|
||||
// if a sensor is disabled, gray it out
|
||||
if (key in this._sensorMenuItems) {
|
||||
@ -534,11 +594,39 @@ var VitalsMenuButton = GObject.registerClass({
|
||||
if (value == 'disabled') return;
|
||||
}
|
||||
|
||||
// add/initialize any gpu groups that we haven't added yet
|
||||
if(typeKey.startsWith('gpu') && typeKey !== 'gpu#1') {
|
||||
const split = typeKey.split('#');
|
||||
if(split.length == 2 && this._numGpus < parseInt(split[1])) {
|
||||
// occasionally two lines from nvidia-smi will be read at once
|
||||
// so we only actually update the number of gpus if we have recieved multiple lines at least 3 times in a row
|
||||
// i.e. we make sure that mutiple queries have detected a new gpu back-to-back
|
||||
if(this._newGpuDetectedCount < 2) {
|
||||
this._newGpuDetected = true;
|
||||
return;
|
||||
}
|
||||
|
||||
this._numGpus = parseInt(split[1]);
|
||||
this._newGpuDetectedCount = 0;
|
||||
this._newGpuDetected = false;
|
||||
// change label for gpu 1 from "Graphics" to "Graphics 1" since we have multiple gpus now
|
||||
this._groups['gpu#1'].label.text = this._ucFirst('gpu#1') + ' 1';
|
||||
for(let i = 2; i <= this._numGpus; i++)
|
||||
if(!('gpu#' + i in this._groups))
|
||||
this._initializeMenuGroup('gpu#' + i, 'gpu', ' ' + i, Object.keys(this._groups).length);
|
||||
}
|
||||
}
|
||||
|
||||
let items = this._values.returnIfDifferent(dwell, label, value, type, format, key);
|
||||
for (let item of Object.values(items))
|
||||
this._updateDisplay(_(item[0]), item[1], item[2], item[3]);
|
||||
}, dwell);
|
||||
|
||||
//if a new gpu has been detected during the last query, then increment the amount of times we've detected a new gpu
|
||||
if(this._newGpuDetected) this._newGpuDetectedCount++;
|
||||
else this._newGpuDetectedCount = 0;
|
||||
this._newGpuDetected = false;
|
||||
|
||||
if (this._warnings.length > 0) {
|
||||
this._notify('Vitals', this._warnings.join("\n"), 'folder-symbolic');
|
||||
this._warnings = [];
|
||||
@ -555,6 +643,7 @@ var VitalsMenuButton = GObject.registerClass({
|
||||
|
||||
destroy() {
|
||||
this._destroyTimer();
|
||||
this._sensors.destroy();
|
||||
|
||||
for (let signal of Object.values(this._settingChangedSignals))
|
||||
this._settings.disconnect(signal);
|
||||
|
||||
@ -0,0 +1,54 @@
|
||||
import GLib from 'gi://GLib';
|
||||
import Gio from 'gi://Gio';
|
||||
|
||||
// convert Uint8Array into a literal string
|
||||
function convertUint8ArrayToString(contents) {
|
||||
const decoder = new TextDecoder('utf-8');
|
||||
return decoder.decode(contents).trim();
|
||||
}
|
||||
|
||||
export function SubProcess(command) {
|
||||
this.sub_process = Gio.Subprocess.new(command, Gio.SubprocessFlags.STDOUT_PIPE);
|
||||
this.stdout = this.sub_process.get_stdout_pipe();
|
||||
}
|
||||
|
||||
SubProcess.prototype.read = function(delimiter = '') {
|
||||
return new Promise((resolve, reject) => {
|
||||
this.stdout.read_bytes_async(512, GLib.PRIORITY_LOW, null, function(stdout, res) {
|
||||
try {
|
||||
let read_bytes = stdout.read_bytes_finish(res).get_data();
|
||||
|
||||
// convert contents to string
|
||||
let read_str = convertUint8ArrayToString(read_bytes);
|
||||
|
||||
// split read_str by delimiter if passed in
|
||||
if (delimiter) {
|
||||
if (read_str == '')
|
||||
read_str = []; // EOF, ''.split(delimiter) would return ['']
|
||||
else
|
||||
read_str = read_str.split(delimiter);
|
||||
}
|
||||
|
||||
// return results
|
||||
resolve(read_str);
|
||||
} catch (e) {
|
||||
if (e.matches(Gio.IOErrorEnum, Gio.IOErrorEnum.PENDING)) {
|
||||
// previous read attempt is still waiting for something from stdout
|
||||
// ignore second attempt, return empty data (like EOF)
|
||||
if (delimiter) resolve([]);
|
||||
else resolve('');
|
||||
} else {
|
||||
reject(e.message);
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
SubProcess.prototype.terminate = function() {
|
||||
const SIGINT = 2;
|
||||
this.sub_process.send_signal(SIGINT);
|
||||
this.sub_process = null;
|
||||
this.stdout.close_async(GLib.PRIORITY_LOW, null, null);
|
||||
this.stdout = null;
|
||||
};
|
||||
|
Before Width: | Height: | Size: 909 B After Width: | Height: | Size: 909 B |
@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16"><path fill="#2e3436" d="M5 0v2s-.707-.016-1.45.355C2.814 2.727 2 3.668 2 5v1H0v1h2v1H0v1h2v1H0v1h2s-.016.707.355 1.445C2.727 13.187 3.668 14 5 14h1v2h1v-2h1v2h1v-2h1v2h1v-2s.707.016 1.45-.355C13.186 13.273 14 12.332 14 11v-1h2V9h-2V8h2V7h-2V6h2V5h-2c0-1.332-.813-2.273-1.55-2.645C11.706 1.985 11 2 11 2h-1V0H9v2H8V0H7v2H6V0zm0 4h6c.555 0 1 .445 1 1v6c0 .555-.445 1-1 1H5c-.555 0-1-.445-1-1V5c0-.555.445-1 1-1zm0 1v6h6V5z"/></svg>
|
||||
|
After Width: | Height: | Size: 492 B |
@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16"><g fill="#2e3434"><path d="M8 0c-.234 0-.459.012-.688.031-1.832 1.216-1.77 3.335-.859 5.405A3 3 0 0 1 8 5a3 3 0 0 1 .418.031c.919-2.154 2.91-3.702 3.55-3.968A7.955 7.955 0 0 0 8 0zM4 1.094a7.982 7.982 0 0 0-3.219 3.5c.12 2.215 1.974 3.23 4.225 3.472A3 3 0 0 1 5 8a3 3 0 0 1 .646-1.85C4.248 4.28 3.912 1.787 4 1.094zm9.156 1.968c-1.423-.044-2.706.924-3.719 2.305a3 3 0 0 1 1.35 1.528C13.127 6.624 15.48 7.587 16 8a7.956 7.956 0 0 0-1.438-4.563 3.386 3.386 0 0 0-1.406-.374zm-2.158 4.872L11 8a3 3 0 0 1-.646 1.85c1.398 1.87 1.734 4.363 1.646 5.056a7.982 7.982 0 0 0 3.219-3.5c-.12-2.214-1.972-3.228-4.221-3.472zM0 8c0 1.698.536 3.268 1.438 4.563 1.973.987 3.79-.113 5.128-1.936A3 3 0 0 1 5.22 9.105C2.877 9.38.52 8.413 0 8zm9.547 2.564A3 3 0 0 1 8 11a3 3 0 0 1-.418-.031c-.919 2.154-2.91 3.702-3.55 3.969a7.955 7.955 0 0 0 4.655 1.03c1.833-1.215 1.772-3.334.86-5.404z"/><circle cx="8" cy="8" r="2"/></g></svg>
|
||||
|
After Width: | Height: | Size: 970 B |
@ -0,0 +1,15 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
|
||||
<svg width="100%" height="100%" viewBox="0 0 512 512" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xml:space="preserve" xmlns:serif="http://www.serif.com/" style="fill-rule:evenodd;clip-rule:evenodd;stroke-linejoin:round;stroke-miterlimit:2;">
|
||||
<g transform="matrix(3.38015e-16,5.5202,-5.5202,3.38015e-16,526.335,-21.2284)">
|
||||
<path d="M18,18L18,8L6,8L6,12L14,12L14,24L6,24L6,41.942L14,41.942L14,50.565L6,50.565L6,68.188L14,68.188L14,84L18,84L18,76L43,76L43,83C43.262,84.981 44.621,85.866 46.73,86L76.27,86C77.384,86 78.257,85.827 78.879,85.369C79.549,84.876 80,84.108 80,83L80,76L84.83,76C88.477,76.314 90.397,75.227 91.886,73.383C93.128,71.845 94.269,69.879 94,66.83L94,18L18,18ZM14,64.188L10,64.188L10,54.565L14,54.565L14,64.188ZM14,37.942L10,37.942L10,28L14,28L14,37.942ZM76,81.05C76,81.783 75.758,82.05 74.84,82.05L48.16,82.05C46.867,82.364 46.769,81.824 47,81.05L47,76L76,76L76,81.05ZM90,65.17C90.472,69.878 88.349,72.291 83.17,72L18,72L18,22L90,22L90,65.17Z" style="fill-rule:nonzero;"/>
|
||||
</g>
|
||||
<g transform="matrix(2.90206e-16,4.73942,-4.73942,2.90206e-16,491.213,161.673)">
|
||||
<path d="M44,66.88C54.906,66.88 63.88,57.906 63.88,47C63.88,36.094 54.906,27.12 44,27.12C33.094,27.12 24.12,36.094 24.12,47C24.131,57.902 33.098,66.869 44,66.88ZM42,62.74C37.914,62.223 34.185,60.135 31.61,56.92L37.67,52.92C38.832,54.175 40.338,55.062 42,55.47L42,62.74ZM46,62.74L46,55.46C47.653,55.082 49.159,54.227 50.33,53L56.39,57C53.801,60.185 50.074,62.244 46,62.74ZM58.06,39.65C60.332,43.951 60.484,49.072 58.47,53.5L52.34,49.5C52.582,48.689 52.707,47.847 52.71,47C52.712,45.831 52.474,44.673 52.01,43.6L58.06,39.65ZM46,31.26C49.762,31.74 53.23,33.554 55.77,36.37L49.63,40.37C48.581,39.483 47.337,38.856 46,38.54L46,31.26ZM48.71,47C48.71,49.584 46.584,51.71 44,51.71C41.416,51.71 39.29,49.584 39.29,47C39.29,44.416 41.416,42.29 44,42.29C46.582,42.295 48.705,44.418 48.71,47ZM42,31.26L42,38.53C40.664,38.854 39.421,39.484 38.37,40.37L32.23,36.37C34.77,33.554 38.238,31.74 42,31.26ZM36,43.6C35.536,44.673 35.298,45.831 35.3,47C35.304,47.843 35.429,48.682 35.67,49.49L29.53,53.49C27.53,49.059 27.681,43.945 29.94,39.64L36,43.6Z" style="fill-rule:nonzero;"/>
|
||||
</g>
|
||||
<g transform="matrix(2.65262e-16,4.33206,-4.33206,2.65262e-16,472.204,-12.7952)">
|
||||
<g>
|
||||
<path d="M44,66.88C54.906,66.88 63.88,57.906 63.88,47C63.88,36.094 54.906,27.12 44,27.12C33.094,27.12 24.12,36.094 24.12,47C24.131,57.902 33.098,66.869 44,66.88ZM42,62.74C37.914,62.223 34.185,60.135 31.61,56.92L37.67,52.92C38.832,54.175 40.338,55.062 42,55.47L42,62.74ZM46,62.74L46,55.46C47.653,55.082 49.159,54.227 50.33,53L56.39,57C53.801,60.185 50.074,62.244 46,62.74ZM58.06,39.65C60.332,43.951 60.484,49.072 58.47,53.5L52.34,49.5C52.582,48.689 52.707,47.847 52.71,47C52.712,45.831 52.474,44.673 52.01,43.6L58.06,39.65ZM46,31.26C49.762,31.74 53.23,33.554 55.77,36.37L49.63,40.37C48.581,39.483 47.337,38.856 46,38.54L46,31.26ZM48.71,47C48.71,49.584 46.584,51.71 44,51.71C41.416,51.71 39.29,49.584 39.29,47C39.29,44.416 41.416,42.29 44,42.29C46.582,42.295 48.705,44.418 48.71,47ZM42,31.26L42,38.53C40.664,38.854 39.421,39.484 38.37,40.37L32.23,36.37C34.77,33.554 38.238,31.74 42,31.26ZM36,43.6C35.536,44.673 35.298,45.831 35.3,47C35.304,47.843 35.429,48.682 35.67,49.49L29.53,53.49C27.53,49.059 27.681,43.945 29.94,39.64L36,43.6Z" style="fill-rule:nonzero;"/>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 3.5 KiB |
@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16"><g fill="#2e3436"><path d="M3 2C1.34 2 0 3.34 0 5v4c0 1.66 1.34 3 3 3h10c1.66 0 3-1.34 3-3V5c0-1.66-1.34-3-3-3zm0 2h10c.555 0 1 .445 1 1v4c0 .555-.445 1-1 1H3c-.555 0-1-.445-1-1V5c0-.555.445-1 1-1z"/><path fill-opacity=".5" d="M4 5h2v4H4zm3 0h2v4H7zm3 0h2v4h-2z"/><path d="M2 10h12v4H2z"/></g></svg>
|
||||
|
After Width: | Height: | Size: 362 B |
@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16"><g fill="#2e3436"><path fill-opacity=".349" d="M12 1a1 1 0 0 1 .707.293l3 3a1 1 0 0 1 0 1.414l-3 3a1 1 0 1 1-1.414-1.414L12.586 6H5c-.55 0-1-.45-1-1s.45-1 1-1h7.586l-1.293-1.293A1 1 0 0 1 12 1zm0 0"/><path d="M4 15a1 1 0 0 1-.707-.293l-3-3a1 1 0 0 1 0-1.414l3-3a1 1 0 1 1 1.414 1.414L3.414 10H11c.55 0 1 .45 1 1s-.45 1-1 1H3.414l1.293 1.293A1 1 0 0 1 4 15zm0 0"/></g></svg>
|
||||
|
After Width: | Height: | Size: 436 B |
@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16"><path fill="#2e3436" d="M12 1a1 1 0 0 0-.707 1.707L12.586 4H5c-.55 0-1 .45-1 1s.45 1 1 1h7.586l-1.293 1.293a1 1 0 1 0 1.414 1.414l3-3a1 1 0 0 0 0-1.414l-3-3A1 1 0 0 0 12 1zM4 7a.993.993 0 0 0-.707.293l-3 3a1 1 0 0 0 0 1.414l3 3a1 1 0 1 0 1.414-1.414L3.414 12H11c.55 0 1-.45 1-1s-.45-1-1-1H3.414l1.293-1.293A1 1 0 0 0 4 7zm0 0"/></svg>
|
||||
|
After Width: | Height: | Size: 397 B |
@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16"><g fill="#2e3436"><path d="M12 1a1 1 0 0 1 .707.293l3 3a1 1 0 0 1 0 1.414l-3 3a1 1 0 1 1-1.414-1.414L12.586 6H5c-.55 0-1-.45-1-1s.45-1 1-1h7.586l-1.293-1.293A1 1 0 0 1 12 1zm0 0"/><path fill-opacity=".349" d="M4 15a1 1 0 0 1-.707-.293l-3-3a1 1 0 0 1 0-1.414l3-3a1 1 0 1 1 1.414 1.414L3.414 10H11c.55 0 1 .45 1 1s-.45 1-1 1H3.414l1.293 1.293A1 1 0 0 1 4 15zm0 0"/></g></svg>
|
||||
|
After Width: | Height: | Size: 436 B |
@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16"><path fill="#2e3436" d="M4 0C2.355 0 1 1.355 1 3v10c0 1.645 1.355 3 3 3h8c1.645 0 3-1.355 3-3V3c0-1.645-1.355-3-3-3zm0 2h8c.57 0 1 .43 1 1v9c0 .57-.43 1-1 1H4c-.555 0-1-.445-1-1V3c0-.555.445-1 1-1zm4 1C5.79 3 4 4.79 4 7v4h4c2.5 0 4-1.79 4-4s-1.79-4-4-4zm0 2a2 2 0 1 1-2 2 2 2 0 0 1 2-2zm0 0"/></svg>
|
||||
|
After Width: | Height: | Size: 362 B |
@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16"><path fill="#2e3436" d="M3 0C1.34 0 0 1.34 0 3v7c0 1.66 1.34 3 3 3h10c1.66 0 3-1.34 3-3V3c0-1.66-1.34-3-3-3zm0 2h10c.555 0 1 .445 1 1v7c0 .555-.445 1-1 1H3c-.555 0-1-.445-1-1V3c0-.555.445-1 1-1zm2 12a2 2 0 0 0-2 2h10a2 2 0 0 0-2-2zm0 0"/></svg>
|
||||
|
After Width: | Height: | Size: 307 B |
@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16"><path fill="#2e3434" d="M8 0C6.338 0 5 1.338 5 3v6c0 .116.007.23.02.342A4 4 0 0 0 4 12a4 4 0 0 0 4 4 4 4 0 0 0 4-4 4 4 0 0 0-1.018-2.666A3.05 3.05 0 0 0 11 9V3c0-1.662-1.338-3-3-3zm0 2c.554 0 1 .446 1 1v1H8v1h1v1H8v1h1v1H8v1h1v1.27a2 2 0 0 1 .316.23 2 2 0 0 1 .082.082 2 2 0 0 1 .182.203 2 2 0 0 1 .08.117 2 2 0 0 1 .125.215 2 2 0 0 1 .063.135A2 2 0 0 1 10 12a2 2 0 0 1-2 2 2 2 0 0 1-2-2 2 2 0 0 1 .15-.732 2 2 0 0 1 .07-.155 2 2 0 0 1 .12-.205 2 2 0 0 1 .082-.119 2 2 0 0 1 .197-.219 2 2 0 0 1 .06-.06A2 2 0 0 1 7 10.277V3c0-.554.446-1 1-1zm0 9a1 1 0 0 0-1 1 1 1 0 0 0 1 1 1 1 0 0 0 1-1 1 1 0 0 0-1-1z"/></svg>
|
||||
|
After Width: | Height: | Size: 674 B |
@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16"><path d="M4 .004v3H2.977A1.97 1.97 0 0 0 1 4.977v2.05c0 .13.012.254.035.375A4.99 4.99 0 0 0 6 13.004 3.015 3.015 0 0 0 9 16h2c1.094 0 2-.906 2-2h1v2h2v-2c0-1.094-.906-2-2-2h-1c-1.094 0-2 .906-2 2H9c-.563 0-1-.434-1-.996a4.99 4.99 0 0 0 4.965-5.602A1.97 1.97 0 0 0 13 7.027v-2.05a1.97 1.97 0 0 0-1.977-1.973H10v-3H8v3H6v-3Zm0 0" style="stroke:none;fill-rule:nonzero;fill:#2e3434;fill-opacity:1"/></svg>
|
||||
|
After Width: | Height: | Size: 464 B |
@ -0,0 +1,8 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<svg width="16" height="16.001" xmlns="http://www.w3.org/2000/svg">
|
||||
<g fill="#474747">
|
||||
<path d="M5 5v2h6V5z" overflow="visible"/>
|
||||
<path d="M5.469 0c-.49 0-.797.216-1.032.456C4.202.696 4 1.012 4 1.486V2H2v14h12V2h-2v-.406l-.002-.028a1.616 1.616 0 0 0-.416-1.011c-.236-.28-.62-.585-1.2-.553L10.438 0zm.53 2h4v2h2v10H4V4h2z" color="#bebebe" font-family="sans-serif" font-weight="400" overflow="visible" style="font-feature-settings:normal;font-variant-alternates:normal;font-variant-caps:normal;font-variant-ligatures:normal;font-variant-numeric:normal;font-variant-position:normal;isolation:auto;mix-blend-mode:normal;shape-padding:0;text-decoration-color:#000;text-decoration-line:none;text-decoration-style:solid;text-indent:0;text-orientation:mixed;text-transform:none" white-space="normal"/>
|
||||
<path d="m5 8v2h6v-2zm0 3v2h6v-2z" overflow="visible"/>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 909 B |
|
Before Width: | Height: | Size: 2.6 KiB After Width: | Height: | Size: 2.6 KiB |
|
Before Width: | Height: | Size: 5.4 KiB After Width: | Height: | Size: 5.4 KiB |
@ -0,0 +1,15 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
|
||||
<svg width="100%" height="100%" viewBox="0 0 512 512" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xml:space="preserve" xmlns:serif="http://www.serif.com/" style="fill-rule:evenodd;clip-rule:evenodd;stroke-linejoin:round;stroke-miterlimit:2;">
|
||||
<g transform="matrix(3.38015e-16,5.5202,-5.5202,3.38015e-16,526.335,-21.2284)">
|
||||
<path d="M18,18L18,8L6,8L6,12L14,12L14,24L6,24L6,41.942L14,41.942L14,50.565L6,50.565L6,68.188L14,68.188L14,84L18,84L18,76L43,76L43,83C43.262,84.981 44.621,85.866 46.73,86L76.27,86C77.384,86 78.257,85.827 78.879,85.369C79.549,84.876 80,84.108 80,83L80,76L84.83,76C88.477,76.314 90.397,75.227 91.886,73.383C93.128,71.845 94.269,69.879 94,66.83L94,18L18,18ZM14,64.188L10,64.188L10,54.565L14,54.565L14,64.188ZM14,37.942L10,37.942L10,28L14,28L14,37.942ZM76,81.05C76,81.783 75.758,82.05 74.84,82.05L48.16,82.05C46.867,82.364 46.769,81.824 47,81.05L47,76L76,76L76,81.05ZM90,65.17C90.472,69.878 88.349,72.291 83.17,72L18,72L18,22L90,22L90,65.17Z" style="fill-rule:nonzero;"/>
|
||||
</g>
|
||||
<g transform="matrix(2.90206e-16,4.73942,-4.73942,2.90206e-16,491.213,161.673)">
|
||||
<path d="M44,66.88C54.906,66.88 63.88,57.906 63.88,47C63.88,36.094 54.906,27.12 44,27.12C33.094,27.12 24.12,36.094 24.12,47C24.131,57.902 33.098,66.869 44,66.88ZM42,62.74C37.914,62.223 34.185,60.135 31.61,56.92L37.67,52.92C38.832,54.175 40.338,55.062 42,55.47L42,62.74ZM46,62.74L46,55.46C47.653,55.082 49.159,54.227 50.33,53L56.39,57C53.801,60.185 50.074,62.244 46,62.74ZM58.06,39.65C60.332,43.951 60.484,49.072 58.47,53.5L52.34,49.5C52.582,48.689 52.707,47.847 52.71,47C52.712,45.831 52.474,44.673 52.01,43.6L58.06,39.65ZM46,31.26C49.762,31.74 53.23,33.554 55.77,36.37L49.63,40.37C48.581,39.483 47.337,38.856 46,38.54L46,31.26ZM48.71,47C48.71,49.584 46.584,51.71 44,51.71C41.416,51.71 39.29,49.584 39.29,47C39.29,44.416 41.416,42.29 44,42.29C46.582,42.295 48.705,44.418 48.71,47ZM42,31.26L42,38.53C40.664,38.854 39.421,39.484 38.37,40.37L32.23,36.37C34.77,33.554 38.238,31.74 42,31.26ZM36,43.6C35.536,44.673 35.298,45.831 35.3,47C35.304,47.843 35.429,48.682 35.67,49.49L29.53,53.49C27.53,49.059 27.681,43.945 29.94,39.64L36,43.6Z" style="fill-rule:nonzero;"/>
|
||||
</g>
|
||||
<g transform="matrix(2.65262e-16,4.33206,-4.33206,2.65262e-16,472.204,-12.7952)">
|
||||
<g>
|
||||
<path d="M44,66.88C54.906,66.88 63.88,57.906 63.88,47C63.88,36.094 54.906,27.12 44,27.12C33.094,27.12 24.12,36.094 24.12,47C24.131,57.902 33.098,66.869 44,66.88ZM42,62.74C37.914,62.223 34.185,60.135 31.61,56.92L37.67,52.92C38.832,54.175 40.338,55.062 42,55.47L42,62.74ZM46,62.74L46,55.46C47.653,55.082 49.159,54.227 50.33,53L56.39,57C53.801,60.185 50.074,62.244 46,62.74ZM58.06,39.65C60.332,43.951 60.484,49.072 58.47,53.5L52.34,49.5C52.582,48.689 52.707,47.847 52.71,47C52.712,45.831 52.474,44.673 52.01,43.6L58.06,39.65ZM46,31.26C49.762,31.74 53.23,33.554 55.77,36.37L49.63,40.37C48.581,39.483 47.337,38.856 46,38.54L46,31.26ZM48.71,47C48.71,49.584 46.584,51.71 44,51.71C41.416,51.71 39.29,49.584 39.29,47C39.29,44.416 41.416,42.29 44,42.29C46.582,42.295 48.705,44.418 48.71,47ZM42,31.26L42,38.53C40.664,38.854 39.421,39.484 38.37,40.37L32.23,36.37C34.77,33.554 38.238,31.74 42,31.26ZM36,43.6C35.536,44.673 35.298,45.831 35.3,47C35.304,47.843 35.429,48.682 35.67,49.49L29.53,53.49C27.53,49.059 27.681,43.945 29.94,39.64L36,43.6Z" style="fill-rule:nonzero;"/>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 3.5 KiB |
|
Before Width: | Height: | Size: 1.8 KiB After Width: | Height: | Size: 1.8 KiB |
|
Before Width: | Height: | Size: 936 B After Width: | Height: | Size: 936 B |
|
Before Width: | Height: | Size: 864 B After Width: | Height: | Size: 864 B |
|
Before Width: | Height: | Size: 934 B After Width: | Height: | Size: 934 B |
|
Before Width: | Height: | Size: 367 B After Width: | Height: | Size: 367 B |
|
Before Width: | Height: | Size: 298 B After Width: | Height: | Size: 298 B |
|
Before Width: | Height: | Size: 2.1 KiB After Width: | Height: | Size: 2.1 KiB |
|
Before Width: | Height: | Size: 3.8 KiB After Width: | Height: | Size: 3.8 KiB |
@ -21,18 +21,18 @@ export const MenuItem = GObject.registerClass({
|
||||
this._gIcon = icon;
|
||||
|
||||
// add icon
|
||||
this.add(new St.Icon({ style_class: 'popup-menu-icon', gicon : this._gIcon }));
|
||||
this.add_child(new St.Icon({ style_class: 'popup-menu-icon', gicon : this._gIcon }));
|
||||
|
||||
// add label
|
||||
this._labelActor = new St.Label({ text: label });
|
||||
this.add(this._labelActor);
|
||||
this.add_child(this._labelActor);
|
||||
|
||||
// add value
|
||||
this._valueLabel = new St.Label({ text: value });
|
||||
this._valueLabel.set_x_align(Clutter.ActorAlign.END);
|
||||
this._valueLabel.set_x_expand(true);
|
||||
this._valueLabel.set_y_expand(true);
|
||||
this.add(this._valueLabel);
|
||||
this.add_child(this._valueLabel);
|
||||
|
||||
this.actor._delegate = this;
|
||||
}
|
||||
|
||||
@ -1,13 +1,17 @@
|
||||
{
|
||||
"_generated": "Generated by SweetTooth, do not edit",
|
||||
"description": "A glimpse into your computer's temperature, voltage, fan speed, memory usage, processor load, system resources, network speed and storage stats. This is a one stop shop to monitor all of your vital sensors. Uses asynchronous polling to provide a smooth user experience. Feature requests or bugs? Please use GitHub.",
|
||||
"donations": {
|
||||
"paypal": "corecoding"
|
||||
},
|
||||
"gettext-domain": "vitals",
|
||||
"name": "Vitals",
|
||||
"settings-schema": "org.gnome.shell.extensions.vitals",
|
||||
"shell-version": [
|
||||
"45"
|
||||
"45",
|
||||
"46"
|
||||
],
|
||||
"url": "https://github.com/corecoding/Vitals",
|
||||
"uuid": "Vitals@CoreCoding.com",
|
||||
"version": 63
|
||||
"version": 66
|
||||
}
|
||||
@ -48,7 +48,8 @@ const Settings = new GObject.Class({
|
||||
'show-network', 'show-storage', 'use-higher-precision',
|
||||
'alphabetize', 'hide-zeros', 'include-public-ip',
|
||||
'show-battery', 'fixed-widths', 'hide-icons',
|
||||
'menu-centered', 'include-static-info' ];
|
||||
'menu-centered', 'include-static-info',
|
||||
'show-gpu', 'include-static-gpu-info' ];
|
||||
|
||||
for (let key in sensors) {
|
||||
let sensor = sensors[key];
|
||||
@ -61,7 +62,7 @@ const Settings = new GObject.Class({
|
||||
}
|
||||
|
||||
// process individual drop down sensor preferences
|
||||
sensors = [ 'position-in-panel', 'unit', 'network-speed-format', 'memory-measurement', 'storage-measurement', 'battery-slot' ];
|
||||
sensors = [ 'position-in-panel', 'unit', 'network-speed-format', 'memory-measurement', 'storage-measurement', 'battery-slot', 'icon-style' ];
|
||||
for (let key in sensors) {
|
||||
let sensor = sensors[key];
|
||||
|
||||
@ -90,7 +91,7 @@ const Settings = new GObject.Class({
|
||||
}
|
||||
|
||||
// makes individual sensor preference boxes appear
|
||||
sensors = [ 'temperature', 'network', 'storage', 'memory', 'battery', 'system', 'processor' ];
|
||||
sensors = [ 'temperature', 'network', 'storage', 'memory', 'battery', 'system', 'processor', 'gpu' ];
|
||||
for (let key in sensors) {
|
||||
let sensor = sensors[key];
|
||||
|
||||
|
||||
@ -136,5 +136,20 @@
|
||||
<summary>Include processor static information</summary>
|
||||
<description>Display processor static information that doesn't change</description>
|
||||
</key>
|
||||
<key type="b" name="show-gpu">
|
||||
<default>false</default>
|
||||
<summary>Monitor GPU</summary>
|
||||
<description>Display GPU information (requires the nvidia-smi tool)</description>
|
||||
</key>
|
||||
<key type="b" name="include-static-gpu-info">
|
||||
<default>false</default>
|
||||
<summary>Include GPU static information</summary>
|
||||
<description>Display GPU static information that doesn't change</description>
|
||||
</key>
|
||||
<key type="i" name="icon-style">
|
||||
<default>0</default>
|
||||
<summary>Icon styles</summary>
|
||||
<description>Set the style for the displayed sensor icons ('original', 'updated')</description>
|
||||
</key>
|
||||
</schema>
|
||||
</schemalist>
|
||||
|
||||
@ -25,6 +25,7 @@
|
||||
*/
|
||||
|
||||
import GObject from 'gi://GObject';
|
||||
import * as SubProcessModule from './helpers/subprocess.js';
|
||||
import * as FileModule from './helpers/file.js';
|
||||
import { gettext as _ } from 'resource:///org/gnome/shell/extensions/extension.js';
|
||||
import NM from 'gi://NM';
|
||||
@ -48,6 +49,15 @@ export const Sensors = GObject.registerClass({
|
||||
|
||||
this._last_processor = { 'core': {}, 'speed': [] };
|
||||
|
||||
this._settingChangedSignals = [];
|
||||
this._addSettingChangedSignal('show-gpu', this._reconfigureNvidiaSmiProcess.bind(this));
|
||||
this._addSettingChangedSignal('update-time', this._reconfigureNvidiaSmiProcess.bind(this));
|
||||
//this._addSettingChangedSignal('include-static-gpu-info', this._reconfigureNvidiaSmiProcess.bind(this));
|
||||
|
||||
this._nvidia_smi_process = null;
|
||||
this._nvidia_labels = [];
|
||||
this._bad_split_count = 0;
|
||||
|
||||
if (hasGTop) {
|
||||
this.storage = new GTop.glibtop_fsusage();
|
||||
this._storageDevice = '';
|
||||
@ -58,6 +68,10 @@ export const Sensors = GObject.registerClass({
|
||||
}
|
||||
}
|
||||
|
||||
_addSettingChangedSignal(key, callback) {
|
||||
this._settingChangedSignals.push(this._settings.connect('changed::' + key, callback));
|
||||
}
|
||||
|
||||
_refreshIPAddress(callback) {
|
||||
// check IP address
|
||||
new FileModule.File('https://corecoding.com/vitals.php').read().then(contents => {
|
||||
@ -473,6 +487,166 @@ export const Sensors = GObject.registerClass({
|
||||
}).catch(err => { });
|
||||
}
|
||||
|
||||
_queryGpu(callback) {
|
||||
if (!this._nvidia_smi_process) {
|
||||
this._disableGpuLabels(callback);
|
||||
return;
|
||||
}
|
||||
|
||||
this._nvidia_smi_process.read('\n').then(lines => {
|
||||
/// for debugging multi-gpu on systems with only one gpu
|
||||
/// duplicates the first gpu's data 3 times, for 4 total gpus
|
||||
///if(lines.length == 0) return;
|
||||
///for(let _gpuNum = 1; _gpuNum <= 3; _gpuNum++)
|
||||
/// lines.push(lines[0]);
|
||||
|
||||
for (let i = 0; i < lines.length; i++) {
|
||||
this._parseNvidiaSmiLine(callback, lines[i], i + 1, lines.length > 1);
|
||||
}
|
||||
|
||||
|
||||
// if we've already updated the static info during the last parse, then stop doing so.
|
||||
// this is so the _parseNvidiaSmiLine function won't return static info anymore
|
||||
// and the nvidia-smi commmand won't be queried for static info either
|
||||
if(!this._nvidia_static_returned) {
|
||||
this._nvidia_static_returned = true;
|
||||
//reconfigure the process to stop querying static info
|
||||
this._reconfigureNvidiaSmiProcess();
|
||||
}
|
||||
}).catch(err => {
|
||||
this._disableGpuLabels(callback);
|
||||
this._terminateNvidiaSmiProcess();
|
||||
});
|
||||
}
|
||||
|
||||
_parseNvidiaSmiLine(callback, csv, gpuNum, multiGpu) {
|
||||
const expectedSplitLength = 19;
|
||||
let csv_split = csv.split(',');
|
||||
|
||||
// occasionally the nvidia-smi command can get cut off before it can be fully read, thus the parse function only gets part of a line
|
||||
// hence we count the number of bad splits and only terminate the process after a few bad splits in a row
|
||||
// this prevents anomalous readings from terminating the process
|
||||
if (csv_split.length < expectedSplitLength) {
|
||||
this._bad_split_count++;
|
||||
//if we've had 2 bad splits/reads in a row, try to restart the process
|
||||
if (this._bad_split_count == 2) this._reconfigureNvidiaSmiProcess();
|
||||
//if we still get a bad read after that, then it's not an anomaly; terminate the process
|
||||
else if (this._bad_split_count >= 3) this._terminateNvidiaSmiProcess();
|
||||
return;
|
||||
}
|
||||
this._bad_split_count = 0;
|
||||
|
||||
let [
|
||||
label,
|
||||
fan_speed_pct,
|
||||
temp_gpu, temp_mem,
|
||||
mem_total, mem_used, mem_reserved, mem_free,
|
||||
util_gpu, util_mem, util_encoder, util_decoder,
|
||||
clock_gpu, clock_mem, clock_encode_decode,
|
||||
power, power_avg,
|
||||
link_gen_current, link_width_current
|
||||
] = csv_split;
|
||||
|
||||
const staticNames = [
|
||||
'temp_limit', 'power_limit',
|
||||
'link_gen_max', 'link_width_max',
|
||||
'addressing_mode',
|
||||
'driver_version', 'vbios', 'serial',
|
||||
'domain_num', 'bus_num', 'device_num', 'device_id', 'sub_device_id'
|
||||
];
|
||||
let staticInfo = {};
|
||||
|
||||
// if we have queried static info this time around, populate our static info object
|
||||
if(csv_split.length == (expectedSplitLength + staticNames.length)){
|
||||
for(let i = 0; i < staticNames.length; i++) {
|
||||
//set the static info to a default (0) if it's undefined
|
||||
const value = csv_split[expectedSplitLength + i];
|
||||
staticInfo[staticNames[i]] = (typeof value !== "undefined") ? value : 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
const typeName = 'gpu#' + gpuNum;
|
||||
const globalLabel = 'GPU' + (multiGpu ? ' ' + gpuNum : '');
|
||||
|
||||
const memTempValid = !isNaN(parseInt(temp_mem));
|
||||
|
||||
|
||||
this._returnGpuValue(callback, 'Graphics', parseInt(util_gpu) * 0.01, typeName + '-group', 'percent');
|
||||
|
||||
this._returnGpuValue(callback, 'Name', label, typeName, '');
|
||||
|
||||
this._returnGpuValue(callback, globalLabel, parseInt(fan_speed_pct) * 0.01, 'fan', 'percent');
|
||||
this._returnGpuValue(callback, 'Fan', parseInt(fan_speed_pct) * 0.01, typeName, 'percent');
|
||||
|
||||
this._returnGpuValue(callback, globalLabel, parseInt(temp_gpu) * 1000, 'temperature', 'temp');
|
||||
this._returnGpuValue(callback, 'Temperature', parseInt(temp_gpu) * 1000, typeName, 'temp');
|
||||
this._returnGpuValue(callback, 'Memory Temperature', parseInt(temp_mem) * 1000, typeName, 'temp', memTempValid);
|
||||
this._returnStaticGpuValue(callback, 'Temperature Limit', parseInt(staticInfo['temp_limit']) * 1000, typeName, 'temp');
|
||||
|
||||
this._returnGpuValue(callback, 'Memory Usage', parseInt(mem_used) / parseInt(mem_total), typeName, 'percent');
|
||||
this._returnGpuValue(callback, 'Memory Total', parseInt(mem_total) * 1000, typeName, 'memory');
|
||||
this._returnGpuValue(callback, 'Memory Used', parseInt(mem_used) * 1000, typeName, 'memory');
|
||||
this._returnGpuValue(callback, 'Memory Reserved', parseInt(mem_reserved) * 1000, typeName, 'memory');
|
||||
this._returnGpuValue(callback, 'Memory Free', parseInt(mem_free) * 1000, typeName, 'memory');
|
||||
|
||||
this._returnGpuValue(callback, 'Memory Utilization', parseInt(util_mem) * 0.01, typeName, 'percent');
|
||||
this._returnGpuValue(callback, 'Utilization', parseInt(util_gpu) * 0.01, typeName, 'percent');
|
||||
this._returnGpuValue(callback, 'Encoder Utilization', parseInt(util_encoder) * 0.01, typeName, 'percent');
|
||||
this._returnGpuValue(callback, 'Decoder Utilization', parseInt(util_decoder) * 0.01, typeName, 'percent');
|
||||
|
||||
this._returnGpuValue(callback, 'Frequency', parseInt(clock_gpu) * 1000 * 1000, typeName, 'hertz');
|
||||
this._returnGpuValue(callback, 'Memory Frequency', parseInt(clock_mem) * 1000 * 1000, typeName, 'hertz');
|
||||
this._returnGpuValue(callback, 'Encoder/Decoder Frequency', parseInt(clock_encode_decode) * 1000 * 1000, typeName, 'hertz');
|
||||
|
||||
//this._returnGpuValue(callback, 'Encoder Sessions', parseInt(encoder_sessions), typeName, 'string');
|
||||
|
||||
this._returnGpuValue(callback, 'Power', power, typeName, 'watt-gpu');
|
||||
this._returnGpuValue(callback, 'Average Power', power_avg, typeName, 'watt-gpu');
|
||||
this._returnStaticGpuValue(callback, 'Power Limit', parseInt(staticInfo['power_limit']), typeName, 'watt-gpu');
|
||||
|
||||
this._returnGpuValue(callback, 'Link Speed', link_gen_current + 'x' + link_width_current, typeName, 'pcie');
|
||||
this._returnStaticGpuValue(callback, 'Maximum Link Speed', staticInfo['link_gen_max'] + 'x' + staticInfo['link_width_max'], typeName, 'pcie');
|
||||
|
||||
this._returnStaticGpuValue(callback, 'Addressing Mode', staticInfo['addressing_mode'], typeName, 'string');
|
||||
|
||||
this._returnStaticGpuValue(callback, 'Driver Version', staticInfo['driver_version'], typeName, 'string');
|
||||
this._returnStaticGpuValue(callback, 'vBIOS Version', staticInfo['vbios'], typeName, 'string');
|
||||
this._returnStaticGpuValue(callback, 'Serial Number', staticInfo['serial'], typeName, 'string');
|
||||
|
||||
this._returnStaticGpuValue(callback, 'Domain Number', staticInfo['domain_num'], typeName, 'string');
|
||||
this._returnStaticGpuValue(callback, 'Bus Number', staticInfo['bus_num'], typeName, 'string');
|
||||
this._returnStaticGpuValue(callback, 'Device Number', staticInfo['device_num'], typeName, 'string');
|
||||
this._returnStaticGpuValue(callback, 'Device ID', staticInfo['device_id'], typeName, 'string');
|
||||
this._returnStaticGpuValue(callback, 'Sub Device ID', staticInfo['sub_device_id'], typeName, 'string');
|
||||
}
|
||||
|
||||
_disableGpuLabels(callback) {
|
||||
for (let labelObj of this._nvidia_labels)
|
||||
this._returnValue(callback, labelObj.label, 'disabled', labelObj.type, labelObj.format);
|
||||
}
|
||||
|
||||
_returnStaticGpuValue(callback, label, value, type, format) {
|
||||
//if we've already tried to return existing static info before or if the option isn't enabled, then do nothing.
|
||||
if (this._nvidia_static_returned || !this._settings.get_boolean('include-static-gpu-info'))
|
||||
return;
|
||||
|
||||
//we don't need to disable static info labels, so just use ordinary returnValue function
|
||||
this._returnValue(callback, label, value, type, format);
|
||||
}
|
||||
|
||||
_returnGpuValue(callback, label, value, type, format, display = true) {
|
||||
if(!display) return;
|
||||
|
||||
if(value === 'N/A' || value === '[N/A]' || isNaN(value)) return;
|
||||
|
||||
let nvidiaLabel = {'label': label, 'type': type, 'format': format};
|
||||
if (!this._nvidia_labels.includes(nvidiaLabel))
|
||||
this._nvidia_labels.push(nvidiaLabel);
|
||||
|
||||
this._returnValue(callback, label, value, type, format);
|
||||
}
|
||||
|
||||
_returnValue(callback, label, value, type, format) {
|
||||
// don't return if value is not a number - will revisit later
|
||||
//if (isNaN(value)) return;
|
||||
@ -564,6 +738,74 @@ export const Sensors = GObject.registerClass({
|
||||
this._returnValue(callback, 'Kernel', kernelArray[2], 'system', 'string');
|
||||
}).catch(err => { });
|
||||
}
|
||||
|
||||
// Launch nvidia-smi subprocess if nvidia querying is enabled
|
||||
this._reconfigureNvidiaSmiProcess();
|
||||
}
|
||||
|
||||
// The nvidia-smi subprocess will keep running and print new sensor data to stdout every
|
||||
// `update_time` seconds. _queryNvidiaSmi() will be called at roughly the same interval and
|
||||
// read from the subprocess's stdout to get new sensor data.
|
||||
|
||||
// Regarding "keeping main process & sub process in sync", there are two possible scenarios:
|
||||
// - For some reason, nvidia-smi prints at a somewhat higher frequency than we call
|
||||
// _queryNvidiaSmi() to read data. This is okay, eventually one call to _queryNvidiaSmi()
|
||||
// will read two sensor data updates in a single call.
|
||||
// - For some reason, _queryNvidiaSmi() is called at a somewhat higher frequency than
|
||||
// nvidia-smi prints data. This is the more likely scenario with user actions triggering
|
||||
// additional reads. This eventually triggers an "IO PENDING" error while attempting to
|
||||
// read, because the previous async read is still waiting. To solve this, the subprocess
|
||||
// module simply ignores PENDING errors. After ignoring the error, the earlier read will
|
||||
// eventually return and sensor data will be updated, so this scenario is handled correctly.
|
||||
|
||||
// Generally speaking, the call to _queryNvidiaSmi() and nvidia-smi's printing to stdout do
|
||||
// not happen at the same time. So the async call in _queryNvidiaSmi() will usually have to
|
||||
// wait up to `update_time` seconds before getting any results and reporting them through the
|
||||
// callback.
|
||||
_reconfigureNvidiaSmiProcess() {
|
||||
if (this._settings.get_boolean('show-gpu')) {
|
||||
this._terminateNvidiaSmiProcess();
|
||||
|
||||
try {
|
||||
let update_time = this._settings.get_int('update-time');
|
||||
let query_interval = Math.max(update_time, 1);
|
||||
let command = [
|
||||
'nvidia-smi',
|
||||
'--query-gpu=name,' +
|
||||
'fan.speed,' +
|
||||
'temperature.gpu,temperature.memory,' +
|
||||
'memory.total,memory.used,memory.reserved,memory.free,' +
|
||||
'utilization.gpu,utilization.memory,utilization.encoder,utilization.decoder,' +
|
||||
'clocks.gr,clocks.mem,clocks.video,' +
|
||||
'power.draw.instant,power.draw.average,' +
|
||||
'pcie.link.gen.gpucurrent,pcie.link.width.current,' +
|
||||
(!this._nvidia_static_returned && this._settings.get_boolean('include-static-gpu-info') ?
|
||||
'temperature.gpu.tlimit,' +
|
||||
'power.limit,' +
|
||||
'pcie.link.gen.max,pcie.link.width.max,' +
|
||||
'addressing_mode,'+
|
||||
'driver_version,vbios_version,serial,' +
|
||||
'pci.domain,pci.bus,pci.device,pci.device_id,pci.sub_device_id,'
|
||||
: ''),
|
||||
'--format=csv,noheader,nounits',
|
||||
'-l', query_interval.toString()
|
||||
];
|
||||
|
||||
this._nvidia_smi_process = new SubProcessModule.SubProcess(command);
|
||||
} catch(e) {
|
||||
// proprietary nvidia driver not installed
|
||||
this._terminateNvidiaSmiProcess();
|
||||
}
|
||||
} else {
|
||||
this._terminateNvidiaSmiProcess();
|
||||
}
|
||||
}
|
||||
|
||||
_terminateNvidiaSmiProcess() {
|
||||
if (this._nvidia_smi_process) {
|
||||
this._nvidia_smi_process.terminate();
|
||||
this._nvidia_smi_process = null;
|
||||
}
|
||||
}
|
||||
|
||||
_processTempVoltFan(callback, sensor_types, name, path, file) {
|
||||
@ -664,8 +906,18 @@ export const Sensors = GObject.registerClass({
|
||||
resetHistory() {
|
||||
this._next_public_ip_check = 0;
|
||||
this._hardware_detected = false;
|
||||
this._nvidia_static_returned = false;
|
||||
this._processor_uses_cpu_info = true;
|
||||
this._battery_time_left_history = [];
|
||||
this._battery_charge_status = '';
|
||||
this._nvidia_labels = [];
|
||||
this._bad_split_count = 0;
|
||||
}
|
||||
|
||||
destroy() {
|
||||
this._terminateNvidiaSmiProcess();
|
||||
|
||||
for (let signal of Object.values(this._settingChangedSignals))
|
||||
this._settings.disconnect(signal);
|
||||
}
|
||||
});
|
||||
|
||||
@ -190,6 +190,10 @@ export const Values = GObject.registerClass({
|
||||
value = value / 1000000;
|
||||
ending = 'W';
|
||||
break;
|
||||
case 'watt-gpu':
|
||||
format = (use_higher_precision)?'%.2f %s':'%.1f %s';
|
||||
ending = 'W';
|
||||
break;
|
||||
case 'watt-hour':
|
||||
format = (use_higher_precision)?'%.2f %s':'%.1f %s';
|
||||
value = value / 1000000;
|
||||
@ -198,6 +202,11 @@ export const Values = GObject.registerClass({
|
||||
case 'load':
|
||||
format = (use_higher_precision)?'%.2f %s':'%.1f %s';
|
||||
break;
|
||||
case 'pcie':
|
||||
let split = value.split('x');
|
||||
value = 'PCIe ' + parseInt(split[0]) + (split.length > 1 ? ' x' + parseInt(split[1]) : '');
|
||||
format = '%s';
|
||||
break;
|
||||
default:
|
||||
format = '%s';
|
||||
break;
|
||||
@ -324,14 +333,22 @@ export const Values = GObject.registerClass({
|
||||
return output;
|
||||
}
|
||||
|
||||
resetHistory() {
|
||||
resetHistory(numGpus) {
|
||||
// don't call this._history = {}, as we want to keep network-rx and network-tx
|
||||
// otherwise network history statistics will start over
|
||||
for (let sensor in this._sensorIcons) {
|
||||
//each gpu has it's own sensor name and thus must be handled separately
|
||||
if(sensor === 'gpu') continue;
|
||||
|
||||
this._history[sensor] = {};
|
||||
this._history[sensor + '-group'] = {};
|
||||
//this._history2[sensor] = {};
|
||||
//this._history2[sensor + '-group'] = {};
|
||||
}
|
||||
|
||||
for(let i = 1; i <= numGpus; i++){
|
||||
this._history['gpu#' + i] = {};
|
||||
this._history['gpu#' + i + '-group'] = {};
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||