From 33ed066dcea9ac0688d34bef5df4198531e61696 Mon Sep 17 00:00:00 2001 From: diego Date: Sat, 10 Dec 2022 19:29:35 +0100 Subject: [PATCH 01/14] Adding battery monitoring support --- extension.js | 4 + icons/bat-icon.svg | 125 +++++++++ lib/battery.js | 262 ++++++++++++++++++ metadata.json | 8 +- schemas/gschemas.compiled | Bin 918 -> 1173 bytes ....gnome.shell.extensions.tophat.gschema.xml | 20 ++ stylesheet.css | 12 + 7 files changed, 427 insertions(+), 4 deletions(-) create mode 100644 icons/bat-icon.svg create mode 100644 lib/battery.js diff --git a/extension.js b/extension.js index 755e3db..12153c8 100644 --- a/extension.js +++ b/extension.js @@ -30,12 +30,14 @@ let GTop = null; let Cpu = null; let Mem = null; let Net = null; +let Bat = null; try { // eslint-disable-next-line no-unused-vars GTop = imports.gi.GTop; Cpu = Me.imports.lib.cpu; Mem = Me.imports.lib.mem; Net = Me.imports.lib.net; + Bat = Me.imports.lib.battery; } catch (err) { log(`[${Me.metadata.name}] Error loading dependencies: ${err}`); depFailures.push(err); @@ -64,9 +66,11 @@ class TopHat { this.cpu = new Cpu.CpuMonitor(this.configHandler); this.mem = new Mem.MemMonitor(this.configHandler); this.net = new Net.NetMonitor(this.configHandler); + this.bat = new Bat.PowerMonitor(this.configHandler); this.container.addMonitor(this.cpu); this.container.addMonitor(this.mem); this.container.addMonitor(this.net); + this.container.addMonitor(this.bat); this.configHandler.settings.connect('changed::position-in-panel', () => { this.moveWithinPanel(); }); diff --git a/icons/bat-icon.svg b/icons/bat-icon.svg new file mode 100644 index 0000000..8300cb9 --- /dev/null +++ b/icons/bat-icon.svg @@ -0,0 +1,125 @@ + + + + + + + + image/svg+xml + + Gnome Symbolic Icon Theme + + + + + + + Gnome Symbolic Icon Theme + + + + + + + + + + + diff --git a/lib/battery.js b/lib/battery.js new file mode 100644 index 0000000..1552155 --- /dev/null +++ b/lib/battery.js @@ -0,0 +1,262 @@ +'use strict'; + +// Copyright (C) 2020 Todd Kulesza + +// This file is part of TopHat. + +// TopHat is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// TopHat is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with TopHat. If not, see . + +/* exported NetMonitor */ + +const Gio = imports.gi.Gio; +const GLib = imports.gi.GLib; +const GObject = imports.gi.GObject; +const GTop = imports.gi.GTop; +const Clutter = imports.gi.Clutter; +const St = imports.gi.St; +const UPowerGlib = imports.gi.UPowerGlib; +const ExtensionUtils = imports.misc.extensionUtils; +const Me = ExtensionUtils.getCurrentExtension(); +const Config = Me.imports.lib.config; +const Shared = Me.imports.lib.shared; +const Monitor = Me.imports.lib.monitor; +const _ = Config.Domain.gettext; + + + +class PowerUse { + constructor(power = 0, battery = 0, state = 0) { + this.power = power; + this.battery = battery; + this.state = state; + } +} + +var PowerMonitor = GObject.registerClass({ + Properties: { + 'battery-color': GObject.ParamSpec.string( + 'battery-color', + 'Battery color', + 'Choose battery line color', + GObject.ParamFlags.READWRITE, + '' + ), + 'charging-color': GObject.ParamSpec.string( + 'charging-color', + 'Charging color', + 'Choose charging color', + GObject.ParamFlags.READWRITE, + '' + ), + 'discharging-color': GObject.ParamSpec.string( + 'discharging-color', + 'Discharging color', + 'Choose discharging color', + GObject.ParamFlags.READWRITE, + '' + ), + }, +}, class TopHatPowerMonitor extends Monitor.TopHatMonitor { + _init(configHandler) { + super._init(`${Me.metadata.name} Power Monitor`); + + let gicon = Gio.icon_new_for_string(`${Me.path}/icons/bat-icon.svg`); + let icon = new St.Icon({gicon, style_class: 'system-status-icon tophat-panel-icon tophat-panel-icon-net'}); + this.add_child(icon); + + let vbox = new St.BoxLayout({vertical: true}); + vbox.connect('notify::vertical', obj => { + obj.vertical = true; + }); + this.add_child(vbox); + + let padding = new St.Widget({y_expand: true}); + vbox.add_child(padding); + let valuePower = new St.Label({text: '0', style_class: 'tophat-meter-value-power'}); + vbox.add_child(valuePower); + this.valuePower = valuePower; + let valueBattery = new St.Label({text: '0', style_class: 'tophat-meter-value-battery'}); + vbox.add_child(valueBattery); + this.valueBattery = valueBattery; + padding = new St.Widget({y_expand: true}); + vbox.add_child(padding); + + // Initialize upower + const upower_client = UPowerGlib.Client.new(); + const upower_devices = upower_client.get_devices(); + + let battery_device = null; + for (const dev of upower_devices) { + + if (dev.is_rechargeable) { + log(`Using battery: ${dev.model}`); + battery_device = dev; + break; + } + } + this.timePrev = GLib.get_monotonic_time(); + this.netPrev = { + power: battery_device.energy_rate, + battery: battery_device.percentage, + }; + this.history = new Array(0); + + this._buildMenu(); + + this.refreshChartsTimer = GLib.timeout_add(GLib.PRIORITY_DEFAULT, Config.UPDATE_INTERVAL_NET, () => this.refreshCharts()); + configHandler.settings.bind('show-bat', this, 'visible', Gio.SettingsBindFlags.DEFAULT); + configHandler.settings.bind('show-icons', icon, 'visible', Gio.SettingsBindFlags.DEFAULT); + configHandler.settings.bind('meter-fg-color', this, 'meter-fg-color', Gio.SettingsBindFlags.DEFAULT); + configHandler.settings.bind('meter-fg-battery-color', this, 'battery-color', Gio.SettingsBindFlags.DEFAULT); + configHandler.settings.bind('meter-fg-charging-color', this, 'charging-color', Gio.SettingsBindFlags.DEFAULT); + configHandler.settings.bind('meter-fg-discharging-color', this, 'discharging-color', Gio.SettingsBindFlags.DEFAULT); + } + + _buildMenu() { + let label = new St.Label({text: _('Power usage'), style_class: 'menu-header'}); + this.addMenuRow(label, 0, 2, 1); + + label = new St.Label({text: _('Power:'), style_class: 'menu-label'}); + this.addMenuRow(label, 0, 1, 1); + this.menuPower = new St.Label({text: '', style_class: 'menu-value'}); + this.addMenuRow(this.menuPower, 1, 1, 1); + + label = new St.Label({text: _('Battery:'), style_class: 'menu-label'}); + this.addMenuRow(label, 0, 1, 1); + this.menuBattery = new St.Label({text: '', style_class: 'menu-value'}); + this.addMenuRow(this.menuBattery, 1, 1, 1); + + this.historyChart = new St.DrawingArea({style_class: 'chart'}); + this.historyChart.connect('repaint', () => this.repaintHistory()); + this.addMenuRow(this.historyChart, 0, 2, 1); + + // FIXME: Don't hardcode this, base it on Config.HISTORY_MAX_SIZE + label = new St.Label({text: _('2 mins ago'), style_class: 'chart-label-then'}); + this.addMenuRow(label, 0, 1, 1); + label = new St.Label({text: _('now'), style_class: 'chart-label-now'}); + this.addMenuRow(label, 1, 1, 1); + + this.buildMenuButtons(); + } + + refreshCharts() { + + let time = GLib.get_monotonic_time(); + const upower_client = UPowerGlib.Client.new(); + const upower_devices = upower_client.get_devices(); + + let battery_device = null; + for (const dev of upower_devices) { + if (dev.is_rechargeable) { + battery_device = dev; + break; + } + } + let power = Math.round(battery_device.energy_rate); + let battery = Math.round(battery_device.percentage); + let state = battery_device.state; + while (this.history.length >= Config.HISTORY_MAX_SIZE) { + this.history.shift(); + } + this.history.push(new PowerUse( + power, + battery, + state)); + let charging = '+'; + if (state === 2) { + charging = '-'; + } + + this.valuePower.text = `${charging}${power}W`; + this.menuPower.text = `${charging}${power}W`; + this.valueBattery.text = `${battery}%`; + this.menuBattery.text = `${battery}%`; + this.historyChart.queue_repaint(); + return true; + } + + repaintHistory() { + let [width, height] = this.historyChart.get_surface_size(); + let pointSpacing = width / (Config.HISTORY_MAX_SIZE - 1); + let xStart = (Config.HISTORY_MAX_SIZE - this.history.length) * pointSpacing; + let ctx = this.historyChart.get_context(); + var fgPowerCharging, fgPowerDischarging, fgBat, bg; + [, fgPowerCharging] = Clutter.Color.from_string(this.charging_color); + [, fgPowerDischarging] = Clutter.Color.from_string(this.discharging_color); + [, fgBat] = Clutter.Color.from_string(this.battery_color); + [, bg] = Clutter.Color.from_string(Config.METER_BG_COLOR); + + // Use a small value to avoid max == 0 + let max_power = 0.001; + for (const powerUse of this.history) { + if (powerUse.power > max_power) { + max_power = powerUse.power; + } + } + + Clutter.cairo_set_source_color(ctx, bg); + ctx.rectangle(0, 0, width, height); + ctx.fill(); + + Clutter.cairo_set_source_color(ctx, fgPowerDischarging); + ctx.moveTo(xStart, height); + for (let i = 0; i < this.history.length; i++) { + let pointHeight = Math.ceil(this.history[i].power / max_power * height); + if (this.history[i].state != 2 ) { + pointHeight = 0; + } + let x = xStart + pointSpacing * i; + let y = height - pointHeight; + ctx.lineTo(x, y); + } + ctx.lineTo(xStart + (this.history.length - 1) * pointSpacing, height); + ctx.closePath(); + ctx.fill(); + + Clutter.cairo_set_source_color(ctx, fgPowerCharging); + ctx.moveTo(xStart, height); + for (let i = 0; i < this.history.length; i++) { + let pointHeight = Math.ceil(this.history[i].power / max_power * height); + if (this.history[i].state == 2 ) { + pointHeight = 0; + } + let x = xStart + pointSpacing * i; + let y = height - pointHeight; + ctx.lineTo(x, y); + } + ctx.lineTo(xStart + (this.history.length - 1) * pointSpacing, height); + ctx.closePath(); + ctx.fill(); + + Clutter.cairo_set_source_color(ctx, fgBat); + ctx.moveTo(xStart, height); + for (let i = 0; i < this.history.length; i++) { + let pointHeight = Math.ceil(this.history[i].battery / 100 * height); + let x = xStart + pointSpacing * i; + let y = height - pointHeight; + ctx.lineTo(x, y); + } + ctx.lineTo(xStart + (this.history.length - 1) * pointSpacing, height); + ctx.stroke(); + ctx.$dispose(); + } + + destroy() { + if (this.refreshChartsTimer !== 0) { + GLib.source_remove(this.refreshChartsTimer); + this.refreshChartsTimer = 0; + } + super.destroy(); + } +}); diff --git a/metadata.json b/metadata.json index 5b3130a..099400d 100644 --- a/metadata.json +++ b/metadata.json @@ -1,10 +1,10 @@ { - "uuid": "tophat@fflewddur.github.io", - "name": "TopHat", + "uuid": "tophat_battery@WiseroOrb.github.io", + "name": "TopHat-Battery", "description": "An elegant system resource monitor.", "version": 5, "shell-version": [ "3.38", "40", "41", "42", "43" ], - "url": "https://github.com/fflewddur/tophat", - "gettext-domain": "tophat@fflewddur.github.io", + "url": "tophat_battery@WiseroOrb.github.io", + "gettext-domain": "tophat_battery@WiseroOrb.github.io", "settings-schema": "org.gnome.shell.extensions.tophat" } diff --git a/schemas/gschemas.compiled b/schemas/gschemas.compiled index ad13eb6bea388145f1789a1e0b418769ef4c0d46..1d5847dc27d954f747e8f8ccf0fb1110bb5fba3c 100644 GIT binary patch literal 1173 zcmZ8fO=#3W7@e(d?T@xq@P{5mDN0tzu752B4=Pygp`ZtmLPeb<(Dfgquwbd#WnCGHkQC~>R0_JZm4P&sCvDsF6Ao9 z!Z^yRd7K2YeW*2rST3Ho23Xrh8Qcx5YoiZLtOo`EOU#xYzGXZ$^X~UegeJ>{Je4D9ewIy_;4IIehD0McU#Ouy%GKg@E96B^V{U1X8aNG1aPnW&n?DN zZ-PG!z7CxHl6TRk?t{Moz713pnFsJ|c=Vcn^qPM3+P_DynMbc-Xc{V4sXgo4j?AH2 zwj0;u6x+qfalM4FvWkgvWNOccp3W}B0lhvQ7M54Zf_UC;s0R0ygymG+q-kr@jZ>A; zHa-|7>iOba_5hrzUVwANdE%ULwl)BqC$vZO13I0I!iLN_xF+99`733Mk$s+Yy|IqE zaXUAVsUJoV%hwYl;}ge5CyxFf=Y`qo(9V3i26PJLnDey}DH{6TNt}f&&kiFyk&&un zjzd4-f5lB$MP1G2%JcDEum}1Z#IY@072y?h81G$}%>{dAwBA^B<58@ZY*tL?(e3v6 oC}loQFWSva`pRxbVJ@6ju3uo~d}ElioiNAitj-s@Xt2J|U&Xlo=Kufz literal 918 zcmYjPziSjh7@b7#a!LF_L?Ml!NMx^=U7{iZ3rj5y>_mt}=XU3I2lp4dd!8v2OMAgm z^bfET1Piej(wfFf5Gzs8PFdfZ*)tCN_};vk`S$zf&9$4VGAeIGH`WnvIqogaMa14I zAzBQ#HnMweL$9}AUf?$Jv*NmVjJUrb1U^wzu^;C}ru{n6Y3l0-jm~RRg>9SD^1BegdN9HzVrg$Dn^l`~@WP!zJqE)CahXlR&lM>L+KNXAn1lE8%&M z`^nd!Zy`PdGTrD(j#VXRCTbFK(T>kog%=I$q?k#Sn@lw{1E=YiH+BoTrY{Hcu$<24 zeyNbkjsWHc*4)6F8yuJ$ICBF$4(A&WECckC-oYB{F@2?{XjR~^v!c2ur?rZ;oaUx` z9OKtrue Animate monitor changes Use animations when the heights of meter bars change. + + + true + Show the network monitor + Show the network monitor. '#1dacd6' Color of the meter bars and chart areas The color of meter bars and chart areas, in either hex or RGBA format. + + '#FFFFFF' + Color of the battery line + Color of the battery line, in either hex or RGBA format. + + + '#8ED5EA' + Color of the power graph when charging + Color of the power graph when charging, in either hex or RGBA format. + + + '#1dacd6' + Color of the power graph when discharging + Color of the power graph when discharging, in either hex or RGBA format. + 0.6 Width of the meter bars diff --git a/stylesheet.css b/stylesheet.css index 3736f3e..aa4831b 100644 --- a/stylesheet.css +++ b/stylesheet.css @@ -21,6 +21,18 @@ min-width: 5em; } +.tophat-meter-value-power { + font-size: 0.7em; + text-align: right; + min-width: 5em; +} + +.tophat-meter-value-battery { + font-size: 0.7em; + text-align: right; + min-width: 5em; +} + .tophat-panel-icon { margin: 0 0.03em; padding-left: 0; From b71040a6e497681c6e590b47c0d184afd3375c5c Mon Sep 17 00:00:00 2001 From: diego Date: Sun, 11 Dec 2022 11:40:52 +0100 Subject: [PATCH 02/14] Refactoring --- lib/battery.js | 50 ++++++++++++++++++++++++-------------------------- 1 file changed, 24 insertions(+), 26 deletions(-) diff --git a/lib/battery.js b/lib/battery.js index 1552155..0ec380a 100644 --- a/lib/battery.js +++ b/lib/battery.js @@ -22,7 +22,6 @@ const Gio = imports.gi.Gio; const GLib = imports.gi.GLib; const GObject = imports.gi.GObject; -const GTop = imports.gi.GTop; const Clutter = imports.gi.Clutter; const St = imports.gi.St; const UPowerGlib = imports.gi.UPowerGlib; @@ -93,22 +92,21 @@ var PowerMonitor = GObject.registerClass({ vbox.add_child(padding); // Initialize upower - const upower_client = UPowerGlib.Client.new(); - const upower_devices = upower_client.get_devices(); - - let battery_device = null; - for (const dev of upower_devices) { + const upowerClient = UPowerGlib.Client.new(); + const upowerDevices = upowerClient.get_devices(); + let batteryDevice = null; + for (const dev of upowerDevices) { if (dev.is_rechargeable) { log(`Using battery: ${dev.model}`); - battery_device = dev; + batteryDevice = dev; break; } } this.timePrev = GLib.get_monotonic_time(); this.netPrev = { - power: battery_device.energy_rate, - battery: battery_device.percentage, + power: batteryDevice.energy_rate, + battery: batteryDevice.percentage, }; this.history = new Array(0); @@ -153,19 +151,19 @@ var PowerMonitor = GObject.registerClass({ refreshCharts() { let time = GLib.get_monotonic_time(); - const upower_client = UPowerGlib.Client.new(); - const upower_devices = upower_client.get_devices(); + const upowerClient = UPowerGlib.Client.new(); + const upowerDevices = upowerClient.get_devices(); - let battery_device = null; - for (const dev of upower_devices) { + let batteryDevice = null; + for (const dev of upowerDevices) { if (dev.is_rechargeable) { - battery_device = dev; + batteryDevice = dev; break; } } - let power = Math.round(battery_device.energy_rate); - let battery = Math.round(battery_device.percentage); - let state = battery_device.state; + let power = Math.round(batteryDevice.energy_rate); + let battery = Math.round(batteryDevice.percentage); + let state = batteryDevice.state; while (this.history.length >= Config.HISTORY_MAX_SIZE) { this.history.shift(); } @@ -198,10 +196,10 @@ var PowerMonitor = GObject.registerClass({ [, bg] = Clutter.Color.from_string(Config.METER_BG_COLOR); // Use a small value to avoid max == 0 - let max_power = 0.001; + let maxPower = 0.001; for (const powerUse of this.history) { - if (powerUse.power > max_power) { - max_power = powerUse.power; + if (powerUse.power > maxPower) { + maxPower = powerUse.power; } } @@ -212,9 +210,9 @@ var PowerMonitor = GObject.registerClass({ Clutter.cairo_set_source_color(ctx, fgPowerDischarging); ctx.moveTo(xStart, height); for (let i = 0; i < this.history.length; i++) { - let pointHeight = Math.ceil(this.history[i].power / max_power * height); - if (this.history[i].state != 2 ) { - pointHeight = 0; + let pointHeight = Math.ceil(this.history[i].power / maxPower * height); + if (this.history[i].state !== 2) { + pointHeight = 0; } let x = xStart + pointSpacing * i; let y = height - pointHeight; @@ -227,9 +225,9 @@ var PowerMonitor = GObject.registerClass({ Clutter.cairo_set_source_color(ctx, fgPowerCharging); ctx.moveTo(xStart, height); for (let i = 0; i < this.history.length; i++) { - let pointHeight = Math.ceil(this.history[i].power / max_power * height); - if (this.history[i].state == 2 ) { - pointHeight = 0; + let pointHeight = Math.ceil(this.history[i].power / maxPower * height); + if (this.history[i].state === 2) { + pointHeight = 0; } let x = xStart + pointSpacing * i; let y = height - pointHeight; From cba6a66e39f7666257a0e7ca62ed4dfc1c934ca8 Mon Sep 17 00:00:00 2001 From: diego Date: Sun, 11 Dec 2022 11:51:07 +0100 Subject: [PATCH 03/14] Reusing upowerClient instead of creating a new one each time --- lib/battery.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/battery.js b/lib/battery.js index 0ec380a..fd0e1d1 100644 --- a/lib/battery.js +++ b/lib/battery.js @@ -93,6 +93,7 @@ var PowerMonitor = GObject.registerClass({ // Initialize upower const upowerClient = UPowerGlib.Client.new(); + this.upowerClient = upowerClient; const upowerDevices = upowerClient.get_devices(); let batteryDevice = null; @@ -151,7 +152,7 @@ var PowerMonitor = GObject.registerClass({ refreshCharts() { let time = GLib.get_monotonic_time(); - const upowerClient = UPowerGlib.Client.new(); + const upowerClient = this.upowerClient; const upowerDevices = upowerClient.get_devices(); let batteryDevice = null; From cfe790ae1cfa3d99208383e93168c49aa0698f7c Mon Sep 17 00:00:00 2001 From: diego Date: Sun, 11 Dec 2022 11:55:58 +0100 Subject: [PATCH 04/14] Added TODO for handling a device with no battery --- lib/battery.js | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/lib/battery.js b/lib/battery.js index fd0e1d1..36450b6 100644 --- a/lib/battery.js +++ b/lib/battery.js @@ -104,6 +104,10 @@ var PowerMonitor = GObject.registerClass({ break; } } + if (batteryDevice === null) { + log('TopHat did not found a rechargeable battery to monitor'); + //TODO handle this case otherwise crash + } this.timePrev = GLib.get_monotonic_time(); this.netPrev = { power: batteryDevice.energy_rate, @@ -162,6 +166,10 @@ var PowerMonitor = GObject.registerClass({ break; } } + if (batteryDevice === null) { + log('TopHat did not found a rechargeable battery to monitor'); + //TODO handle this case otherwise crash + } let power = Math.round(batteryDevice.energy_rate); let battery = Math.round(batteryDevice.percentage); let state = batteryDevice.state; From 7d3794bfccd5379307c89a9c216523cd2ef8a0a3 Mon Sep 17 00:00:00 2001 From: diego Date: Sun, 11 Dec 2022 12:03:47 +0100 Subject: [PATCH 05/14] Encapsulate finding the battery device --- lib/battery.js | 35 +++++++++++++++-------------------- 1 file changed, 15 insertions(+), 20 deletions(-) diff --git a/lib/battery.js b/lib/battery.js index 36450b6..8b0e4e4 100644 --- a/lib/battery.js +++ b/lib/battery.js @@ -94,16 +94,7 @@ var PowerMonitor = GObject.registerClass({ // Initialize upower const upowerClient = UPowerGlib.Client.new(); this.upowerClient = upowerClient; - const upowerDevices = upowerClient.get_devices(); - - let batteryDevice = null; - for (const dev of upowerDevices) { - if (dev.is_rechargeable) { - log(`Using battery: ${dev.model}`); - batteryDevice = dev; - break; - } - } + let batteryDevice = this.findBatteryDevice(); if (batteryDevice === null) { log('TopHat did not found a rechargeable battery to monitor'); //TODO handle this case otherwise crash @@ -156,16 +147,7 @@ var PowerMonitor = GObject.registerClass({ refreshCharts() { let time = GLib.get_monotonic_time(); - const upowerClient = this.upowerClient; - const upowerDevices = upowerClient.get_devices(); - - let batteryDevice = null; - for (const dev of upowerDevices) { - if (dev.is_rechargeable) { - batteryDevice = dev; - break; - } - } + let batteryDevice = this.findBatteryDevice(); if (batteryDevice === null) { log('TopHat did not found a rechargeable battery to monitor'); //TODO handle this case otherwise crash @@ -259,6 +241,19 @@ var PowerMonitor = GObject.registerClass({ ctx.$dispose(); } + findBatteryDevice() { + const upowerDevices = this.upowerClient.get_devices(); + + let batteryDevice = null; + for (const dev of upowerDevices) { + if (dev.is_rechargeable) { + batteryDevice = dev; + break; + } + } + return batteryDevice; + } + destroy() { if (this.refreshChartsTimer !== 0) { GLib.source_remove(this.refreshChartsTimer); From 273216c346c3acf2316ecb8c44aa14bc368f5c0c Mon Sep 17 00:00:00 2001 From: diego Date: Sun, 11 Dec 2022 12:07:01 +0100 Subject: [PATCH 06/14] Add comments on the possible battery states --- lib/battery.js | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/lib/battery.js b/lib/battery.js index 8b0e4e4..c04a21c 100644 --- a/lib/battery.js +++ b/lib/battery.js @@ -39,6 +39,17 @@ class PowerUse { this.power = power; this.battery = battery; this.state = state; + + // UNKNOWN = 0 + // CHARGING = 1 + // DISCHARGING = 2 + // EMPTY = 3 + // FULLY_CHARGED = 4 + // PENDING_CHARGE = 5 + // PENDING_DISCHARGE = 6 + // LAST = 7 + + } } From 5334dd4bd7caddb0c9a8a9a36e46206ea3c31e69 Mon Sep 17 00:00:00 2001 From: WiseroOrb Date: Sun, 11 Dec 2022 15:00:42 +0100 Subject: [PATCH 07/14] Change the way get the values. Upower updates only after 30 seconds, way to slow. So now from upower I get the device files locations. Then I directly read voltage current and charge. This allows for much more fine grained graphs. --- lib/battery.js | 81 ++++++++++++++++++++++++++++++++++---------------- 1 file changed, 55 insertions(+), 26 deletions(-) diff --git a/lib/battery.js b/lib/battery.js index c04a21c..df1c5a8 100644 --- a/lib/battery.js +++ b/lib/battery.js @@ -48,8 +48,6 @@ class PowerUse { // PENDING_CHARGE = 5 // PENDING_DISCHARGE = 6 // LAST = 7 - - } } @@ -105,16 +103,7 @@ var PowerMonitor = GObject.registerClass({ // Initialize upower const upowerClient = UPowerGlib.Client.new(); this.upowerClient = upowerClient; - let batteryDevice = this.findBatteryDevice(); - if (batteryDevice === null) { - log('TopHat did not found a rechargeable battery to monitor'); - //TODO handle this case otherwise crash - } - this.timePrev = GLib.get_monotonic_time(); - this.netPrev = { - power: batteryDevice.energy_rate, - battery: batteryDevice.percentage, - }; + this.history = new Array(0); this._buildMenu(); @@ -158,21 +147,15 @@ var PowerMonitor = GObject.registerClass({ refreshCharts() { let time = GLib.get_monotonic_time(); - let batteryDevice = this.findBatteryDevice(); - if (batteryDevice === null) { - log('TopHat did not found a rechargeable battery to monitor'); - //TODO handle this case otherwise crash - } - let power = Math.round(batteryDevice.energy_rate); - let battery = Math.round(batteryDevice.percentage); - let state = batteryDevice.state; + let batteryValues = this.getPowerValues(); + + let power = Math.round(batteryValues.power); + let battery = Math.round(batteryValues.battery); + let state = batteryValues.state; while (this.history.length >= Config.HISTORY_MAX_SIZE) { this.history.shift(); } - this.history.push(new PowerUse( - power, - battery, - state)); + this.history.push(batteryValues); let charging = '+'; if (state === 2) { charging = '-'; @@ -252,7 +235,7 @@ var PowerMonitor = GObject.registerClass({ ctx.$dispose(); } - findBatteryDevice() { + getPowerValues() { const upowerDevices = this.upowerClient.get_devices(); let batteryDevice = null; @@ -262,7 +245,53 @@ var PowerMonitor = GObject.registerClass({ break; } } - return batteryDevice; + if (batteryDevice === null) { + log('TopHat did not found a rechargeable battery to monitor'); + //TODO handle this case otherwise crash + } + const path = batteryDevice.native_path; + const basePath = `/sys/class/power_supply/${path}`; + const currentPath = `${basePath}/current_now`; + const voltagePath = `${basePath}/voltage_now`; + const chargePath = `${basePath}/charge_now`; + const chargeFullPath = `${basePath}/charge_full`; + const statusPath = `${basePath}/status`; + + const current = this.parseValue(currentPath)*1e-6; + const voltage = this.parseValue(voltagePath)*1e-6; + const charge = this.parseValue(chargePath); + const chargeFull = Math.max(this.parseValue(chargeFullPath), 1); //avoid division by zero + + const status = this.parseStatus(statusPath).replace(/[\n\r]/g, '').toUpperCase(); + const state = UPowerGlib.DeviceState[status]; + + + return new PowerUse( + voltage*current, + charge/chargeFull*100, + state, + ); + } + + parseValue(path) { + try { + return parseFloat( + new TextDecoder("utf-8").decode( + GLib.file_get_contents(path)[1])); + } + catch (err) { + return 0; + } + } + + parseStatus(path) { + try { + return new TextDecoder("utf-8").decode( + (GLib.file_get_contents(path)[1])); + } + catch { + return 'Unknown'; + } } destroy() { From 281384fc384f67ac035de3fc23296c61cc612e3f Mon Sep 17 00:00:00 2001 From: WiseroOrb Date: Sun, 11 Dec 2022 20:49:34 +0100 Subject: [PATCH 08/14] Caching intermediate results --- lib/battery.js | 52 +++++++++++++++++++++++--------------------------- 1 file changed, 24 insertions(+), 28 deletions(-) diff --git a/lib/battery.js b/lib/battery.js index df1c5a8..42e116f 100644 --- a/lib/battery.js +++ b/lib/battery.js @@ -102,8 +102,26 @@ var PowerMonitor = GObject.registerClass({ // Initialize upower const upowerClient = UPowerGlib.Client.new(); - this.upowerClient = upowerClient; + const upowerDevices = upowerClient.get_devices(); + let batteryDevice = null; + for (const dev of upowerDevices) { + if (dev.is_rechargeable) { + batteryDevice = dev; + break; + } + } + if (batteryDevice === null) { + log('TopHat did not found a rechargeable battery to monitor'); + //TODO handle this case otherwise crash + } + const path = batteryDevice.native_path; + const basePath = `/sys/class/power_supply/${path}`; + this.currentPath = `${basePath}/current_now`; + this.voltagePath = `${basePath}/voltage_now`; + this.chargePath = `${basePath}/charge_now`; + this.chargeFullPath = `${basePath}/charge_full`; + this.statusPath = `${basePath}/status`; this.history = new Array(0); this._buildMenu(); @@ -236,33 +254,11 @@ var PowerMonitor = GObject.registerClass({ } getPowerValues() { - const upowerDevices = this.upowerClient.get_devices(); - - let batteryDevice = null; - for (const dev of upowerDevices) { - if (dev.is_rechargeable) { - batteryDevice = dev; - break; - } - } - if (batteryDevice === null) { - log('TopHat did not found a rechargeable battery to monitor'); - //TODO handle this case otherwise crash - } - const path = batteryDevice.native_path; - const basePath = `/sys/class/power_supply/${path}`; - const currentPath = `${basePath}/current_now`; - const voltagePath = `${basePath}/voltage_now`; - const chargePath = `${basePath}/charge_now`; - const chargeFullPath = `${basePath}/charge_full`; - const statusPath = `${basePath}/status`; - - const current = this.parseValue(currentPath)*1e-6; - const voltage = this.parseValue(voltagePath)*1e-6; - const charge = this.parseValue(chargePath); - const chargeFull = Math.max(this.parseValue(chargeFullPath), 1); //avoid division by zero - - const status = this.parseStatus(statusPath).replace(/[\n\r]/g, '').toUpperCase(); + const current = this.parseValue(this.currentPath)*1e-6; + const voltage = this.parseValue(this.voltagePath)*1e-6; + const charge = this.parseValue(this.chargePath); + const chargeFull = Math.max(this.parseValue(this.chargeFullPath), 1); //avoid division by zero + const status = this.parseStatus(this.statusPath).replace(/[\n\r]/g, '').toUpperCase(); const state = UPowerGlib.DeviceState[status]; From b3fbdc4998d2be2dc2185f8354e0900cd59081b4 Mon Sep 17 00:00:00 2001 From: WiseroOrb Date: Thu, 15 Dec 2022 14:59:52 +0100 Subject: [PATCH 09/14] Detect the absence of a battery and displaing N/A instead of power and battery level --- lib/battery.js | 58 +++--- package-lock.json | 461 +++++++++------------------------------------- package.json | 2 +- 3 files changed, 121 insertions(+), 400 deletions(-) diff --git a/lib/battery.js b/lib/battery.js index 42e116f..743a96b 100644 --- a/lib/battery.js +++ b/lib/battery.js @@ -17,7 +17,7 @@ // You should have received a copy of the GNU General Public License // along with TopHat. If not, see . -/* exported NetMonitor */ +/* exported PowerMonitor */ const Gio = imports.gi.Gio; const GLib = imports.gi.GLib; @@ -28,7 +28,6 @@ const UPowerGlib = imports.gi.UPowerGlib; const ExtensionUtils = imports.misc.extensionUtils; const Me = ExtensionUtils.getCurrentExtension(); const Config = Me.imports.lib.config; -const Shared = Me.imports.lib.shared; const Monitor = Me.imports.lib.monitor; const _ = Config.Domain.gettext; @@ -111,19 +110,20 @@ var PowerMonitor = GObject.registerClass({ break; } } + this.batteryDevice = batteryDevice; if (batteryDevice === null) { log('TopHat did not found a rechargeable battery to monitor'); - //TODO handle this case otherwise crash + // TODO handle this case otherwise crash + } else { + const path = batteryDevice.native_path; + const basePath = `/sys/class/power_supply/${path}`; + this.currentPath = `${basePath}/current_now`; + this.voltagePath = `${basePath}/voltage_now`; + this.chargePath = `${basePath}/charge_now`; + this.chargeFullPath = `${basePath}/charge_full`; + this.statusPath = `${basePath}/status`; } - const path = batteryDevice.native_path; - const basePath = `/sys/class/power_supply/${path}`; - this.currentPath = `${basePath}/current_now`; - this.voltagePath = `${basePath}/voltage_now`; - this.chargePath = `${basePath}/charge_now`; - this.chargeFullPath = `${basePath}/charge_full`; - this.statusPath = `${basePath}/status`; this.history = new Array(0); - this._buildMenu(); this.refreshChartsTimer = GLib.timeout_add(GLib.PRIORITY_DEFAULT, Config.UPDATE_INTERVAL_NET, () => this.refreshCharts()); @@ -163,10 +163,16 @@ var PowerMonitor = GObject.registerClass({ } refreshCharts() { + if (this.batteryDevice === null) { + this.valuePower.text = 'N/A'; + this.menuPower.text = 'N/A'; + this.valueBattery.text = 'N/A'; + this.menuBattery.text = 'N/A'; + this.historyChart.queue_repaint(); + return false; + } - let time = GLib.get_monotonic_time(); let batteryValues = this.getPowerValues(); - let power = Math.round(batteryValues.power); let battery = Math.round(batteryValues.battery); let state = batteryValues.state; @@ -254,38 +260,36 @@ var PowerMonitor = GObject.registerClass({ } getPowerValues() { - const current = this.parseValue(this.currentPath)*1e-6; - const voltage = this.parseValue(this.voltagePath)*1e-6; + const current = this.parseValue(this.currentPath) * 1e-6; + const voltage = this.parseValue(this.voltagePath) * 1e-6; const charge = this.parseValue(this.chargePath); - const chargeFull = Math.max(this.parseValue(this.chargeFullPath), 1); //avoid division by zero + const chargeFull = Math.max(this.parseValue(this.chargeFullPath), 1); // avoid division by zero const status = this.parseStatus(this.statusPath).replace(/[\n\r]/g, '').toUpperCase(); const state = UPowerGlib.DeviceState[status]; return new PowerUse( - voltage*current, - charge/chargeFull*100, - state, + voltage * current, + charge / chargeFull * 100, + state ); } parseValue(path) { try { return parseFloat( - new TextDecoder("utf-8").decode( + new TextDecoder('utf-8').decode( GLib.file_get_contents(path)[1])); - } - catch (err) { - return 0; + } catch (err) { + return 0; } } parseStatus(path) { try { - return new TextDecoder("utf-8").decode( - (GLib.file_get_contents(path)[1])); - } - catch { + return new TextDecoder('utf-8').decode( + GLib.file_get_contents(path)[1]); + } catch { return 'Unknown'; } } diff --git a/package-lock.json b/package-lock.json index 9ff1aa1..a595979 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,11 +1,11 @@ { - "name": "tophat", + "name": "tophat_battery@WiseroOrb.github.io", "lockfileVersion": 2, "requires": true, "packages": { "": { "devDependencies": { - "eslint": "^8.23.0", + "eslint": "^8.29.0", "eslint-plugin-jsdoc": "^39.3.2" } }, @@ -24,9 +24,9 @@ } }, "node_modules/@eslint/eslintrc": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-1.3.1.tgz", - "integrity": "sha512-OhSY22oQQdw3zgPOOwdoj01l/Dzl1Z+xyUP33tkSN+aqyEhymJCcPHyXt+ylW8FSe0TfRC2VG+ROQOapD0aZSQ==", + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-1.3.3.tgz", + "integrity": "sha512-uj3pT6Mg+3t39fvLrj8iuCIJ38zKO9FpGtJ4BBJebJhEwjoT+KLVNCcHT5QC9NGRIEi7fZ0ZR8YRb884auB4Lg==", "dev": true, "dependencies": { "ajv": "^6.12.4", @@ -47,29 +47,19 @@ } }, "node_modules/@humanwhocodes/config-array": { - "version": "0.10.4", - "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.10.4.tgz", - "integrity": "sha512-mXAIHxZT3Vcpg83opl1wGlVZ9xydbfZO3r5YfRSH6Gpp2J/PfdBP0wbDa2sO6/qRbcalpoevVyW6A/fI6LfeMw==", + "version": "0.11.8", + "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.8.tgz", + "integrity": "sha512-UybHIJzJnR5Qc/MsD9Kr+RpO2h+/P1GhOwdiLPXK5TWk5sgTdu88bTD9UP+CKbPPh5Rni1u0GjAdYQLemG8g+g==", "dev": true, "dependencies": { "@humanwhocodes/object-schema": "^1.2.1", "debug": "^4.1.1", - "minimatch": "^3.0.4" + "minimatch": "^3.0.5" }, "engines": { "node": ">=10.10.0" } }, - "node_modules/@humanwhocodes/gitignore-to-minimatch": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/@humanwhocodes/gitignore-to-minimatch/-/gitignore-to-minimatch-1.0.2.tgz", - "integrity": "sha512-rSqmMJDdLFUsyxR6FMtD00nfQKKLFb1kv+qBbOVKqErvloEIJLo5bDTJTQNTYgeyp78JsA7u/NPi5jT1GR/MuA==", - "dev": true, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/nzakas" - } - }, "node_modules/@humanwhocodes/module-importer": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", @@ -125,9 +115,9 @@ } }, "node_modules/acorn": { - "version": "8.8.0", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.8.0.tgz", - "integrity": "sha512-QOxyigPVrpZ2GXT+PFyZTl6TtOFc5egxHIP9IlQ+RbupQuX4RkT/Bee4/kQuC02Xkzg84JcT7oLYtDIQxp+v7w==", + "version": "8.8.1", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.8.1.tgz", + "integrity": "sha512-7zFpHzhnqYKrkYdUjF1HI1bzd0VygEGX8lFk4k5zVMqHEoES+P+7TKI+EvLO9WVMJ8eekdO0aDEK044xTXwPPA==", "dev": true, "bin": { "acorn": "bin/acorn" @@ -191,15 +181,6 @@ "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", "dev": true }, - "node_modules/array-union": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz", - "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==", - "dev": true, - "engines": { - "node": ">=8" - } - }, "node_modules/balanced-match": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", @@ -216,18 +197,6 @@ "concat-map": "0.0.1" } }, - "node_modules/braces": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", - "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", - "dev": true, - "dependencies": { - "fill-range": "^7.0.1" - }, - "engines": { - "node": ">=8" - } - }, "node_modules/callsites": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", @@ -323,18 +292,6 @@ "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", "dev": true }, - "node_modules/dir-glob": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", - "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==", - "dev": true, - "dependencies": { - "path-type": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, "node_modules/doctrine": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", @@ -360,15 +317,15 @@ } }, "node_modules/eslint": { - "version": "8.23.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.23.0.tgz", - "integrity": "sha512-pBG/XOn0MsJcKcTRLr27S5HpzQo4kLr+HjLQIyK4EiCsijDl/TB+h5uEuJU6bQ8Edvwz1XWOjpaP2qgnXGpTcA==", + "version": "8.29.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.29.0.tgz", + "integrity": "sha512-isQ4EEiyUjZFbEKvEGJKKGBwXtvXX+zJbkVKCgTuB9t/+jUBcy8avhkEwWJecI15BkRkOYmvIM5ynbhRjEkoeg==", "dev": true, "dependencies": { - "@eslint/eslintrc": "^1.3.1", - "@humanwhocodes/config-array": "^0.10.4", - "@humanwhocodes/gitignore-to-minimatch": "^1.0.2", + "@eslint/eslintrc": "^1.3.3", + "@humanwhocodes/config-array": "^0.11.6", "@humanwhocodes/module-importer": "^1.0.1", + "@nodelib/fs.walk": "^1.2.8", "ajv": "^6.10.0", "chalk": "^4.0.0", "cross-spawn": "^7.0.2", @@ -384,15 +341,15 @@ "fast-deep-equal": "^3.1.3", "file-entry-cache": "^6.0.1", "find-up": "^5.0.0", - "functional-red-black-tree": "^1.0.1", - "glob-parent": "^6.0.1", + "glob-parent": "^6.0.2", "globals": "^13.15.0", - "globby": "^11.1.0", "grapheme-splitter": "^1.0.4", "ignore": "^5.2.0", "import-fresh": "^3.0.0", "imurmurhash": "^0.1.4", "is-glob": "^4.0.0", + "is-path-inside": "^3.0.3", + "js-sdsl": "^4.1.4", "js-yaml": "^4.1.0", "json-stable-stringify-without-jsonify": "^1.0.1", "levn": "^0.4.1", @@ -486,9 +443,9 @@ } }, "node_modules/espree": { - "version": "9.4.0", - "resolved": "https://registry.npmjs.org/espree/-/espree-9.4.0.tgz", - "integrity": "sha512-DQmnRpLj7f6TgN/NYb0MTzJXL+vJF9h3pHy4JhCIs3zwcgez8xmGg3sXHcEO97BrmO2OSvCwMdfdlyl+E9KjOw==", + "version": "9.4.1", + "resolved": "https://registry.npmjs.org/espree/-/espree-9.4.1.tgz", + "integrity": "sha512-XwctdmTO6SIvCzd9810yyNzIrOrqNYV9Koizx4C/mRhf9uq0o4yHoCEU/670pOxOL/MSraektvSAji79kX90Vg==", "dev": true, "dependencies": { "acorn": "^8.8.0", @@ -550,34 +507,6 @@ "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", "dev": true }, - "node_modules/fast-glob": { - "version": "3.2.12", - "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.12.tgz", - "integrity": "sha512-DVj4CQIYYow0BlaelwK1pHl5n5cRSJfM60UA0zK891sVInoPri2Ekj7+e1CT3/3qxXenpI+nBBmQAcJPJgaj4w==", - "dev": true, - "dependencies": { - "@nodelib/fs.stat": "^2.0.2", - "@nodelib/fs.walk": "^1.2.3", - "glob-parent": "^5.1.2", - "merge2": "^1.3.0", - "micromatch": "^4.0.4" - }, - "engines": { - "node": ">=8.6.0" - } - }, - "node_modules/fast-glob/node_modules/glob-parent": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", - "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", - "dev": true, - "dependencies": { - "is-glob": "^4.0.1" - }, - "engines": { - "node": ">= 6" - } - }, "node_modules/fast-json-stable-stringify": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", @@ -591,9 +520,9 @@ "dev": true }, "node_modules/fastq": { - "version": "1.13.0", - "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.13.0.tgz", - "integrity": "sha512-YpkpUnK8od0o1hmeSc7UUs/eB/vIPWJYjKck2QKIzAf71Vm1AAQ3EbuZB3g2JIy+pg+ERD0vqI79KyZiB2e2Nw==", + "version": "1.14.0", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.14.0.tgz", + "integrity": "sha512-eR2D+V9/ExcbF9ls441yIuN6TI2ED1Y2ZcA5BmMtJsOkWOFRJQ0Jt0g1UwqXJJVAb+V+umH5Dfr8oh4EVP7VVg==", "dev": true, "dependencies": { "reusify": "^1.0.4" @@ -611,18 +540,6 @@ "node": "^10.12.0 || >=12.0.0" } }, - "node_modules/fill-range": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", - "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", - "dev": true, - "dependencies": { - "to-regex-range": "^5.0.1" - }, - "engines": { - "node": ">=8" - } - }, "node_modules/find-up": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", @@ -664,12 +581,6 @@ "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", "dev": true }, - "node_modules/functional-red-black-tree": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz", - "integrity": "sha512-dsKNQNdj6xA3T+QlADDA7mOSlX0qiMINjn0cgr+eGHGsbSHzTabcIogz2+p/iqP1Xs6EP/sS2SbqH+brGTbq0g==", - "dev": true - }, "node_modules/glob": { "version": "7.2.3", "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", @@ -703,9 +614,9 @@ } }, "node_modules/globals": { - "version": "13.17.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-13.17.0.tgz", - "integrity": "sha512-1C+6nQRb1GwGMKm2dH/E7enFAMxGTmGI7/dEdhy/DNelv85w9B72t3uc5frtMNXIbzrarJJ/lTCjcaZwbLJmyw==", + "version": "13.19.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-13.19.0.tgz", + "integrity": "sha512-dkQ957uSRWHw7CFXLUtUHQI3g3aWApYhfNR2O6jn/907riyTYKVBmxYVROkBcY614FSSeSJh7Xm7SrUWCxvJMQ==", "dev": true, "dependencies": { "type-fest": "^0.20.2" @@ -717,26 +628,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/globby": { - "version": "11.1.0", - "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz", - "integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==", - "dev": true, - "dependencies": { - "array-union": "^2.1.0", - "dir-glob": "^3.0.1", - "fast-glob": "^3.2.9", - "ignore": "^5.2.0", - "merge2": "^1.4.1", - "slash": "^3.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/grapheme-splitter": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/grapheme-splitter/-/grapheme-splitter-1.0.4.tgz", @@ -753,9 +644,9 @@ } }, "node_modules/ignore": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.0.tgz", - "integrity": "sha512-CmxgYGiEPCLhfLnpPp1MoRmifwEIOgjcHXxOBjv7mY96c+eWScsOP9c112ZyLdWHi0FxHjI+4uVhKYp/gcdRmQ==", + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.1.tgz", + "integrity": "sha512-d2qQLzTJ9WxQftPAuEQpSPmKqzxePjzVbpAVv62AQ64NTL+wR4JkrVqR/LqFsFEUsHDAiId52mJteHDFuDkElA==", "dev": true, "engines": { "node": ">= 4" @@ -823,13 +714,13 @@ "node": ">=0.10.0" } }, - "node_modules/is-number": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", - "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "node_modules/is-path-inside": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz", + "integrity": "sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==", "dev": true, "engines": { - "node": ">=0.12.0" + "node": ">=8" } }, "node_modules/isexe": { @@ -838,6 +729,16 @@ "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", "dev": true }, + "node_modules/js-sdsl": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/js-sdsl/-/js-sdsl-4.2.0.tgz", + "integrity": "sha512-dyBIzQBDkCqCu+0upx25Y2jGdbTGxE9fshMsCdK0ViOongpV+n5tXRcZY9v7CaVQ79AGS9KA1KHtojxiM7aXSQ==", + "dev": true, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/js-sdsl" + } + }, "node_modules/js-yaml": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", @@ -917,28 +818,6 @@ "node": ">=10" } }, - "node_modules/merge2": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", - "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", - "dev": true, - "engines": { - "node": ">= 8" - } - }, - "node_modules/micromatch": { - "version": "4.0.5", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz", - "integrity": "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==", - "dev": true, - "dependencies": { - "braces": "^3.0.2", - "picomatch": "^2.3.1" - }, - "engines": { - "node": ">=8.6" - } - }, "node_modules/minimatch": { "version": "3.1.2", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", @@ -1058,27 +937,6 @@ "node": ">=8" } }, - "node_modules/path-type": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", - "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/picomatch": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", - "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", - "dev": true, - "engines": { - "node": ">=8.6" - }, - "funding": { - "url": "https://github.com/sponsors/jonschlinkert" - } - }, "node_modules/prelude-ls": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", @@ -1222,15 +1080,6 @@ "node": ">=8" } }, - "node_modules/slash": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", - "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", - "dev": true, - "engines": { - "node": ">=8" - } - }, "node_modules/spdx-exceptions": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.3.0.tgz", @@ -1295,18 +1144,6 @@ "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==", "dev": true }, - "node_modules/to-regex-range": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", - "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", - "dev": true, - "dependencies": { - "is-number": "^7.0.0" - }, - "engines": { - "node": ">=8.0" - } - }, "node_modules/type-check": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", @@ -1402,9 +1239,9 @@ } }, "@eslint/eslintrc": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-1.3.1.tgz", - "integrity": "sha512-OhSY22oQQdw3zgPOOwdoj01l/Dzl1Z+xyUP33tkSN+aqyEhymJCcPHyXt+ylW8FSe0TfRC2VG+ROQOapD0aZSQ==", + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-1.3.3.tgz", + "integrity": "sha512-uj3pT6Mg+3t39fvLrj8iuCIJ38zKO9FpGtJ4BBJebJhEwjoT+KLVNCcHT5QC9NGRIEi7fZ0ZR8YRb884auB4Lg==", "dev": true, "requires": { "ajv": "^6.12.4", @@ -1419,22 +1256,16 @@ } }, "@humanwhocodes/config-array": { - "version": "0.10.4", - "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.10.4.tgz", - "integrity": "sha512-mXAIHxZT3Vcpg83opl1wGlVZ9xydbfZO3r5YfRSH6Gpp2J/PfdBP0wbDa2sO6/qRbcalpoevVyW6A/fI6LfeMw==", + "version": "0.11.8", + "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.8.tgz", + "integrity": "sha512-UybHIJzJnR5Qc/MsD9Kr+RpO2h+/P1GhOwdiLPXK5TWk5sgTdu88bTD9UP+CKbPPh5Rni1u0GjAdYQLemG8g+g==", "dev": true, "requires": { "@humanwhocodes/object-schema": "^1.2.1", "debug": "^4.1.1", - "minimatch": "^3.0.4" + "minimatch": "^3.0.5" } }, - "@humanwhocodes/gitignore-to-minimatch": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/@humanwhocodes/gitignore-to-minimatch/-/gitignore-to-minimatch-1.0.2.tgz", - "integrity": "sha512-rSqmMJDdLFUsyxR6FMtD00nfQKKLFb1kv+qBbOVKqErvloEIJLo5bDTJTQNTYgeyp78JsA7u/NPi5jT1GR/MuA==", - "dev": true - }, "@humanwhocodes/module-importer": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", @@ -1474,9 +1305,9 @@ } }, "acorn": { - "version": "8.8.0", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.8.0.tgz", - "integrity": "sha512-QOxyigPVrpZ2GXT+PFyZTl6TtOFc5egxHIP9IlQ+RbupQuX4RkT/Bee4/kQuC02Xkzg84JcT7oLYtDIQxp+v7w==", + "version": "8.8.1", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.8.1.tgz", + "integrity": "sha512-7zFpHzhnqYKrkYdUjF1HI1bzd0VygEGX8lFk4k5zVMqHEoES+P+7TKI+EvLO9WVMJ8eekdO0aDEK044xTXwPPA==", "dev": true }, "acorn-jsx": { @@ -1519,12 +1350,6 @@ "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", "dev": true }, - "array-union": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz", - "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==", - "dev": true - }, "balanced-match": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", @@ -1541,15 +1366,6 @@ "concat-map": "0.0.1" } }, - "braces": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", - "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", - "dev": true, - "requires": { - "fill-range": "^7.0.1" - } - }, "callsites": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", @@ -1619,15 +1435,6 @@ "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", "dev": true }, - "dir-glob": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", - "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==", - "dev": true, - "requires": { - "path-type": "^4.0.0" - } - }, "doctrine": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", @@ -1644,15 +1451,15 @@ "dev": true }, "eslint": { - "version": "8.23.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.23.0.tgz", - "integrity": "sha512-pBG/XOn0MsJcKcTRLr27S5HpzQo4kLr+HjLQIyK4EiCsijDl/TB+h5uEuJU6bQ8Edvwz1XWOjpaP2qgnXGpTcA==", + "version": "8.29.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.29.0.tgz", + "integrity": "sha512-isQ4EEiyUjZFbEKvEGJKKGBwXtvXX+zJbkVKCgTuB9t/+jUBcy8avhkEwWJecI15BkRkOYmvIM5ynbhRjEkoeg==", "dev": true, "requires": { - "@eslint/eslintrc": "^1.3.1", - "@humanwhocodes/config-array": "^0.10.4", - "@humanwhocodes/gitignore-to-minimatch": "^1.0.2", + "@eslint/eslintrc": "^1.3.3", + "@humanwhocodes/config-array": "^0.11.6", "@humanwhocodes/module-importer": "^1.0.1", + "@nodelib/fs.walk": "^1.2.8", "ajv": "^6.10.0", "chalk": "^4.0.0", "cross-spawn": "^7.0.2", @@ -1668,15 +1475,15 @@ "fast-deep-equal": "^3.1.3", "file-entry-cache": "^6.0.1", "find-up": "^5.0.0", - "functional-red-black-tree": "^1.0.1", - "glob-parent": "^6.0.1", + "glob-parent": "^6.0.2", "globals": "^13.15.0", - "globby": "^11.1.0", "grapheme-splitter": "^1.0.4", "ignore": "^5.2.0", "import-fresh": "^3.0.0", "imurmurhash": "^0.1.4", "is-glob": "^4.0.0", + "is-path-inside": "^3.0.3", + "js-sdsl": "^4.1.4", "js-yaml": "^4.1.0", "json-stable-stringify-without-jsonify": "^1.0.1", "levn": "^0.4.1", @@ -1739,9 +1546,9 @@ "dev": true }, "espree": { - "version": "9.4.0", - "resolved": "https://registry.npmjs.org/espree/-/espree-9.4.0.tgz", - "integrity": "sha512-DQmnRpLj7f6TgN/NYb0MTzJXL+vJF9h3pHy4JhCIs3zwcgez8xmGg3sXHcEO97BrmO2OSvCwMdfdlyl+E9KjOw==", + "version": "9.4.1", + "resolved": "https://registry.npmjs.org/espree/-/espree-9.4.1.tgz", + "integrity": "sha512-XwctdmTO6SIvCzd9810yyNzIrOrqNYV9Koizx4C/mRhf9uq0o4yHoCEU/670pOxOL/MSraektvSAji79kX90Vg==", "dev": true, "requires": { "acorn": "^8.8.0", @@ -1785,30 +1592,6 @@ "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", "dev": true }, - "fast-glob": { - "version": "3.2.12", - "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.12.tgz", - "integrity": "sha512-DVj4CQIYYow0BlaelwK1pHl5n5cRSJfM60UA0zK891sVInoPri2Ekj7+e1CT3/3qxXenpI+nBBmQAcJPJgaj4w==", - "dev": true, - "requires": { - "@nodelib/fs.stat": "^2.0.2", - "@nodelib/fs.walk": "^1.2.3", - "glob-parent": "^5.1.2", - "merge2": "^1.3.0", - "micromatch": "^4.0.4" - }, - "dependencies": { - "glob-parent": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", - "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", - "dev": true, - "requires": { - "is-glob": "^4.0.1" - } - } - } - }, "fast-json-stable-stringify": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", @@ -1822,9 +1605,9 @@ "dev": true }, "fastq": { - "version": "1.13.0", - "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.13.0.tgz", - "integrity": "sha512-YpkpUnK8od0o1hmeSc7UUs/eB/vIPWJYjKck2QKIzAf71Vm1AAQ3EbuZB3g2JIy+pg+ERD0vqI79KyZiB2e2Nw==", + "version": "1.14.0", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.14.0.tgz", + "integrity": "sha512-eR2D+V9/ExcbF9ls441yIuN6TI2ED1Y2ZcA5BmMtJsOkWOFRJQ0Jt0g1UwqXJJVAb+V+umH5Dfr8oh4EVP7VVg==", "dev": true, "requires": { "reusify": "^1.0.4" @@ -1839,15 +1622,6 @@ "flat-cache": "^3.0.4" } }, - "fill-range": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", - "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", - "dev": true, - "requires": { - "to-regex-range": "^5.0.1" - } - }, "find-up": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", @@ -1880,12 +1654,6 @@ "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", "dev": true }, - "functional-red-black-tree": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz", - "integrity": "sha512-dsKNQNdj6xA3T+QlADDA7mOSlX0qiMINjn0cgr+eGHGsbSHzTabcIogz2+p/iqP1Xs6EP/sS2SbqH+brGTbq0g==", - "dev": true - }, "glob": { "version": "7.2.3", "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", @@ -1910,28 +1678,14 @@ } }, "globals": { - "version": "13.17.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-13.17.0.tgz", - "integrity": "sha512-1C+6nQRb1GwGMKm2dH/E7enFAMxGTmGI7/dEdhy/DNelv85w9B72t3uc5frtMNXIbzrarJJ/lTCjcaZwbLJmyw==", + "version": "13.19.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-13.19.0.tgz", + "integrity": "sha512-dkQ957uSRWHw7CFXLUtUHQI3g3aWApYhfNR2O6jn/907riyTYKVBmxYVROkBcY614FSSeSJh7Xm7SrUWCxvJMQ==", "dev": true, "requires": { "type-fest": "^0.20.2" } }, - "globby": { - "version": "11.1.0", - "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz", - "integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==", - "dev": true, - "requires": { - "array-union": "^2.1.0", - "dir-glob": "^3.0.1", - "fast-glob": "^3.2.9", - "ignore": "^5.2.0", - "merge2": "^1.4.1", - "slash": "^3.0.0" - } - }, "grapheme-splitter": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/grapheme-splitter/-/grapheme-splitter-1.0.4.tgz", @@ -1945,9 +1699,9 @@ "dev": true }, "ignore": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.0.tgz", - "integrity": "sha512-CmxgYGiEPCLhfLnpPp1MoRmifwEIOgjcHXxOBjv7mY96c+eWScsOP9c112ZyLdWHi0FxHjI+4uVhKYp/gcdRmQ==", + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.1.tgz", + "integrity": "sha512-d2qQLzTJ9WxQftPAuEQpSPmKqzxePjzVbpAVv62AQ64NTL+wR4JkrVqR/LqFsFEUsHDAiId52mJteHDFuDkElA==", "dev": true }, "import-fresh": { @@ -1997,10 +1751,10 @@ "is-extglob": "^2.1.1" } }, - "is-number": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", - "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "is-path-inside": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz", + "integrity": "sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==", "dev": true }, "isexe": { @@ -2009,6 +1763,12 @@ "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", "dev": true }, + "js-sdsl": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/js-sdsl/-/js-sdsl-4.2.0.tgz", + "integrity": "sha512-dyBIzQBDkCqCu+0upx25Y2jGdbTGxE9fshMsCdK0ViOongpV+n5tXRcZY9v7CaVQ79AGS9KA1KHtojxiM7aXSQ==", + "dev": true + }, "js-yaml": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", @@ -2070,22 +1830,6 @@ "yallist": "^4.0.0" } }, - "merge2": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", - "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", - "dev": true - }, - "micromatch": { - "version": "4.0.5", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz", - "integrity": "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==", - "dev": true, - "requires": { - "braces": "^3.0.2", - "picomatch": "^2.3.1" - } - }, "minimatch": { "version": "3.1.2", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", @@ -2175,18 +1919,6 @@ "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", "dev": true }, - "path-type": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", - "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", - "dev": true - }, - "picomatch": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", - "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", - "dev": true - }, "prelude-ls": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", @@ -2265,12 +1997,6 @@ "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", "dev": true }, - "slash": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", - "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", - "dev": true - }, "spdx-exceptions": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.3.0.tgz", @@ -2323,15 +2049,6 @@ "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==", "dev": true }, - "to-regex-range": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", - "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", - "dev": true, - "requires": { - "is-number": "^7.0.0" - } - }, "type-check": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", diff --git a/package.json b/package.json index a8bc00c..abb5289 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "devDependencies": { - "eslint": "^8.23.0", + "eslint": "^8.29.0", "eslint-plugin-jsdoc": "^39.3.2" } } From b527faa3c8fac085e146b88ca8fba1dbee4475ed Mon Sep 17 00:00:00 2001 From: WiseroOrb Date: Sun, 18 Dec 2022 11:33:06 +0100 Subject: [PATCH 10/14] Added an option to the preferences panel to hide the battery monitor --- lib/battery.js | 1 - prefs.js | 3 +++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/lib/battery.js b/lib/battery.js index 743a96b..a2c6be1 100644 --- a/lib/battery.js +++ b/lib/battery.js @@ -113,7 +113,6 @@ var PowerMonitor = GObject.registerClass({ this.batteryDevice = batteryDevice; if (batteryDevice === null) { log('TopHat did not found a rechargeable battery to monitor'); - // TODO handle this case otherwise crash } else { const path = batteryDevice.native_path; const basePath = `/sys/class/power_supply/${path}`; diff --git a/prefs.js b/prefs.js index 85b5948..876b6fb 100644 --- a/prefs.js +++ b/prefs.js @@ -67,6 +67,9 @@ function fillPreferencesWindow(window) { addComboRow(_('Measurement unit'), choices, 'networkUnit', group, configHandler); page.add(group); + group = new Adw.PreferencesGroup({title: _('Battery')}); + addActionRow(_('Show the battery monitor'), 'show-bat', group, configHandler); + page.add(group); // window.set_default_size(300, 600); } From ea3be446e97034fddcec15cde82a94ab98e7de82 Mon Sep 17 00:00:00 2001 From: WiseroOrb Date: Mon, 19 Dec 2022 16:08:21 +0100 Subject: [PATCH 11/14] Added a secondary color setting and relative setting. If needed it can be used in other panel. --- lib/battery.js | 5 ++-- lib/config.js | 8 ++++++ prefs.js | 24 ++++++++++++++++++ schemas/gschemas.compiled | Bin 1173 -> 1173 bytes ....gnome.shell.extensions.tophat.gschema.xml | 10 ++++---- 5 files changed, 39 insertions(+), 8 deletions(-) diff --git a/lib/battery.js b/lib/battery.js index a2c6be1..af42f9a 100644 --- a/lib/battery.js +++ b/lib/battery.js @@ -128,10 +128,9 @@ var PowerMonitor = GObject.registerClass({ this.refreshChartsTimer = GLib.timeout_add(GLib.PRIORITY_DEFAULT, Config.UPDATE_INTERVAL_NET, () => this.refreshCharts()); configHandler.settings.bind('show-bat', this, 'visible', Gio.SettingsBindFlags.DEFAULT); configHandler.settings.bind('show-icons', icon, 'visible', Gio.SettingsBindFlags.DEFAULT); - configHandler.settings.bind('meter-fg-color', this, 'meter-fg-color', Gio.SettingsBindFlags.DEFAULT); configHandler.settings.bind('meter-fg-battery-color', this, 'battery-color', Gio.SettingsBindFlags.DEFAULT); - configHandler.settings.bind('meter-fg-charging-color', this, 'charging-color', Gio.SettingsBindFlags.DEFAULT); - configHandler.settings.bind('meter-fg-discharging-color', this, 'discharging-color', Gio.SettingsBindFlags.DEFAULT); + configHandler.settings.bind('meter-fg-secondary-color', this, 'charging-color', Gio.SettingsBindFlags.DEFAULT); + configHandler.settings.bind('meter-fg-color', this, 'discharging-color', Gio.SettingsBindFlags.DEFAULT); } _buildMenu() { diff --git a/lib/config.js b/lib/config.js index 0adf350..1404b8c 100644 --- a/lib/config.js +++ b/lib/config.js @@ -71,6 +71,14 @@ var ConfigHandler = class ConfigHandler { this._settings.set_string('meter-fg-color', value); } + get meterFGSecondayColor() { + return this._settings.get_string('meter-fg-secondary-color'); + } + + set meterFGSecondayColor(value) { + this._settings.set_string('meter-fg-secondary-color', value); + } + get meterBarWidth() { return this._settings.get_int('meter-bar-width'); } diff --git a/prefs.js b/prefs.js index 876b6fb..9bea04d 100644 --- a/prefs.js +++ b/prefs.js @@ -47,6 +47,7 @@ function fillPreferencesWindow(window) { choices.append(_('Right edge')); addComboRow(_('Position in panel'), choices, 'positionInPanel', group, configHandler); addColorRow(_('Meter color'), 'meterFGColor', group, configHandler); + addColorRow(_('Meter secondary color'), 'meterFGSecondayColor', group, configHandler); addActionRow(_('Show icons beside monitors'), 'show-icons', group, configHandler); addActionRow(_('Show animations'), 'show-animations', group, configHandler); @@ -97,6 +98,7 @@ function addColorRow(label, setting, group, configHandler) { const button = new Gtk.ColorButton(); const rgba = new Gdk.RGBA(); + log(Object.keys(configHandler)); rgba.parse(configHandler[setting]); button.set_rgba(rgba); button.connect('color-set', widget => { @@ -151,6 +153,7 @@ function buildPrefsWidget3() { choices.push(_('Right edge')); addPref3(buildDropDown3('positionInPanel', _('Position in panel'), choices, configHandler), group); addPref3(buildColorButton3('meterFGColor', _('Meter color'), configHandler), group); + addPref3(buildColorButton3('meterFGSecondaryColor', _('Meter color'), configHandler), group); addPref3(buildSwitch3('show-icons', _('Show icons beside monitors'), configHandler.settings), group); addPref3(buildSwitch3('show-animations', _('Show animations'), configHandler.settings), group); frame.add(group); @@ -183,6 +186,18 @@ function buildPrefsWidget3() { choices.push(_('Bits')); addPref3(buildDropDown3('networkUnit', _('Measurement unit'), choices, configHandler), group); frame.add(group); + group = new Gtk.Box({ + orientation: Gtk.Orientation.VERTICAL, + spacing: 12, + }); + + group = new Gtk.Box({ + orientation: Gtk.Orientation.VERTICAL, + spacing: 12, + }); + addPref3(buildHeader3(_('Battery')), group); + addPref3(buildSwitch3('show-bat', _('Show the battery monitor'), configHandler.settings), group); + frame.add(group); frame.connect('realize', () => { let window = frame.get_toplevel(); @@ -275,6 +290,7 @@ function buildPrefsWidget4() { choices.append(_('Right edge')); addPref4(buildDropDown4('positionInPanel', _('Position in panel'), choices, configHandler), group); addPref4(buildColorButton4('meterFGColor', _('Meter color'), configHandler), group); + addPref4(buildColorButton4('meterFGSecondaryColor', _('Meter color'), configHandler), group); addPref4(buildSwitch4('show-icons', _('Show icons beside monitors'), configHandler.settings), group); addPref4(buildSwitch4('show-animations', _('Show animations'), configHandler.settings), group); frame.append(group); @@ -308,6 +324,14 @@ function buildPrefsWidget4() { addPref4(buildDropDown4('networkUnit', _('Measurement unit'), choices, configHandler), group); frame.append(group); + group = new Gtk.Box({ + orientation: Gtk.Orientation.VERTICAL, + spacing: 12, + }); + addPref4(buildHeader4(_('Battery')), group); + addPref4(buildSwitch4('show-bat', _('Show the battery monitor'), configHandler.settings), group); + frame.append(group); + frame.connect('realize', () => { let window = frame.get_root(); window.default_width = 300; diff --git a/schemas/gschemas.compiled b/schemas/gschemas.compiled index 1d5847dc27d954f747e8f8ccf0fb1110bb5fba3c..37a9c7da901ffaf98f4cfe91d5435eaa6095e3fc 100644 GIT binary patch delta 267 zcmbQrIhAw58bMA51_lu324Y?ip1AjMz1Fw5cdS584Ko7+2SXV{2axUs;$52YU~v!| zBt8R3&jn)ZWHk+tdJtO>D82zm^RX~6ME`-917d^JO8{wEAl`c?KpUhU#FhYxTL5Vn zAfCtecQR0%iNR&EBGYX}kbC%m800oKAO^XU2Z;HB7-$0n*JN4d_{mF{7h2_}mZTQx zrlso^rzYp;r6d+r>L%ysi_@% delta 263 zcmbQrIhAw58bK}w1_lu30b)K7p1AjM{g0l6E380H4Ko9S6hj%q3?RJ(h_$}Oy#tAZ z*c?Fd4M2J;5bx5A2aAK)An^l0`X~@vC#z|I)PvZ9K=B(u+Kh#PA^H!*91t6%-T_Fv z0`WYyzmtLLnHXFrD>B_yColor of the meter bars and chart areas The color of meter bars and chart areas, in either hex or RGBA format. + + '#8ED5EA' + Secondary color of the meter bars and chart areas + The secondary color of meter bars and chart areas, in either hex or RGBA format. + '#FFFFFF' Color of the battery line @@ -63,11 +68,6 @@ Color of the power graph when charging Color of the power graph when charging, in either hex or RGBA format. - - '#1dacd6' - Color of the power graph when discharging - Color of the power graph when discharging, in either hex or RGBA format. - 0.6 Width of the meter bars From 9238471d8d860bc5a5935bffb64ef7688289fda4 Mon Sep 17 00:00:00 2001 From: WiseroOrb Date: Fri, 6 Jan 2023 14:59:47 +0100 Subject: [PATCH 12/14] Revert to previous metadata --- metadata.json | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/metadata.json b/metadata.json index 099400d..1a9f946 100644 --- a/metadata.json +++ b/metadata.json @@ -1,10 +1,10 @@ { - "uuid": "tophat_battery@WiseroOrb.github.io", - "name": "TopHat-Battery", + "uuid": "tophat@fflewddur.github.io", + "name": "TopHat", "description": "An elegant system resource monitor.", - "version": 5, + "version": 6, "shell-version": [ "3.38", "40", "41", "42", "43" ], - "url": "tophat_battery@WiseroOrb.github.io", - "gettext-domain": "tophat_battery@WiseroOrb.github.io", + "url": "https://github.com/fflewddur/tophat", + "gettext-domain": "tophat@fflewddur.github.io", "settings-schema": "org.gnome.shell.extensions.tophat" -} +} \ No newline at end of file From c4ad220907139735835128b2f659d966d79299bc Mon Sep 17 00:00:00 2001 From: WiseroOrb Date: Fri, 6 Jan 2023 15:22:49 +0100 Subject: [PATCH 13/14] Remove battery level report --- lib/battery.js | 34 +------------------ package-lock.json | 2 +- ....gnome.shell.extensions.tophat.gschema.xml | 5 --- 3 files changed, 2 insertions(+), 39 deletions(-) diff --git a/lib/battery.js b/lib/battery.js index af42f9a..24ab60a 100644 --- a/lib/battery.js +++ b/lib/battery.js @@ -52,13 +52,6 @@ class PowerUse { var PowerMonitor = GObject.registerClass({ Properties: { - 'battery-color': GObject.ParamSpec.string( - 'battery-color', - 'Battery color', - 'Choose battery line color', - GObject.ParamFlags.READWRITE, - '' - ), 'charging-color': GObject.ParamSpec.string( 'charging-color', 'Charging color', @@ -93,9 +86,6 @@ var PowerMonitor = GObject.registerClass({ let valuePower = new St.Label({text: '0', style_class: 'tophat-meter-value-power'}); vbox.add_child(valuePower); this.valuePower = valuePower; - let valueBattery = new St.Label({text: '0', style_class: 'tophat-meter-value-battery'}); - vbox.add_child(valueBattery); - this.valueBattery = valueBattery; padding = new St.Widget({y_expand: true}); vbox.add_child(padding); @@ -128,7 +118,6 @@ var PowerMonitor = GObject.registerClass({ this.refreshChartsTimer = GLib.timeout_add(GLib.PRIORITY_DEFAULT, Config.UPDATE_INTERVAL_NET, () => this.refreshCharts()); configHandler.settings.bind('show-bat', this, 'visible', Gio.SettingsBindFlags.DEFAULT); configHandler.settings.bind('show-icons', icon, 'visible', Gio.SettingsBindFlags.DEFAULT); - configHandler.settings.bind('meter-fg-battery-color', this, 'battery-color', Gio.SettingsBindFlags.DEFAULT); configHandler.settings.bind('meter-fg-secondary-color', this, 'charging-color', Gio.SettingsBindFlags.DEFAULT); configHandler.settings.bind('meter-fg-color', this, 'discharging-color', Gio.SettingsBindFlags.DEFAULT); } @@ -142,11 +131,6 @@ var PowerMonitor = GObject.registerClass({ this.menuPower = new St.Label({text: '', style_class: 'menu-value'}); this.addMenuRow(this.menuPower, 1, 1, 1); - label = new St.Label({text: _('Battery:'), style_class: 'menu-label'}); - this.addMenuRow(label, 0, 1, 1); - this.menuBattery = new St.Label({text: '', style_class: 'menu-value'}); - this.addMenuRow(this.menuBattery, 1, 1, 1); - this.historyChart = new St.DrawingArea({style_class: 'chart'}); this.historyChart.connect('repaint', () => this.repaintHistory()); this.addMenuRow(this.historyChart, 0, 2, 1); @@ -164,15 +148,12 @@ var PowerMonitor = GObject.registerClass({ if (this.batteryDevice === null) { this.valuePower.text = 'N/A'; this.menuPower.text = 'N/A'; - this.valueBattery.text = 'N/A'; - this.menuBattery.text = 'N/A'; this.historyChart.queue_repaint(); return false; } let batteryValues = this.getPowerValues(); let power = Math.round(batteryValues.power); - let battery = Math.round(batteryValues.battery); let state = batteryValues.state; while (this.history.length >= Config.HISTORY_MAX_SIZE) { this.history.shift(); @@ -185,8 +166,6 @@ var PowerMonitor = GObject.registerClass({ this.valuePower.text = `${charging}${power}W`; this.menuPower.text = `${charging}${power}W`; - this.valueBattery.text = `${battery}%`; - this.menuBattery.text = `${battery}%`; this.historyChart.queue_repaint(); return true; } @@ -196,10 +175,9 @@ var PowerMonitor = GObject.registerClass({ let pointSpacing = width / (Config.HISTORY_MAX_SIZE - 1); let xStart = (Config.HISTORY_MAX_SIZE - this.history.length) * pointSpacing; let ctx = this.historyChart.get_context(); - var fgPowerCharging, fgPowerDischarging, fgBat, bg; + var fgPowerCharging, fgPowerDischarging, bg; [, fgPowerCharging] = Clutter.Color.from_string(this.charging_color); [, fgPowerDischarging] = Clutter.Color.from_string(this.discharging_color); - [, fgBat] = Clutter.Color.from_string(this.battery_color); [, bg] = Clutter.Color.from_string(Config.METER_BG_COLOR); // Use a small value to avoid max == 0 @@ -244,16 +222,6 @@ var PowerMonitor = GObject.registerClass({ ctx.closePath(); ctx.fill(); - Clutter.cairo_set_source_color(ctx, fgBat); - ctx.moveTo(xStart, height); - for (let i = 0; i < this.history.length; i++) { - let pointHeight = Math.ceil(this.history[i].battery / 100 * height); - let x = xStart + pointSpacing * i; - let y = height - pointHeight; - ctx.lineTo(x, y); - } - ctx.lineTo(xStart + (this.history.length - 1) * pointSpacing, height); - ctx.stroke(); ctx.$dispose(); } diff --git a/package-lock.json b/package-lock.json index a595979..cad6155 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,5 +1,5 @@ { - "name": "tophat_battery@WiseroOrb.github.io", + "name": "tophat@fflewddur.github.io", "lockfileVersion": 2, "requires": true, "packages": { diff --git a/schemas/org.gnome.shell.extensions.tophat.gschema.xml b/schemas/org.gnome.shell.extensions.tophat.gschema.xml index 0a11404..9f16ba7 100644 --- a/schemas/org.gnome.shell.extensions.tophat.gschema.xml +++ b/schemas/org.gnome.shell.extensions.tophat.gschema.xml @@ -58,11 +58,6 @@ Secondary color of the meter bars and chart areas The secondary color of meter bars and chart areas, in either hex or RGBA format. - - '#FFFFFF' - Color of the battery line - Color of the battery line, in either hex or RGBA format. - '#8ED5EA' Color of the power graph when charging From 98f7d4680d004539283dfab8c21c20a8084d0839 Mon Sep 17 00:00:00 2001 From: WiseroOrb Date: Fri, 6 Jan 2023 15:33:29 +0100 Subject: [PATCH 14/14] Remove unused charging color --- schemas/org.gnome.shell.extensions.tophat.gschema.xml | 5 ----- 1 file changed, 5 deletions(-) diff --git a/schemas/org.gnome.shell.extensions.tophat.gschema.xml b/schemas/org.gnome.shell.extensions.tophat.gschema.xml index 9f16ba7..63320ff 100644 --- a/schemas/org.gnome.shell.extensions.tophat.gschema.xml +++ b/schemas/org.gnome.shell.extensions.tophat.gschema.xml @@ -58,11 +58,6 @@ Secondary color of the meter bars and chart areas The secondary color of meter bars and chart areas, in either hex or RGBA format. - - '#8ED5EA' - Color of the power graph when charging - Color of the power graph when charging, in either hex or RGBA format. - 0.6 Width of the meter bars