Skip to content

Commit b525701

Browse files
committed
support new brightness scale behavior in gnome 49.2
1 parent b447d29 commit b525701

File tree

7 files changed

+163
-22
lines changed

7 files changed

+163
-22
lines changed

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ This extension addresses some of the above with custom implementation:
1717
- **Improved Algorithm**: More stable under often changing light conditions
1818
- **Smooth Transitions**: Gradually changes brightness to avoid jarring jumps
1919
- **Customizable Brightness Curves**: Configure brightness response with an interactive graph-based UI
20-
- **Configuration Backup/Restore**: Export settings to JSON for backup, sharing, or manual editing to create custom brightness configurations.
20+
- **Configuration Backup/Restore**: Export settings to JSON for backup, sharing, or manual editing to create custom brightness configurations - [example](examples/win11-brightness-config.json).
2121

2222
# Installation
2323

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
{"brightness-buckets":[[0,10,0.1],[5,50,0.25],[15,100,0.4],[60,300,0.55],[150,400,0.7],[250,650,0.85],[350,10000,1]],"keyboard-backlight-levels":[1,0,0,0,0,0,0],"keyboard-idle-timeout":10}

lib/BrightnessManager.js

Lines changed: 21 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,18 @@
1-
import * as Main from 'resource:///org/gnome/shell/ui/main.js';
1+
import * as Config from 'resource:///org/gnome/shell/misc/config.js';
22
import { CallbackManager } from './CallbackManager.js';
33

