lock screen?
This commit is contained in:
@@ -0,0 +1,24 @@
|
|||||||
|
# Agent Guidelines for z-bar-qt
|
||||||
|
|
||||||
|
## Build & Test
|
||||||
|
- **Build**: `cmake -B build -G Ninja && ninja -C build` (uses CMake + Ninja)
|
||||||
|
- **Install**: `sudo ninja -C build install` (installs to /usr/lib/qt6/qml)
|
||||||
|
- **No test suite**: Project has no automated tests currently
|
||||||
|
- **Update script**: `scripts/update.sh` (runs `yay -Sy`)
|
||||||
|
|
||||||
|
## Code Style - C++
|
||||||
|
- **Standard**: C++20 with strict warnings enabled (see CMakeLists.txt line 14-20)
|
||||||
|
- **Headers**: `#pragma once` for header guards
|
||||||
|
- **Types**: Use [[nodiscard]] for getters, explicit constructors, const correctness
|
||||||
|
- **Qt Integration**: QML_ELEMENT/QML_UNCREATABLE macros, Q_PROPERTY for QML exposure
|
||||||
|
- **Naming**: camelCase for methods/variables, m_ prefix for member variables
|
||||||
|
- **Includes**: Qt headers with lowercase (qobject.h, qqmlintegration.h)
|
||||||
|
- **Namespaces**: Use `namespace ZShell` for plugin code
|
||||||
|
|
||||||
|
## Code Style - QML
|
||||||
|
- **Pragma**: Start with `pragma ComponentBehavior: Bound` for type safety
|
||||||
|
- **Imports**: Qt modules first, then Quickshell, then local (qs.Modules, qs.Config, qs.Helpers)
|
||||||
|
- **Aliases**: Use `qs` prefix for local module imports
|
||||||
|
- **Properties**: Use `required property` for mandatory bindings
|
||||||
|
- **Types**: Explicit type annotations in JavaScript (`: void`, `: string`)
|
||||||
|
- **Structure**: Components in Components/, Modules in Modules/, Config singletons in Config/
|
||||||
@@ -23,6 +23,8 @@ Scope {
|
|||||||
screen: modelData
|
screen: modelData
|
||||||
color: "transparent"
|
color: "transparent"
|
||||||
property var root: Quickshell.shellDir
|
property var root: Quickshell.shellDir
|
||||||
|
|
||||||
|
WlrLayershell.namespace: "ZShell-Bar"
|
||||||
WlrLayershell.exclusionMode: ExclusionMode.Ignore
|
WlrLayershell.exclusionMode: ExclusionMode.Ignore
|
||||||
|
|
||||||
PanelWindow {
|
PanelWindow {
|
||||||
@@ -69,7 +71,7 @@ Scope {
|
|||||||
Variants {
|
Variants {
|
||||||
id: popoutRegions
|
id: popoutRegions
|
||||||
model: panels.children
|
model: panels.children
|
||||||
|
|
||||||
Region {
|
Region {
|
||||||
required property Item modelData
|
required property Item modelData
|
||||||
|
|
||||||
|
|||||||
@@ -22,6 +22,8 @@ Singleton {
|
|||||||
property alias transparency: adapter.transparency
|
property alias transparency: adapter.transparency
|
||||||
property alias baseFont: adapter.baseFont
|
property alias baseFont: adapter.baseFont
|
||||||
property alias animScale: adapter.animScale
|
property alias animScale: adapter.animScale
|
||||||
|
property alias lock: adapter.lock
|
||||||
|
property alias idle: adapter.idle
|
||||||
|
|
||||||
FileView {
|
FileView {
|
||||||
id: root
|
id: root
|
||||||
@@ -52,6 +54,8 @@ Singleton {
|
|||||||
property Transparency transparency: Transparency {}
|
property Transparency transparency: Transparency {}
|
||||||
property string baseFont: "Segoe UI Variable Text"
|
property string baseFont: "Segoe UI Variable Text"
|
||||||
property real animScale: 1.0
|
property real animScale: 1.0
|
||||||
|
property LockConf lock: LockConf {}
|
||||||
|
property IdleTimeout idle: IdleTimeout {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,15 @@
|
|||||||
|
import Quickshell.Io
|
||||||
|
|
||||||
|
JsonObject {
|
||||||
|
property list<var> timeouts: [
|
||||||
|
{
|
||||||
|
timeout: 180,
|
||||||
|
idleAction: "lock"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
timeout: 300,
|
||||||
|
idleAction: "dpms off",
|
||||||
|
activeAction: "dpms on"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
@@ -0,0 +1,14 @@
|
|||||||
|
import Quickshell.Io
|
||||||
|
|
||||||
|
JsonObject {
|
||||||
|
property bool recolourLogo: false
|
||||||
|
property bool enableFprint: true
|
||||||
|
property int maxFprintTries: 3
|
||||||
|
property Sizes sizes: Sizes {}
|
||||||
|
|
||||||
|
component Sizes: JsonObject {
|
||||||
|
property real heightMult: 0.7
|
||||||
|
property real ratio: 16 / 9
|
||||||
|
property int centerWidth: 600
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
pragma Singleton
|
||||||
|
|
||||||
|
import Quickshell
|
||||||
|
import Quickshell.Services.Mpris
|
||||||
|
|
||||||
|
Singleton {
|
||||||
|
id: root
|
||||||
|
|
||||||
|
readonly property list<MprisPlayer> list: Mpris.players.values
|
||||||
|
}
|
||||||
@@ -19,6 +19,7 @@ Searcher {
|
|||||||
function setWallpaper(path: string): void {
|
function setWallpaper(path: string): void {
|
||||||
actualCurrent = path;
|
actualCurrent = path;
|
||||||
WallpaperPath.currentWallpaperPath = path;
|
WallpaperPath.currentWallpaperPath = path;
|
||||||
|
Quickshell.execDetached(["python3", Quickshell.shellPath("scripts/LockScreenBg.py"), `--input_image=${root.actualCurrent}`, `--output_path=${Paths.state}/lockscreen_bg.png`]);
|
||||||
}
|
}
|
||||||
|
|
||||||
function preview(path: string): void {
|
function preview(path: string): void {
|
||||||
|
|||||||
@@ -2,11 +2,13 @@ pragma Singleton
|
|||||||
|
|
||||||
import Quickshell
|
import Quickshell
|
||||||
import Quickshell.Io
|
import Quickshell.Io
|
||||||
|
import qs.Paths
|
||||||
|
|
||||||
Singleton {
|
Singleton {
|
||||||
id: root
|
id: root
|
||||||
|
|
||||||
property alias currentWallpaperPath: adapter.currentWallpaperPath
|
property alias currentWallpaperPath: adapter.currentWallpaperPath
|
||||||
|
property alias lockscreenBg: adapter.lockscreenBg
|
||||||
|
|
||||||
FileView {
|
FileView {
|
||||||
id: fileView
|
id: fileView
|
||||||
@@ -18,6 +20,7 @@ Singleton {
|
|||||||
JsonAdapter {
|
JsonAdapter {
|
||||||
id: adapter
|
id: adapter
|
||||||
property string currentWallpaperPath: ""
|
property string currentWallpaperPath: ""
|
||||||
|
property string lockscreenBg: `${Paths.state}/lockscreen_bg.png`
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -22,6 +22,7 @@ Scope {
|
|||||||
color: "transparent"
|
color: "transparent"
|
||||||
visible: false
|
visible: false
|
||||||
|
|
||||||
|
WlrLayershell.namespace: "ZShell-Launcher"
|
||||||
WlrLayershell.layer: WlrLayer.Overlay
|
WlrLayershell.layer: WlrLayer.Overlay
|
||||||
WlrLayershell.keyboardFocus: WlrKeyboardFocus.Exclusive
|
WlrLayershell.keyboardFocus: WlrKeyboardFocus.Exclusive
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,39 @@
|
|||||||
|
pragma ComponentBehavior: Bound
|
||||||
|
|
||||||
|
import Quickshell
|
||||||
|
import Quickshell.Wayland
|
||||||
|
import qs.Config
|
||||||
|
import qs.Helpers
|
||||||
|
|
||||||
|
Scope {
|
||||||
|
id: root
|
||||||
|
|
||||||
|
required property Lock lock
|
||||||
|
readonly property bool enabled: !Players.list.some( p => p.isPlaying )
|
||||||
|
|
||||||
|
function handleIdleAction( action: var ): void {
|
||||||
|
if ( !action )
|
||||||
|
return;
|
||||||
|
|
||||||
|
if ( action === "lock" )
|
||||||
|
lock.lock.locked = true;
|
||||||
|
else if ( action === "unlock" )
|
||||||
|
lock.lock.locked = false;
|
||||||
|
else if ( typeof action === "string" )
|
||||||
|
Hypr.dispatch( action );
|
||||||
|
else
|
||||||
|
Quickshell.execDetached( action );
|
||||||
|
}
|
||||||
|
|
||||||
|
Variants {
|
||||||
|
model: Config.idle.timeouts
|
||||||
|
|
||||||
|
IdleMonitor {
|
||||||
|
required property var modelData
|
||||||
|
|
||||||
|
enabled: root.enabled && modelData.timeout > 0 ? true : false
|
||||||
|
timeout: modelData.timeout
|
||||||
|
onIsIdleChanged: root.handleIdleAction( isIdle ? modelData.idleAction : modelData.activeAction )
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,37 @@
|
|||||||
|
pragma ComponentBehavior: Bound
|
||||||
|
|
||||||
|
import Quickshell
|
||||||
|
import Quickshell.Wayland
|
||||||
|
import Quickshell.Hyprland
|
||||||
|
import QtQuick
|
||||||
|
|
||||||
|
Scope {
|
||||||
|
id: root
|
||||||
|
property alias lock: lock
|
||||||
|
|
||||||
|
WlSessionLock {
|
||||||
|
id: lock
|
||||||
|
|
||||||
|
signal unlock
|
||||||
|
|
||||||
|
LockSurface {
|
||||||
|
lock: lock
|
||||||
|
pam: pam
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Pam {
|
||||||
|
id: pam
|
||||||
|
|
||||||
|
lock: lock
|
||||||
|
}
|
||||||
|
|
||||||
|
GlobalShortcut {
|
||||||
|
name: "lock"
|
||||||
|
description: "Lock the current session"
|
||||||
|
appid: "zshell-lock"
|
||||||
|
onPressed: {
|
||||||
|
lock.locked = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,286 @@
|
|||||||
|
pragma ComponentBehavior: Bound
|
||||||
|
|
||||||
|
import Quickshell
|
||||||
|
import Quickshell.Wayland
|
||||||
|
import QtQuick
|
||||||
|
import QtQuick.Controls
|
||||||
|
import QtQuick.Layouts
|
||||||
|
import QtQuick.Effects
|
||||||
|
import qs.Config
|
||||||
|
import qs.Helpers
|
||||||
|
import qs.Effects
|
||||||
|
import qs.Components
|
||||||
|
import qs.Modules
|
||||||
|
|
||||||
|
WlSessionLockSurface {
|
||||||
|
id: root
|
||||||
|
|
||||||
|
required property WlSessionLock lock
|
||||||
|
required property Pam pam
|
||||||
|
|
||||||
|
color: "transparent"
|
||||||
|
|
||||||
|
TextInput {
|
||||||
|
id: hiddenInput
|
||||||
|
focus: true
|
||||||
|
visible: false
|
||||||
|
|
||||||
|
Keys.onPressed: function(event: KeyEvent): void {
|
||||||
|
root.pam.handleKey(event);
|
||||||
|
event.accepted = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
onTextChanged: text = ""
|
||||||
|
}
|
||||||
|
|
||||||
|
ScreencopyView {
|
||||||
|
id: background
|
||||||
|
|
||||||
|
anchors.fill: parent
|
||||||
|
captureSource: root.screen
|
||||||
|
opacity: 1
|
||||||
|
|
||||||
|
layer.enabled: true
|
||||||
|
layer.effect: MultiEffect {
|
||||||
|
autoPaddingEnabled: false
|
||||||
|
blurEnabled: true
|
||||||
|
blur: 2
|
||||||
|
blurMax: 32
|
||||||
|
blurMultiplier: 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Image {
|
||||||
|
// id: backgroundImage
|
||||||
|
// anchors.fill: parent
|
||||||
|
// asynchronous: true
|
||||||
|
// source: WallpaperPath.lockscreenBg
|
||||||
|
// }
|
||||||
|
|
||||||
|
Rectangle {
|
||||||
|
anchors.fill: parent
|
||||||
|
color: "transparent"
|
||||||
|
|
||||||
|
Rectangle {
|
||||||
|
id: contentBox
|
||||||
|
anchors.centerIn: parent
|
||||||
|
|
||||||
|
// Material Design 3: Use surfaceContainer for elevated surfaces
|
||||||
|
color: DynamicColors.tPalette.m3surfaceContainer
|
||||||
|
radius: 28
|
||||||
|
|
||||||
|
// M3 spacing: 24px horizontal, 32px vertical padding
|
||||||
|
implicitWidth: Math.floor(childrenRect.width + 48)
|
||||||
|
implicitHeight: Math.floor(childrenRect.height + 64)
|
||||||
|
|
||||||
|
// M3 Elevation 2 shadow effect
|
||||||
|
layer.enabled: true
|
||||||
|
layer.effect: MultiEffect {
|
||||||
|
source: contentBox
|
||||||
|
blurEnabled: false
|
||||||
|
blurMax: 12
|
||||||
|
shadowBlur: 1
|
||||||
|
shadowColor: DynamicColors.palette.m3shadow
|
||||||
|
shadowOpacity: 0.3
|
||||||
|
shadowEnabled: true
|
||||||
|
autoPaddingEnabled: true
|
||||||
|
}
|
||||||
|
|
||||||
|
ColumnLayout {
|
||||||
|
id: mainLayout
|
||||||
|
anchors.centerIn: parent
|
||||||
|
width: childrenRect.width
|
||||||
|
spacing: 0
|
||||||
|
|
||||||
|
// Title: M3 Display Small (32sp, 400 weight)
|
||||||
|
Text {
|
||||||
|
id: titleText
|
||||||
|
Layout.alignment: Qt.AlignHCenter
|
||||||
|
Layout.bottomMargin: 8
|
||||||
|
|
||||||
|
text: "Session Locked"
|
||||||
|
font.pixelSize: 32
|
||||||
|
font.weight: Font.Normal
|
||||||
|
font.letterSpacing: 0.5
|
||||||
|
color: DynamicColors.palette.m3onSurface
|
||||||
|
}
|
||||||
|
|
||||||
|
// Support text: M3 Body Medium (14sp, 500 weight)
|
||||||
|
Text {
|
||||||
|
id: supportText
|
||||||
|
Layout.alignment: Qt.AlignHCenter
|
||||||
|
Layout.bottomMargin: 24
|
||||||
|
|
||||||
|
text: "Please enter your password to unlock"
|
||||||
|
font.pixelSize: 14
|
||||||
|
font.weight: Font.Medium
|
||||||
|
color: DynamicColors.palette.m3onSurfaceVariant
|
||||||
|
}
|
||||||
|
|
||||||
|
// Input field container
|
||||||
|
Rectangle {
|
||||||
|
id: inputContainer
|
||||||
|
Layout.alignment: Qt.AlignHCenter
|
||||||
|
Layout.bottomMargin: 16
|
||||||
|
|
||||||
|
Layout.preferredWidth: 320
|
||||||
|
Layout.preferredHeight: 48
|
||||||
|
|
||||||
|
color: DynamicColors.tPalette.m3surfaceContainerHigh
|
||||||
|
radius: 1000
|
||||||
|
|
||||||
|
border.width: 1
|
||||||
|
border.color: {
|
||||||
|
if (root.pam.state === "error" || root.pam.state === "fail") {
|
||||||
|
return DynamicColors.palette.m3error;
|
||||||
|
}
|
||||||
|
return DynamicColors.palette.m3outline;
|
||||||
|
}
|
||||||
|
|
||||||
|
Behavior on border.color {
|
||||||
|
ColorAnimation { duration: 150 }
|
||||||
|
}
|
||||||
|
|
||||||
|
ListView {
|
||||||
|
id: charList
|
||||||
|
|
||||||
|
readonly property int fullWidth: count * (implicitHeight + spacing) - spacing
|
||||||
|
|
||||||
|
function bindImWidth(): void {
|
||||||
|
imWidthBehavior.enabled = false;
|
||||||
|
implicitWidth = Qt.binding(() => fullWidth);
|
||||||
|
imWidthBehavior.enabled = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
anchors.centerIn: parent
|
||||||
|
anchors.horizontalCenterOffset: implicitWidth > root.width ? -(implicitWidth - root.width) / 2 : 0
|
||||||
|
|
||||||
|
implicitWidth: fullWidth
|
||||||
|
implicitHeight: 16
|
||||||
|
|
||||||
|
orientation: Qt.Horizontal
|
||||||
|
spacing: 8
|
||||||
|
interactive: false
|
||||||
|
|
||||||
|
model: ScriptModel {
|
||||||
|
values: root.pam.buffer.split("")
|
||||||
|
}
|
||||||
|
|
||||||
|
delegate: CustomRect {
|
||||||
|
id: ch
|
||||||
|
|
||||||
|
implicitWidth: implicitHeight
|
||||||
|
implicitHeight: charList.implicitHeight
|
||||||
|
|
||||||
|
color: DynamicColors.palette.m3onSurface
|
||||||
|
radius: 1000
|
||||||
|
|
||||||
|
opacity: 0
|
||||||
|
scale: 0
|
||||||
|
Component.onCompleted: {
|
||||||
|
opacity = 1;
|
||||||
|
scale = 1;
|
||||||
|
}
|
||||||
|
ListView.onRemove: removeAnim.start()
|
||||||
|
|
||||||
|
SequentialAnimation {
|
||||||
|
id: removeAnim
|
||||||
|
|
||||||
|
PropertyAction {
|
||||||
|
target: ch
|
||||||
|
property: "ListView.delayRemove"
|
||||||
|
value: true
|
||||||
|
}
|
||||||
|
ParallelAnimation {
|
||||||
|
Anim {
|
||||||
|
target: ch
|
||||||
|
property: "opacity"
|
||||||
|
to: 0
|
||||||
|
}
|
||||||
|
Anim {
|
||||||
|
target: ch
|
||||||
|
property: "scale"
|
||||||
|
to: 0.5
|
||||||
|
}
|
||||||
|
}
|
||||||
|
PropertyAction {
|
||||||
|
target: ch
|
||||||
|
property: "ListView.delayRemove"
|
||||||
|
value: false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Behavior on opacity {
|
||||||
|
Anim {}
|
||||||
|
}
|
||||||
|
|
||||||
|
Behavior on scale {
|
||||||
|
Anim {
|
||||||
|
duration: MaterialEasing.expressiveFastSpatialTime
|
||||||
|
easing.bezierCurve: MaterialEasing.expressiveFastSpatial
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Behavior on implicitWidth {
|
||||||
|
id: imWidthBehavior
|
||||||
|
|
||||||
|
Anim {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Input focus indicator (M3 focused state)
|
||||||
|
Rectangle {
|
||||||
|
anchors.fill: parent
|
||||||
|
radius: 12
|
||||||
|
color: "transparent"
|
||||||
|
border.width: 2
|
||||||
|
border.color: DynamicColors.palette.m3primary
|
||||||
|
opacity: 0
|
||||||
|
visible: hiddenInput.activeFocus
|
||||||
|
|
||||||
|
Behavior on opacity {
|
||||||
|
NumberAnimation { duration: 150 }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Component.onCompleted: {
|
||||||
|
if (hiddenInput.activeFocus) opacity = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Message display: M3 Body Small (12sp, 500 weight) for error messages
|
||||||
|
Text {
|
||||||
|
id: messageDisplay
|
||||||
|
|
||||||
|
Layout.alignment: Qt.AlignHCenter
|
||||||
|
Layout.topMargin: 8
|
||||||
|
|
||||||
|
text: {
|
||||||
|
if (root.pam.lockMessage) {
|
||||||
|
return root.pam.lockMessage;
|
||||||
|
}
|
||||||
|
if (root.pam.state === "error") {
|
||||||
|
return "Authentication error";
|
||||||
|
}
|
||||||
|
if (root.pam.state === "fail") {
|
||||||
|
return "Invalid password";
|
||||||
|
}
|
||||||
|
if (root.pam.state === "max") {
|
||||||
|
return "Maximum attempts reached";
|
||||||
|
}
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
visible: text.length > 0
|
||||||
|
font.pixelSize: 12
|
||||||
|
font.weight: Font.Medium
|
||||||
|
color: root.pam.state === "max" ? DynamicColors.palette.m3error : DynamicColors.palette.m3onSurfaceVariant
|
||||||
|
wrapMode: Text.WordWrap
|
||||||
|
horizontalAlignment: Text.AlignHCenter
|
||||||
|
Layout.preferredWidth: 320
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Component.onCompleted: hiddenInput.forceActiveFocus()
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,97 @@
|
|||||||
|
import Quickshell
|
||||||
|
import Quickshell.Wayland
|
||||||
|
import Quickshell.Services.Pam
|
||||||
|
import QtQuick
|
||||||
|
|
||||||
|
Scope {
|
||||||
|
id: root
|
||||||
|
|
||||||
|
required property WlSessionLock lock
|
||||||
|
|
||||||
|
readonly property alias passwd: passwd
|
||||||
|
property string lockMessage
|
||||||
|
property string state
|
||||||
|
property string fprintState
|
||||||
|
property string buffer
|
||||||
|
|
||||||
|
signal flashMsg
|
||||||
|
|
||||||
|
function handleKey(event: KeyEvent): void {
|
||||||
|
if (passwd.active || state === "max")
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (event.key === Qt.Key_Enter || event.key === Qt.Key_Return) {
|
||||||
|
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 (" abcdefghijklmnopqrstuvwxyz1234567890`~!@#$%^&*()-_=+[{]}\\|;:'\",<.>/?".includes(event.text.toLowerCase())) {
|
||||||
|
buffer += event.text;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
PamContext {
|
||||||
|
id: passwd
|
||||||
|
|
||||||
|
config: "passwd"
|
||||||
|
configDirectory: Quickshell.shellDir + "/assets/pam.d"
|
||||||
|
|
||||||
|
onMessageChanged: {
|
||||||
|
if ( message.startsWith( "The account is locked" ))
|
||||||
|
root.lockMessage = message;
|
||||||
|
else if ( root.lockMessage && message.endsWith( " left to unlock)" ))
|
||||||
|
root.lockMessage += "\n" + message;
|
||||||
|
}
|
||||||
|
|
||||||
|
onResponseRequiredChanged: {
|
||||||
|
if ( !responseRequired )
|
||||||
|
return;
|
||||||
|
|
||||||
|
respond(root.buffer);
|
||||||
|
root.buffer = "";
|
||||||
|
}
|
||||||
|
|
||||||
|
onCompleted: res => {
|
||||||
|
if (res === PamResult.Success)
|
||||||
|
return root.lock.locked = false;
|
||||||
|
|
||||||
|
if (res === PamResult.Error)
|
||||||
|
root.state = "error";
|
||||||
|
else if (res === PamResult.MaxTries)
|
||||||
|
root.state = "max";
|
||||||
|
else if (res === PamResult.Failed)
|
||||||
|
root.state = "fail";
|
||||||
|
|
||||||
|
root.flashMsg();
|
||||||
|
stateReset.restart();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Timer {
|
||||||
|
id: stateReset
|
||||||
|
|
||||||
|
interval: 4000
|
||||||
|
onTriggered: {
|
||||||
|
if (root.state !== "max")
|
||||||
|
root.state = "";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Connections {
|
||||||
|
target: root.lock
|
||||||
|
|
||||||
|
function onSecureChanged(): void {
|
||||||
|
if (root.lock.secure) {
|
||||||
|
root.buffer = "";
|
||||||
|
root.state = "";
|
||||||
|
root.fprintState = "";
|
||||||
|
root.lockMessage = "";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -21,6 +21,7 @@ PanelWindow {
|
|||||||
bottom: true
|
bottom: true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
WlrLayershell.namespace: "ZShell-Notifs"
|
||||||
WlrLayershell.layer: WlrLayer.Overlay
|
WlrLayershell.layer: WlrLayer.Overlay
|
||||||
WlrLayershell.keyboardFocus: WlrKeyboardFocus.OnDemand
|
WlrLayershell.keyboardFocus: WlrKeyboardFocus.OnDemand
|
||||||
required property PanelWindow bar
|
required property PanelWindow bar
|
||||||
|
|||||||
@@ -13,6 +13,7 @@ PanelWindow {
|
|||||||
id: root
|
id: root
|
||||||
color: "transparent"
|
color: "transparent"
|
||||||
screen: root.bar.screen
|
screen: root.bar.screen
|
||||||
|
|
||||||
anchors {
|
anchors {
|
||||||
top: true
|
top: true
|
||||||
right: true
|
right: true
|
||||||
@@ -20,9 +21,11 @@ PanelWindow {
|
|||||||
bottom: true
|
bottom: true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
WlrLayershell.namespace: "ZShell-Notifs"
|
||||||
|
WlrLayershell.layer: WlrLayer.Overlay
|
||||||
|
|
||||||
mask: Region { regions: root.notifRegions }
|
mask: Region { regions: root.notifRegions }
|
||||||
exclusionMode: ExclusionMode.Ignore
|
exclusionMode: ExclusionMode.Ignore
|
||||||
WlrLayershell.layer: WlrLayer.Overlay
|
|
||||||
property list<Region> notifRegions: []
|
property list<Region> notifRegions: []
|
||||||
required property bool centerShown
|
required property bool centerShown
|
||||||
required property PanelWindow bar
|
required property PanelWindow bar
|
||||||
@@ -30,10 +33,6 @@ PanelWindow {
|
|||||||
property color backgroundColor: Config.useDynamicColors ? DynamicColors.tPalette.m3surface : Config.baseBgColor
|
property color backgroundColor: Config.useDynamicColors ? DynamicColors.tPalette.m3surface : Config.baseBgColor
|
||||||
visible: Hyprland.monitorFor(screen).focused
|
visible: Hyprland.monitorFor(screen).focused
|
||||||
|
|
||||||
Component.onCompleted: {
|
|
||||||
console.log(NotifServer.list.filter( n => n.popup ).length + " notification popups loaded.");
|
|
||||||
}
|
|
||||||
|
|
||||||
ListView {
|
ListView {
|
||||||
id: notifListView
|
id: notifListView
|
||||||
model: ScriptModel {
|
model: ScriptModel {
|
||||||
|
|||||||
@@ -0,0 +1,3 @@
|
|||||||
|
auth required pam_fprintd.so
|
||||||
|
auth include common-auth
|
||||||
|
account include common-account
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
#%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
|
||||||
@@ -0,0 +1,18 @@
|
|||||||
|
from PIL import Image, ImageFilter
|
||||||
|
import argparse
|
||||||
|
|
||||||
|
def gen_blurred_image(input_image, output_path):
|
||||||
|
img = Image.open(input_image)
|
||||||
|
|
||||||
|
img = img.filter(ImageFilter.GaussianBlur(40))
|
||||||
|
|
||||||
|
img.save(output_path, "PNG")
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
parser = argparse.ArgumentParser(description="Generate a blurred lock screen background image.")
|
||||||
|
parser.add_argument("--input_image", type=str)
|
||||||
|
parser.add_argument("--output_path", type=str)
|
||||||
|
|
||||||
|
args = parser.parse_args()
|
||||||
|
|
||||||
|
gen_blurred_image(args.input_image, args.output_path)
|
||||||
@@ -2,6 +2,7 @@
|
|||||||
//@ pragma Env QSG_RENDER_LOOP=threaded
|
//@ pragma Env QSG_RENDER_LOOP=threaded
|
||||||
import Quickshell
|
import Quickshell
|
||||||
import qs.Modules
|
import qs.Modules
|
||||||
|
import qs.Modules.Lock
|
||||||
import qs.Helpers
|
import qs.Helpers
|
||||||
|
|
||||||
Scope {
|
Scope {
|
||||||
@@ -9,4 +10,11 @@ Scope {
|
|||||||
Wallpaper {}
|
Wallpaper {}
|
||||||
Launcher {}
|
Launcher {}
|
||||||
AreaPicker {}
|
AreaPicker {}
|
||||||
|
Lock {
|
||||||
|
id: lock
|
||||||
|
}
|
||||||
|
|
||||||
|
IdleInhibitor {
|
||||||
|
lock: lock
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user