Skip to content

Keep the Windows notch itself clear of the taskbar - #268

Merged
vinzdg merged 4 commits into
vinzdg:mainfrom
RawJat:fix/windows-notch-work-area
Sep 19, 2026
Merged

vinzdg merged 4 commits into
vinzdg:mainfrom
RawJat:fix/windows-notch-work-area

Conversation

@RawJat

@RawJat RawJat commented Sep 18, 2026

Copy link
Copy Markdown
Contributor

The pill was pinned to the monitor's physical edge, so a notch on the edge the taskbar is docked to sat behind it. Both windows are topmost, and the notch is deliberately focusable: false, so it can never win a z-order decided by activation — it loses to the taskbar every time.

#241 already worked out the work area, but spent it on the hover card alone: work_insets moves the card, and the pill stayed where it was. This gives the pill the same treatment.

What changed, all in main.rs:

  • edge_origin measures against the work area instead of the monitor, so the pill clears the taskbar on whichever edge it is docked to. An edge with no taskbar is unchanged.
  • Screen::area() falls back to the whole monitor when the platform reports no usable work area, rather than pinning the notch to (0, 0) with no span to slide along.
  • The drag's saved ratio moves to the same span. place_notch reads that ratio back against the work area, so measuring it against the monitor made every drop next to the taskbar land short of the pointer.
  • The move handle's drop zones follow, for the same reason: the zone offering the taskbar's edge was still drawn against the monitor, so it promised a place the notch would no longer take. The zones are welded to the overlay window's own edges, so sizing that window to the work area moves all four and leaves dropzones.html untouched, and the edge the pointer picks is read against that same rectangle — the diagonals deciding it now meet the corners of the outlines actually drawn.

On the divergence from the Mac: it places against frame rather than visibleFrame on purpose, but what it overlaps there is the menu bar, which macOS lets a notch cover and which holds no menu items behind the notch anyway. The taskbar wins the z-order among topmost windows and is a click target of its own, so it is room lost rather than room shared.

Keeping up with the taskbar: placing against the work area means the notch's position now depends on a number that changes without us — move the taskbar to another edge and the notch would stay where the old work area put it, floating out in the gap the taskbar had left. Nothing hands us WM_SETTINGCHANGE, so the work area is re-read once a second and the notch placed again when it differs. Polled rather than hooked because it changes by hand, a second late is not noticeable, and hooking it would mean subclassing a window we do not own to catch something that happens once in a session. Skipped mid-drag, where the notch is already following the pointer.

Testing: cargo test 97 pass, 0 fail, 2 ignored, including a new the_notch_is_placed_inside_the_work_area covering all four edges against a bottom taskbar, a left-docked one, and the no-work-area fallback. Clippy unchanged: the one standing tray.rs:127 type-complexity warning, nothing new. Checked by hand on Windows 11: the notch on all four edges, the hover card open on the bottom edge, the taskbar moved to each of the four edges in turn, taskbar auto-hide toggled on and off, and the move handle's zones checked against each taskbar position.

#239 and #257 also touch main.rs, at the pointer watchdog and at get_usage/main() respectively; this change is at edge_origin (153) and place_notch (214), so they should not collide.

Refs #241

The pill was pinned to the monitor's physical edge, so a notch on the edge
the taskbar is docked to sat behind it: both windows are topmost, and a
notch that is deliberately never focusable cannot win an order decided by
activation.

vinzdg#241 already worked out the work area, but spent it on the hover card
alone — `work_insets` moved the card and left the pill where it was.
`edge_origin` now measures against the work area itself, so the pill
clears the taskbar on whichever edge it is docked to, and a screen with
no taskbar on that edge is unchanged. `Screen::area()` falls back to the
whole monitor when the platform reports nothing usable, rather than
pinning the notch to (0, 0) with no span to slide along.

The drag's saved ratio moves to the same span. `place_notch` reads it
back against the work area, so measuring it against the monitor made
every drop next to the taskbar land short of the pointer.

The Mac places against `frame` rather than `visibleFrame` on purpose, but
what it overlaps there is the menu bar, which macOS lets a notch cover.
The taskbar wins the z-order among topmost windows and is a click target
of its own, so it is room lost rather than room shared.

Not covered: nothing watches for the work area itself changing. Toggling
taskbar auto-hide or moving it to another edge leaves the notch where it
was until something else re-places it.
…ands

The notch now clears the taskbar, but the zone offering it that edge was
still drawn against the monitor, so the bottom outline promised a place
the notch would no longer take.

The zones are welded to the overlay window's own edges, so sizing that
window to the work area moves all four with it and leaves dropzones.html
alone. The edge the pointer picks is read against the same rectangle:
the diagonals that decide it now meet the corners of the outlines that
were actually drawn.
Placing the notch against the work area means its position now depends on
a number that changes without us: move the taskbar to another edge and the
notch stayed where the old work area put it, floating a taskbar's width
out in the gap the taskbar had left behind.

Nothing hands us WM_SETTINGCHANGE, so the work area is re-read once a
second and the notch placed again when it differs. Polled rather than
hooked: it changes by hand, a second late is not noticeable, and hooking
it would mean subclassing a window we do not own to catch something that
happens once in a session. Skipped mid-drag, where the notch is already
following the pointer.
The work area is physical, and the window builder's position and size are
logical, so a work area that does not start at the monitor's own corner
was placed a scale factor out: with the taskbar at the top the overlay
began a few pixels below the work area and hung off the bottom of the
screen by the same amount, trimming the bottom zone. A taskbar on the left
or right padded the near side and fell short of the far one. At the bottom
the corner is still (0, 0), which is why only that edge looked right.

Position and size are asserted again in physical pixels once the window
exists, the way place_notch pins the notch, so the overlay lands on the
work area whichever corner it starts from.
@RawJat
RawJat requested a review from vinzdg as a code owner September 18, 2026 17:49
@vinzdg
vinzdg merged commit 80dc722 into vinzdg:main Sep 19, 2026
4 checks passed
@RawJat
RawJat deleted the fix/windows-notch-work-area branch September 19, 2026 07:42
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