Pad the masthead against window controls on both edges - #33
Merged
Conversation
The hidden_inset_tall masthead only padded WindowChrome.insets.left, so it cleared the macOS traffic lights and nothing else. Windows puts its min/max/close cluster on the right instead and reports it as insets.right, which onChrome dropped on the floor. That left the update dot and the gear button laid out underneath the DWM caption buttons. It also made those buttons flicker. The Windows host resamples the app pixel 8px leading of the cluster on every present and pushes it through DWMWA_CAPTION_COLOR plus DWMWA_USE_IMMERSIVE_DARK_MODE, which picks the button glyph palette by luminance. With the gear sitting there the sample landed on an antialiased glyph edge rather than flat header, so it flipped between readings, each flip forced a caption repaint, and the light/dark verdict flipped with it. Map both horizontal insets into chrome_leading / chrome_trailing and spacer both ends of the row, which is the shape the SDK documents on WindowChrome. The row's existing gap keeps the sampled pixel on flat header. onboarding and lock already end in a growing spacer, so they were never affected, and Linux is unchanged because the inset is honestly zero there.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
A user on Windows 11 25H2 reported the icons at the top right flickering. Those are the OS min/max/close buttons, and the cause is on our side.
What was wrong
The main window is
titlebar = "hidden_inset_tall", so the OS window controls overlay our own masthead. The SDK tells us where they land viaWindowChrome.insets, and the cluster sits on a different edge per platform: macOS puts traffic lights on the left, Windows puts min/max/close on the right.onChromeonly mappedinsets.topandinsets.left. That is complete on macOS. On Windowsinsets.rightis the full width of the caption cluster, roughly 140px, and we threw it away, so the update dot and the gear button were laid out underneath the DWM caption buttons.That is also what makes them flicker. The Windows host runs
syncHiddenCaptionColoron every present: it samples the app pixel 8px to the left of the cluster and pushes it throughDWMWA_CAPTION_COLORplusDWMWA_USE_IMMERSIVE_DARK_MODE, the latter deciding whether the button glyphs draw light or dark by luminance. With the gear button sitting exactly on that sample point, it read an antialiased glyph edge instead of flat header. Any wobble flips the colour, the flip forces a DWM caption repaint, and the light/dark verdict flips with it, so the glyphs strobe.The SDK's own doc comment on
WindowChromestates the contract we were breaking: "A header that pads BOTHinsets.leftandinsets.righttherefore clears the controls on every platform with no per-platform code."The fix
ChromeInsetsgainstrailing, the model gainschrome_trailing,onChromemapsinsets.right, andplayer-top.nativeends with a<spacer width="{chrome_trailing}"/>. The row's existinggap="12"then keeps the sampled pixel on flat header rather than the gear's edge.onboarding.nativeandlock.nativealready end in a growing spacer, so they were never affected and are untouched.Testing
Test written first, failing on the missing field, passing after. 107/107 green,
native checkclean. A headless Linux screenshot is pixel identical, sincechrome_trailingis honestly zero there.Not verified on Windows. I have no Windows machine here. The layout bug is proven from the source: the host reports a non-zero right inset and we ignored it. The flicker mechanism is traced through the host rather than observed, though it is the only path I found that repaints those buttons. Worth confirming on a Windows build before we tell the reporter it is fixed.