feat: scale the whole session, not just the classroom's own windows

UI_SCALE only ever reached the surfaces we draw ourselves. Chrome stayed
tiny — its tabs, omnibox and menus are Chrome's own pixels, and Ctrl+
only scales page content, which is no use to a volunteer reading a
toolbar from across the room.

UI_SCALE is a property of the television, not of one program, so it now
sets sway's output scale, which every client is measured against.
classroom-scale runs first in the session and applies it. The display
mode is untouched: the panel stays at 1920x1080 and only the logical
coordinate space shrinks, which is what makes everything in it larger.

Our own surfaces stop scaling themselves. They are measured in the same
logical pixels sway is already scaling, so applying UI_SCALE again would
double it. SHELL_SCALE is that decision in one named place, and setting
it back to ui_scale(config) would restore per-surface scaling without
touching a template.

Measured at 1920x1080 with Chrome 152. Chrome's tab strip 40 -> 49 ->
59px against 1.0, 1.25, 1.5; sway's title bar 25 -> 31 -> 38px; the
classroom dock 74 -> 92 -> 110px. Everything scales once, together, and
1.0 is identical to no scaling at all.

Two tradeoffs, both measured rather than assumed. GTK 3 has no
fractional scaling, so at 1.5 it renders at 2x and sway scales down —
very slightly softer, invisible at classroom distance. XWayland is
softer too: terminal text at 1.5 showed about 50% more intermediate-tone
pixels than at 1.0. VLC is the only XWayland application here, and in
DVD mode none of its interface is on screen, only video from a 720x480
disc that is being upscaled regardless. Chrome is a native Wayland
client and stays sharp, which is what matters for reading.

Co-Authored-By: Claude Opus 5 <[email protected]>
This commit is contained in:
ekklesia
2026-09-04 23:17:37 -05:00
co-authored by Claude Opus 5
parent 37f8166401
commit 8bed3d186a
9 changed files with 177 additions and 47 deletions
+71 -35
View File
@@ -2,7 +2,7 @@
Every classroom gets the same design at a size that suits its TV. A 32"
panel a few feet from the children and a 65" set across a hall want
different sizes of the same dock, not different docks.
different sizes of the same room, not different rooms.
## Changing it
@@ -18,43 +18,79 @@ Then restart the classroom shell:
sudo systemctl restart getty@tty1
```
That ends the session and the autologin brings it straight back with the
new size. A reboot does the same thing. Nothing else needs touching, and
no CSS or source file is ever edited to change a room's size.
## Values
| UI_SCALE | Roughly |
| --- | --- |
| 0.8 | Small or close-up panel |
| 1.0 | Default. 1080p classroom TV, 32–50" |
| 1.25 | Large room, or a set viewed from further back |
| 1.5 | 65"+ |
Anything outside 0.8–1.5 is clamped to that range, and anything that is
not a number at all falls back to 1.0, so a typo in device.conf cannot
produce an unusable shell.
That ends the session and the autologin brings it straight back at the
new size. A reboot does the same. Nothing else needs touching, and no
CSS or source file is ever edited to change a room's size.
## What it scales
- Dock height, and the reserved strip at the bottom of the screen
- Dock corner radius, padding and the spacing between buttons
- Button size, padding and corner radius
- Every dock icon
- Clock text size, padding, corner radius and its inset from the edge
- Notification width, height, padding, margin, corner radius, text size
and icon size
**Everything.** UI_SCALE is a property of the television, not of one
program, so it is applied where it reaches the whole session: sway's
output scale.
Colours, translucency and the hairline borders do not scale: those are
the design, not the size. At `UI_SCALE=1.0` the rendered stylesheet is
byte-identical to the one the shell used before scaling existed.
- Chrome's tabs, omnibox, toolbar icons and menus
- VLC, and any other application's own interface
- The dock, the clock, notifications and the DVD control bar
- Mouse hit targets, because they scale with the widgets
## How it works
The display mode is **not** changed. The panel stays at its native
1920x1080. Only the logical coordinate space shrinks, which is what
makes everything drawn in it larger:
`/etc/ekklesia-classroom/dock/style.css.in` and
`/etc/ekklesia-classroom/mako/config.in` are templates carrying
measurement tokens. `classroom-dock` resolves the stylesheet in memory at
startup; `classroom-notifications` resolves the notification config into
the session's runtime directory and hands it to mako. Neither template is
ever rewritten on disk, so an update cannot lose a room's setting and a
room's setting cannot drift from the packaged design.
| UI_SCALE | Logical space | Roughly |
| --- | --- | --- |
| 0.8 | 2400x1350 | Small or close-up panel |
| 1.0 | 1920x1080 | Default. 32–50" classroom TV |
| 1.25 | 1536x864 | Large room, or a set viewed from further back |
| 1.5 | 1280x720 | 65"+ |
Anything outside 0.8–1.5 is clamped, and anything that is not a number
falls back to 1.0, so a typo in device.conf cannot produce an unusable
shell.
## Measured
Against 1920x1080 under sway, with Chrome 152:
| | 1.0 | 1.25 | 1.5 |
| --- | --- | --- | --- |
| Chrome tab strip | 40px | 49px (x1.23) | 59px (x1.48) |
| sway title bar | 25px | 31px (x1.24) | 38px (x1.52) |
| Classroom dock | 74px | 92px (x1.24) | 110px (x1.49) |
Everything scales once, together.
## Why our own surfaces do not scale themselves
`classroom-scale` runs first in the sway config and sets the output
scale. From then on the dock, the notifications and the DVD control bar
are measured in the same logical pixels sway is already scaling, so they
must render **unscaled** — `SHELL_SCALE` in `classroom_config.py` is
`1.0`. Scaling them again would apply UI_SCALE twice and the dock would
come out half again too big.
The stylesheet templates still take a scale, and `SHELL_SCALE` is the
one place it comes from. If compositor scaling ever has to be abandoned,
setting it back to `ui_scale(config)` restores per-surface scaling
without touching a template.
## Tradeoffs
**GTK 3 has no fractional scaling.** At UI_SCALE=1.5 sway advertises an
integer scale of 2 to GTK, which renders at 2x, and sway scales the
result down to 1.5x. The dock is the right size but very slightly softer
than at 1.0. On a TV at classroom distance this is not visible.
**XWayland is softer at fractional scale.** X11 clients have no concept
of a fractional output scale, so sway renders them at the logical size
and scales the buffer. Measured on terminal text, scale 1.5 produced
about 50% more intermediate-tone pixels than scale 1.0 — real, modest
softening.
VLC is the only XWayland application in the classroom, and in DVD mode
none of its interface is on screen: only video, from a 720x480 disc
being upscaled regardless. Chrome runs on Wayland natively and is sharp
at every scale, which is what matters for reading.
At UI_SCALE=1.0 nothing is scaled at all and the session is identical to
one with no scaling.