44
// GNOME49 introduces new interface to manage brightness
55
// https://gitlab.gnome.org/GNOME/gnome-shell/-/blob/gnome-49/js/misc/brightnessManager.js?ref_type=heads
66
export class BrightnessManager {
7-
constructor() {
8-
this._manager = Main.brightnessManager;
7+
constructor(brightnessManager) {
8+
const [major, minor] = Config.PACKAGE_VERSION.split('.').map((x) => Number.parseInt(x));
9+
10+
// gnome 49.2 introduced new behavour of brightness slider in auto-brightness mode
11+
// slider adjusts user preference (bias) for automatic brightness value
12+
// https://gitlab.gnome.org/GNOME/gnome-shell/-/commit/30645802ef3282fe1e24bb73cb9fcf23586d593f
13+
this._supportsBiasSlider = major > 49 || (major === 49 && minor >= 2);
14+
15+
this._manager = brightnessManager;
916
this._changedSignalId = null;
1017
this._globalScaleSignalId = null;
1118
this._currentGlobalScale = null; // Keep reference for cleanup
@@ -40,16 +47,23 @@ export class BrightnessManager {
4047
// Listen to globalScale changes to capture user preference (e.g., hotkeys)
4148
// This fires even during dimming when user tries to adjust brightness
4249
this._currentGlobalScale = this._manager.globalScale;
43-
this._globalScaleSignalId = this._currentGlobalScale.connect('notify::value', () => {
44-
const userPreference = this._manager?.globalScale?.value ?? null;
45-
this.onUserPreferenceChange.invoke(userPreference);
46-
});
50+
51+
if (!this._supportsBiasSlider) {
52+
this._globalScaleSignalId = this._currentGlobalScale.connect('notify::value', () => {
53+
const userPreference = this._manager?.globalScale?.value ?? null;
54+
this.onUserPreferenceChange.invoke(userPreference);
55+
});
56+
}
4757

4858
// Listen to monitor backlight changes to detect actual brightness changes
4959
// This includes: manual changes, dimming, and system-initiated changes
5060
// Store references to the scale objects for proper cleanup
5161
const scales = this._manager.scales || [];
5262
for (const scale of scales) {
63+
if (this._supportsBiasSlider) {
64+
scale.value = 0.5; // set neutral bias on monitor change
65+
}
66+
5367
const signalId = scale.connect('backlights-changed', () => {
5468
this.onBrightnessChange.invoke(this.brightness);
5569
});

lib/DisplayBrightnessService.js

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import GLib from 'gi://GLib';
22
import Gio from 'gi://Gio';
3-
import * as Config from 'resource:///org/gnome/shell/misc/config.js';
3+
import * as Main from 'resource:///org/gnome/shell/ui/main.js';
44
import { BrightnessAnimator } from './BrightnessAnimator.js';
55
import { BrightnessManager } from './BrightnessManager.js';
66
import { BrightnessDbus } from './BrightnessDbus.js';
@@ -12,11 +12,9 @@ export class DisplayBrightnessService {
1212
schema: 'org.gnome.settings-daemon.plugins.power',
1313
});
1414

15-
const [major] = Config.PACKAGE_VERSION.split('.');
16-
this.backend =
17-
Number.parseInt(major) < 49
18-
? new BrightnessDbus(this._powerSettings)
19-
: new BrightnessManager();
15+
this.backend = Main.brightnessManager
16+
? new BrightnessManager(Main.brightnessManager)
17+
: new BrightnessDbus(this._powerSettings);
2018

2119
// Brightness animation
2220
this._animator = new BrightnessAnimator();

metadata.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,5 +10,5 @@
1010
"github": "dmy3k",
1111
"buymeacoffee": "dm3k"
1212
},
13-
"version": 18
13+
"version": 20
1414
}

tests/BrightnessManager.test.js

Lines changed: 128 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,15 @@
11
import { describe, it, expect, beforeEach, afterEach, jest } from '@jest/globals';
22
import { BrightnessManager } from '../lib/BrightnessManager.js';
33
import * as Main from 'resource:///org/gnome/shell/ui/main.js';
4+
import * as Config from 'resource:///org/gnome/shell/misc/config.js';
45

56
describe('BrightnessManager', () => {
67
let manager;
78

89
beforeEach(() => {
910
Main.resetBrightnessManager(true);
10-
manager = new BrightnessManager();
11+
Config.setPackageVersion('49.2'); // Default to 49.2 for testing
12+
manager = new BrightnessManager(Main.brightnessManager);
1113
});
1214

1315
afterEach(() => {
@@ -55,14 +57,13 @@ describe('BrightnessManager', () => {
5557
expect(secondId).toBeDefined();
5658
});
5759

58-
it('should setup globalScale listener when changed signal is emitted', () => {
60+
it('should setup monitor scale listeners when changed signal is emitted', () => {
5961
manager.connect();
6062

61-
// Trigger the 'changed' signal which should set up globalScale listener
63+
// Trigger the 'changed' signal which should set up monitor scale listeners
6264
Main.brightnessManager.emit('changed');
6365

64-
expect(manager._globalScaleSignalId).toBeDefined();
65-
expect(typeof manager._globalScaleSignalId).toBe('number');
66+
expect(manager._monitorScaleSignalIds.length).toBeGreaterThan(0);
6667
});
6768
});
6869

@@ -218,7 +219,7 @@ describe('BrightnessManager', () => {
218219
manager.connect();
219220
Main.brightnessManager.emit('changed'); // Set up listeners
220221

221-
expect(manager._globalScaleSignalId).not.toBeNull();
222+
// Monitor scale listeners should always be set up
222223
expect(manager._monitorScaleSignalIds.length).toBeGreaterThan(0);
223224

224225
manager.destroy();
@@ -260,4 +261,125 @@ describe('BrightnessManager', () => {
260261
expect(manager._manager).toBeNull();
261262
});
262263
});
264+
265+
describe('version-specific behavior', () => {
266+
describe('GNOME 49.2+ (bias slider support)', () => {
267+
beforeEach(() => {
268+
Config.setPackageVersion('49.2');
269+
Main.resetBrightnessManager(true);
270+
manager = new BrightnessManager(Main.brightnessManager);
271+
});
272+
273+
it('should detect GNOME 49.2+ and enable bias slider support', () => {
274+
expect(manager._supportsBiasSlider).toBe(true);
275+
});
276+
277+
it('should NOT setup globalScale value listener on GNOME 49.2+', () => {
278+
manager.connect();
279+
Main.brightnessManager.emit('changed');
280+
281+
// globalScale listener should not be set up for bias slider versions
282+
expect(manager._globalScaleSignalId).toBeNull();
283+
});
284+
285+
it('should set monitor scales to neutral bias (0.5) on monitor change', () => {
286+
manager.connect();
287+
Main.brightnessManager.emit('changed');
288+
289+
const scales = Main.brightnessManager.scales;
290+
expect(scales.length).toBeGreaterThan(0);
291+
for (const scale of scales) {
292+
expect(scale.value).toBe(0.5);
293+
}
294+
});
295+
296+
it('should not trigger user preference callbacks', () => {
297+
const callback = jest.fn();
298+
manager.onUserPreferenceChange.add(callback);
299+
300+
manager.connect();
301+
Main.brightnessManager.emit('changed');
302+
303+
// Change globalScale value
304+
Main.brightnessManager.globalScale.value = 0.8;
305+
306+
// Callback should NOT be invoked on 49.2+
307+
expect(callback).not.toHaveBeenCalled();
308+
});
309+
});
310+
311+
describe('GNOME 49.0-49.1 (no bias slider)', () => {
312+
beforeEach(() => {
313+
Config.setPackageVersion('49.0');
314+
Main.resetBrightnessManager(true);
315+
manager = new BrightnessManager(Main.brightnessManager);
316+
});
317+
318+
it('should detect GNOME 49.0 and disable bias slider support', () => {
319+
expect(manager._supportsBiasSlider).toBe(false);
320+
});
321+
322+
it('should setup globalScale value listener on GNOME 49.0', () => {
323+
manager.connect();
324+
Main.brightnessManager.emit('changed');
325+
326+
// globalScale listener should be set up for non-bias slider versions
327+
expect(manager._globalScaleSignalId).not.toBeNull();
328+
expect(typeof manager._globalScaleSignalId).toBe('number');
329+
});
330+
331+
it('should NOT set monitor scales to neutral bias', () => {
332+
manager.connect();
333+
334+
// Set scales to different values before triggering change
335+
const scales = Main.brightnessManager.scales;
336+
const originalValue = scales[0].value;
337+
338+
Main.brightnessManager.emit('changed');
339+
340+
// On GNOME 49.0 (no bias slider), scales should NOT be reset to 0.5
341+
// They keep their original values
342+
expect(scales[0].value).toBe(originalValue);
343+
});
344+
345+
it('should trigger user preference callbacks on globalScale changes', () => {
346+
const callback = jest.fn();
347+
manager.onUserPreferenceChange.add(callback);
348+
349+
manager.connect();
350+
Main.brightnessManager.emit('changed');
351+
352+
// Change globalScale value - this should trigger the callback
353+
Main.brightnessManager.globalScale.value = 0.8;
354+
355+
expect(callback).toHaveBeenCalledWith(0.8);
356+
});
357+
});
358+
359+
describe('GNOME 50+ (future versions)', () => {
360+
beforeEach(() => {
361+
Config.setPackageVersion('50.0');
362+
Main.resetBrightnessManager(true);
363+
manager = new BrightnessManager(Main.brightnessManager);
364+
});
365+
366+
it('should detect GNOME 50+ and enable bias slider support', () => {
367+
expect(manager._supportsBiasSlider).toBe(true);
368+
});
369+
370+
it('should behave like GNOME 49.2+ for future versions', () => {
371+
manager.connect();
372+
Main.brightnessManager.emit('changed');
373+
374+
// Should not set up globalScale listener
375+
expect(manager._globalScaleSignalId).toBeNull();
376+
377+
// Should set neutral bias
378+
const scales = Main.brightnessManager.scales;
379+
for (const scale of scales) {
380+
expect(scale.value).toBe(0.5);
381+
}
382+
});
383+
});
384+
});
263385
});

tests/__mocks__/resource/org/gnome/shell/misc/config.js

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,4 +2,10 @@
22
* Mock for GNOME Shell's config module
33
*/
44

5-
export const PACKAGE_VERSION = '49.0';
5+
// Default to GNOME 49.2 for testing bias slider behavior
6+
export let PACKAGE_VERSION = '49.2';
7+
8+
// Helper to change version for testing
9+
export function setPackageVersion(version) {
10+
PACKAGE_VERSION = version;
11+
}

0 commit comments

Comments
 (0)