Repository navigation
Conversation
legacy.dart addressed nativeapi.WindowManager.instance.getCurrent() and cached the first answer. On Windows that is GetActiveWindow(), which returns nothing while the app's window is still hidden. An app that keeps its window hidden until ready and calls addListener, setPreventClose(true) and show() during startup therefore lost all of them: native events were never wired, so close requests were not intercepted and onWindowClose never fired, and show() did nothing. - A missing window is never remembered: every call looks again, and the first window found gets the listeners and prevent-close set up before it existed. - On Windows, when there is no current window, the bridge takes the application's primary window if one is set, else this process's only unowned top-level window hosting a Flutter view (a child of window class FLUTTERVIEW), hidden or not, found with EnumWindows. With several candidates it answers nothing rather than guess. Linux and macOS are unchanged: their getCurrent() already falls back to a hidden window. - A show() without a window is kept and carried out on the first window found or bound; hide() cancels it. A one-time debug message points to bindWindow. - New public WindowManager.bindWindow(window) addresses a given nativeapi.Window and moves listeners and prevent-close to it; bindWindow(null) goes back to the current window. package:ffi becomes a direct dependency (it was already transitive through nativeapi).
This was referenced Nov 10, 2026
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.
Problem
package:window_manager/legacy.dartaddressesnativeapi.WindowManager.instance.getCurrent()and caches the first answer. On Windows,GetCurrentis implemented withGetActiveWindow(), which returns no window while the app's window is still hidden (Linux and macOS fall back to a realized/first window). Apps that keep their window hidden until ready and calladdListener,setPreventClose(true)andshow()during startup hit this:_wireNativeEventsreturns early and is never retried), so close requests are not intercepted andonWindowClosenever fires;isVisible()answers false, early calls do nothing, andshow()returns without showing anything.Change
FLUTTERVIEW, which the runner parents to its top-level window), hidden or not, wrapped withnativeapi.Window.createWithNativeWindow. Top-level windows are walked withEnumWindows. With several candidates it answers nothing rather than guess;bindWindowis the way to choose. Linux and macOS are unchanged.show(). Ashow()with no window yet is kept and carried out on the first window found or bound;hide()cancels it. A one-time debug-mode log points tobindWindow.WindowManager.bindWindow(nativeapi.Window? window)(public): addresses the given window and moves listeners and prevent-close to it;nullgoes back to the current window.package:ffibecomes a direct dependency (already transitive through nativeapi).legacy.dartaddresses".Tests
test/legacy_late_window_test.dart(fake windows, a fake close request and@visibleForTesting debugCurrentWindowOverride): a window found after the listener is wired then and its close request is cancelled under prevent-close; a missing window is looked up again on every call while a found one is kept;ensureInitializedwires a window found late; ashow()without a window is carried out on the window found or bound;hide()cancels it;bindWindowmoves listeners and prevent-close, andbindWindow(null)goes back.test/flutter_host_window_win32_test.dart(Windows only): real hidden top-level windows with aFLUTTERVIEWchild; the sole host is found, owned windows are skipped, several candidates answer nothing, and a bare test process has none.dart format --set-exit-if-changed .,flutter analyze(package and example) andflutter test(package and example) pass locally (Flutter 3.47.7, Windows), and the full CI workflow passes on the identical commit in my fork.Related
Part of a set of independent PRs, each based on
mainand mergeable on its own: widgets #598, #599, #600, #601; legacy bridge #602, #603, #604, #605, #606 (this).Expected conflict with #602 (show/hide events) in
show()/hide(): keep the pending-show handling here and move #602's visibility check andshow/hideemits into_showWindow/hide(). Merges cleanly with #603, #604 and #605; once #602/#604/#605 land, theirdebugBindWindowseam can delegate tobindWindow, and #605'sdebugApplicationOverridecould also serve the primary-window lookup here.