A GNOME Shell extension that lets you use any video as your lock screen background and desktop wallpaper. This is a fork of Live Lock Screen by nick-redwill, extended with additional features. Features: • Video lock screen and desktop wallpaper playback • Multi-video playlists with random or sequential playback • Per-monitor video configuration for multi-display setups • Auto FPS detection for smooth playback • Blur and brightness effects with password prompt customization • Battery optimization (separate controls for lockscreen and wallpaper) • Panel quick controls for play/pause, next video, and settings • Dynamic panel icons that change based on wallpaper/lockscreen state • Sleep/wake handling for proper video management during system suspend • Pause when hidden modes to save resources • GTK4 renderer for high-performance playback (with legacy appsink fallback) Note: Requires GStreamer plugins and ffmpeg (for thumbnail generation). See the README on GitHub for installation instructions. Based on Live Lock Screen by nick-redwill (https://github.com/nick-redwill/LiveLockScreen)
Note: Binary files aren't shown on the web site. To see all files, please download the extension zipfile.
EGO-A-004 warning
extension files should not contain excessive ungated console logging
File contains 13 ungated console.log/warn/error calls (threshold: 5).
core/pipeline.js:60
console.error(`[Pipeline:${this._name}] init: video file not found: ${this._videoPath}`)
core/pipeline.js:295
console.error('Pipeline init failed: ', e.message)
core/pipeline.js:444
console.error(`[Pipeline:${this._name}] Error in frame processing: ${e.message}`)
core/pipeline.js:101
console.log(`[Pipeline:${this._name}] GPU colour conversion: ✓ (glupload → glcolorconvert → gldownload)`)
core/pipeline.js:103
console.log(`[Pipeline:${this._name}] GPU colour conversion: ✗ GL elements not available, falling back to CPU videoconvert`)
core/pipeline.js:159
console.log(`[Pipeline:${this._name}] Warning: failed to link ${binElements[i].name} → ${binElements[i + 1].name}`)
core/pipeline.js:268
console.log(`[Pipeline:${this._name}] Initialized: ${this._framerate} fps (${interval.toFixed(1)}ms${scaleInfo}${staggerInfo}), polling: ${deliveryLabel}, priority: ${prioLabel}, hwdec: ${hwLabel}, gpu-cc: ${gpuLabel}`)
core/pipeline.js:274
console.log(`[Pipeline:${this._name}] Stagger delay elapsed, starting frame timer`)
core/pipeline.js:328
console.log(`[Pipeline:${this._name}] HW decoder ranks boosted: ${boosted.join(', ')}`)
core/pipeline.js:330
console.log(`[Pipeline:${this._name}] No hardware decoders found on this system`)
EGO-X-002 warning
extensions should not use synchronous subprocess APIs in shell code
Shell code should avoid synchronous subprocess APIs like `GLib.spawn_command_line_sync()` and `GLib.spawn_sync()`.
core/player_process.js:271
GLib.spawn_command_line_sync(`kill ${pid}`)
EGO-C49-003 error
extensions targeting GNOME 49 must not call maximize or unmaximize with Meta.MaximizeFlags
This extension explicitly targets GNOME Shell 49 but still passes `Meta.MaximizeFlags` to `maximize()` or `unmaximize()`.
core/player_process.js:162
win.unmaximize(Meta.MaximizeFlags.BOTH)
EGO-A-004 warning
extension files should not contain excessive ungated console logging
File contains 120 ungated console.log/warn/error calls (threshold: 5).
extension.js:147
console.error('[LiveLockPaper] Failed to initialize GStreamer')
extension.js:205
console.error(`[LiveLockPaper] Activation failed: ${e.message}\n${e.stack}`)
extension.js:210
console.error(`[LiveLockPaper] _deferredInit failed: ${e.message}\n${e.stack}`)
extension.js:254
console.error(`[LiveLockPaper] _fullTeardown failed: ${e.message}\n${e.stack}`)
extension.js:279
console.error(`[LiveLockPaper] _onSessionModeChanged crashed: ${e.message}\n${e.stack}`)
extension.js:1108
console.error('[LockScreen] screenShield._dialog not available after retries')
extension.js:1128
console.error(`[LockScreen] _enableLockScreen failed: ${e.message}\n${e.stack}`)
extension.js:1523
console.error(`[LockScreen:GTK4] Failed to spawn player: ${e.message}`)
extension.js:1609
console.error(`[LockScreen:GTK4] ${err}`)
extension.js:2096
console.error(`[LockScreen] Pipeline init/play failed: ${e.message}`)
EGO-A-004 warning
extension files should not contain excessive ungated console logging
File contains 85 ungated console.log/warn/error calls (threshold: 5).
prefs.js:820
console.log('Could not migrate video path:', e)
prefs.js:848
console.log(`[Video] Error opening video ${row._videoPath}:`, e)
prefs.js:974
console.log('Error unpacking metadata:', e)
prefs.js:988
console.log(`[Metadata] Raw metadata for ${path}: ${metaStr}`)
prefs.js:996
console.log(`[Metadata] Extracting variant type: ${variantType}`)
prefs.js:999
console.log(`[Metadata] Extracted int value: ${result}`)
prefs.js:1012
console.log(`[Metadata] Could not extract value from variant:`, e2)
prefs.js:1019
console.log(`[Metadata] Extracted via get_int32: ${result}`)
prefs.js:1040
console.log(`[Metadata] Extracted values for ${path}:`, { width, height, fps, duration, playCount })
prefs.js:1061
console.log(`[Metadata] Displaying duration: ${minutes}:${seconds.toString().padStart(2, '0')} for ${path}`)
EGO-P-006 warning
unnecessary build and translation artifacts should not be shipped
Package contains files that often should not be shipped for review.
Don't include unnecessary files
screenshots/lockscreen-clock.png
screenshots/lockscreen-clock.png
EGO-P-006 warning
unnecessary build and translation artifacts should not be shipped
Compiled GSettings schemas should not be shipped for 45+ packages.
Don't include unnecessary files
schemas/gschemas.compiled
schemas/gschemas.compiled
EGO-P-004 error
GSettings schema XML filename must match schema id
GSettings schema filename must match `<schema-id>.gschema.xml`.
schemas/org.gnome.shell.extensions.live-lockscreen.gschema.xml
id='org.gnome.shell.extensions.live-lockpaper-deluca21' path='/org/gnome/shell/extensions/live-lockpaper-deluca21/'
EGO-P-007 warning
JavaScript files should be reachable from extension.js or prefs.js
Some JavaScript files are not reachable from `extension.js` or `prefs.js` imports.
Don't include unnecessary files
external/command_handler.js
external/pipeline.js
external/player.js
external/run.js
EGO-L-002 warning
objects created by extension should be destroyed in disable()
Objects assigned in `enable()` are missing matching `.destroy()` calls in `disable()` or its helper methods.
extension.js:598
this._menuGtkRendererSwitch = new PopupMenu.PopupSwitchMenuItem(
'Use GTK4 renderer',
!this._settings.get_boolean(Keys.DEBUG_USE_GTK4_SINK)
)
extension.js:583
this._menuLockscreenDisableOnBatterySwitch = new PopupMenu.PopupSwitchMenuItem(
'Disable on battery',
this._settings.get_boolean(Keys.LOCKSCREEN_DISABLE_ON_BATTERY)
)
extension.js:508
this._menuLockscreenEnabledSwitch = new PopupMenu.PopupSwitchMenuItem(
'Lock screen video',
this._settings.get_boolean(Keys.LOCKSCREEN_ENABLED)
)
extension.js:505
this._menuLockscreenGroup = new PopupMenu.PopupSubMenuMenuItem('Lock screen', true)
extension.js:554
this._menuLsBlurSwitch = new PopupMenu.PopupSwitchMenuItem(
'Blur',
(this._settings.get_int(Keys.BLUR_RADIUS) ?? 0) > 0
)
extension.js:573
this._menuLsGrayscaleSwitch = new PopupMenu.PopupSwitchMenuItem(
'Grayscale effect',
this._settings.get_boolean(Keys.PROMPT_GRAYSCALE)
)
extension.js:535
this._menuLsMuteSwitch = new PopupMenu.PopupSwitchMenuItem(
'Mute lockscreen audio',
this._settings.get_int(Keys.AUDIO_VOLUME) === 0
)
extension.js:526
this._menuLsPerMonitorSwitch = new PopupMenu.PopupSwitchMenuItem(
'Per-monitor videos',
this._settings.get_boolean(Keys.LOCKSCREEN_PER_MONITOR)
)
extension.js:517
this._menuLsRandomOrderSwitch = new PopupMenu.PopupSwitchMenuItem(
'Random order',
this._settings.get_boolean(Keys.VIDEO_RANDOM_ORDER)
)
extension.js:453
this._menuMuteSwitch = new PopupMenu.PopupSwitchMenuItem(
'Mute wallpaper audio',
this._settings.get_int(Keys.WALLPAPER_VOLUME) === 0
)
extension.js:393
this._menuNextItem = new PopupMenu.PopupMenuItem('Next Video')
extension.js:433
this._menuPauseWhenHiddenItem = new PopupMenu.PopupMenuItem('')
extension.js:422
this._menuPerMonitorSwitch = new PopupMenu.PopupSwitchMenuItem(
'Per-monitor videos',
this._settings.get_boolean(Keys.WALLPAPER_PER_MONITOR)
)
extension.js:386
this._menuPlayPauseItem = new PopupMenu.PopupMenuItem('Pause Wallpaper')
extension.js:413
this._menuRandomOrderSwitch = new PopupMenu.PopupSwitchMenuItem(
'Random order',
this._settings.get_boolean(Keys.WALLPAPER_RANDOM_ORDER)
)
extension.js:609
this._menuRestartItem = new PopupMenu.PopupMenuItem('Restart Wallpaper')
extension.js:617
this._menuSettingsItem = new PopupMenu.PopupMenuItem('Open Settings')
extension.js:472
this._menuWallpaperBlurSwitch = new PopupMenu.PopupSwitchMenuItem(
'Wallpaper blur',
(this._settings.get_int(Keys.WALLPAPER_BLUR_RADIUS) ?? 0) > 0
)
extension.js:492
this._menuWallpaperDisableOnBatterySwitch = new PopupMenu.PopupSwitchMenuItem(
'Disable on battery',
this._settings.get_boolean(Keys.WALLPAPER_DISABLE_ON_BATTERY)
)
extension.js:404
this._menuWallpaperEnabledSwitch = new PopupMenu.PopupSwitchMenuItem(
'Wallpaper enabled',
this._settings.get_boolean(Keys.WALLPAPER_ENABLED)
)
extension.js:401
this._menuWallpaperGroup = new PopupMenu.PopupSubMenuMenuItem('Wallpaper', true)
extension.js:379
this._panelIcon = new St.Icon({
icon_name: 'preferences-desktop-wallpaper-symbolic',
fallback_icon_name: 'image-x-generic-symbolic',
style_class: 'system-status-icon',
})
EGO-L-005 warning
owned object references should be released in disable()
Owned references that are cleaned up in `disable()` should also be released with `null` or `undefined`.
extension.js:505
this._menuLockscreenGroup = new PopupMenu.PopupSubMenuMenuItem('Lock screen', true)
extension.js:554
this._menuLsBlurSwitch = new PopupMenu.PopupSwitchMenuItem(
'Blur',
(this._settings.get_int(Keys.BLUR_RADIUS) ?? 0) > 0
)
extension.js:535
this._menuLsMuteSwitch = new PopupMenu.PopupSwitchMenuItem(
'Mute lockscreen audio',
this._settings.get_int(Keys.AUDIO_VOLUME) === 0
)
extension.js:526
this._menuLsPerMonitorSwitch = new PopupMenu.PopupSwitchMenuItem(
'Per-monitor videos',
this._settings.get_boolean(Keys.LOCKSCREEN_PER_MONITOR)
)
extension.js:517
this._menuLsRandomOrderSwitch = new PopupMenu.PopupSwitchMenuItem(
'Random order',
this._settings.get_boolean(Keys.VIDEO_RANDOM_ORDER)
)
extension.js:401
this._menuWallpaperGroup = new PopupMenu.PopupSubMenuMenuItem('Wallpaper', true)
EGO-L-003 warning
signals connected by extension should be disconnected in disable()
Signals assigned in `enable()` are missing matching disconnect calls in `disable()` or its helper methods.
extension.js:558
this._menuLsBlurId = this._menuLsBlurSwitch.connect('toggled', (_item, state) => {
const current = this._settings.get_int(Keys.BLUR_RADIUS);
if (!state) {
if (current > 0)
this._panelLsBlurRestoreRadius = current;
th
extension.js:539
this._menuLsMuteId = this._menuLsMuteSwitch.connect('toggled', (_item, state) => {
const current = this._settings.get_int(Keys.AUDIO_VOLUME);
if (state) {
if (current > 0)
this._panelLsMuteRestoreVolume = current;
th
extension.js:530
this._menuLsPerMonitorId = this._menuLsPerMonitorSwitch.connect('toggled', (_item, state) => {
this._settings.set_boolean(Keys.LOCKSCREEN_PER_MONITOR, state);
})
extension.js:521
this._menuLsRandomOrderId = this._menuLsRandomOrderSwitch.connect('toggled', (_item, state) => {
this._settings.set_boolean(Keys.VIDEO_RANDOM_ORDER, state);
})
EGO-L-004 warning
main loop sources should be removed in disable()
Main loop sources assigned in `enable()` are missing matching removals in `disable()` or its helper methods.
extension.js:2754
GLib.timeout_add(GLib.PRIORITY_DEFAULT, 1000, () => {
this._setupPauseWhenHidden();
this._wpPauseWhenHiddenReady = true;
return GLib.SOURCE_REMOVE;
})
extension.js:2908
GLib.timeout_add(GLib.PRIORITY_DEFAULT, 1000, () => {
this._setupPauseWhenHiddenSubprocess();
this._wpPauseWhenHiddenReady = true;
return GLib.SOURCE_REMOVE;
})
extension.js:3150
GLib.timeout_add(GLib.PRIORITY_DEFAULT, 1000, () => {
if (this._wpPlayerProcess) {
// Subprocess mode
this._setupPauseWhenHiddenSubprocess();
} else if (this._wpPipelines && this._wpPipelines.leng
extension.js:3204
GLib.timeout_add(GLib.PRIORITY_DEFAULT, 500, () => {
this._refreshGtkHelperWindowHints('settings-restart-500ms');
this._debugDumpWindowSnapshot('settings-restart-500ms');
// Only verify windows if using GTK4
extension.js:3217
GLib.timeout_add(GLib.PRIORITY_DEFAULT, 1500, () => {
// Double-check we're still not in a restart
if (this._wpRestartInFlight || this._wpRestartTimeout || !this._active) {
return GLib.SOU
extension.js:3745
GLib.timeout_add(GLib.PRIORITY_DEFAULT, 200, () => {
if (hasPipelines) this._checkDesktopVisibility();
if (hasSubprocess) {
this._checkDesktopVisibilitySubprocess();
}
return GLib.SOURCE_REMOVE;
extension.js:3755
GLib.timeout_add(GLib.PRIORITY_DEFAULT, 900, () => {
if (Main.sessionMode.currentMode !== 'user')
return GLib.SOURCE_REMOVE;
if (hasSubprocess && this._wpPlayerProcess) {
this._wpPlayerProcess.play();
extension.js:3771
GLib.timeout_add(GLib.PRIORITY_DEFAULT, 600, () => {
if (Main.sessionMode.currentMode !== 'user')
return GLib.SOURCE_REMOVE;
this._refreshGtkHelperWindowHints('post-resume-600ms');
return GLib.SOURCE_REMOVE;
EGO-L-007 warning
main loop sources should be removed before being recreated
Main loop sources should be removed before creating a new source on the same field.
extension.js:83
this._deferredInitId = GLib.timeout_add(GLib.PRIORITY_DEFAULT, delay, () => {
this._deferredInitId = null;
if (!this._active) return GLib.SOURCE_REMOVE;
this._deferredInit();
return GLib.SOURCE_REMOVE;
})
extension.js:3046
this._wpVisibilityCheckId = GLib.timeout_add(
GLib.PRIORITY_DEFAULT,
300,
() => {
this._checkDesktopVisibilitySubprocess();
return GLib.SOURCE_CONTINUE;
}
)
EGO-M-008 warning
extensions using unlock-dialog must document it in disable() comments
Extensions using `unlock-dialog` should document the reason in `disable()` comments.
extension.js:94
disable() {
const mode = Main.sessionMode.currentMode;
console.log(`[LiveLockPaper] disable() called, sessionMode=${mode}`);
this._active = false;
// Cancel pending deferred init (the main debounce mechanism)
if (this._deferredInitId) {
GLib.
| Version | Status |
|---|---|
| 1 | Unreviewed |