From 3aa1d5f1ed23e0b857e1bd895f2979612d500696 Mon Sep 17 00:00:00 2001 From: 0blivi0nis <182329535+0blivi0nis@users.noreply.github.com> Date: Sun, 26 Oct 2025 14:50:50 -0700 Subject: [PATCH] =?UTF-8?q?=E2=9C=A8=20feat(lock):=20add=20fingerprint=20s?= =?UTF-8?q?upport?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Credit to @wooze-pao for providing the required code in #2162 --- .../quickshell/ii/modules/lock/Lock.qml | 10 ++++ .../ii/modules/lock/LockContext.qml | 46 +++++++++++++++++++ .../ii/modules/lock/LockSurface.qml | 22 +++++++++ .../ii/modules/lock/pam/fprintd.conf | 1 + 4 files changed, 79 insertions(+) create mode 100644 dots/.config/quickshell/ii/modules/lock/pam/fprintd.conf diff --git a/dots/.config/quickshell/ii/modules/lock/Lock.qml b/dots/.config/quickshell/ii/modules/lock/Lock.qml index 15950093c..5cfc12d72 100644 --- a/dots/.config/quickshell/ii/modules/lock/Lock.qml +++ b/dots/.config/quickshell/ii/modules/lock/Lock.qml @@ -32,6 +32,16 @@ Scope { } } + Connections { + target: GlobalStates + function onScreenLockedChanged() { + if (GlobalStates.screenLocked) { + lockContext.reset(); + lockContext.tryFingerUnlock(); + } + } + } + onUnlocked: (targetAction) => { // Perform the target action if it's not just unlocking if (targetAction == LockContext.ActionEnum.Poweroff) { diff --git a/dots/.config/quickshell/ii/modules/lock/LockContext.qml b/dots/.config/quickshell/ii/modules/lock/LockContext.qml index 7d030fc42..8a1bd5854 100644 --- a/dots/.config/quickshell/ii/modules/lock/LockContext.qml +++ b/dots/.config/quickshell/ii/modules/lock/LockContext.qml @@ -2,6 +2,7 @@ import qs import qs.modules.common import QtQuick import Quickshell +import Quickshell.Io import Quickshell.Services.Pam Scope { @@ -18,8 +19,13 @@ Scope { property string currentText: "" property bool unlockInProgress: false property bool showFailure: false + property bool fingerprintsConfigured: false property var targetAction: LockContext.ActionEnum.Unlock + Component.onCompleted: { + fingerprintCheckProcess.running = true; + } + function resetTargetAction() { root.targetAction = LockContext.ActionEnum.Unlock; } @@ -37,6 +43,46 @@ Scope { root.clearText(); root.unlockInProgress = false; } + + function tryFingerUnlock() { + fingerPam.start(); + } + + function stopPam() { + fingerPam.abort(); + } + + Process { + id: fingerprintCheckProcess + command: ["bash", "-c", "fprintd-list $(whoami)"] + stdout: StdioCollector { + id: fingerprintOutputCollector + onStreamFinished: { + root.fingerprintsConfigured = fingerprintOutputCollector.text.includes("Fingerprints for user"); + } + } + onExited: (exitCode, exitStatus) => { + if (exitCode !== 0) { + console.warn("fprintd-list command exited with error:", exitCode, exitStatus); + root.fingerprintsConfigured = false; + } + } + } + + PamContext { + id: fingerPam + + configDirectory: "pam" + config: "fprintd.conf" + + onCompleted: result => { + if (result == PamResult.Success) { + root.unlocked(root.targetAction); + } else if (result == PamResult.Error){ // if timeout or etc.. + tryFingerUnlock() + } + } + } Timer { id: passwordClearTimer diff --git a/dots/.config/quickshell/ii/modules/lock/LockSurface.qml b/dots/.config/quickshell/ii/modules/lock/LockSurface.qml index 5feba6c72..1f7c47c75 100644 --- a/dots/.config/quickshell/ii/modules/lock/LockSurface.qml +++ b/dots/.config/quickshell/ii/modules/lock/LockSurface.qml @@ -98,6 +98,28 @@ MouseArea { scale: root.toolbarScale opacity: root.toolbarOpacity + // Fingerprint + Loader { + Layout.leftMargin: 10 + Layout.alignment: Qt.AlignVCenter + active: root.context.fingerprintsConfigured // Bind to actual fingerprint availability + visible: root.context.fingerprintsConfigured + + sourceComponent: Row { + spacing: 8 + + MaterialSymbol { + id: fingerprintIcon + anchors.verticalCenter: parent.verticalCenter + fill: 1 + text: "fingerprint" + iconSize: Appearance.font.pixelSize.huge + color: Appearance.colors.colOnSurfaceVariant + animateChange: true + } + } + } + ToolbarTextField { id: passwordBox placeholderText: GlobalStates.screenUnlockFailed ? Translation.tr("Incorrect password") : Translation.tr("Enter password") diff --git a/dots/.config/quickshell/ii/modules/lock/pam/fprintd.conf b/dots/.config/quickshell/ii/modules/lock/pam/fprintd.conf new file mode 100644 index 000000000..73d9cc725 --- /dev/null +++ b/dots/.config/quickshell/ii/modules/lock/pam/fprintd.conf @@ -0,0 +1 @@ +auth sufficient pam_fprintd.so \ No newline at end of file