Skip to content

Windows: a folded pill you can find on any backdrop - #347

Open
RawJat wants to merge 2 commits into
vinzdg:mainfrom
RawJat:feat/windows-pill-contrast
Open

RawJat wants to merge 2 commits into
vinzdg:mainfrom
RawJat:feat/windows-pill-contrast

Conversation

@RawJat

@RawJat RawJat commented Sep 23, 2026

Copy link
Copy Markdown
Contributor

Folded, the notch is a 10 × 79 pill at the screen edge, and it is all Codenotch shows. Since #320 that pill took the Theme's colours: near-white in Light, which vanished against a white page, and black in Dark with a #2e2e2e edge, 1.4:1 against a black wallpaper.

Two commits. The first is a fix. The second is an opt-in that reads the screen, so it is your call, and it can be dropped without touching the first.

1. The folded pill leaves Theme. Black in both appearances, as the Mac's Solid black and Dark glass styles draw it, with a #5c5c5c edge, 3:1 against black. The open notch and the card still follow Theme. CSS only.

2. Appearance → Adaptive pill, off by default. With it on, the pill turns light over a dark backdrop, the way the iPhone's home indicator follows what is under it. The Mac's default gets much the same from its material: in the Liquid Glass style the folded pill is glass (since a85139e), which follows the Mac's appearance and takes on what is behind it. Windows has no such material, so this reads the screen instead.

  • While folded, the new backdrop.rs reads a thin strip of the screen beside the pill twice a second (GDI BitBlt, no new dependency) and reduces it to one average luminance.
  • It flips only when the other pill would stand out 1.5 times more, so a middling or scrolling backdrop does not make it flicker.
  • The strip is beside the pill, not under it: what a screen read sees of the notch window changes with click-through, and beside the pill nothing is drawn while folded.
  • Nothing is read with the switch off, the notch open, or Show on Always show, and only the average is kept. The Settings caption and the README say so.
  • Opt-in because it reads the screen, and for the reason you gave on Ramp the usage ring's colour across the full 0-100% range #332. The row's two strings are English only for now.

Only the pill adapts. The open notch and card are the user's choice through Theme; the pill's only job is to be found.

Test plan

vinzdg#320 gave the folded pill the Theme's colours. In Light it was
near-white, and vanished against a white document. In Dark its #2e2e2e
edge was 1.4:1 against a black wallpaper, where that edge is the only
thing showing the pill at all.

The folded pill now takes no part in Theme: black, as the Mac's Solid
black and Dark glass styles draw it, with a #5c5c5c edge, 3:1 against
black. The open notch and the card still follow Theme. (The Mac's
default, Liquid Glass, makes the folded pill glass, which Windows has
no material for.)
A black pill with a visible edge can be found anywhere, but over a dark
editor or wallpaper it is only the edge. The iPhone's home indicator
solves the same problem by following what is under it: light over dark
content, dark over light. Appearance → Adaptive pill does that here. It
is off unless switched on, because it reads the screen.

While the notch is folded, backdrop.rs reads a strip of the screen
beside the pill twice a second (GDI BitBlt, already in the windows
crate's features), reduces it to one average luminance, and tells the
page when the other pill would stand out 1.5 times more. The margin is
hysteresis: a middling backdrop, or a page scrolling past, keeps the
pill it has. The page sends the strip with the wake rectangle, beside
the pill rather than under it, because what a screen read sees of the
notch window changes with click-through, and beside the pill nothing is
drawn while folded.

With the switch off, the notch open, or Show on Always show, nothing is
read, and only the average is ever kept. The Settings caption and the
README both say so. Switching it off puts the black pill back at once.

The Mac's default gets much the same from its material: in the Liquid
Glass style the folded pill is glass, which follows the Mac's
appearance and takes on what is behind it. Windows has no such
material, so this reads the screen instead. It can be dropped without
touching the previous commit.
@RawJat
RawJat requested a review from vinzdg as a code owner September 23, 2026 15:46
@vinzdg

vinzdg commented Sep 24, 2026

Copy link
Copy Markdown
Owner

Thanks @RawJat. The idea is good and the careful parts are genuinely careful — the probe is only sent in the folded branch, the hysteresis and settle delay are sound, and the "beside, not under" reasoning is right and unit-tested.

Three things before it can land.

Blocker — it wakes 10 times a second, forever, whether or not the feature is on. backdrop.rs:100-129: start() spawns a thread whose loop is an unconditional sleep(100ms). The expensive part (the GDI capture) is properly gated, but the tick isn't — so it runs from launch, with adaptive_pill off by default, with the notch unfolded, even with the notch hidden. That's ~864,000 wake-ups a day for a feature nobody switched on. Park on a Condvar signalled by set_enabled/set_probe, or at minimum sleep long while disabled. (This is the same note I had on #322, and you'll see that one landed today after it moved to EVENT_SYSTEM_FOREGROUND with a 30s backstop — same shape of fix.)

Blocker — the two new strings aren't translated. ui/settings.html:151-152 adds "Adaptive pill" and its caption, and neither key is in any of the seven *_STATIC tables. CI won't catch it — check-ui-scripts.mjs only checks that the page parses.

Your call needed — it changes the default look. On main, #rest drew with background:var(--pill);border:1px solid var(--edge), so the folded pill followed the Theme setting that landed yesterday in #320. ui/notch.html:203-206 replaces those with hardcoded --rest:#000;--rest-edge:#5c5c5c. So with Adaptive pill off — the default — a Light-theme user's folded pill goes from light to black. I can see the argument (a black pill is what reads as a notch), and you documented it in the README, but it quietly undoes yesterday's work for the default case. Either keep the tokens when adaptive is off, or say explicitly that the folded pill is always dark and we'll make that the documented rule.

Smaller: renderAll() (settings.html:1499-1509) repaints sw-autostart and sw-move but not sw-adaptive, so the new switch doesn't refresh on a language change the way its neighbours do. And backdrop.rs:76 uses slice::as_chunks, stable only since Rust 1.88 — fine on dtolnay/rust-toolchain@stable today, but the crate pins no rust-version.

Fix the wake-ups and the strings, and tell me which way you want the default pill, and I'll take it.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants