From 862ddc9059883900024d3e41f6a86f259134035a Mon Sep 17 00:00:00 2001 From: Gregor Kleen Date: Thu, 4 Sep 2025 20:14:56 +0200 Subject: ... --- accounts/gkleen@sif/default.nix | 3 +- .../shell/quickshell-plugins/FileSelector.cpp | 2 + accounts/gkleen@sif/shell/quickshell/Clock.qml | 4 +- .../gkleen@sif/shell/quickshell/Lockscreen.qml | 260 +++++++++++++++++++++ accounts/gkleen@sif/shell/quickshell/shell.qml | 2 + 5 files changed, 269 insertions(+), 2 deletions(-) create mode 100644 accounts/gkleen@sif/shell/quickshell/Lockscreen.qml (limited to 'accounts') diff --git a/accounts/gkleen@sif/default.nix b/accounts/gkleen@sif/default.nix index 190a5016..8ccba793 100644 --- a/accounts/gkleen@sif/default.nix +++ b/accounts/gkleen@sif/default.nix @@ -49,7 +49,8 @@ let ]; }; - lockCommand = "${lib.getExe' config.systemd.package "systemctl"} --user start gtklock.service"; + # lockCommand = "${lib.getExe' config.systemd.package "systemctl"} --user start gtklock.service"; + lockCommand = "${lib.getExe' cfg.programs.quickshell.package "qs"} ipc call lock lock"; editor = pkgs.symlinkJoin { inherit (cfg.services.emacs.package) name; diff --git a/accounts/gkleen@sif/shell/quickshell-plugins/FileSelector.cpp b/accounts/gkleen@sif/shell/quickshell-plugins/FileSelector.cpp index 3a0537b6..a3a35273 100644 --- a/accounts/gkleen@sif/shell/quickshell-plugins/FileSelector.cpp +++ b/accounts/gkleen@sif/shell/quickshell-plugins/FileSelector.cpp @@ -40,6 +40,8 @@ QString FileSelector::seed() const { void FileSelector::setSeed(QString seed) { this->mSeed = seed; emit this->seedChanged(); + if (this->mDirectory && this->mEpoch) + emit this->selectedChanged(); } QString FileSelector::selected() const { diff --git a/accounts/gkleen@sif/shell/quickshell/Clock.qml b/accounts/gkleen@sif/shell/quickshell/Clock.qml index edce57e3..d0c9178b 100644 --- a/accounts/gkleen@sif/shell/quickshell/Clock.qml +++ b/accounts/gkleen@sif/shell/quickshell/Clock.qml @@ -9,6 +9,8 @@ import Quickshell.Widgets Item { id: clockItem + property bool calendarPopup: true + width: clock.contentWidth height: parent.height anchors.verticalCenter: parent.verticalCenter @@ -18,7 +20,7 @@ Item { anchors.fill: parent hoverEnabled: true - enabled: true + enabled: clockItem.calendarPopup property real angleRem: 0 property real sensitivity: 1 / 120 diff --git a/accounts/gkleen@sif/shell/quickshell/Lockscreen.qml b/accounts/gkleen@sif/shell/quickshell/Lockscreen.qml new file mode 100644 index 00000000..c7d28ffa --- /dev/null +++ b/accounts/gkleen@sif/shell/quickshell/Lockscreen.qml @@ -0,0 +1,260 @@ +import Quickshell +import Quickshell.Wayland +import Quickshell.Io +import Quickshell.Services.Pam +import Quickshell.Widgets +import QtQuick.Effects +import QtQuick.Layouts +import QtQuick +import QtQuick.Controls +import QtQuick.Controls.Fusion +import qs.Services +// import QtQml.Models + +Scope { + id: lockscreen + + property string currentText: "" + + PamContext { + id: pam + + property list messages: [] + + config: "quickshell" + onCompleted: result => { + if (result === PamResult.Success) { + lock.locked = false; + } + } + onPamMessage: { + messages = Array.from(messages).concat([{ "text": pam.message, "error": pam.messageIsError }]) + } + onActiveChanged: { + messages = []; + } + } + + IpcHandler { + target: "lock" + + function lock(): void { lock.locked = true; } + } + + WlSessionLock { + id: lock + + onLockedChanged: { + if (!locked && pam.active) + pam.abort(); + } + + WlSessionLockSurface { + id: lockSurface + + color: "#000000" + + onScreenChanged: selector.seed = lockSurface.screen.name + + Item { + id: background + + anchors.fill: parent + + property Img current: one + property string source: selector.selected + + WallpaperSelector { + id: selector + seed: "" + } + + onSourceChanged: { + if (!source) + current = null; + else if (current === one) + two.update() + else + one.update() + } + + Img { id: one } + Img { id: two } + + component Img: Item { + id: img + + property string source + + function update() { + source = background.source || "" + } + + anchors.fill: parent + + Image { + id: imageSource + + source: img.source + sourceSize: Qt.size(parent.width, parent.height) + fillMode: Image.PreserveAspectCrop + smooth: true + visible: false + asynchronous: true + cache: false + + onStatusChanged: { + if (status === Image.Ready) { + background.current = img + } + } + } + + MultiEffect { + id: imageEffect + + source: imageSource + anchors.fill: parent + blurEnabled: true + blur: 1 + blurMax: 64 + blurMultiplier: 2 + + opacity: 0 + + states: State { + name: "visible" + when: background.current === img + + PropertyChanges { + imageEffect.opacity: 1 + } + StateChangeScript { + name: "unloadOther" + script: { + if (img === one) + two.source = "" + if (img === two) + one.source = "" + } + } + } + + transitions: Transition { + SequentialAnimation { + NumberAnimation { + target: imageEffect + properties: "opacity" + duration: 5000 + easing.type: Easing.OutCubic + } + ScriptAction { + scriptName: "unloadOther" + } + } + } + } + } + } + + Item { + anchors { + top: lockSurface.top + left: lockSurface.left + right: lockSurface.right + } + + implicitWidth: lockSurface.width + implicitHeight: 21 + + Rectangle { + anchors.fill: parent + color: Qt.rgba(0, 0, 0, 0.75) + } + + Clock { + anchors.centerIn: parent + calendarPopup: false + } + } + + WrapperRectangle { + id: unlockUi + + Keys.onPressed: event => { + if (!pam.active) { + event.accepted = true; + pam.start(); + } + } + focus: !passwordBox.visible + + visible: pam.active + + color: Qt.rgba(0, 0, 0, 0.75) + margin: 8 + + anchors.centerIn: parent + + ColumnLayout { + spacing: 4 + + BusyIndicator { + visible: running + running: !Array.from(pam.messages).length && !pam.responseRequired + } + + Repeater { + model: pam.messages + + Text { + required property var modelData + + font.pointSize: 10 + font.family: "Fira Sans" + color: modelData.error ? "#f28a21" : "#ffffff" + + text: modelData.text + + Layout.fillWidth: true + horizontalAlignment: Text.AlignHCenter + } + } + + TextField { + id: passwordBox + + visible: pam.responseRequired + echoMode: pam.responseVisible ? TextInput.Normal : TextInput.Password + inputMethodHints: Qt.ImhSensitiveData + + onTextChanged: lockscreen.currentText = passwordBox.text + onAccepted: { + passwordBox.readOnly = true; + pam.respond(lockscreen.currentText); + } + + Connections { + target: lockscreen + function onCurrentTextChanged() { + passwordBox.text = lockscreen.currentText + } + } + Connections { + target: pam + function onResponseRequiredChanged() { + if (pam.responseRequired) + passwordBox.readOnly = false; + passwordBox.focus = true; + passwordBox.selectAll(); + } + } + + Layout.topMargin: 4 + Layout.fillWidth: true + } + } + } + } + } +} diff --git a/accounts/gkleen@sif/shell/quickshell/shell.qml b/accounts/gkleen@sif/shell/quickshell/shell.qml index 2ddecad9..1da9457d 100644 --- a/accounts/gkleen@sif/shell/quickshell/shell.qml +++ b/accounts/gkleen@sif/shell/quickshell/shell.qml @@ -39,4 +39,6 @@ ShellRoot { } } } + + Lockscreen {} } -- cgit v1.2.3