Skip to content

fix(windows): mount the drag strip ahead of the app root so no-drag opt-outs win - #469

Open
1499501762 wants to merge 1 commit into
dataelement:mainfrom
1499501762:fix/windows-drag-strip-order
Open

1499501762 wants to merge 1 commit into
dataelement:mainfrom
1499501762:fix/windows-drag-strip-order

Conversation

@1499501762

Copy link
Copy Markdown

Summary

The Windows shell's 36px drag strip is appended to <body> -- after the app root. Electron resolves overlapping -webkit-app-region rectangles in tree order (every drag rectangle is added, every no-drag rectangle is subtracted while the tree is walked), so the drag rectangle is applied after every no-drag opt-out that came before it -- including this repo's own rule for button / a / input / [role=button] / [role=tab] / [role=menuitem] / [data-dsh-no-drag].

Consequence in the Windows shell: any control that lives inside the strip and comes before the strip in the tree -- i.e. everything the app root renders, including the conversation header's row 1 (breadcrumb, agent-preset chip, and every plugin entry registered in conversation.session.header.actions) -- looks right and never receives a click. The point resolves as a caption point, the renderer never sees a mouse event, and the window drags instead. The same page in a plain browser (no strip) works, which is why this keeps being reported as "that plugin's button is dead".

This file already knows the strip swallows those clicks: its modal workaround hides the region completely "so all buttons (especially near the top 36px) are 100% clickable".

Fix

  1. Mount the strip ahead of the app root, so the opt-outs that follow it subtract -- which is what the no-drag rule above is for.
  2. Keep the marker behind the app content (z-index: -1), so a point that is exempted reaches the control under it instead of landing on the transparent overlay.

Dragging is unaffected: the drag rectangle comes from -webkit-app-region: drag, not from hit testing. (pointer-events: none is the other way to keep a marker out of hit testing, but Chromium's region collection under pointer-events: none is not documented; a negative z-index leaves the region semantics untouched.)

Evidence

  • Measured in the shipping shell (DSH Desktop 0.9.0, Windows, 1256px content): the header action row renders at y 13-37, inside the 36px strip; with a strip-shaped overlay present (position: fixed; z-index: 10; height: 36px), document.elementFromPoint(<button center>) returns that overlay, not the button.
  • With both changes applied (Chromium, same DOM/CSS shape): the strip is <body>'s first element child with z-index: -1, and elementFromPoint returns the <button> again.
  • Regression test added to test/windows-titlebar.test.ts. It fails on the current source (mountsAhead=false, behindContent=false) and passes after the change; npx vitest run test/windows-titlebar.test.ts -> 9 passed.

Relation to #221

#221 made the shell publish the titlebar geometry (--dsh-titlebar-safe-inset-top, dsh-desktop-titlebar-inset), which lets a panel keep its content clear of the strip. This is the other half of the same area: the strip's own click path. No published geometry changes here, and the strip still covers the same rectangle.

…pt-outs win

The 36px strip was appended to <body>, after the app root. Electron resolves
overlapping app-region rectangles in tree order (drag adds, no-drag subtracts),
so the drag rectangle was applied after every no-drag opt-out that came before
it -- including this repo's own rule for button/a/input/[role=button]/
[role=tab]/[role=menuitem]/[data-dsh-no-drag]. Controls drawn inside the strip
(the conversation header's row 1: breadcrumb, agent-preset chip and every plugin
entry registered in conversation.session.header.actions) therefore looked right
and never received a click: the point resolved as caption and the renderer never
saw a mouse event.

Mount the strip as the first child of <body> so the opt-outs that follow it
subtract, and keep the marker behind the app content (z-index: -1) so an
exempted point reaches the control underneath. The drag rectangle itself is
unchanged, so the strip still drags the window wherever nothing opted out.

Adds a regression test to test/windows-titlebar.test.ts.
@cinderzhan cinderzhan self-assigned this Sep 24, 2026
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