aboutsummaryrefslogtreecommitdiffstats
path: root/appearance/README.md
blob: aba231a6f66c4ccccd26773409b974307dc99e2c (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
# appearance

Wallpapers and colour scheme in one drawer. `SUPER+Return` opens it on the
Wallpaper tab; Tab switches tabs, Escape closes.

    ┌─[ Wallpaper ]─[ Theme ]──────────────────────────┐
    │  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 other tab.

## 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/<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 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/wal/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,
    })