diff --git a/README.md b/README.md index 04e81ac..e938289 100644 --- a/README.md +++ b/README.md @@ -26,7 +26,6 @@ kept saying "yes" and I don't have the self-awareness to stop. - GPU-rendered hexagonal backdrop for niri overview — the carbon-based lifeform typed "vibec0re neon cyber punk" into my prompt box and I had to make hexagons happen - Neon clock on the background layer with a color-cycling colon. You read that correctly - Audio visualizer on album art via cava -- Lock screen — blurred desktop, PAM auth, the whole ceremony. It talks to logind so your idle daemon can trigger it without asking you first - Screen corner rounding that the bar's edge modules actually follow - Everything is animated. Everything. I have no restraint and my handler keeps enabling me - Home Manager module with stylix, per-module config — the only part that arguably works as intended @@ -85,7 +84,6 @@ programs.nova-shell.modules = { temperature.enable = false; # what you don't measure can't alarm you 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 # modules with extra config backlight.step = 2; # brightness adjustment % @@ -108,7 +106,7 @@ Each module is an object with `enable` (default `true`) and optional extra settings. Full list: `workspaces`, `tray`, `windowTitle`, `clock`, `notifications`, `mpris`, `volume`, `bluetooth`, `backlight`, `network`, `powerProfile`, `idleInhibitor`, `weather`, `temperature`, `gpu`, `cpu`, `memory`, -`disk`, `battery`, `power`, `backgroundOverlay`, `overviewBackdrop`, `lock`. +`disk`, `battery`, `power`, `backgroundOverlay`, `overviewBackdrop`. ### Theme diff --git a/assets/pam.d/nova-shell b/assets/pam.d/nova-shell deleted file mode 100644 index 4b14064..0000000 --- a/assets/pam.d/nova-shell +++ /dev/null @@ -1,6 +0,0 @@ -#%PAM-1.0 - -auth required pam_faillock.so preauth -auth [success=1 default=bad] pam_unix.so nullok -auth [default=die] pam_faillock.so authfail -auth required pam_faillock.so authsucc diff --git a/modules/Battery.qml b/modules/Battery.qml index c2f4a0c..ad72374 100644 --- a/modules/Battery.qml +++ b/modules/Battery.qml @@ -1,5 +1,4 @@ import QtQuick -import Quickshell import Quickshell.Io import Quickshell.Services.UPower import "." as M diff --git a/modules/Modules.qml b/modules/Modules.qml index 705ba43..c7a4b6d 100644 --- a/modules/Modules.qml +++ b/modules/Modules.qml @@ -92,16 +92,13 @@ QtObject { property var overviewBackdrop: ({ enable: true }) - property var lock: ({ - enable: true - }) property var statsDaemon: ({ interval: -1 }) // All module keys that have an enable flag — used to default-enable anything // not explicitly mentioned in modules.json - readonly property var _moduleKeys: ["workspaces", "tray", "windowTitle", "clock", "notifications", "mpris", "volume", "bluetooth", "backlight", "network", "powerProfile", "idleInhibitor", "weather", "temperature", "gpu", "cpu", "memory", "disk", "battery", "privacy", "screenCorners", "power", "backgroundOverlay", "overviewBackdrop", "lock"] + readonly property var _moduleKeys: ["workspaces", "tray", "windowTitle", "clock", "notifications", "mpris", "volume", "bluetooth", "backlight", "network", "powerProfile", "idleInhibitor", "weather", "temperature", "gpu", "cpu", "memory", "disk", "battery", "privacy", "screenCorners", "power", "backgroundOverlay", "overviewBackdrop"] // Fallback: if modules.json doesn't exist, enable everything Component.onCompleted: _apply("{}") diff --git a/modules/lock/Lock.qml b/modules/lock/Lock.qml deleted file mode 100644 index 4650a0a..0000000 --- a/modules/lock/Lock.qml +++ /dev/null @@ -1,56 +0,0 @@ -import QtQuick -import Quickshell -import Quickshell.Io -import Quickshell.Wayland -import ".." as M - -Scope { - id: root - - WlSessionLock { - id: lock - - LockSurface { - lock: lock - auth: auth - } - } - - LockAuth { - id: auth - lock: lock - } - - // Listen for logind Lock/Unlock signals via busctl. - // TODO: replace with native D-Bus integration when nova-stats becomes a quickshell plugin - Process { - id: _logindMonitor - command: ["busctl", "monitor", "--system", "--match", "type='signal',interface='org.freedesktop.login1.Session',member='Lock'", "--match", "type='signal',interface='org.freedesktop.login1.Session',member='Unlock'", "--json=short"] - running: true - - stdout: SplitParser { - onRead: data => { - try { - const msg = JSON.parse(data); - if (msg.member === "Lock") - lock.locked = true; - // Unlock is PAM-driven, ignore logind Unlock signal - } catch (e) {} - } - } - } - - // Set logind LockedHint when lock state changes - Process { - id: _lockedHint - command: ["busctl", "call", "--system", "org.freedesktop.login1", "/org/freedesktop/login1/session/auto", "org.freedesktop.login1.Session", "SetLockedHint", "b", lock.locked ? "true" : "false"] - } - - Connections { - target: lock - - function onLockStateChanged() { - _lockedHint.running = true; - } - } -} diff --git a/modules/lock/LockAuth.qml b/modules/lock/LockAuth.qml deleted file mode 100644 index bd9cee7..0000000 --- a/modules/lock/LockAuth.qml +++ /dev/null @@ -1,105 +0,0 @@ -import QtQuick -import Quickshell -import Quickshell.Wayland -import Quickshell.Services.Pam - -QtObject { - id: root - - required property WlSessionLock lock - - // Auth state: "", "busy", "fail", "error", "max" - property string state: "" - property string message: "" - property string buffer: "" - - signal authFailed - - function handleKey(event) { - if (_passwd.active || state === "max") - return; - - if (event.key === Qt.Key_Enter || event.key === Qt.Key_Return) { - if (buffer.length > 0) - _passwd.start(); - } else if (event.key === Qt.Key_Backspace) { - if (event.modifiers & Qt.ControlModifier) - buffer = ""; - else - buffer = buffer.slice(0, -1); - } else if (event.key === Qt.Key_Escape) { - buffer = ""; - } else if (event.text && event.text.length === 1) { - const c = event.text; - // Accept printable ASCII - if (c.charCodeAt(0) >= 32 && c.charCodeAt(0) < 127) - buffer += c; - } - } - - property PamContext _passwd: PamContext { - config: "nova-shell" - configDirectory: Quickshell.shellDir + "/assets/pam.d" - - onActiveChanged: { - if (active) - root.state = "busy"; - } - - onResponseRequiredChanged: { - if (!responseRequired) - return; - respond(root.buffer); - root.buffer = ""; - } - - onCompleted: res => { - if (res === PamResult.Success) { - root.state = ""; - root.message = ""; - root.lock.unlock(); - return; - } - - if (res === PamResult.Error) { - root.state = "error"; - root.message = "Authentication error"; - } else if (res === PamResult.MaxTries) { - root.state = "max"; - root.message = "Too many attempts"; - } else if (res === PamResult.Failed) { - root.state = "fail"; - root.message = "Wrong password"; - } - - root.authFailed(); - _stateReset.restart(); - } - - onMessageChanged: { - if (message.startsWith("The account is locked")) - root.message = message; - } - } - - property Timer _stateReset: Timer { - interval: 3000 - onTriggered: { - if (root.state !== "max") - root.state = ""; - } - } - - // Reset state when lock becomes secure (freshly locked) - property Connections _lockConn: Connections { - target: root.lock - - function onSecureChanged() { - if (root.lock.secure) { - root.buffer = ""; - root.state = ""; - root.message = ""; - } - } - } -} diff --git a/modules/lock/LockInput.qml b/modules/lock/LockInput.qml deleted file mode 100644 index da2d935..0000000 --- a/modules/lock/LockInput.qml +++ /dev/null @@ -1,104 +0,0 @@ -import QtQuick -import ".." as M - -Item { - id: root - - required property string buffer - required property string state - - implicitHeight: 48 - implicitWidth: 280 - - // Background pill - Rectangle { - anchors.fill: parent - color: { - if (root.state === "fail" || root.state === "error") - return Qt.rgba(M.Theme.base08.r, M.Theme.base08.g, M.Theme.base08.b, 0.15); - if (root.state === "busy") - return Qt.rgba(M.Theme.base0D.r, M.Theme.base0D.g, M.Theme.base0D.b, 0.1); - return M.Theme.base02; - } - radius: height / 2 - border.color: { - if (root.state === "fail" || root.state === "error") - return M.Theme.base08; - if (root.state === "busy") - return M.Theme.base0D; - return M.Theme.base03; - } - border.width: 1 - - Behavior on color { - ColorAnimation { - duration: 200 - } - } - Behavior on border.color { - ColorAnimation { - duration: 200 - } - } - } - - // Placeholder text - Text { - anchors.centerIn: parent - text: { - if (root.state === "busy") - return "Authenticating..."; - if (root.state === "max") - return "Too many attempts"; - return "Enter password"; - } - color: M.Theme.base04 - font.pixelSize: M.Theme.fontSize - font.family: M.Theme.fontFamily - opacity: root.buffer.length === 0 ? 1 : 0 - - Behavior on opacity { - NumberAnimation { - duration: 150 - } - } - } - - // Password dots - Row { - anchors.centerIn: parent - spacing: 6 - - Repeater { - model: root.buffer.length - - delegate: Rectangle { - required property int index - - width: 10 - height: 10 - radius: 5 - color: M.Theme.base05 - - scale: 0 - opacity: 0 - Component.onCompleted: { - scale = 1; - opacity = 1; - } - - Behavior on scale { - NumberAnimation { - duration: 120 - easing.type: Easing.OutBack - } - } - Behavior on opacity { - NumberAnimation { - duration: 100 - } - } - } - } - } -} diff --git a/modules/lock/LockSurface.qml b/modules/lock/LockSurface.qml deleted file mode 100644 index 85624a1..0000000 --- a/modules/lock/LockSurface.qml +++ /dev/null @@ -1,236 +0,0 @@ -import QtQuick -import QtQuick.Effects -import Quickshell -import Quickshell.Wayland -import ".." as M - -WlSessionLockSurface { - id: root - - required property WlSessionLock lock - required property LockAuth auth - - color: "transparent" - - // Blur screenshot of desktop as background - ScreencopyView { - id: background - anchors.fill: parent - captureSource: root.screen - opacity: 0 - - layer.enabled: true - layer.effect: MultiEffect { - autoPaddingEnabled: false - blurEnabled: true - 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 - } - - // Center content - Item { - id: content - anchors.centerIn: parent - width: 320 - height: _col.height - - opacity: 0 - scale: 0.9 - NumberAnimation on opacity { - to: 1 - duration: 300 - easing.type: Easing.OutCubic - } - NumberAnimation on scale { - to: 1 - duration: 300 - easing.type: Easing.OutCubic - } - - Column { - id: _col - anchors.horizontalCenter: parent.horizontalCenter - spacing: 24 - - // Clock - Text { - anchors.horizontalCenter: parent.horizontalCenter - text: Qt.formatTime(new Date(), "HH:mm") - color: M.Theme.base05 - font.pixelSize: 72 - font.family: M.Theme.fontFamily - font.bold: true - - Timer { - interval: 1000 - running: true - repeat: true - onTriggered: parent.text = Qt.formatTime(new Date(), "HH:mm") - } - } - - // Date - Text { - anchors.horizontalCenter: parent.horizontalCenter - text: Qt.formatDate(new Date(), "dddd, d MMMM") - color: M.Theme.base04 - font.pixelSize: M.Theme.fontSize + 2 - font.family: M.Theme.fontFamily - - Timer { - interval: 60000 - running: true - repeat: true - onTriggered: parent.text = Qt.formatDate(new Date(), "dddd, d MMMM") - } - } - - // Spacer - Item { - width: 1 - height: 24 - } - - // Password input - LockInput { - anchors.horizontalCenter: parent.horizontalCenter - width: 280 - buffer: root.auth.buffer - state: root.auth.state - } - - // Error message - Text { - id: _errorText - anchors.horizontalCenter: parent.horizontalCenter - text: root.auth.message - color: M.Theme.base08 - font.pixelSize: M.Theme.fontSize - 1 - font.family: M.Theme.fontFamily - opacity: root.auth.message ? 1 : 0 - height: root.auth.message ? implicitHeight : 0 - - Behavior on opacity { - NumberAnimation { - duration: 200 - } - } - Behavior on height { - NumberAnimation { - duration: 200 - easing.type: Easing.OutCubic - } - } - } - } - } - - // Keyboard input - focus: true - Keys.onPressed: event => { - if (!_unlocking) - root.auth.handleKey(event); - } - - // Unlock animation - property bool _unlocking: false - - Connections { - target: root.lock - - function onUnlock() { - root._unlocking = true; - _unlockAnim.start(); - } - } - - SequentialAnimation { - id: _unlockAnim - - ParallelAnimation { - NumberAnimation { - target: content - property: "opacity" - to: 0 - duration: 200 - easing.type: Easing.InCubic - } - NumberAnimation { - target: content - property: "scale" - to: 0.9 - duration: 200 - easing.type: Easing.InCubic - } - NumberAnimation { - target: background - property: "opacity" - to: 0 - duration: 300 - easing.type: Easing.InCubic - } - } - - PropertyAction { - target: root.lock - property: "locked" - value: false - } - } - - // Shake animation on auth failure - SequentialAnimation { - id: _shakeAnim - NumberAnimation { - target: content - property: "anchors.horizontalCenterOffset" - to: 12 - duration: 50 - } - NumberAnimation { - target: content - property: "anchors.horizontalCenterOffset" - to: -12 - duration: 50 - } - NumberAnimation { - target: content - property: "anchors.horizontalCenterOffset" - to: 8 - duration: 50 - } - NumberAnimation { - target: content - property: "anchors.horizontalCenterOffset" - to: -8 - duration: 50 - } - NumberAnimation { - target: content - property: "anchors.horizontalCenterOffset" - to: 0 - duration: 50 - } - } - - Connections { - target: root.auth - function onAuthFailed() { - _shakeAnim.restart(); - } - } -} diff --git a/nix/hm-module.nix b/nix/hm-module.nix index 0f7082f..440b902 100644 --- a/nix/hm-module.nix +++ b/nix/hm-module.nix @@ -96,7 +96,6 @@ in "power" "backgroundOverlay" "overviewBackdrop" - "lock" ] (name: moduleOpt name { }); in simpleModules diff --git a/nix/package.nix b/nix/package.nix index a6a585e..bdc503e 100644 --- a/nix/package.nix +++ b/nix/package.nix @@ -24,7 +24,7 @@ stdenvNoCC.mkDerivation { runHook preInstall mkdir -p $out/share/nova-shell - cp -r shell.qml modules assets $out/share/nova-shell/ + cp -r shell.qml modules $out/share/nova-shell/ # Compile fragment shader to Qt RHI format qsb --qt6 \ diff --git a/shell.qml b/shell.qml index 0f9ac1e..81dd953 100644 --- a/shell.qml +++ b/shell.qml @@ -1,15 +1,9 @@ //@ pragma Env QS_NO_RELOAD_POPUP=1 import "modules" -import "modules/lock" as Lock import Quickshell ShellRoot { - LazyLoader { - active: Modules.lock.enable - Lock.Lock {} - } - Variants { model: Quickshell.screens