quickshell and hyprland additions

This commit is contained in:
2026-03-15 13:56:00 +02:00
parent c9c27d1554
commit 1ad06b82a6
509 changed files with 68371 additions and 19 deletions

View File

@@ -0,0 +1,56 @@
import QtQuick
import Quickshell
import Quickshell.Services.Pam
// I just copied the default example and modified it. lol
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;
}
}
}

View File

@@ -0,0 +1,41 @@
import Quickshell
import Quickshell.Io
import Quickshell.Wayland
Scope {
// 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;
}
}
WlSessionLock {
id: lock
// Lock the session immediately when quickshell starts.
locked: false
WlSessionLockSurface {
LockSurface {
anchors.fill: parent
context: lockContext
}
}
}
IpcHandler {
target: "lockscreen"
function lock() {
lock.locked = true;
}
function unlock() {
lock.locked = false;
}
}
}

View File

@@ -0,0 +1,267 @@
import "../../components/morphedPolygons/geometry/offset.js" as Offset
import "../../components/morphedPolygons/material-shapes.js" as MaterialShapes // For polygons
import "../../components/morphedPolygons/shapes/corner-rounding.js" as CornerRounding
import QtQuick
import QtQuick.Controls.Fusion
import QtQuick.Layouts
import Quickshell.Wayland
import qs.config
import qs.modules.functions
import qs.modules.interface.background
import qs.modules.components
import qs.modules.components.morphedPolygons
import qs.services
Rectangle {
id: root
required property LockContext context
color: "transparent"
Image {
anchors.fill: parent
z: -1
source: Config.runtime.appearance.background.path
}
RowLayout {
spacing: Metrics.spacing(20)
anchors {
top: parent.top
right: parent.right
topMargin: Metrics.spacing(20)
rightMargin: Metrics.spacing(30)
}
MaterialSymbol {
id: themeIcon
fill: 1
icon: Config.runtime.appearance.theme === "light" ? "light_mode" : "dark_mode"
iconSize: Metrics.fontSize("hugeass")
}
MaterialSymbol {
id: wifi
icon: Network.icon
iconSize: Metrics.fontSize("hugeass")
}
MaterialSymbol {
id: btIcon
icon: Bluetooth.icon
iconSize: Metrics.fontSize("hugeass")
}
StyledText {
id: keyboardLayoutIcon
text: SystemDetails.keyboardLayout
font.pixelSize: Metrics.fontSize(Appearance.font.size.huge - 4)
}
}
ColumnLayout {
anchors {
horizontalCenter: parent.horizontalCenter
top: parent.top
topMargin: Metrics.margin(150)
}
StyledText {
id: clock
visible: !Config.runtime.appearance.background.clock.isAnalog
Layout.alignment: Qt.AlignBottom
animate: false
renderType: Text.NativeRendering
font.pixelSize: Metrics.fontSize(180)
text: Time.format("hh:mm")
}
StyledText {
id: date
visible: !Config.runtime.appearance.background.clock.isAnalog
Layout.alignment: Qt.AlignCenter
animate: false
renderType: Text.NativeRendering
font.pixelSize: Metrics.fontSize(50)
text: Time.format("dddd, dd/MM")
}
Item {
id: analogClockContainer
property int hours: parseInt(Time.format("hh"))
property int minutes: parseInt(Time.format("mm"))
property int seconds: parseInt(Time.format("ss"))
readonly property real cx: width / 2
readonly property real cy: height / 2
property var shapes: [MaterialShapes.getCookie7Sided, MaterialShapes.getCookie9Sided, MaterialShapes.getCookie12Sided, MaterialShapes.getPixelCircle, MaterialShapes.getCircle, MaterialShapes.getGhostish]
visible: Config.runtime.appearance.background.clock.isAnalog
width: 350
height: 350
// Polygon
MorphedPolygon {
id: shapeCanvas
anchors.fill: parent
color: Appearance.m3colors.m3secondaryContainer
roundedPolygon: analogClockContainer.shapes[Config.runtime.appearance.background.clock.shape]()
}
ClockDial {
anchors.fill: parent
anchors.margins: parent.width * 0.12
color: Appearance.colors.colOnSecondaryContainer
z: 0
}
// Hour hand
StyledRect {
z: 2
width: 10
height: parent.height * 0.3
radius: Metrics.radius("full")
color: Qt.darker(Appearance.m3colors.m3secondary, 0.8)
x: analogClockContainer.cx - width / 2
y: analogClockContainer.cy - height
transformOrigin: Item.Bottom
rotation: (analogClockContainer.hours % 12 + analogClockContainer.minutes / 60) * 30
}
StyledRect {
anchors.centerIn: parent
width: 16
height: 16
radius: width / 2
color: Appearance.m3colors.m3secondary
z: 99 // Ensures its on top of everthing
// Inner dot
StyledRect {
width: parent.width / 2
height: parent.height / 2
radius: width / 2
anchors.centerIn: parent
z: 100
color: Appearance.m3colors.m3primaryContainer
}
}
// Minute hand
StyledRect {
width: 14
height: parent.height * 0.35
radius: Metrics.radius("full")
color: Appearance.m3colors.m3secondary
x: analogClockContainer.cx - width / 2
y: analogClockContainer.cy - height
transformOrigin: Item.Bottom
rotation: analogClockContainer.minutes * 6
z: 10 // On top of all hands
}
// Second hand
StyledRect {
visible: true
width: 4
height: parent.height * 0.28
radius: Metrics.radius("full")
color: Appearance.m3colors.m3error
x: analogClockContainer.cx - width / 2
y: analogClockContainer.cy - height
transformOrigin: Item.Bottom
rotation: analogClockContainer.seconds * 6
z: 2
}
StyledText {
text: Time.format("hh")
anchors.top: parent.top
anchors.horizontalCenter: parent.horizontalCenter
anchors.topMargin: Metrics.margin(60)
font.pixelSize: Metrics.fontSize(100)
font.bold: true
opacity: 0.3
animate: false
}
StyledText {
text: Time.format("mm")
anchors.top: parent.top
anchors.horizontalCenter: parent.horizontalCenter
anchors.topMargin: Metrics.margin(150)
font.pixelSize: Metrics.fontSize(100)
font.bold: true
opacity: 0.3
animate: false
}
}
}
ColumnLayout {
// Commenting this will make the password entry visible on all monitors.
visible: Window.active
anchors {
horizontalCenter: parent.horizontalCenter
bottom: parent.bottom
bottomMargin: Metrics.margin(20)
}
RowLayout {
StyledTextField {
id: passwordBox
implicitWidth: 300
padding: Metrics.padding(10)
placeholder: root.context.showFailure ? "Incorrect Password" : "Enter Password"
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 {
function onCurrentTextChanged() {
passwordBox.text = root.context.currentText;
}
target: root.context
}
}
StyledButton {
icon: "chevron_right"
padding: Metrics.padding(10)
radius: Metrics.radius("unsharpenmore")
// don't steal focus from the text box
focusPolicy: Qt.NoFocus
enabled: !root.context.unlockInProgress && root.context.currentText !== ""
onClicked: root.context.tryUnlock()
}
}
}
}

View File

@@ -0,0 +1 @@
auth required pam_unix.so