pre-capture lock screen screenshots via hidden window and ScreenshotService
This commit is contained in:
parent
62cd0f9a76
commit
73e480d14b
7 changed files with 129 additions and 10 deletions
|
|
@ -20,12 +20,21 @@ Scope {
|
||||||
lock: _lock
|
lock: _lock
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Capture screenshots before locking, with timeout for security
|
||||||
|
Timer {
|
||||||
|
id: _lockTimeout
|
||||||
|
interval: 150
|
||||||
|
onTriggered: _lock.locked = true
|
||||||
|
}
|
||||||
|
|
||||||
Connections {
|
Connections {
|
||||||
target: S.LockService
|
target: S.LockService
|
||||||
|
|
||||||
function onLockRequested() {
|
function onLockRequested() {
|
||||||
if (S.LockService.enabled)
|
if (!S.LockService.enabled)
|
||||||
_lock.locked = true;
|
return;
|
||||||
|
S.ScreenshotService.capture(Quickshell.screens.length);
|
||||||
|
_lockTimeout.start();
|
||||||
}
|
}
|
||||||
|
|
||||||
function onUnlockRequested() {
|
function onUnlockRequested() {
|
||||||
|
|
@ -39,6 +48,17 @@ Scope {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Connections {
|
||||||
|
target: S.ScreenshotService
|
||||||
|
|
||||||
|
function onCaptureComplete() {
|
||||||
|
if (_lockTimeout.running) {
|
||||||
|
_lockTimeout.stop();
|
||||||
|
_lock.locked = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Connections {
|
Connections {
|
||||||
target: _lock
|
target: _lock
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -15,15 +15,16 @@ WlSessionLockSurface {
|
||||||
|
|
||||||
property real _unlockFade: 1
|
property real _unlockFade: 1
|
||||||
|
|
||||||
// Clear desktop screenshot - visible immediately
|
// Clear desktop screenshot from ScreenshotService - visible immediately
|
||||||
ScreencopyView {
|
Image {
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
captureSource: root.screen
|
source: S.ScreenshotService.get(root.screen?.name ?? "")
|
||||||
visible: S.Modules.lock.screenshot ?? true
|
visible: (S.Modules.lock.screenshot ?? true) && source !== ""
|
||||||
opacity: _unlockFade
|
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 {
|
Item {
|
||||||
id: _overlay
|
id: _overlay
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
|
|
@ -47,10 +48,11 @@ WlSessionLockSurface {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Blurred screenshot
|
// Blurred screenshot
|
||||||
ScreencopyView {
|
Image {
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
captureSource: root.screen
|
source: S.ScreenshotService.get(root.screen?.name ?? "")
|
||||||
visible: S.Modules.lock.screenshot ?? true
|
visible: (S.Modules.lock.screenshot ?? true) && source !== ""
|
||||||
|
fillMode: Image.PreserveAspectCrop
|
||||||
|
|
||||||
layer.enabled: true
|
layer.enabled: true
|
||||||
layer.effect: MultiEffect {
|
layer.effect: MultiEffect {
|
||||||
|
|
|
||||||
44
shell/modules/ScreenCapture.qml
Normal file
44
shell/modules/ScreenCapture.qml
Normal 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);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -32,6 +32,7 @@ PowerModule 1.0 PowerModule.qml
|
||||||
PowerProfileModule 1.0 PowerProfileModule.qml
|
PowerProfileModule 1.0 PowerProfileModule.qml
|
||||||
PrivacyModule 1.0 PrivacyModule.qml
|
PrivacyModule 1.0 PrivacyModule.qml
|
||||||
ProcessList 1.0 ProcessList.qml
|
ProcessList 1.0 ProcessList.qml
|
||||||
|
ScreenCapture 1.0 ScreenCapture.qml
|
||||||
ScreenCorners 1.0 ScreenCorners.qml
|
ScreenCorners 1.0 ScreenCorners.qml
|
||||||
TemperatureModule 1.0 TemperatureModule.qml
|
TemperatureModule 1.0 TemperatureModule.qml
|
||||||
ThemedIcon 1.0 ThemedIcon.qml
|
ThemedIcon 1.0 ThemedIcon.qml
|
||||||
|
|
|
||||||
44
shell/services/ScreenshotService.qml
Normal file
44
shell/services/ScreenshotService.qml
Normal 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] || "";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -11,6 +11,7 @@ singleton NetworkService 1.0 NetworkService.qml
|
||||||
singleton NiriIpc 1.0 NiriIpc.qml
|
singleton NiriIpc 1.0 NiriIpc.qml
|
||||||
singleton NotifService 1.0 NotifService.qml
|
singleton NotifService 1.0 NotifService.qml
|
||||||
singleton PowerProfileService 1.0 PowerProfileService.qml
|
singleton PowerProfileService 1.0 PowerProfileService.qml
|
||||||
|
singleton ScreenshotService 1.0 ScreenshotService.qml
|
||||||
singleton SystemStats 1.0 SystemStats.qml
|
singleton SystemStats 1.0 SystemStats.qml
|
||||||
singleton Theme 1.0 Theme.qml
|
singleton Theme 1.0 Theme.qml
|
||||||
# keep-sorted end
|
# keep-sorted end
|
||||||
|
|
|
||||||
|
|
@ -44,6 +44,13 @@ ShellRoot {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
LazyLoader {
|
||||||
|
active: Modules.lock.enable && (Modules.lock.screenshot ?? true)
|
||||||
|
ScreenCapture {
|
||||||
|
screen: scope.modelData
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
LazyLoader {
|
LazyLoader {
|
||||||
active: Modules.screenCorners.enable
|
active: Modules.screenCorners.enable
|
||||||
ScreenCorners {
|
ScreenCorners {
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue