Skip to content

fix(main): exit fullscreen before hiding a window on macOS#26

Merged
loc merged 1 commit into
loc:mainfrom
codebytere-ant:fix/fullscreen-hide
Jul 6, 2026
Merged

fix(main): exit fullscreen before hiding a window on macOS#26
loc merged 1 commit into
loc:mainfrom
codebytere-ant:fix/fullscreen-hide

Conversation

@codebytere-ant

Copy link
Copy Markdown
Contributor

On macOS, BrowserWindow.hide() on a window that is in native fullscreen (or mid fullscreen transition) doesn't take: the orderOut is swallowed while AppKit collapses the fullscreen space, and the window comes back visible with mangled bounds once the transition settles. Pool windows hit this whenever macOS adopts a freshly shown window into an active fullscreen space (or the user green-buttons one) and it's later released. The release prop reset can't help because currentProps.fullscreen never tracks native transitions, and isFullScreen() can't be trusted at hide time either: a bounds write on a fullscreen window starts a leave transition that already reports false while still in flight. The result is a stranded, blank, still-visible pool window.

This tracks native state from the enter/leave-full-screen events the instance already listens to, and makes WindowInstance.hide() on macOS exit fullscreen and complete the hide once leave-full-screen fires. Repeated hides arm a single deferred hide, show() cancels a pending one (so a pooled window re-acquired mid-transition isn't hidden out from under its consumer), and the forced exit is written back to currentProps.fullscreen so a later fullscreen: true update isn't skipped as unchanged. The hideOnClose close interception and the visible: false prop path now route through hide(); other platforms keep the direct hide. Verified against a real pooled popout on macOS: before, releasing a fullscreen-adopted window leaves it visible and blank; after, it exits fullscreen, hides, and the pool reuses it normally. Unit tests cover the fullscreen, mid-transition, repeat-hide, show-cancel, prop-reapply, and non-mac paths.

One known limit: a window that is fullscreen but not fullscreenable never gets leave-full-screen, so its deferred hide waits until the next show().

On macOS, hiding a window that is in native fullscreen (or mid fullscreen
transition) doesn't work: the orderOut is swallowed and the window comes
back visible with mangled bounds once the transition settles. Pool
windows hit this whenever the OS adopts a freshly shown window into a
fullscreen space (or the user fullscreens one via the green button) and
it is later released. The release prop reset can't help because
currentProps.fullscreen never tracks native transitions, and
isFullScreen() alone can't be trusted either: a bounds write on a
fullscreen window kicks off a leave transition that already reports
false while still in flight.

Track the native state from the enter/leave-full-screen events the
instance already listens to, and make WindowInstance.hide() on macOS
exit fullscreen and complete the hide once leave-full-screen fires.
Repeated hides arm a single deferred hide, show() cancels a pending one
so a window re-shown mid-transition stays visible, and the forced exit
is written back to currentProps.fullscreen so a later fullscreen:true
update isn't skipped as unchanged. The hideOnClose interception and the
visible:false prop path now route through hide() so every hide path
gets the same treatment; other platforms keep the direct hide.
@loc loc merged commit aa76511 into loc:main Jul 6, 2026
9 checks passed
@github-actions

github-actions Bot commented Jul 6, 2026

Copy link
Copy Markdown

🎉 This PR is included in version 1.2.0 🎉

The release is available on:

Your semantic-release bot 📦🚀

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants