Show live wallpaper through workspace-switch animation and lock screen
Both gnome-shell animations paint their own independent static copy of the desktop background on top of the live wallpaper actor: the workspace-switch swipe (WorkspaceBackground) and the lock screen (UnlockDialog, which already applies native blur). Patch both private _createBackground methods to hide the static clone / attach a shared-content actor so the live video shows through instead, gated on the existing apply-to-lock-screen settings
This commit is contained in:
@@ -4,6 +4,8 @@ import Clutter from 'gi://Clutter';
|
|||||||
import Graphene from 'gi://Graphene';
|
import Graphene from 'gi://Graphene';
|
||||||
import St from 'gi://St';
|
import St from 'gi://St';
|
||||||
import * as Main from 'resource:///org/gnome/shell/ui/main.js';
|
import * as Main from 'resource:///org/gnome/shell/ui/main.js';
|
||||||
|
import * as WorkspaceAnimation from 'resource:///org/gnome/shell/ui/workspaceAnimation.js';
|
||||||
|
import * as UnlockDialogModule from 'resource:///org/gnome/shell/ui/unlockDialog.js';
|
||||||
|
|
||||||
import {SettingsKey} from './settingsKeys.js';
|
import {SettingsKey} from './settingsKeys.js';
|
||||||
import {loadGstreamerModules, GSTREAMER_INSTALL_HINT} from './gstreamerAvailability.js';
|
import {loadGstreamerModules, GSTREAMER_INSTALL_HINT} from './gstreamerAvailability.js';
|
||||||
@@ -96,6 +98,9 @@ export class LiveWallpaperManager {
|
|||||||
|
|
||||||
this._transitionOverlay = null;
|
this._transitionOverlay = null;
|
||||||
this._fadeInPending = false;
|
this._fadeInPending = false;
|
||||||
|
|
||||||
|
this._patchedMethods = [];
|
||||||
|
this._lockScreenActors = [];
|
||||||
}
|
}
|
||||||
|
|
||||||
get isAvailable() {
|
get isAvailable() {
|
||||||
@@ -128,6 +133,7 @@ export class LiveWallpaperManager {
|
|||||||
|
|
||||||
this._monitorsChangedId = Main.layoutManager.connect('monitors-changed', () => this._layoutActor());
|
this._monitorsChangedId = Main.layoutManager.connect('monitors-changed', () => this._layoutActor());
|
||||||
|
|
||||||
|
this._patchShellIntegration();
|
||||||
this._sync();
|
this._sync();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -141,10 +147,96 @@ export class LiveWallpaperManager {
|
|||||||
this._monitorsChangedId = 0;
|
this._monitorsChangedId = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
this._unpatchShellIntegration();
|
||||||
this._stop();
|
this._stop();
|
||||||
this._clearTransition();
|
this._clearTransition();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Two of gnome-shell's own animations paint a *second*, independent
|
||||||
|
* background on top of ours, hiding the live wallpaper behind a frozen
|
||||||
|
* static image: the workspace-switch swipe (which clones the desktop
|
||||||
|
* picture per-workspace so it can slide, see WorkspaceBackground in
|
||||||
|
* workspaceAnimation.js) and the lock screen (which blurs its own
|
||||||
|
* separate copy of the desktop picture, see UnlockDialog in
|
||||||
|
* unlockDialog.js). Neither exposes a public hook for this, so both are
|
||||||
|
* patched at the prototype level — wrapped in try/catch per-patch since
|
||||||
|
* this reaches into shell-private methods that could rename across
|
||||||
|
* versions, and one patch failing shouldn't take down the other.
|
||||||
|
*/
|
||||||
|
_patchShellIntegration() {
|
||||||
|
const manager = this;
|
||||||
|
|
||||||
|
try {
|
||||||
|
const {WorkspaceBackground} = WorkspaceAnimation;
|
||||||
|
this._patchMethod(WorkspaceBackground.prototype, '_createBackground', original => function (...args) {
|
||||||
|
const result = original.call(this, ...args);
|
||||||
|
// Only the freshly-added static background clone is hidden
|
||||||
|
// (not the whole WorkspaceBackground group), so any real
|
||||||
|
// desktop-icon windows it also hosts stay visible.
|
||||||
|
const staticBackground = this.get_last_child();
|
||||||
|
if (manager.isActive && staticBackground)
|
||||||
|
staticBackground.visible = false;
|
||||||
|
return result;
|
||||||
|
});
|
||||||
|
} catch (e) {
|
||||||
|
this._logger.debug(`Workspace-switch live wallpaper integration unavailable (${e.message ?? e})`);
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
const {UnlockDialog} = UnlockDialogModule;
|
||||||
|
this._patchMethod(UnlockDialog.prototype, '_createBackground', original => function (monitorIndex) {
|
||||||
|
const result = original.call(this, monitorIndex);
|
||||||
|
manager._attachLockScreenActor(this._backgroundGroup.get_last_child());
|
||||||
|
return result;
|
||||||
|
});
|
||||||
|
} catch (e) {
|
||||||
|
this._logger.debug(`Lock screen live wallpaper integration unavailable (${e.message ?? e})`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
_patchMethod(obj, name, wrap) {
|
||||||
|
const original = obj[name];
|
||||||
|
obj[name] = wrap(original);
|
||||||
|
this._patchedMethods.push({obj, name, original});
|
||||||
|
}
|
||||||
|
|
||||||
|
_unpatchShellIntegration() {
|
||||||
|
for (const {obj, name, original} of this._patchedMethods)
|
||||||
|
obj[name] = original;
|
||||||
|
this._patchedMethods = [];
|
||||||
|
this._lockScreenActors = [];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds an actor sharing our live frame's Content onto the lock screen's
|
||||||
|
* already-blurred per-monitor background widget (native Shell.BlurEffect
|
||||||
|
* radius 90, see UnlockDialog._createBackground) — reusing gnome-shell's
|
||||||
|
* own blur rather than applying a second one. Content is a step behind
|
||||||
|
* a frame: _updateFrame() re-points every tracked actor at `_image`
|
||||||
|
* each time a new one is decoded, so this needs no per-frame decode of
|
||||||
|
* its own and needs no update here if playback hasn't started yet
|
||||||
|
* (nothing to show is just transparent, revealing the native static
|
||||||
|
* background beneath).
|
||||||
|
*/
|
||||||
|
_attachLockScreenActor(container) {
|
||||||
|
if (!container || !this._available || !this._settings.get_boolean(SettingsKey.APPLY_TO_LOCK_SCREEN))
|
||||||
|
return;
|
||||||
|
|
||||||
|
const actor = new Clutter.Actor({
|
||||||
|
x: 0, y: 0,
|
||||||
|
width: container.width,
|
||||||
|
height: container.height,
|
||||||
|
content: this._image,
|
||||||
|
content_gravity: Clutter.ContentGravity.RESIZE_FILL,
|
||||||
|
});
|
||||||
|
container.add_child(actor);
|
||||||
|
this._lockScreenActors.push(actor);
|
||||||
|
actor.connect('destroy', () => {
|
||||||
|
this._lockScreenActors = this._lockScreenActors.filter(a => a !== actor);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
async _loadGstreamer() {
|
async _loadGstreamer() {
|
||||||
try {
|
try {
|
||||||
const {Gst, Cogl} = await loadGstreamerModules();
|
const {Gst, Cogl} = await loadGstreamerModules();
|
||||||
@@ -397,6 +489,10 @@ export class LiveWallpaperManager {
|
|||||||
}
|
}
|
||||||
strategy.upload(this._image, this._Cogl, data, width, height);
|
strategy.upload(this._image, this._Cogl, data, width, height);
|
||||||
this._actor.set_content(this._image);
|
this._actor.set_content(this._image);
|
||||||
|
for (const lockActor of this._lockScreenActors) {
|
||||||
|
lockActor.set_content(this._image);
|
||||||
|
lockActor.visible = true;
|
||||||
|
}
|
||||||
return;
|
return;
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
this._logger.warn(
|
this._logger.warn(
|
||||||
@@ -715,6 +811,13 @@ export class LiveWallpaperManager {
|
|||||||
this._videoHeight = 0;
|
this._videoHeight = 0;
|
||||||
this._fadeInPending = false;
|
this._fadeInPending = false;
|
||||||
|
|
||||||
|
// Leaves the frozen last frame's Content in place rather than
|
||||||
|
// clearing it — a stopped/paused live wallpaper just hides its lock
|
||||||
|
// screen actor, revealing the native static blurred background
|
||||||
|
// beneath, without losing the tracked actor if playback resumes.
|
||||||
|
for (const lockActor of this._lockScreenActors)
|
||||||
|
lockActor.visible = false;
|
||||||
|
|
||||||
this._setActive(false);
|
this._setActive(false);
|
||||||
this._paused = false;
|
this._paused = false;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user