aboutsummaryrefslogtreecommitdiffstats
path: root/theme/Main.qml
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()
    }
}