blob: 05f0aec1fe43b1672edd73173d2eb6a46f46ce0a (
plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
|
// SPDX-License-Identifier: GPL-2.0-only
// Copyright (C) 2026 Danilo M. <danix@danix.xyz>
//
// UDT SDDM greeter. SDDM creates one window per screen, each sized to its own
// screen and carrying a one-row ScreenModel, so this root item is exactly one
// screen. The wallpaper fills it; the login panel draws only on the screen
// named by config uiScreen, else on the primary screen. Input wakes the panel
// after it fades.
import QtQuick
import "components"
Item {
id: root
// SDDM creates one window per screen and sizes it to that screen. The
// model holds exactly one row and geometry(index) ignores index, returning
// this window's own screen at origin (0,0).
readonly property var windowGeometry: screenModel.geometry(0)
width: windowGeometry.width
height: windowGeometry.height
// Palette. Values come from theme.conf, overridden live by theme.conf.user.
readonly property string baseColor: config.stringValue("base")
readonly property string wallpaperUrl:
config.stringValue("background") === ""
? ""
: "file://" + config.stringValue("background")
// The screen the panel belongs on: config uiScreen if non-empty, else the
// primary screen. `primaryScreen` is a per-window context property SDDM
// sets true only on the window showing the primary screen.
readonly property string wantedScreen: config.stringValue("uiScreen")
property string thisScreenName: ""
readonly property bool cardScreen: wantedScreen === ""
? primaryScreen
: (thisScreenName === wantedScreen)
// The wallpaper fills this window's single screen. The frosted panel
// samples this image.
Image {
id: wallpaperImage
anchors.fill: parent
source: root.wallpaperUrl
fillMode: Image.PreserveAspectCrop
sourceSize.width: width
sourceSize.height: height
smooth: true
asynchronous: true
}
// Scrim so the panel and text read on any wallpaper.
Rectangle {
anchors.fill: parent
color: root.baseColor
opacity: 0.45
}
// Non-visual: reads the model's single row to learn this screen's name.
Repeater {
model: screenModel
delegate: Item {
visible: false
Component.onCompleted: root.thisScreenName = name
}
}
// Idle: fade the panel after fadeoutMs, restore on any input.
property bool uiVisible: true
// While faded the panel is disabled, which clears its focus; take focus on
// the root so the first key press wakes the panel instead of vanishing.
onUiVisibleChanged: {
if (!uiVisible)
root.forceActiveFocus()
}
Timer {
id: idle
interval: config.intValue("fadeoutMs") > 0 ? config.intValue("fadeoutMs") : 60000
running: root.uiVisible
repeat: false
onTriggered: root.uiVisible = false
}
function wake() {
if (!root.uiVisible) {
root.uiVisible = true
panel.restoreFocus()
}
idle.restart()
}
MouseArea {
anchors.fill: parent
hoverEnabled: true
onPressed: root.wake()
onPositionChanged: root.wake()
}
Keys.onPressed: event => {
root.wake()
event.accepted = false
}
// Panel width as a fraction of the window, with a sane fallback when the
// key is missing or malformed.
readonly property real panelWidth: {
var v = parseFloat(config.stringValue("panelWidth"))
return v > 0 ? Math.min(v, 1) : 0.20
}
Panel {
id: panel
anchors.left: parent.left
anchors.top: parent.top
anchors.bottom: parent.bottom
width: parent.width * root.panelWidth
visible: root.cardScreen
enabled: root.uiVisible
opacity: root.uiVisible ? 1 : 0
Behavior on opacity { NumberAnimation { duration: 260; easing.type: Easing.OutCubic } }
backdropSource: wallpaperImage
onWake: root.wake()
}
}
|