[gnome] Update extensions

This commit is contained in:
2024-10-31 10:19:02 -04:00
parent 851ec4a772
commit 6d1e6d1132
238 changed files with 8705 additions and 4185 deletions

View File

@ -11,6 +11,14 @@ import GLib from 'gi://GLib';
import GObject from 'gi://GObject';
import Gio from 'gi://Gio';
/*
* On some models the start threshold 0 is not allowed, instead 95 is used (Ex: E14 Gen 3)
* See issues:
* #8: https://gitlab.com/marcosdalvarez/thinkpad-battery-threshold-extension/-/issues/8
* #20: https://gitlab.com/marcosdalvarez/thinkpad-battery-threshold-extension/-/issues/20
*/
const ALTERNATIVE_DISABLED_START = /(Think[pP]ad) (E14 Gen 3|P14s Gen 2a)/;
// Driver constants
const BASE_PATH = '/sys/class/power_supply';
const START_FILE_OLD = 'charge_start_threshold'; // kernel 4.17 and newer
@ -24,7 +32,7 @@ const END_FILE_NEW = 'charge_control_end_threshold'; // kernel 5.9 and newer
* @param {string} path Path of file
* @returns {string} File contents
*/
const readFile = function(path) {
const readFile = function (path) {
try {
const f = Gio.File.new_for_path(path);
const [, contents,] = f.load_contents(null);
@ -41,7 +49,7 @@ const readFile = function(path) {
* @param {string} path Path of file
* @returns {number|null} Return a integer or null
*/
const readFileInt = function(path) {
const readFileInt = function (path) {
try {
const v = readFile(path);
if (v) {
@ -52,15 +60,15 @@ const readFileInt = function(path) {
} catch (e) {
return null;
}
}
}
/**
* Test file/direcory exists
* Test file/directory exists
*
* @param {string} path File/directory path
* @returns {boolean}
*/
const fileExists = function(path) {
const fileExists = function (path) {
try {
const f = Gio.File.new_for_path(path);
return f.query_exists(null);
@ -79,7 +87,7 @@ const Environment = GObject.registerClass({
get productVersion() {
if (this._productVersion === undefined) {
const tmp = readFile('/sys/class/dmi/id/product_version');
if (tmp) {
if (tmp) {
// Remove non-alphanumeric characters
const sanitize = /([^ A-Za-z0-9])+/g;
this._productVersion = tmp.replace(sanitize, '');
@ -109,23 +117,23 @@ const Environment = GObject.registerClass({
get kernelMajorVersion() {
if (this._kernelMajorVersion === undefined) {
[this._kernelMajorVersion , this._kernelMinorVersion] = this.kernelRelease.split('.', 2);
[this._kernelMajorVersion, this._kernelMinorVersion] = this.kernelRelease.split('.', 2);
}
return this._kernelMajorVersion;
}
get kernelMinorVersion() {
if (this._kernelMinorVersion === undefined) {
[this._kernelMajorVersion , this._kernelMinorVersion] = this.kernelRelease.split('.', 2);
[this._kernelMajorVersion, this._kernelMinorVersion] = this.kernelRelease.split('.', 2);
}
return this._kernelMinorVersion;
}
checkMinKernelVersion(major, minor) {
return (
this.kernelMajorVersion > major ||
(this,this.kernelMajorVersion === major && this.kernelMinorVersion >= minor)
);
this.kernelMajorVersion > major ||
(this.kernelMajorVersion === major && this.kernelMinorVersion >= minor)
);
}
});
@ -140,7 +148,7 @@ const Runnable = GObject.registerClass({
GTypeName: 'Runnable',
Signals: {
'command-completed': {
param_types: [GObject.TYPE_JSOBJECT /* erro */]
param_types: [GObject.TYPE_JSOBJECT /* error */]
}
}
}, class Runnable extends GObject.Object {
@ -167,8 +175,8 @@ const Runnable = GObject.registerClass({
try {
GLib.spawn_check_exit_status(status);
this.emit('command-completed', null);
} catch(e) {
if (e.code == 126) {
} catch (e) {
if (e.code == 126) {
// Cancelled
} else {
logError(e);
@ -272,13 +280,6 @@ export const ThinkPadBattery = GObject.registerClass({
throw Error('Battery name not defined');
}
// Signals handlers IDs
this._monitorId = null;
this._settingStartId = null;
this._settingEndId = null;
this._startId = null;
this._endId = null;
// Battery directory
this._baseDirectoryPath = `${BASE_PATH}/${this.name}`;
this._baseDirectory = Gio.File.new_for_path(this._baseDirectoryPath);
@ -334,28 +335,29 @@ export const ThinkPadBattery = GObject.registerClass({
// Update flags on changes in threshold values
this._startId = this.connect(
'notify::start-value', () => {
this.isActive = this._checkActive();
this.isAvailable = this.startValue !== null || this.endValue !== null;
this.pendingChanges = this._checkPendingChanges();
this._updateStatuses();
}
);
this._endId = this.connect(
'notify::end-value', () => {
this.isActive = this._checkActive();
this.isAvailable = this.startValue !== null || this.endValue !== null;
this.pendingChanges = this._checkPendingChanges();
this._updateStatuses();
}
);
// Update pending changes flag on changes to setting values
this._settingStartId = this.settings.connect(
`changed::start-${this.name.toLowerCase()}`, () => {
this.pendingChanges = this._checkPendingChanges();
this._updateStatuses();
}
);
this._settingEndId = this.settings.connect(
`changed::end-${this.name.toLowerCase()}`, () => {
this.pendingChanges = this._checkPendingChanges();
this._updateStatuses();
}
);
this._settingDisabledValueId = this.settings.connect(
`changed::disabled-start-${this.name.toLowerCase()}-value`, () => {
this._updateStatuses();
}
);
@ -366,33 +368,34 @@ export const ThinkPadBattery = GObject.registerClass({
}
/**
* Check if thresholds is active
*
* @returns {boolean} Returns true if the battery has active thresholds
* Update the statuses
*/
_checkActive() {
// RegExs
/* On some models the start threshold 0 is not allowed, instead 95 is used (Ex: E14 Gen 3)
* See issue #8: https://gitlab.com/marcosdalvarez/thinkpad-battery-threshold-extension/-/issues/8
*/
const disableStart95 = /(Think[pP]ad) (E14 Gen 3)/;
_updateStatuses() {
// Check if is available
this.isAvailable = this.startValue !== null || this.endValue !== null;
if (this.environment.productVersion.search(disableStart95) >= 0) {
return (this.startValue !== 95 && this.startValue !== null) || (this.endValue !== 100 && this.endValue !== null);
// Check if thresholds is active
const disabledStartValue = this.settings.get_int(`disabled-start-${this.name.toLowerCase()}-value`);
if (disabledStartValue === -1) {
// Use model detection
if (this.environment.productVersion.search(ALTERNATIVE_DISABLED_START) >= 0) {
this.isActive = (this.startValue !== null && this.startValue !== 95) || (this.endValue !== null && this.endValue !== 100);
} else {
this.isActive = (this.startValue !== null && this.startValue !== 0) || (this.endValue !== null && this.endValue !== 100);
}
} else {
return (this.startValue !== 0 && this.startValue !== null) || (this.endValue !== 100 && this.endValue !== null);
// Use user settings
this.isActive = (this.startValue !== null && this.startValue !== disabledStartValue) || (this.endValue !== null && this.endValue !== 100);
}
}
/**
* Check if there are changes to the settings that need to be applied
*
* @returns {boolean} Returns true if there are changes to the settings that need to be applied
*/
_checkPendingChanges() {
const startSetting = this.settings.get_int(`start-${this.name.toLowerCase()}`);
const endSetting = this.settings.get_int(`end-${this.name.toLowerCase()}`);
return ((this.startValue != null && this.startValue !== startSetting) || (this.endValue != null && this.endValue !== endSetting));
if (this.isActive) {
this.pendingChanges = (this.startValue !== null && this.startValue !== startSetting) || (this.endValue !== null && this.endValue !== endSetting);
} else {
this.pendingChanges = false;
}
}
/**
@ -419,7 +422,7 @@ export const ThinkPadBattery = GObject.registerClass({
}
} catch (e) {
// Ignored
}
}
return false;
}
@ -446,12 +449,12 @@ export const ThinkPadBattery = GObject.registerClass({
}
get isAvailable() {
return this._isAvaialble;
return this._isAvailable;
}
set isAvailable(value) {
if (this.isAvailable !== value) {
this._isAvaialble = value;
this._isAvailable = value;
this.notify('is-available');
}
}
@ -627,6 +630,9 @@ export const ThinkPadBattery = GObject.registerClass({
if (this._settingEndId) {
this.settings.disconnect(this._settingEndId);
}
if (this._settingDisabledValueId) {
this.settings.disconnect(this._settingDisabledValueId);
}
if (this._monitorId) {
this._baseMonitor.disconnect(this._monitorId);
}
@ -660,6 +666,13 @@ export const ThinkPad = GObject.registerClass({
GObject.ParamFlags.READABLE,
false
),
'pending-changes': GObject.ParamSpec.boolean(
'pending-changes',
'Pending changes',
'Indicates if the current values do not match the configured values',
GObject.ParamFlags.READABLE,
false
),
'batteries': GObject.ParamSpec.jsobject(
'batteries',
'Batteries',
@ -706,12 +719,12 @@ export const ThinkPad = GObject.registerClass({
this.batteries = [
new ThinkPadBattery({
'environment': this.environment,
'name': 'BAT0',
'name': 'BAT0',
'settings': this.settings
}),
new ThinkPadBattery({
'environment': this.environment,
'name': 'BAT1',
'name': 'BAT1',
'settings': this.settings
}),
];
@ -728,6 +741,11 @@ export const ThinkPad = GObject.registerClass({
this.isActive = this._checkActive();
}
);
const pendingChangesId = battery.connect(
'notify::pending-changes', (bat) => {
this.pendingChanges = this._checkPendingChanges();
}
);
const enableCompletedId = battery.connect(
'enable-completed', (bat, error) => {
this.emit('enable-battery-completed', bat, error);
@ -744,6 +762,7 @@ export const ThinkPad = GObject.registerClass({
// Load initial values
this.isAvailable = this._checkAvailable();
this.isActive = this._checkActive();
this.pendingChanges = this._checkPendingChanges();
}
get environment() {
@ -754,12 +773,12 @@ export const ThinkPad = GObject.registerClass({
}
get isAvailable() {
return this._isAvaialble;
return this._isAvailable;
}
set isAvailable(value) {
if (this.isAvailable !== value) {
this._isAvaialble = value;
this._isAvailable = value;
this.notify('is-available');
}
}
@ -775,6 +794,28 @@ export const ThinkPad = GObject.registerClass({
}
}
get pendingChanges() {
return this._pendingChanges;
}
set pendingChanges(value) {
if (this.pendingChanges !== value) {
this._pendingChanges = value;
this.notify('pending-changes');
}
}
/**
* Check if there are changes to the settings that need to be applied
*
* @returns {boolean} Returns true if there are changes to the settings that need to be applied
*/
_checkPendingChanges() {
return this.batteries.some(bat => {
return bat.pendingChanges;
});
}
/**
* Check if at least one battery has the thresholds active
*
@ -817,7 +858,7 @@ export const ThinkPad = GObject.registerClass({
runnable.connect('command-completed', (obj, error) => {
this.emit('enable-all-completed', error);
})
runnable.run();
runnable.run();
}
/**
@ -840,7 +881,7 @@ export const ThinkPad = GObject.registerClass({
runnable.connect('command-completed', (obj, error) => {
this.emit('disable-all-completed', error);
})
runnable.run();
runnable.run();
}
destroy() {

View File

@ -37,9 +37,6 @@ const BatteryItem = GObject.registerClass({
this._settings = settings;
this._battery = battery;
// Flag to prevent the PopupImageMenuItem from being activated when the reload icon is clicked
this._reloading = false;
const box = new St.BoxLayout({
'opacity': 128,
@ -58,9 +55,8 @@ const BatteryItem = GObject.registerClass({
});
this._reload.connectObject(
'button-press-event', () => {
this._reloading = true;
this._battery.enable();
return true; // Does not prevent event propagation???
return true;
},
this
);
@ -91,10 +87,7 @@ const BatteryItem = GObject.registerClass({
// Menu item action
this.connectObject(
'activate', () => {
if (!this._reloading) {
this._battery.toggle();
}
this._reloading = false;
this._battery.toggle();
},
'destroy', () => {
this._settings.disconnectObject(this);
@ -123,7 +116,11 @@ const BatteryItem = GObject.registerClass({
if (this._battery.isActive) {
// TRANSLATORS: %s is the name of the battery.
this.label.text = _('Disable thresholds (%s)').format(this._battery.name);
this.setIcon(getIcon('threshold-active', colorMode));
if (this._battery.pendingChanges) {
this.setIcon(getIcon('threshold-active-warning', colorMode));
} else {
this.setIcon(getIcon('threshold-active', colorMode));
}
// Status text
const showCurrentValues = this._settings.get_boolean('show-current-values');
if (showCurrentValues) {
@ -249,6 +246,9 @@ export const ThresholdIndicator = GObject.registerClass({
'notify::is-active', () => {
this._updateIndicator();
},
'notify::pending-changes', () => {
this._updateIndicator();
},
'enable-battery-completed', (driver, battery, error) => {
if (!error) {
this._notifyEnabled(
@ -330,6 +330,15 @@ export const ThresholdIndicator = GObject.registerClass({
this._driver = null;
this._extension = null;
});
// Pending changes alert
this._driver.batteries.every(battery => {
if (battery.pendingChanges && battery.isActive) {
this._notify(_('Battery Threshold'), _('The currently set thresholds do not match the configured ones'), 'threshold-active-warning', false);
return false;
}
return true;
});
}
/**
@ -339,7 +348,11 @@ export const ThresholdIndicator = GObject.registerClass({
const colorMode = this._settings.get_boolean('color-mode');
if (this._driver.isAvailable) {
if (this._driver.isActive) {
this._indicator.gicon = getIcon('threshold-active', colorMode);
if (this._driver.pendingChanges) {
this._indicator.gicon = getIcon('threshold-active-warning', colorMode);
} else {
this._indicator.gicon = getIcon('threshold-active', colorMode);
}
} else {
this._indicator.gicon = getIcon('threshold-inactive', colorMode);
}
@ -352,14 +365,14 @@ export const ThresholdIndicator = GObject.registerClass({
case 0: // Active
this._indicator.visible = this._driver.isActive;
break;
case 1: // Inactive
this._indicator.visible = !this._driver.isActive;
case 1: // Inactive (or pending changes)
this._indicator.visible = !this._driver.isActive || this._driver.pendingChanges;
break;
case 2: // Always
this._indicator.visible = true;
break;
case 3: // Never
this._indicator.visible = false;
case 3: // Never (or pending changes)
this._indicator.visible = this._driver.pendingChanges;
break;
default:
this._indicator.visible = true;
@ -368,15 +381,15 @@ export const ThresholdIndicator = GObject.registerClass({
}
/**
* Show notificaion.
* Show notification.
*
* @param {string} msg Title
* @param {string} details Message
* @param {string} iconName Icon name
* @param {boolean} [transient=true] Transient notification
*/
_notify(msg, details, iconName) {
_notify(msg, details, iconName, transient=true) {
if (!this._settings.get_boolean('show-notifications')) return;
const colorMode = this._settings.get_boolean('color-mode');
if (SHELL_VERSION === 45) {
const source = new MessageTray.Source(this._name);
Main.messageTray.add(source);
@ -384,9 +397,9 @@ export const ThresholdIndicator = GObject.registerClass({
source,
msg,
details,
{gicon: getIcon(iconName, colorMode)}
{gicon: getIcon(iconName, true)}
);
notification.setTransient(true);
notification.setTransient(transient);
source.showNotification(notification);
} else {
const source = new MessageTray.Source({'title': this._name});
@ -395,8 +408,8 @@ export const ThresholdIndicator = GObject.registerClass({
source: source,
title: msg,
body: details,
isTransient: true,
gicon: getIcon(iconName, colorMode)
isTransient: transient,
gicon: getIcon(iconName, true)
});
source.addNotification(notification);
}
@ -408,7 +421,7 @@ export const ThresholdIndicator = GObject.registerClass({
* @param {string} message Message
*/
_notifyError(message) {
this._notify(_('Battery Threshold'), message, 'threshold-error');
this._notify(_('Battery Threshold'), message, 'threshold-error', false);
}
/**