# 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 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/` then `/usr/share/icons/` for `.svg` or `-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. Further revised: `panelWidth` defaults to 0.20, the clock and avatar are larger, the confirm and back controls use chevron icons, and the panel blur is stronger. ## 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 /theme`: layout, blur, clock, greeting, staged field, power icon shapes, session selector. - `sudo -u sddm test -r ` 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.