Skip to content

Blend the blit pipeline so popups don't get a black outline - #27

Open
fegauthier-paragon wants to merge 1 commit into
J-x-Z:mainfrom
fegauthier-paragon:fix/blend-blit-so-popups-composite
Open

Blend the blit pipeline so popups don't get a black outline#27
fegauthier-paragon wants to merge 1 commit into
J-x-Z:mainfrom
fegauthier-paragon:fix/blend-blit-so-popups-composite

Conversation

@fegauthier-paragon

Copy link
Copy Markdown

Every context menu in a client rendered with a black outline around it. In rootless mode with an Electron app it's very visible, since those draw their own menus with a shadow and rounded corners.

Cause

render_toplevel_popups draws popups into the parent toplevel's drawable, at an offset, using the same blit_pipeline as the toplevel. That pipeline was built with blending off:

// blit is OPAQUE — tile content always replaces the background completely.
// Using blending=false prevents any transparent holes from showing through.
let blit_pipeline = make_pipeline(&device, &vert, &frag_blit, false)?;

The comment holds for a toplevel — its alpha=0 regions end up showing the clear colour whether you replace or blend, so the distinction is invisible there. It does not hold for a popup: the popup is drawn over already-rendered toplevel content, so its translucent edges replace that content with transparent black rather than compositing over it. That's the outline.

Fix

One flag. border_pipeline on the next line is already built with blending enabled, so this makes blit consistent with it.

Verified

Built on main and run in rootless mode over waypipe with Claude Desktop for Linux (Electron) in a Lima VM: menus composite correctly, shadows and rounded corners land as they should, and toplevel rendering is unchanged.

If blending = false was guarding a case I haven't hit — a client whose surface genuinely needs to punch through — the narrower fix is a second, blended pipeline used only by render_toplevel_popups, and I'm happy to switch this PR to that shape.

Aside

Thanks for the rootless display-worker design — spawning one worker per application gives each guest window its own Dock entry and tile on macOS, which is exactly what I needed and worked without patching anything.

Popups are rendered into the parent toplevel's drawable at an offset, through the same
blit pipeline as the toplevel itself. That pipeline was built with blending disabled,
so a popup's translucent edges — a menu's shadow, its rounded corners — replaced what
was underneath with transparent black instead of compositing over it. Every context
menu came out with a black outline.

Enabling blending fixes the popup case and leaves the toplevel case unchanged: a
toplevel is drawn over the clear colour, so replacing and blending give the same
result there.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@J-x-Z

J-x-Z commented Sep 1, 2026

Copy link
Copy Markdown
Owner

I've been busy lately, I'll check the code and consider merging your PR in two weeks

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