diff options
Diffstat (limited to 'desktop/modules/appearance/README.md')
| -rw-r--r-- | desktop/modules/appearance/README.md | 174 |
1 files changed, 174 insertions, 0 deletions
diff --git a/desktop/modules/appearance/README.md b/desktop/modules/appearance/README.md new file mode 100644 index 0000000..b1823fb --- /dev/null +++ b/desktop/modules/appearance/README.md @@ -0,0 +1,174 @@ +# appearance + +Five pages of the settings window: Wallpaper, Theme, Icons & cursor, Sunset +and Idle. Until October 2026 they were the tabs of a separate `appearance/` +shell with an overlay of its own; they moved into the desktop process when +the settings window gave them the room that shell existed to provide. + +Each page is a `*Module.qml` here wrapping a `*Tab.qml`, and the work is done +by singletons (`Wallpapers`, `Udt`, `Icons`, `Hyprsunset`, `Hypridle`, +`Steps`). The window's open calls each module's `refresh()`, which rescans: +schemes, wallpapers and themes can all change during a session, and a scan +done only at startup would go stale. + +The old shell's IPC target is kept in `desktop/shell.qml` with the same verbs, +so its callers only changed the path: + + qs -p ~/Programming/GIT/quickshell/desktop ipc call appearance wallpaper + +Verbs: `wallpaper` (also `toggle`), `theme`, `sunset`, `idle`, `icons` open +that page; `steps` pokes the steps window; `selftest` runs the parsers' own +checks. Write the path out in full in the Hyprland config: `exec_cmd` has no +shell to expand `~`. + +Search finds a scheme by name and an icon or cursor theme by name, and +scrolls to it. + +## 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, `~/.config/udt/cursor.lua`, which +hypr-theme's `environment.lua` `dofile()`s at login. A local file rather than +an edit to `environment.lua`, which is tracked and was left dirty by every +cursor switch. The GTK theme names do +not come from `gsettings` alone here, so the Icons page 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. + +An icon switch also regenerates the two consumers that resolve icons by name +when they are generated rather than when they run: `udt-accent` rewrites the +SDDM power icons. It is chained after the `gsettings` write in one shell, +since it reads it. Waybar is gone, so the icon switch no longer reruns +waybar-theme-udt's `install.sh` or signals waybar. + +## 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. + +The thumbnails are grouped by folder, each a header that opens and closes +it, closed to begin with and remembered while the shell runs. The local +groups are the top-level folders of `~/Pictures/wallpapers`, with the images +loose in it as a group of its own; after them come the distribution's, +`/usr/share/wallpapers`, as `system` for its loose images and `Plasma` for +its packages. A Plasma package holds one picture at several resolutions, +some in a dark version too, so it shows once: dark where there is one, then +the largest, named after the package rather than its `5120x2880.png`. + +The list is flat, one row of thumbnails per item, so only the rows in view +exist and decode, and a folder of hundreds loads as it scrolls. Opening or +closing a folder inserts or removes just its rows, which keeps the scroll +position and the thumbnails around it. A first version made each folder one +item, which loaded every thumbnail of a folder the moment it opened. + +Each thumbnail's border says how it will look on the targeted screen, from +its real size, which `file` reads from the header after each scan (half a +second for a thousand). `swaybg -m fill` scales to cover, so the measure is +how far it enlarges: not at all is green, up to 1.33x yellow, past that red. +Under the mock screens a note in the same colour says why, for the hovered +image or else the staged one. The staged image keeps the accent border. + +"Open wallhaven-dl" under the mock screens launches the wallhaven-dl app, +which searches wallhaven.cc and finds larger copies of low-res wallpapers, +and closes the settings window, as a successful Apply does, so the desk +shows. It goes through `gtk-launch` and the app's desktop +entry, so `~/bin` need not be on quickshell's PATH. + +`wallp` does the actual work, including running `udt-accent`, so the accent +follows the new wallpaper exactly as it does from a terminal. This page +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 pane **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/<name>.conf` holds the colours +under the scheme's own names, `palette/roles-<name>.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 +settings window opens: the desktop process 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 and reloads Hyprland, +kitty and conky. Its whole output becomes the `install` tab of the +steps window below. The notice names what is left: Qt and GTK apps only reread +a theme when they restart, and neovim needs `:colorscheme udt`. + +## Steps + +A separate window, `StepsWindow.qml`, for the manual steps +unified-desktop-theme cannot run itself: the root copies into `/boot` and +`/usr/share/sddm`, the finish on the homepage host, and the last `install.sh` +log, shown first as "General recap". Its `udt-steps` writes one file per consumer under `~/.cache/udt/steps/` +and calls the `steps` verb, which reloads the tabs and opens the window if any +remain; an empty file set closes it. Nothing is watched: the poke is the +signal. The same verb reopens it after Close. + +Centred on DP-3, on the `top` layer with on-demand keyboard focus, so it can +stay open while commands are pasted into a terminal elsewhere. A line indented +two spaces is a command block with a Copy button (`wl-copy`), and the text is +selectable too. Done deletes the tab's file; the producer also clears it once +its consumer is up to date. + +The window's height comes from its content, so the scroll area is capped +against the screen and never against the window: binding it to the window's +own height collapsed the window to its margins. + +## 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 + +`Theme` is the desktop's shared one, through `import "../.."`: the palette +comes from `~/.cache/udt/udt-palette.qml` and is watched. The settings window +is a normal toplevel, so it takes Hyprland's ordinary window blur; the old +`blur-appearance` layer rule went with the overlay. |
