pre-capture lock screen screenshots via hidden window and ScreenshotService

This commit is contained in:
Damocles 2026-04-18 12:32:55 +02:00
parent 62cd0f9a76
commit 73e480d14b
7 changed files with 129 additions and 10 deletions

View file

@ -20,12 +20,21 @@ Scope {
lock: _lock
}
// Capture screenshots before locking, with timeout for security
Timer {
id: _lockTimeout
interval: 150
onTriggered: _lock.locked = true
}
Connections {
target: S.LockService
function onLockRequested() {
if (S.LockService.enabled)
_lock.locked = true;
if (!S.LockService.enabled)
return;
S.ScreenshotService.capture(Quickshell.screens.length);
_lockTimeout.start();
}
function onUnlockRequested() {
@ -39,6 +48,17 @@ Scope {
}
}
Connections {
target: S.ScreenshotService
function onCaptureComplete() {
if (_lockTimeout.running) {
_lockTimeout.stop();
_lock.locked = true;
}
}
}
Connections {
target: _lock

View file

@ -15,15 +15,16 @@ WlSessionLockSurface {
property real _unlockFade: 1
// Clear desktop screenshot - visible immediately
ScreencopyView {
// Clear desktop screenshot from ScreenshotService - visible immediately
Image {
anchors.fill: parent
captureSource: root.screen
visible: S.Modules.lock.screenshot ?? true
source: S.ScreenshotService.get(root.screen?.name ?? "")
visible: (S.Modules.lock.screenshot ?? true) && source !== ""
opacity: _unlockFade
fillMode: Image.PreserveAspectCrop
}
// Overlay group: blur + dim + hexes, revealed per-pixel by wave position
// Overlay group: blur + hexes, revealed per-pixel by wave position
Item {
id: _overlay
anchors.fill: parent
@ -47,10 +48,11 @@ WlSessionLockSurface {
}
// Blurred screenshot
ScreencopyView {
Image {
anchors.fill: parent
captureSource: root.screen
visible: S.Modules.lock.screenshot ?? true
source: S.ScreenshotService.get(root.screen?.name ?? "")
visible: (S.Modules.lock.screenshot ?? true) && source !== ""
fillMode: Image.PreserveAspectCrop
layer.enabled: true
layer.effect: MultiEffect {

View file

@ -0,0 +1,44 @@
import QtQuick
import Quickshell
import Quickshell.Wayland
import "../services" as S
PanelWindow {
id: root
required property var screen
color: "transparent"
WlrLayershell.layer: WlrLayer.Background
WlrLayershell.exclusiveZone: -1
WlrLayershell.namespace: "nova-screenshot"
mask: Region {}
anchors.top: true
anchors.left: true
anchors.right: true
anchors.bottom: true
ScreencopyView {
id: _capture
anchors.fill: parent
captureSource: root.screen
}
Connections {
target: S.ScreenshotService
function onCaptureRequested() {
_capture.captureFrame();
}
}
Connections {
target: _capture
function onHasContentChanged() {
if (_capture.hasContent)
_capture.grabToImage(result => {
S.ScreenshotService.store(root.screen.name, result);
});
}
}
}

View file

@ -32,6 +32,7 @@ PowerModule 1.0 PowerModule.qml
PowerProfileModule 1.0 PowerProfileModule.qml
PrivacyModule 1.0 PrivacyModule.qml
ProcessList 1.0 ProcessList.qml
ScreenCapture 1.0 ScreenCapture.qml
ScreenCorners 1.0 ScreenCorners.qml
TemperatureModule 1.0 TemperatureModule.qml
ThemedIcon 1.0 ThemedIcon.qml

View file

@ -0,0 +1,44 @@
pragma Singleton
import QtQuick
QtObject {
id: root
// Screen name -> in-memory image URL from grabToImage
property var screenshots: ({})
property int _pending: 0
// Keep references to prevent garbage collection of the image data
property var _results: ({})
signal captureRequested
signal captureComplete
function capture(screenCount) {
_pending = screenCount;
if (_pending === 0) {
captureComplete();
return;
}
captureRequested();
}
function store(screenName, result) {
const s = Object.assign({}, screenshots);
s[screenName] = result.url;
screenshots = s;
const r = Object.assign({}, _results);
r[screenName] = result;
_results = r;
_pending--;
if (_pending <= 0)
captureComplete();
}
function get(screenName) {
return screenshots[screenName] || "";
}
}

View file

@ -11,6 +11,7 @@ singleton NetworkService 1.0 NetworkService.qml
singleton NiriIpc 1.0 NiriIpc.qml
singleton NotifService 1.0 NotifService.qml
singleton PowerProfileService 1.0 PowerProfileService.qml
singleton ScreenshotService 1.0 ScreenshotService.qml
singleton SystemStats 1.0 SystemStats.qml
singleton Theme 1.0 Theme.qml
# keep-sorted end

View file

@ -44,6 +44,13 @@ ShellRoot {
}
}
LazyLoader {
active: Modules.lock.enable && (Modules.lock.screenshot ?? true)
ScreenCapture {
screen: scope.modelData
}
}
LazyLoader {
active: Modules.screenCorners.enable
ScreenCorners {