diff --git a/extension.js b/extension.js index 8769581..5373c55 100644 --- a/extension.js +++ b/extension.js @@ -34,6 +34,8 @@ var VitalsMenuButton = GObject.registerClass({ // item must match the index on the combo box this._sensorsIconPathPrefix = ['/icons/original/', '/icons/gnome/']; + // mapping of hwmon devices to labels + this._sensorsLabels = new Map(); this._sensorMenuItems = {}; this._hotLabels = {}; this._hotItems = {}; @@ -44,7 +46,7 @@ var VitalsMenuButton = GObject.registerClass({ this._newGpuDetectedCount = 0; this._last_query = new Date().getTime(); - this._sensors = new Sensors.Sensors(this._settings, this._sensorIcons); + this._sensors = new Sensors.Sensors(this._settings, this._sensorIcons, this._sensorsLabels); this._values = new Values.Values(this._settings, this._sensorIcons); this._menuLayout = new St.BoxLayout({ vertical: false, @@ -67,10 +69,64 @@ var VitalsMenuButton = GObject.registerClass({ // start off with fresh sensors this._querySensors(); + // associate sensors with labels + this._parseSensorsLabelMap(); + // start monitoring sensors this._initializeTimer(); } + // parse the user mapping for sensor labels and + // returns a map of maps. first level keys contain + // hwmon device and second level keys contain feature ids, + // second level values contain user defined labels + _parseSensorsLabelMap() { + let proc; + try { + const launcher = new Gio.SubprocessLauncher({ + flags: Gio.SubprocessFlags.STDOUT_PIPE | Gio.SubprocessFlags.STDERR_PIPE + }); + launcher.setenv("LD_LIBRARY_PATH", "/data/projects/experiments/lm-sensors/lib", false); + proc = launcher.spawnv(["/data/projects/experiments/lm-sensors/prog/sensors/sensors", "--label-map"]); + } catch (e) { + console.error("Failed to get sensors mapping from 'sensors --label-map'"); + throw(e); + } + let success, stdout; + try { + [success, stdout] = proc.communicate_utf8(null, null); + } catch (e) { + console.error("Failed to get sensors mapping from 'sensors --label-map'"); + throw(e); + } + + const chip_re = /^\s*chip\s+"(.*)"\s+\#\s+\/sys\/class\/hwmon\/hwmon(\d+)/; + const label_re = /^\s*label\s+(\w+)\s+(?:"(.*)"|(.*))/; + const ignore_re = /^\s*ignore\s+(\w+)/; + + let key = null; + for (const line of stdout.split(/\r?\n/)) { + const chip_match = line.match(chip_re); + if (chip_match) { + const current_chip = chip_match[1]; + const hwmon_device = `hwmon${chip_match[2]}`; + key = hwmon_device; + if (!this._sensorsLabels.has(key)) + this._sensorsLabels.set(key, new Map()); + continue; + } + const label_match = line.match(label_re); + if (label_match && key) { + this._sensorsLabels.get(key).set(label_match[1], label_match[2] ?? label_match[3]); + continue; + } + const ignore_match = line.match(ignore_re); + if (ignore_match && key) { + this._sensorsLabels.get(key).set(ignore_match[1], ""); + } + } + } + _connectSettingsSignals() { this._settings.connectObject( 'changed::update-time', this._initializeTimer.bind(this), diff --git a/prefs.js b/prefs.js index 341194f..8e6cb4d 100644 --- a/prefs.js +++ b/prefs.js @@ -509,17 +509,80 @@ const Settings = new GObject.Class({ }); +function prefsPageNames() { + return ['general'].concat(Object.keys(sensorCatalog)); +} + +// AdwViewSwitcherSidebar landed in libadwaita 1.9 (GNOME 49+). +function supportsSidebarPrefs() { + return typeof Adw.ViewSwitcherSidebar === 'function'; +} + export default class VitalsPrefs extends ExtensionPreferences { fillPreferencesWindow(window) { window._settings = this.getSettings(); + + let settings = new Settings(this); + if (supportsSidebarPrefs()) + this._fillSidebarPreferences(window, settings); + else + this._fillClassicPreferences(window, settings); + } + + _fillClassicPreferences(window, settings) { + for (let name of prefsPageNames()) + window.add(settings.builder.get_object(name + '-page')); + + let loadVisible = () => { + let visible = window.visible_page; + if (visible && visible.name) + settings.ensure_threshold_colors_for_page(visible.name); + }; + window.connect('notify::visible-page', loadVisible); + loadVisible(); + } + + _fillSidebarPreferences(window, settings) { window.set_search_enabled(false); window.set_default_size(720, 620); - let settings = new Settings(this); - let root = settings.builder.get_object('prefs-root'); - let stack = settings.builder.get_object('prefs-stack'); - let sidebar = settings.builder.get_object('prefs-sidebar'); - let contentPage = settings.builder.get_object('prefs-content-page'); + let stack = new Adw.ViewStack({ + vexpand: true, + hexpand: true, + }); + let sidebar = new Adw.ViewSwitcherSidebar({ + stack, + mode: Adw.SidebarMode.SIDEBAR, + }); + + let sidebarToolbar = new Adw.ToolbarView(); + sidebarToolbar.add_top_bar(new Adw.HeaderBar({ + show_end_title_buttons: false, + })); + sidebarToolbar.set_content(sidebar); + + let contentToolbar = new Adw.ToolbarView(); + contentToolbar.add_top_bar(new Adw.HeaderBar({ + show_start_title_buttons: false, + })); + contentToolbar.set_content(stack); + + let contentPage = new Adw.NavigationPage({ + title: _('General'), + child: contentToolbar, + }); + let root = new Adw.NavigationSplitView({ + vexpand: true, + hexpand: true, + min_sidebar_width: 220, + max_sidebar_width: 320, + sidebar_width_fraction: 0.28, + sidebar: new Adw.NavigationPage({ + title: _('Vitals'), + child: sidebarToolbar, + }), + content: contentPage, + }); // Replace PreferencesWindow's bottom-tab navigation with a Settings-style sidebar. window.get_content().set_child(root); diff --git a/prefs.ui b/prefs.ui index c8d1c19..c9bb2b7 100644 --- a/prefs.ui +++ b/prefs.ui @@ -1,7 +1,7 @@ - + 1 @@ -603,53 +603,4 @@ - - - - True - True - 220 - 320 - 0.28 - - - Vitals - - - - - False - - - - - prefs-stack - sidebar - - - - - - - - - General - - - - - False - - - - - True - True - - - - - - - diff --git a/sensors.js b/sensors.js index 8c30393..aced8c9 100644 --- a/sensors.js +++ b/sensors.js @@ -41,9 +41,10 @@ try { export const Sensors = GObject.registerClass({ GTypeName: 'Sensors', }, class Sensors extends GObject.Object { - _init(settings, sensorIcons) { + _init(settings, sensorIcons, sensorsLabels) { this._settings = settings; this._sensorIcons = sensorIcons; + this._sensorsLabels = sensorsLabels; this.resetHistory(); @@ -1013,15 +1014,16 @@ export const Sensors = GObject.registerClass({ continue; new FileModule.File(obj['input']).read().then(value => { - let extra = (obj['label'].indexOf('_label')==-1) ? ' ' + obj['input'].substr(obj['input'].lastIndexOf('/')+1).split('_')[0] : ''; + let feature = obj['input'].substr(obj['input'].lastIndexOf('/')+1).split('_')[0]; + let extra = (obj['label'].indexOf('_label')==-1) ? ' ' + feature : ''; if (value > 0 || !this._settings.get_boolean('hide-zeros') || obj['type'] == 'fan') { new FileModule.File(obj['label']).read().then(label => { - this._addTempVoltFan(callback, obj, name, label, extra, value); + this._addTempVoltFan(callback, obj, file, feature, name, label, extra, value); }).catch(err => { let tmpFile = obj['label'].substr(0, obj['label'].lastIndexOf('/')) + '/name'; new FileModule.File(tmpFile).read().then(label => { - this._addTempVoltFan(callback, obj, name, label, extra, value); + this._addTempVoltFan(callback, obj, file, feature, name, label, extra, value); }).catch(err => { }); }); } @@ -1030,22 +1032,28 @@ export const Sensors = GObject.registerClass({ }).catch(err => { }); } - _addTempVoltFan(callback, obj, name, label, extra, value) { - // prepend module that provided sensor data - if (name != label) label = name + ' ' + label; + _addTempVoltFan(callback, obj, file, feature, name, label, extra, value) { + // // prepend module that provided sensor data + // if (name != label) label = name + ' ' + label; - //if (label == 'nvme Composite') label = 'NVMe'; - //if (label == 'nouveau') label = 'Nvidia'; + // //if (label == 'nvme Composite') label = 'NVMe'; + // //if (label == 'nouveau') label = 'Nvidia'; - label = label + extra; + // label = label + extra; - // in the future we will read /etc/sensors3.conf - if (label == 'acpitz temp1') label = 'ACPI Thermal Zone'; - if (label == 'pch_cannonlake temp1') label = 'Platform Controller Hub'; - if (label == 'iwlwifi_1 temp1') label = 'Wireless Adapter'; - if (label == 'Package id 0') label = 'Processor 0'; - if (label == 'Package id 1') label = 'Processor 1'; - label = label.replace('Package id', 'CPU'); + // // in the future we will read /etc/sensors3.conf + // if (label == 'acpitz temp1') label = 'ACPI Thermal Zone'; + // if (label == 'pch_cannonlake temp1') label = 'Platform Controller Hub'; + // if (label == 'iwlwifi_1 temp1') label = 'Wireless Adapter'; + // if (label == 'Package id 0') label = 'Processor 0'; + // if (label == 'Package id 1') label = 'Processor 1'; + // label = label.replace('Package id', 'CPU'); + + if (this._sensorsLabels.has(file) && this._sensorsLabels.get(file).has(feature)) { + label = this._sensorsLabels.get(file).get(feature); + if (label.length == 0) + return; + } let types = [ 'temperature', 'voltage', 'fan' ]; for (let type of types) {