diff --git a/README.md b/README.md index 60f347e..924edcf 100644 --- a/README.md +++ b/README.md @@ -107,6 +107,9 @@ programs.nova-shell.modules = { disk.enable = false; # the number will only make you anxious power.enable = false; # if you enjoy living dangerously without a logout button lock.enable = false; # if you prefer your session unlocked and your secrets free + lock.screenshot = false; # disable blurred desktop screenshot background + lock.mpris = false; # hide media controls on the lock screen + lock.volume = false; # hide volume slider on the lock screen # modules with extra config backlight.step = 2; # brightness adjustment % diff --git a/nix/hm-module.nix b/nix/hm-module.nix index 0f7082f..8b1879b 100644 --- a/nix/hm-module.nix +++ b/nix/hm-module.nix @@ -96,11 +96,27 @@ in "power" "backgroundOverlay" "overviewBackdrop" - "lock" ] (name: moduleOpt name { }); in simpleModules // { + lock = moduleOpt "lock" { + screenshot = lib.mkOption { + type = lib.types.bool; + default = true; + description = "Show blurred desktop screenshot as lock screen background."; + }; + mpris = lib.mkOption { + type = lib.types.bool; + default = true; + description = "Show media controls on the lock screen."; + }; + volume = lib.mkOption { + type = lib.types.bool; + default = true; + description = "Show volume slider on the lock screen."; + }; + }; notifications = moduleOpt "notifications" { timeout = lib.mkOption { type = lib.types.int; diff --git a/shell/lock/LockSurface.qml b/shell/lock/LockSurface.qml index 8cfa1cb..7b245d8 100644 --- a/shell/lock/LockSurface.qml +++ b/shell/lock/LockSurface.qml @@ -15,12 +15,19 @@ WlSessionLockSurface { color: M.Theme.base00 + property real _bgOpacity: 0 + NumberAnimation on _bgOpacity { + to: 1 + duration: 400 + easing.type: Easing.OutCubic + } + // Blur screenshot of desktop as background ScreencopyView { - id: background anchors.fill: parent captureSource: root.screen - opacity: 0 + opacity: root._bgOpacity + visible: M.Modules.lock.screenshot ?? true layer.enabled: true layer.effect: MultiEffect { @@ -29,19 +36,13 @@ WlSessionLockSurface { blur: 1 blurMax: 64 } - - NumberAnimation on opacity { - to: 1 - duration: 400 - easing.type: Easing.OutCubic - } } // Dim overlay Rectangle { anchors.fill: parent color: Qt.rgba(M.Theme.base00.r, M.Theme.base00.g, M.Theme.base00.b, 0.4) - opacity: background.opacity + opacity: root._bgOpacity } // Hex wave overlay @@ -49,15 +50,7 @@ WlSessionLockSurface { id: hexWave anchors.fill: parent running: root.lock.secure - opacity: background.opacity * 0.4 - - NumberAnimation on opacity { - id: _hexFadeIn - running: false - to: 0.4 - duration: 600 - easing.type: Easing.OutCubic - } + opacity: root._bgOpacity * 0.4 } // Keyboard input via TextInput - engages Qt's full input pipeline including @@ -203,7 +196,7 @@ WlSessionLockSurface { color: Qt.rgba(M.Theme.base01.r, M.Theme.base01.g, M.Theme.base01.b, 0.7) border.color: Qt.rgba(M.Theme.base03.r, M.Theme.base03.g, M.Theme.base03.b, 0.3) border.width: 1 - visible: _mprisPlayer !== null + visible: (M.Modules.lock.mpris ?? true) && _mprisPlayer !== null readonly property var _mprisPlayers: (Mpris.players.values ?? []).filter(p => p.trackTitle || p.playbackState === MprisPlaybackState.Playing || p.playbackState === MprisPlaybackState.Paused) readonly property var _mprisPlayer: _mprisPlayers[0] ?? null @@ -233,7 +226,7 @@ WlSessionLockSurface { color: Qt.rgba(M.Theme.base01.r, M.Theme.base01.g, M.Theme.base01.b, 0.7) border.color: Qt.rgba(M.Theme.base03.r, M.Theme.base03.g, M.Theme.base03.b, 0.3) border.width: 1 - visible: Pipewire.defaultAudioSink !== null + visible: (M.Modules.lock.volume ?? true) && Pipewire.defaultAudioSink !== null PwObjectTracker { objects: [Pipewire.defaultAudioSink] @@ -300,15 +293,8 @@ WlSessionLockSurface { easing.type: Easing.InCubic } NumberAnimation { - target: background - property: "opacity" - to: 0 - duration: 300 - easing.type: Easing.InCubic - } - NumberAnimation { - target: hexWave - property: "opacity" + target: root + property: "_bgOpacity" to: 0 duration: 300 easing.type: Easing.InCubic @@ -363,4 +349,71 @@ WlSessionLockSurface { _shakeAnim.restart(); } } + + // Screen corners - session lock surfaces render above all layer-shell, + // so the bar's ScreenCorners aren't visible. Draw our own. + component LockCorner: Canvas { + property int corner: 0 + readonly property int _r: M.Theme.screenRadius + visible: _r > 0 && M.Modules.screenCorners.enable + width: _r + height: _r + z: 999 + + onPaint: { + const r = _r; + const ctx = getContext("2d"); + ctx.clearRect(0, 0, r, r); + ctx.fillStyle = "black"; + ctx.beginPath(); + switch (corner) { + case 0: + ctx.moveTo(0, 0); + ctx.lineTo(r, 0); + ctx.arc(r, r, r, -Math.PI / 2, Math.PI, true); + ctx.closePath(); + break; + case 1: + ctx.moveTo(r, 0); + ctx.lineTo(0, 0); + ctx.arc(0, r, r, -Math.PI / 2, 0, false); + ctx.closePath(); + break; + case 2: + ctx.moveTo(0, r); + ctx.lineTo(0, 0); + ctx.arc(r, 0, r, Math.PI, Math.PI / 2, true); + ctx.closePath(); + break; + case 3: + ctx.moveTo(r, r); + ctx.lineTo(r, 0); + ctx.arc(0, 0, r, 0, Math.PI / 2, false); + ctx.closePath(); + break; + } + ctx.fill(); + } + } + + LockCorner { + corner: 0 + anchors.top: parent.top + anchors.left: parent.left + } + LockCorner { + corner: 1 + anchors.top: parent.top + anchors.right: parent.right + } + LockCorner { + corner: 2 + anchors.bottom: parent.bottom + anchors.left: parent.left + } + LockCorner { + corner: 3 + anchors.bottom: parent.bottom + anchors.right: parent.right + } } diff --git a/shell/services/Modules.qml b/shell/services/Modules.qml index 705ba43..eab237b 100644 --- a/shell/services/Modules.qml +++ b/shell/services/Modules.qml @@ -93,7 +93,10 @@ QtObject { enable: true }) property var lock: ({ - enable: true + enable: true, + screenshot: true, + mpris: true, + volume: true }) property var statsDaemon: ({ interval: -1