# appearance Wallpapers and colour scheme in one drawer. `SUPER+Return` opens it on the Wallpaper tab; Tab switches tabs, Escape closes. ┌─[ Wallpaper ]─[ Theme ]─[ Sunset ]─[ Idle ]─[ Icons ]──┐ │ Set on [Horizontal] [Vertical] 261 wallpapers │ │ ┌────┐ ┌────┐ ┌────┐ ┌────┐ ┌──┐ ┌─────┐ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ └────┘ └────┘ └────┘ └────┘ └┬─┘ └──┬──┘ │ │ ┌────┐ ┌────┐ ┌────┐ ┌────┐ ═╧═ ══╧══ │ │ │ │ │ │ │ │ │ │ [Apply] [Reset] │ │ └────┘ └────┘ └────┘ └────┘ │ └────────────────────────────────────────────────────────┘ ## Running it qs -p . It is started from `autostart.lua` and reached over IPC, so the shell has to be running for the keybind to work: hl.bind(mainMod .. " + Return", hl.dsp.exec_cmd( "qs -p ~/Programming/GIT/quickshell/appearance ipc call appearance wallpaper")) Write that path out in full in the real config: `exec_cmd` has no shell to expand `~`. `ipc call appearance theme` opens the Theme tab. IPC verbs: `wallpaper`, `theme`, `sunset`, `idle`, `icons`. ## Sunset A port of `hyprsunset-qt` (`~/Programming/GIT/sunset-qt`): profiles in `~/.config/hypr/hyprsunset.conf`, location in `~/.config/hyprsunset-qt/config`, sunrise/sunset from the same API and cache. Both apps read and write the identical file format, so either can edit it. ## Idle Timeout and enabled only; the commands in `~/.config/hypr/hypridle.conf` are fixed. Everything before the first `listener` (the `general` block and the comments explaining the design) is preserved verbatim. A disabled listener is written commented out. Save restarts `hypridle`, which resets its timers. ## Icons Switches the icon and cursor theme, and the pointer size. Icon previews come from a GTK lookup per theme. Cursor previews come from one python pass per open: for every theme it extracts four shapes (arrow, hand, text, horizontal resize) out of a hyprcursor `.hlc`, a shape directory's SVG, or a legacy Xcursor binary via `xcur2png`, so a card shows the cases that tell themes apart. Hovering a card changes the real cursor and reverts it on leave. Applying writes `gsettings` (which GTK3 and GTK4 both read), the Qt configs (`qt6ct`/`qt5ct`), and, for cursors, `environment.lua`. The GTK theme names do not come from `gsettings` alone here, so the drawer also rewrites `gtk-3.0/settings.ini` and `gtk-4.0/settings.ini` to match. Apps and a relogin are needed to see the rest. The theme name is still hardcoded in `unified-desktop-theme`, `waybar-theme-udt` and rofi, which is tracked as a follow-up in those repos. ## Wallpapers Clicking a thumbnail **stages** it rather than setting it, so both screens can be composed before anything changes, and Apply then makes a single `wallp --set H=… V=…` call. The mock screens on the right show what the desk would look like: the staged pick where there is one, what is currently set where there is not, and the hovered thumbnail on the targeted screen while the pointer is over it. `wallp` does the actual work, including running `udt-accent`, so the accent follows the new wallpaper exactly as it does from a terminal. This panel replaces its qarma file dialog, not the script. The two monitors are drawn at their real proportions, read from `hyprctl monitors`: DP-1 is 2560x1080 and DP-3 is 1920x1080 with `transform=1`, which makes it 1080x1920 on the desk. They are centred against each other because that is how Hyprland has them, both spanning y=0. The bezel and stand are Rectangles rather than an SVG: no asset to ship, sharp at any size, and the case stays a fixed near-black while the accent marks which screen is targeted. Their proportions come from the panel **width**, not its height. Scaling the stand off height gave the wide monitor a 20px stand that was invisible and would have given the vertical one an absurd long neck. ## Themes Each scheme shows its real colours, parsed from the pair of files unified-desktop-theme keeps for it: `palette/.conf` holds the colours under the scheme's own names, `palette/roles-.conf` says what each colour is for, so a role is resolved by looking its value up as a key in the first file. Beside the swatches is a small mock of a panel painted in that scheme, which says how the colours sit together rather than only what they are. The list comes from the palette directory rather than a hardcoded set, so adding a scheme to unified-desktop-theme is enough to make it appear here. Both the scheme list and the wallpaper scan are redone every time the panel opens: this shell is autostarted and runs all session, so a scan done only at startup would go stale the first time anything was added. Applying writes the `scheme =` line in `~/.config/udt/roles.conf` and runs `install.sh`, which regenerates every themed config. **It reloads nothing**, because `install.sh` reloads nothing: the panel reports what is still showing the old scheme instead of pretending the switch is complete. `hyprctl reload`, waybar, kitty and conky each need a nudge, and Qt and GTK apps only reread a theme when they restart. ## Two QML traps met here **There is no `String.matchAll`.** QML's JS engine does not have it. It threw inside a `try` and left every swatch empty with nothing in the log. The palette parser uses an `exec` loop instead. **Assigning `running = true` to a Process that is already running does nothing.** The scheme loader reuses one `Process` for each scheme in turn and stopped after the first until it set `running = false` immediately before. ## Theme and blur `Theme.qml` is the shared one: the palette comes from `~/.cache/udt/udt-palette.qml` and is watched. Frosting is Hyprland's, matched on this window's namespace: hl.layer_rule({ name = "blur-appearance", match = { namespace = "^(quickshell-appearance)$" }, blur = true, xray = false, ignore_alpha = 0.1, })