Skip to content

fix(desktop): keep an approval on the screen it appeared on - #184

Merged
kamrul1157024 merged 1 commit into
mainfrom
fix/hud-anchor-pin
Sep 7, 2026
Merged

fix(desktop): keep an approval on the screen it appeared on#184
kamrul1157024 merged 1 commit into
mainfrom
fix/hud-anchor-pin

Conversation

@kamrul1157024

Copy link
Copy Markdown
Owner

Summary

The HUD is resized every time a card is added or removed. The stack measures itself and reports one number — its height — and the window is set to match. The bounds carrying that height carried a position too, and anchor() recomputed the position from the pointer on every report.

So a second approval arriving after you had moved to the other monitor took the first one across with it, mid-read. The renderer said "taller". The main process heard "taller, and move to wherever the pointer is".

HudAnchor now picks the corner from the work area the first time it is asked and holds it until the HUD hides. A later resize changes only the height. Which display the HUD opens on is unchanged — still the one the pointer is on when the approval lands — and hide() releases the corner so the next one can land somewhere else.

Found while debugging a report of desktop notifications disrupting focus. Two other causes turned up and are not in this PR: a stale dev instance doubling every notification (environmental), and AeroSpace switching workspace when Helios is activated, which needs a decision about app.focus({ steal: true }) in Hud.focus() rather than a bug fix.

Measured and cleared of blame: the HUD is a non-activating panel, and showing or clicking it raises neither did-become-active nor browser-window-focus. The panel fix from #111 works. The window moving was the whole of it.

Test plan

  • npm test — 297 pass, 0 fail (5 new in hud-anchor.test.ts)
  • npm run typecheck — clean
  • node build.mjs — clean
  • Mutation-checked: forcing the corner to be recomputed on every call fails exactly the regression case (not ok 3 - a card arriving after the pointer moved does not follow it) and nothing else
  • Not verified on two displays. Only the built-in display was attached, and there the old and new code produce identical coordinates. Someone docked should confirm a second approval no longer drags the stack across.

The HUD is resized every time a card is added or removed: the stack
measures itself, reports one number, and the window is set to match. But
the bounds carrying that height carried a position too, and the position
was recomputed from the pointer on every report. So a second approval
arriving after the user had moved to the other monitor took the first one
across with it, mid-read. The renderer said "taller"; the main process
heard "taller, and move to wherever the pointer is".

The corner now belongs to the showing rather than to the resize. HudAnchor
picks it from the work area the first time it is asked and holds it until
the HUD hides, so a later resize changes only the height. Which display
the HUD opens on is unchanged: still the one the pointer is on when the
approval lands, and hide() releases the corner so the next one can land
somewhere else.

Covered by hud-anchor.test.ts, which was checked against the old
behaviour: forcing the corner to be recomputed on every call fails the
regression case and nothing else. Not verified on two displays — only the
built-in one was attached, and there the two versions agree.
@kamrul1157024
kamrul1157024 merged commit b054621 into main Sep 7, 2026
6 checks passed
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.

1 participant