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
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
|
# sddm-theme-udt, Left Panel Redesign
Date: 2026-09-17
Status: approved, not yet implemented
This spec supersedes the greeter layout and interaction sections of
`2026-09-17-sddm-theme-udt-design.md` (the centered login card, its single
password flow and its power bar placement). Every other decision there, the
palette, the live `theme.conf.user` tracking, the per-window screen model, the
idle fade, the security model and the colour names, still stands.
## Goal
Replace the centered login card with a full-height panel pinned to the left
edge, about 30% of the screen width, blurred underneath. Top to bottom the
panel carries a clock and date, a configurable greeting, the avatar, a single
credential slot that advances from username to password, a row of power
buttons, and the session selector pinned to the bottom. The power button icons
follow the icon theme selected in the `appearance` drawer instead of the four
bundled SVGs, falling back to the bundled set when the theme has no match.
## Problem
The current greeter is one card floating in the middle of the screen. It shows
username and password side by side, which is more fields than the flow needs,
and its power icons are fixed line art that does not match the desktop's
selected icon theme. The user asked for a left panel with a staged login and
theme-following power icons.
## Decisions
1. **Left panel, flush, square.** The panel is anchored to the left, top and
bottom edges of its greeter window, `panelWidth` of the window width, with
no rounded corners and no left margin. A 2px `accent` border runs along the
exposed edges. The background under it is frosted with the existing
`Backdrop` (wallpaper snapshot, blur, tint), masked to the panel rectangle
with radius 0. Rejected: a detached card with rounded corners and margins
(the user asked for a panel flush to the edge and without rounding).
2. **One credential slot, two stages.** A single field slot shows the username
first. Confirming it slides the username out to the left and the password in
from the right. Confirming the password logs in. The two fields are never
visible at once, so the slot reads as one control that advances. Rejected:
keeping both fields stacked (the behaviour the redesign replaces).
3. **Touch-reachable confirm and back.** Besides Enter, each stage has a
confirm arrow button. The password stage also shows a back chevron that
returns to the username, keeping its text. Rejected: Enter-only (a touch
user could not advance) and Esc-only back (the same, for touch).
4. **Power icons resolved by `udt-accent` from gsettings.** The icon theme name
is read from `org.gnome.desktop.interface icon-theme` while `udt-accent` runs
as the login user. Absolute paths to the four resolved SVGs are written into
the generated `~/.local/share/udt/sddm-theme.conf`, next to the palette, so
the greeter stays data-only and never reads a file. Empty values fall back to
the bundled `theme/icons/*.svg`. Rejected: reading `qt6ct.conf` or gsettings
from inside the greeter (the greeter runs as `sddm`, has no `QML` file-read
API and no user dconf); resolving FreeDesktop icon lookup in QML (fragile,
and the theme spec's decision 1 already closed the file-read path).
5. **Icon theme switching is picked up on the next `udt-accent` run.** A
wallpaper change already runs it. Switching the icon theme in the drawer
does not, so a manually triggered `udt-accent` is needed until the drawer is
wired to call it. Recorded as a TODO in the quickshell repository rather than
solved here.
6. **Kept from the original design.** Palette and live tracking through
`theme.conf.user`; one greeter window per screen with the panel shown only
where `uiScreen` matches, else on the primary window; the 1s clock is the
only new timer; `fadeoutMs` idle hide and input wake; `blur`;
`EnableAvatars`; the security argument that the only user-writable input is
INI data.
## Architecture
```
wallpaper change
wallp -> udt-accent <image>
extracts + snaps accent, reads gsettings icon-theme,
resolves the four power icon paths, then writes
~/.local/share/udt/sddm-theme.conf (0644, world-readable)
palette keys
powerIcon / rebootIcon / suspendIcon / hibernateIcon
(absolute paths, empty when unresolved)
greeter start (as sddm), one window per screen
reads theme.conf + theme.conf.user into `config`
wallpaper fills the window
panel, blurred, on the uiScreen window only
```
The root install block is unchanged. Re-running the root copy is only needed
when theme code changes.
## Panel layout
Anchored inside the panel (`panelWidth` wide, 32px horizontal padding):
| position | element | detail |
| --- | --- | --- |
| top | time | `Text`, `timeFormat` (default `HH:mm`), large |
| | date | `Text`, `dateFormat` (default `dddd, d MMMM`), `subtext0` |
| | greeting | `Text`, `greeting` (default `hello there`) |
| | avatar | 96px circle, `accent` ring, face from `userModel`, initials fallback, centered |
| | credential slot | one field, staged, with confirm arrow and back chevron |
| | message | login failure (`red`) or Caps Lock hint (`yellow`) |
| flexible gap | | |
| bottom | power row | four buttons, centered, ~40px icons on 56px targets |
| bottom | session selector | full panel width, pinned to the bottom edge |
The clock refreshes from a 1s `Timer` into a `now` property, formatted with
`Qt.formatDateTime(now, fmt)`.
## Credential flow
- `stage` is `user` or `pass`.
- `user`: username field prefilled with `userModel.lastUser`; the avatar
reflects the current text. Confirm with Enter or the arrow, ignored when
empty, advances to `pass`.
- Transition: username slides to `-slot.width` and fades, password slides from
`slot.width` to 0, 220ms `OutCubic`. The slot clips. The avatar remains and
follows the confirmed username.
- `pass`: password field focused. Confirm with Enter or the arrow calls
`sddm.login(username, password, sessionBox.currentIndex)`.
- Back: Esc on the password field or the back chevron returns to `user` and
keeps the username; the password is cleared.
- Failure: `sddm.loginFailed` clears the password, shows `Login failed` in
`red`, shakes the panel, and stays in `pass`. Caps Lock shows in `yellow`.
- Idle hide and wake are unchanged; wake focuses the field for the current
stage.
## Config
Added to the root `theme.conf` with these defaults, overridden live in the
generated `theme.conf.user`:
| key | default | meaning |
| --- | --- | --- |
| `panelWidth` | `0.30` | panel width as a fraction of the window width |
| `timeFormat` | `HH:mm` | Qt time format string |
| `dateFormat` | `dddd, d MMMM` | Qt date format string |
| `greeting` | `hello there` | greeting line |
| `powerIcon` | (empty) | absolute path to the shutdown icon |
| `rebootIcon` | (empty) | absolute path to the restart icon |
| `suspendIcon` | (empty) | absolute path to the sleep icon |
| `hibernateIcon` | (empty) | absolute path to the hibernate icon |
Unchanged: the palette keys, `uiScreen`, `fadeoutMs`, `blur`.
`udt-accent` gains the four icon keys in its emitted key list and writes the
resolved paths. `theme.conf` keeps them empty so a missing or unreachable icon
falls back to the bundled SVG.
## Icon resolution in `udt-accent`
1. Read the icon theme name:
`gsettings get org.gnome.desktop.interface icon-theme`, strip quotes. An
empty or failed read leaves every icon key empty.
2. FreeDesktop names, with fallbacks:
- shutdown: `system-shutdown`
- restart: `system-reboot`
- sleep: `system-suspend`
- hibernate: `system-hibernate`, then `system-suspend-hibernate`
3. Search `~/.local/share/icons/<theme>` then `/usr/share/icons/<theme>` for
`<name>.svg` or `<name>-symbolic.svg`. Prefer a `symbolic` hit, then the
largest size directory; a plain recursive search with that ordering is
enough and avoids parsing `index.theme`.
4. Write the absolute path, or leave the key empty when nothing matches.
Icons are drawn as a flat silhouette through the existing `MultiEffect`
colorization (`subtext0`, `accent` on hover), so the theme icon contributes its
shape; the UDT palette still supplies the colour.
Revised after implementation: a resolved theme icon is drawn in the colours the
theme ships, and only the bundled fallback line art is tinted to the palette.
## Files touched
This repository:
- `theme/Main.qml`: swap `LoginCard` for `Panel`; panel geometry per window.
- `theme/components/Panel.qml` (new): layout, clock, greeting, avatar, power
row, session selector, shake, idle wiring.
- `theme/components/Credentials.qml` (new): the staged slot and its animation.
- `theme/components/PowerBar.qml`: read the four config paths, bundled
fallback, larger targets.
- `theme/components/LoginCard.qml`: deleted.
- `theme/theme.conf`: new keys.
- `README.md`: describe the panel and the new keys.
Other repositories:
- `unified-desktop-theme/bin/udt-accent`: add the four icon keys to the emitted
INI, add the resolver, extend `--selftest`.
- `quickshell/TODO.md`: record that the appearance drawer should run
`udt-accent` when the icon theme changes, so the greeter follows without a
wallpaper change.
## Testing
- `unified-desktop-theme/bin/udt-accent --selftest`: the emitted INI contains
every key including the four icon keys; with a known theme name the resolver
returns an existing readable path for each icon; an unknown theme leaves the
keys empty. This is the runnable check for the new logic.
- `sddm-greeter-qt6 --test-mode --theme <repo>/theme`: layout, blur, clock,
greeting, staged field, power icon shapes, session selector.
- `sudo -u sddm test -r <resolved icon>` for one resolved path, confirming the
greeter user can read the theme's icons.
- Confirm the generated INI still carries every palette key, so the palette
path is unregressed.
## Risks
- **Icon theme switch lag.** Until the quickshell TODO lands, a new icon theme
reaches the greeter at the next wallpaper change or manual `udt-accent` run.
- **`gsettings` unavailable.** If the read fails, all four keys are empty and
the bundled icons draw. Cosmetic only.
- **A theme without the expected names.** Some themes omit a symbolic variant
or use different names; the fallback list and the bundled set cover the
common cases, and the worst case is the bundled icon.
- **`panelWidth` on very wide screens.** A 30% fraction can be wide. It is a
config key, so it can be lowered without a code change.
- **Date locale in the greeter.** `Qt.formatDateTime` uses the greeter's
locale, which may be `C`. If the date must be localized, a future
`QLocale`-based format or a fixed numeric format can be added.
- **Blur needs a working GL context**, as before; the tint alone still reads.
## Out of scope
- Wiring the appearance drawer to run `udt-accent` on icon change (TODO only).
- Bundling or installing fonts.
- Displays other than SDDM.
- Light schemes and per-scheme artwork.
## Development Approach
This project is developed using AI-assisted tools. Code is generated with the help of AI based on human-provided specifications, design decisions, and iterative feedback.
All contributions are reviewed, tested, and curated by the maintainer before being included in the codebase. AI is used as a productivity and exploration tool, while human oversight remains central to all decisions.
The goal is to combine the flexibility of AI-assisted development with standard open-source practices such as transparency, review, and accountability.
|