Move the macOS window by its toolbar - #22
Merged
chrisuthe merged 2 commits intoSep 2, 2026
Merged
Conversation
Extending the client area into the decorations leaves no native title bar to grab, so the main window could not be moved at all on macOS. Re-running ShellSpike chrome on macOS 26.6.2 with Avalonia 12.1.1 shows the 28 px title strip the hint uncovers does not move the window either, which ARCHITECTURE.md claimed it did; that line is corrected. The same reading is what makes a fix possible: a press that gets eaten is a press that arrived, so BeginMoveDrag has something to work with. The drag surface is the whole toolbar Border, given a transparent background while the decorations are extended and none at all where they are native, so Linux and Windows keep an untouched, un-hit-testable toolbar. It has to be the Border rather than the inset content, because a margin sits outside a control's bounds and the strip is exactly the part the inset holds clear. BeginsWindowDrag is a pure static over the three conditions: extended decorations, the primary button — macOS opens the window's own menu on a secondary press in the title area — and a press outside the traffic-light cluster, whose rectangle is read off the toolbar inset rather than restating the 78 px. AppKit hit-tests those buttons first, so the carve-out is a guard that does not depend on that staying true. The press is left to bubble and is not taken handledEventsToo, so the settings ToggleButton marks its own press handled and the gear keeps toggling instead of dragging. Reading the strip's height instead of assuming it also earned its keep: the shipped app reports a 32 px decoration margin where the spike measured 28, on the same OS and Avalonia build, and no code carries the figure.
chrisuthe
marked this pull request as ready for review
September 2, 2026 12:09
The only conflict was a numbering collision in docs/NEXT_STEPS.md: master's artwork-channel item and this branch's double-click-to-zoom item both landed at slot 9. Master's keeps 9 and this branch's becomes 10, which also matches the file's stated ordering — the follow-up here is the least blocking of the two.
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.
On macOS the main window could not be moved at all.
MainWindowextends the client area into the decorations, so there is no native title bar to grab, and nothing calledBeginMoveDrag.The toolbar is now the drag handle. It gets a transparent — so hit-testable — background while the decorations are extended, and none at all where they are native, and a bubbling
PointerPressedcallsBeginMoveDragbehind a pure static: extended decorations, the primary button, and a press outside the traffic-light cluster.docs/ARCHITECTURE.mdclaimed the 28 px title strip the hint uncovers still moved the window. Re-runningShellSpike chromeon macOS 26.6.2 with Avalonia 12.1.1 shows it does not, so that line is corrected. The same reading is what makes the fix work — a press that gets eaten is a press that arrived — and it is why the surface has to be the whole toolbarBorderrather than its inset content: a margin sits outside a control's bounds, and the strip is exactly the part the inset holds clear.Verified by hand on the Mac: the toolbar and the strip drag, the gear still toggles Settings on a single click, a right-click starts no drag, the traffic lights and the art bleeding up behind them are untouched, and the top edge and top-right corner still resize — AppKit keeps the resize edges, so a press only ever begins a move on a pixel it has already declined. Nothing changes on Linux or Windows, where
IsExtendedIntoWindowDecorationsisFalseand the toolbar gets no drag surface at all.Measured on the way and recorded: the shipped app reports a 32 px decoration margin where the spike measured 28, on the same OS and Avalonia build. The cause is not established, and no code carries the figure. Double-click-to-zoom was asked for alongside this and deliberately left out — Avalonia 12 cannot read the macOS
AppleActionOnDoubleClickpreference, so any behaviour would hardcode one of three answers;docs/NEXT_STEPS.mditem 10 records the argument and the first action.