breakManager: Switch from lightbox to a Clutter effect for fading out

From some testing on a full session with break reminders enabled, it
seems that it’s possible to break the stacking order of the lightbox
actor if the user continues to interact with the session while it’s
visible (for example, while they’re supposed to be taking a movement
break).

Rather than try and work out what’s going on with the lightbox here, it
seems more robust to switch to using a Clutter effect, like we did with
the screen time UI (in `timeLimitsManager`). Then the effect can be
applied to the main UI group, and doesn’t depend on a separate actor
being placed in the right place in the scene graph.

So, remove the lightbox, and instead add a
`ClutterBrightnessSaturationEffect`, and use its brightness property to
fade the screen slightly while in breaks.

Signed-off-by: Philip Withnall <pwithnall@gnome.org>
Part-of: <https://gitlab.gnome.org/GNOME/gnome-shell/-/merge_requests/3655>
This commit is contained in:
Philip Withnall
2025-03-03 18:31:28 +00:00
committed by Marge Bot
parent 0d238a82e0
commit 5d1157cdfa

View File

@ -22,6 +22,7 @@
// SPDX-License-Identifier: GPL-2.0-or-later
import Clutter from 'gi://Clutter';
import Cogl from 'gi://Cogl';
import Gio from 'gi://Gio';
import GLib from 'gi://GLib';
import GObject from 'gi://GObject';
@ -29,7 +30,6 @@ import Shell from 'gi://Shell';
import St from 'gi://St';
import * as Gettext from 'gettext';
import * as Lightbox from '../ui/lightbox.js';
import * as Main from '../ui/main.js';
import * as MessageTray from '../ui/messageTray.js';
import * as SystemActions from './systemActions.js';
@ -40,8 +40,8 @@ const BREAK_OVERDUE_TIME_SECONDS = 60; // time after a break is due when the us
const BREAK_UPCOMING_NOTIFICATION_TIME_SECONDS = [2 * 60]; // notify the user 2min before a break is due; this must be kept in descending order
const BREAK_COUNTDOWN_TIME_SECONDS = 60;
const LIGHTBOX_FADE_TIME_SECONDS = 3;
const LIGHTBOX_FADE_FACTOR = 0.6;
const BRIGHTNESS_FADE_TIME_SECONDS = 3;
const BRIGHTNESS_FACTOR = 0.6;
/** @enum {number} */
const IdleState = {
@ -715,7 +715,7 @@ class BreakDispatcher extends GObject.Object {
this._systemActions = SystemActions.getDefault();
this._notificationSource = null;
this._lightbox = null;
this._brightnessEffect = null;
this._countdownOsd = null;
this._countdownTimerId = 0;
@ -736,11 +736,11 @@ class BreakDispatcher extends GObject.Object {
if (this._notificationSource === null)
this._notificationSource = new BreakNotificationSource(this._manager);
if (this._lightbox === null) {
this._lightbox = new Lightbox.Lightbox(Main.uiGroup, {
inhibitEvents: false,
fadeFactor: LIGHTBOX_FADE_FACTOR,
});
if (this._brightnessEffect === null) {
this._brightnessEffect = new Clutter.BrightnessContrastEffect({name: 'brightness'});
this._brightnessEffect.set_enabled(false);
Main.layoutManager.uiGroup.add_effect(this._brightnessEffect);
Main.layoutManager.uiGroup.connect('destroy', () => (this._brightnessEffect = null));
}
}
@ -748,8 +748,9 @@ class BreakDispatcher extends GObject.Object {
this._notificationSource?.destroy();
this._notificationSource = null;
this._lightbox?.destroy();
this._lightbox = null;
if (this._brightnessEffect !== null)
Main.layoutManager.uiGroup.remove_effect(this._brightnessEffect);
this._brightnessEffect = null;
this._removeCountdown();
@ -786,7 +787,7 @@ class BreakDispatcher extends GObject.Object {
if (this._previousState === BreakState.IN_BREAK)
this._maybePlayCompleteSound();
this._lightbox?.lightOff();
this._brightnessEffect.set_enabled(false);
// Work out when the next break is due, and schedule a countdown.
const currentTime = this._manager.getCurrentTime();
@ -821,7 +822,7 @@ class BreakDispatcher extends GObject.Object {
if (this._previousState === BreakState.IN_BREAK)
this._maybePlayCompleteSound();
this._lightbox?.lightOff();
this._brightnessEffect.set_enabled(false);
break;
}
@ -830,12 +831,10 @@ class BreakDispatcher extends GObject.Object {
this._ensureEnabled();
if (this._manager.breakTypeShouldLockScreen(this._manager.currentBreakType) &&
this._previousState !== BreakState.IN_BREAK) {
this._previousState !== BreakState.IN_BREAK)
this._systemActions.activateLockScreen();
} else if (this._manager.breakTypeShouldFadeScreen(this._manager.currentBreakType)) {
Main.uiGroup.set_child_above_sibling(this._lightbox, null);
this._lightbox.lightOn(LIGHTBOX_FADE_TIME_SECONDS * 1000);
}
else if (this._manager.breakTypeShouldFadeScreen(this._manager.currentBreakType))
this._brightnessEffectOn();
this._removeCountdown();
@ -858,12 +857,39 @@ class BreakDispatcher extends GObject.Object {
}
_onTakeBreak() {
if (this._manager.breakTypeShouldLockScreen(this._manager.currentBreakType)) {
if (this._manager.breakTypeShouldLockScreen(this._manager.currentBreakType))
this._systemActions.activateLockScreen();
} else if (this._manager.breakTypeShouldFadeScreen(this._manager.currentBreakType)) {
Main.uiGroup.set_child_above_sibling(this._lightbox, null);
this._lightbox.lightOn(LIGHTBOX_FADE_TIME_SECONDS * 1000);
}
else if (this._manager.breakTypeShouldFadeScreen(this._manager.currentBreakType))
this._brightnessEffectOn();
}
_brightnessEffectOn() {
// the effect value is in the range [0, 255] with 127 as the no change mid-point
const startVal = 127;
const startColor = new Cogl.Color({
red: startVal,
green: startVal,
blue: startVal,
alpha: 255,
});
const finishVal = 127 * BRIGHTNESS_FACTOR;
const finishColor = new Cogl.Color({
red: finishVal,
green: finishVal,
blue: finishVal,
alpha: 255,
});
this._brightnessEffect.brightness = startColor;
this._brightnessEffect.set_enabled(true);
Main.layoutManager.uiGroup.ease_property(
'@effects.brightness.brightness', finishColor,
{
duration: BRIGHTNESS_FADE_TIME_SECONDS * 1000,
mode: Clutter.AnimationMode.EASE_OUT_QUAD,
});
}
});