Skip to content

fix(gui): the Windows title bar answers as the caption, so Snap works again (#6825) - #6830

Open
nigelfenton wants to merge 1 commit into
mainfrom
fix/6825-windows-snap-htcaption
Open

nigelfenton wants to merge 1 commit into
mainfrom
fix/6825-windows-snap-htcaption

Conversation

@nigelfenton

Copy link
Copy Markdown
Contributor

Fixes #6825.

What

On Windows with the expanded client area, MainWindow::nativeEvent answered WM_NCHITTEST with the resize band at the edges and HTCLIENT everywhere else, so the 52 px title bar never reported HTCAPTION. Windows keys drag-to-edge Snap and the Snap Assist picker off that answer, so neither was offered: dragging the window to a screen edge did nothing.

expandedFrameHit() gains a Caption hit and an opt-in captionHeight. nativeEvent passes the bar's height, scaled to the physical pixels WM_NCHITTEST works in, but only when TitleBar::isSystemMoveAreaAt() says the cursor is over the bar's empty background — the same test the bar's own drag already uses, so a point either starts a system move or stays client, never both. Answering HTCAPTION over the tabs, menus and caption buttons is what closed menus as they opened (#6272), and those keep reporting HTCLIENT.

captionHeight defaults to 0, so every other caller is unchanged.

isSystemMoveAreaAt() has been public and uncalled since #6198 removed the custom frame; this restores the HTCAPTION clause that #3069 added and #6198 dropped.

Measured on Windows 11 (26300), AetherSDR 26.10.4, Qt 6.12

Hit test down the centre of the title bar, before and after:

offset from window top before after Notepad (control)
+0..+7 px HTTOP HTTOP HTTOP
+8..+43 px HTCLIENT HTCAPTION HTCAPTION
+44 px and below HTCLIENT HTCLIENT HTCLIENT

Scanning across the bar after the fix, the ☰ menu, the tab strip's controls and the caption buttons all still report HTCLIENT; only the empty background between them reports HTCAPTION. The caption ends at ~+43 rather than +52 because isSystemMoveAreaAt() reports the lower strip as occupied by widgets — the two mechanisms agreeing.

WS_MAXIMIZEBOX was already set (applyWindowsCaptionStyles), which is why Win+Left/Right always worked while the mouse drag did not — keyboard snap bypasses hit-testing. That asymmetry is what isolated the fault to hit-testing rather than window styles, and Win+Arrow is a usable workaround for anyone on a release before this lands.

Relationship to existing issues

Same root cause as #6224 item W1 ("Snap Layouts hover (Windows 11). This is a known regression."), but W1 covers only the hover flyout over the maximize button. #6825 adds drag-to-edge and the Snap Assist picker. This PR fixes the drag and the picker; the HTMAXBUTTON half of W1 is untouched and still open.

The chrome landed in v26.10.2 (5f09371e, PR #6198), not 26.10.4 as the issue title suggests — 26.10.4's only TitleBar.cpp change is the update badge, and the drag path is byte-identical to 26.10.3. Worth confirming with the reporter which version was last good.

Tests

unified_title_bar_test gains 10 assertions: the caption strip, its lower boundary, the resize band and corners still winning over it, the maximized case (the caption must answer or a maximized window cannot be dragged free of the top of the screen), and that a 0 captionHeight leaves the old answer untouched.

Verified the tests bite: with the caption clause disabled, exactly 3 fail and the rest pass.

The suite has a pre-existing failure on this machine at "four radios fit whole in an 1800 px bar" — font metrics, confirmed identical on unmodified main by stashing this change and rebuilding. Because that masks the new assertions in the full binary, they were also run in a standalone harness that includes the real WindowChrome.h: 21/21 pass.

Not verified

That the ☰ menu still opens and stays open under a real mouse click (the #6272 symptom). The hit-test scan covers the mechanism — the menu reports HTCLIENT, so Qt handles the press — but a human click is the real proof. A reviewer on Windows 11 clicking the hamburger menu and dragging the bar to a screen edge would close that gap.

🤖 Generated with Claude Code

… again (#6825). Principle VIII.

Fixes #6825.

## What

On Windows with the expanded client area, `MainWindow::nativeEvent` answered
`WM_NCHITTEST` with the resize band at the edges and `HTCLIENT` everywhere
else, so the 52 px title bar never reported `HTCAPTION`. Windows keys
drag-to-edge Snap and the Snap Assist picker off that answer, so neither was
offered: dragging the window to a screen edge did nothing.

`expandedFrameHit()` gains a `Caption` hit and an opt-in `captionHeight`.
`nativeEvent` passes the bar's height, scaled to the physical pixels
`WM_NCHITTEST` works in, but only when `TitleBar::isSystemMoveAreaAt()` says
the cursor is over the bar's empty background — the same test the bar's own
drag already uses, so a point either starts a system move or stays client,
never both. Answering `HTCAPTION` over the tabs, menus and caption buttons is
what closed menus as they opened (#6272), and those keep reporting `HTCLIENT`.

`captionHeight` defaults to 0, so every other caller is unchanged.

`isSystemMoveAreaAt()` has been public and uncalled since #6198 removed the
custom frame; this restores the `HTCAPTION` clause that #3069 added and #6198
dropped.

## Measured on Windows 11 (26300), AetherSDR 26.10.4, Qt 6.12

Hit test down the centre of the title bar, before and after:

| offset from window top | before | after | Notepad (control) |
|---|---|---|---|
| +0..+7 px | HTTOP | HTTOP | HTTOP |
| +8..+43 px | HTCLIENT | **HTCAPTION** | HTCAPTION |
| +44 px and below | HTCLIENT | HTCLIENT | HTCLIENT |

Scanning across the bar after the fix, the ☰ menu, the tab strip's controls
and the caption buttons all still report `HTCLIENT`; only the empty background
between them reports `HTCAPTION`.

`WS_MAXIMIZEBOX` was already set (`applyWindowsCaptionStyles`), which is why
Win+Left/Right always worked while the mouse drag did not — keyboard snap
bypasses hit-testing.

## Tests

`unified_title_bar_test` gains 10 assertions: the caption strip, its lower
boundary, the resize band and corners still winning over it, the maximized
case (the caption must answer or a maximized window cannot be dragged free),
and that a 0 `captionHeight` leaves the old answer untouched.

Verified they fail when the caption clause is disabled (3 fail, the rest
pass). The suite's pre-existing "four radios fit whole in an 1800 px bar"
failure on this machine is a font-metrics issue, confirmed identical on
unmodified main.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@nigelfenton
nigelfenton requested a review from a team as a code owner October 29, 2026 00:04

This branch has not been deployed

No deployments
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.

win11 windows integration problem with 26.10.4

1 participant