lockscreen: replace lockscreen example
The new one uses the pam module and looks much nicer.
This commit is contained in:
parent
c30a4faf18
commit
a64b477dea
|
@ -1,43 +0,0 @@
|
|||
import QtQuick
|
||||
import Quickshell
|
||||
import Quickshell.Io
|
||||
|
||||
QtObject {
|
||||
property int status: AuthContext.Status.FirstLogin
|
||||
signal unlocked();
|
||||
|
||||
enum Status {
|
||||
FirstLogin,
|
||||
Authenticating,
|
||||
LoginFailed
|
||||
}
|
||||
|
||||
property string password
|
||||
|
||||
property var pamtester: Process {
|
||||
property bool failed: true
|
||||
|
||||
command: ["pamtester", "login", Quickshell.env("USER"), "authenticate"]
|
||||
|
||||
onStarted: this.write(`${password}\n`)
|
||||
|
||||
stdout: SplitParser {
|
||||
// fails go to stderr
|
||||
onRead: pamtester.failed = false
|
||||
}
|
||||
|
||||
onExited: {
|
||||
if (failed) {
|
||||
status = AuthContext.Status.LoginFailed;
|
||||
} else {
|
||||
unlocked();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function tryLogin(password: string) {
|
||||
this.password = password
|
||||
status = AuthContext.Status.Authenticating;
|
||||
pamtester.running = true;
|
||||
}
|
||||
}
|
54
lockscreen/LockContext.qml
Normal file
54
lockscreen/LockContext.qml
Normal file
|
@ -0,0 +1,54 @@
|
|||
import QtQuick
|
||||
import Quickshell
|
||||
import Quickshell.Services.Pam
|
||||
|
||||
Scope {
|
||||
id: root
|
||||
signal unlocked()
|
||||
signal failed()
|
||||
|
||||
// These properties are in the context and not individual lock surfaces
|
||||
// so all surfaces can share the same state.
|
||||
property string currentText: ""
|
||||
property bool unlockInProgress: false
|
||||
property bool showFailure: false
|
||||
|
||||
// Clear the failure text once the user starts typing.
|
||||
onCurrentTextChanged: showFailure = false;
|
||||
|
||||
function tryUnlock() {
|
||||
if (currentText === "") return;
|
||||
|
||||
root.unlockInProgress = true;
|
||||
pam.start();
|
||||
}
|
||||
|
||||
PamContext {
|
||||
id: pam
|
||||
|
||||
// Its best to have a custom pam config for quickshell, as the system one
|
||||
// might not be what your interface expects, and break in some way.
|
||||
// This particular example only supports passwords.
|
||||
configDirectory: "pam"
|
||||
config: "password.conf"
|
||||
|
||||
// pam_unix will ask for a response for the password prompt
|
||||
onPamMessage: {
|
||||
if (this.responseRequired) {
|
||||
this.respond(root.currentText);
|
||||
}
|
||||
}
|
||||
|
||||
// pam_unix won't send any important messages so all we need is the completion status.
|
||||
onCompleted: result => {
|
||||
if (result == PamResult.Success) {
|
||||
root.unlocked();
|
||||
} else {
|
||||
root.currentText = "";
|
||||
root.showFailure = true;
|
||||
}
|
||||
|
||||
root.unlockInProgress = false;
|
||||
}
|
||||
}
|
||||
}
|
104
lockscreen/LockSurface.qml
Normal file
104
lockscreen/LockSurface.qml
Normal file
|
@ -0,0 +1,104 @@
|
|||
import QtQuick
|
||||
import QtQuick.Layouts
|
||||
import QtQuick.Controls.Fusion
|
||||
import Quickshell.Wayland
|
||||
|
||||
Rectangle {
|
||||
id: root
|
||||
required property LockContext context
|
||||
readonly property ColorGroup colors: Window.active ? palette.active : palette.inactive
|
||||
|
||||
color: colors.window
|
||||
|
||||
Button {
|
||||
text: "Its not working, let me out"
|
||||
onClicked: context.unlocked();
|
||||
}
|
||||
|
||||
Label {
|
||||
id: clock
|
||||
property var date: new Date()
|
||||
|
||||
anchors {
|
||||
horizontalCenter: parent.horizontalCenter
|
||||
top: parent.top
|
||||
topMargin: 100
|
||||
}
|
||||
|
||||
// The native font renderer tends to look nicer at large sizes.
|
||||
renderType: Text.NativeRendering
|
||||
font.pointSize: 80
|
||||
|
||||
// updates the clock every second
|
||||
Timer {
|
||||
running: true
|
||||
repeat: true
|
||||
interval: 1000
|
||||
|
||||
onTriggered: clock.date = new Date();
|
||||
}
|
||||
|
||||
// updated when the date changes
|
||||
text: {
|
||||
const hours = this.date.getHours().toString().padStart(2, '0');
|
||||
const minutes = this.date.getMinutes().toString().padStart(2, '0');
|
||||
return `${hours}:${minutes}`;
|
||||
}
|
||||
}
|
||||
|
||||
ColumnLayout {
|
||||
// Uncommenting this will make the password entry invisible except on the active monitor.
|
||||
// visible: Window.active
|
||||
|
||||
anchors {
|
||||
horizontalCenter: parent.horizontalCenter
|
||||
top: parent.verticalCenter
|
||||
}
|
||||
|
||||
RowLayout {
|
||||
TextField {
|
||||
id: passwordBox
|
||||
|
||||
implicitWidth: 400
|
||||
padding: 10
|
||||
|
||||
focus: true
|
||||
enabled: !root.context.unlockInProgress
|
||||
echoMode: TextInput.Password
|
||||
inputMethodHints: Qt.ImhSensitiveData
|
||||
|
||||
// Update the text in the context when the text in the box changes.
|
||||
onTextChanged: root.context.currentText = this.text;
|
||||
|
||||
// Try to unlock when enter is pressed.
|
||||
onAccepted: root.context.tryUnlock();
|
||||
|
||||
// Update the text in the box to match the text in the context.
|
||||
// This makes sure multiple monitors have the same text.
|
||||
Connections {
|
||||
target: root.context
|
||||
|
||||
function onCurrentTextChanged() {
|
||||
passwordBox.text = root.context.currentText;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Button {
|
||||
text: "Unlock"
|
||||
padding: 10
|
||||
|
||||
// don't steal focus from the text box
|
||||
focusPolicy: Qt.NoFocus
|
||||
|
||||
enabled: !root.context.unlockInProgress && root.context.currentText !== "";
|
||||
onClicked: root.context.tryUnlock();
|
||||
}
|
||||
}
|
||||
|
||||
Label {
|
||||
visible: root.context.showFailure
|
||||
text: "Incorrect password"
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,52 +0,0 @@
|
|||
import QtQuick
|
||||
import QtQuick.Controls.Basic
|
||||
|
||||
Item {
|
||||
required property AuthContext context
|
||||
|
||||
Item {
|
||||
anchors.centerIn: parent
|
||||
|
||||
TextField {
|
||||
id: entryBox
|
||||
anchors.centerIn: parent
|
||||
width: 600
|
||||
font.pointSize: 24
|
||||
|
||||
enabled: context.status != AuthContext.Status.Authenticating
|
||||
focus: true
|
||||
horizontalAlignment: TextInput.AlignHCenter
|
||||
echoMode: TextInput.Password
|
||||
inputMethodHints: Qt.ImhSensitiveData
|
||||
placeholderText: "Enter password"
|
||||
|
||||
onAccepted: {
|
||||
if (text != "") context.tryLogin(text)
|
||||
}
|
||||
|
||||
onEnabledChanged: {
|
||||
if (enabled) text = ""
|
||||
}
|
||||
}
|
||||
|
||||
Text {
|
||||
id: status
|
||||
color: "white"
|
||||
font.pointSize: 24
|
||||
|
||||
anchors {
|
||||
horizontalCenter: entryBox.horizontalCenter
|
||||
top: entryBox.bottom
|
||||
topMargin: 40
|
||||
}
|
||||
|
||||
text: {
|
||||
switch (context.status) {
|
||||
case AuthContext.Status.FirstLogin: return ""
|
||||
case AuthContext.Status.Authenticating: return "Authenticating"
|
||||
case AuthContext.Status.LoginFailed: return "Login Failed"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,7 +1,7 @@
|
|||
# Lockscreen
|
||||
|
||||
This is a barebones lockscreen with a password input box.
|
||||
Note that you MUST have `pamtester` installed or you won't be able to log in.
|
||||
This is a simple but functional lockscreen that follows the system color scheme.
|
||||
The only authentication method it supports is a password.
|
||||
|
||||
You can run the lockscreen with `quickshell -p shell.qml`.
|
||||
|
||||
|
|
Binary file not shown.
Before Width: | Height: | Size: 22 KiB After Width: | Height: | Size: 21 KiB |
1
lockscreen/pam/password.conf
Normal file
1
lockscreen/pam/password.conf
Normal file
|
@ -0,0 +1 @@
|
|||
auth required pam_unix.so
|
|
@ -1,38 +1,31 @@
|
|||
import QtQuick
|
||||
import QtQuick.Controls.Basic
|
||||
import Quickshell
|
||||
import Quickshell.Wayland
|
||||
|
||||
ShellRoot {
|
||||
AuthContext {
|
||||
id: authContext
|
||||
onUnlocked: lock.locked = false
|
||||
// This stores all the information shared between the lock surfaces on each screen.
|
||||
LockContext {
|
||||
id: lockContext
|
||||
|
||||
onUnlocked: {
|
||||
// Unlock the screen before exiting, or the compositor will display a
|
||||
// fallback lock you can't interact with.
|
||||
lock.locked = false;
|
||||
|
||||
Qt.quit();
|
||||
}
|
||||
}
|
||||
|
||||
WlSessionLock {
|
||||
id: lock
|
||||
|
||||
// Lock the session immediately when quickshell starts.
|
||||
locked: true
|
||||
|
||||
onLockedChanged: {
|
||||
if (!locked) Qt.quit();
|
||||
}
|
||||
|
||||
WlSessionLockSurface {
|
||||
// You probably want to replace this with an image.
|
||||
color: "#303030"
|
||||
|
||||
// For your own sanity you should probably keep this
|
||||
// while working on the lockscreen.
|
||||
Button {
|
||||
text: "Help! I misconfigured my lockscreen!"
|
||||
onClicked: lock.locked = false
|
||||
}
|
||||
|
||||
Lockscreen {
|
||||
LockSurface {
|
||||
anchors.fill: parent
|
||||
context: authContext
|
||||
context: lockContext
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -2,17 +2,24 @@ import QtQuick
|
|||
import Quickshell
|
||||
|
||||
ShellRoot {
|
||||
AuthContext {
|
||||
id: authContext
|
||||
onUnlocked: Qt.quit()
|
||||
LockContext {
|
||||
id: lockContext
|
||||
onUnlocked: Qt.quit();
|
||||
}
|
||||
|
||||
FloatingWindow {
|
||||
color: "#303030"
|
||||
|
||||
Lockscreen {
|
||||
LockSurface {
|
||||
anchors.fill: parent
|
||||
context: authContext
|
||||
context: lockContext
|
||||
}
|
||||
}
|
||||
|
||||
// exit the example if the window closes
|
||||
Connections {
|
||||
target: Quickshell
|
||||
|
||||
function onLastWindowClosed() {
|
||||
Qt.quit();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue