You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Cancellable window close request (and app quit request) event #65
There's no way to intercept a window being closed. Only WindowClosedEvent fires after the fact. window_manager 0.6.0 currently can't implement setPreventClose / onWindowClose for the system close button, and documents that as a gap.
Proposal: a cancellable close-request event per window, raised by the close button, Alt+F4, the taskbar/Dock menu and delete-event, plus Window::Close(). Requirements from the reports below:
system shutdown, logoff and installer-initiated closes (WM_QUERYENDSESSION/WM_ENDSESSION, or a WM_CLOSE from another process) must not be silently swallowed
Cmd+Q / app termination on macOS should surface as an application-level quit request (cancellable), distinct from window close
it must not break Flutter's own AppLifecycleListener.onExitRequested when nobody listens
possibly the same pattern for minimize/maximize requests
Shared EventRequest / EventDecision for cancellation and deferred decisions, with retained async delivery and immediate unsubscription.
Application::Quit() and Window::Close() go through confirmation requests; native window close (macOS, Windows, GTK) and native macOS app quit are routed there, keeping host delegates and their decisions.
Binding-owned votes are fenced by their event loop's lifetime. JS keeps deliveries alive through Promise completion and cancels its votes when its environment ends; Python decides from asyncio.
Verified: core CTest 26/26 on macOS. Real Flutter 3.47.6: multi-window ownership (19 checks) and Application/AppLifecycleListener exit (31 checks). Real Node regressions on macOS, Windows and Linux (18 each). The window fixture still prints "Communicating on a dead channel." at engine shutdown, with exit 0.
Still open: checking the real desktop entry points, i.e. the OS title-bar close button, the system-menu close, and app quit from the Dock/menu/taskbar.
flutter_window_title_bar_example gets a Closing option: Keep open cancels every WindowCloseRequestedEvent through event.request.cancel() and counts it; Allow lets it through. tools/gui/flutter_window_title_bar_close_test.ps1 drives it on Windows 11 with owner-guarded real clicks on the example's own window and menu, no keyboard. 3/3 runs, all checks passing:
Keep open, a real click on the window's own close button (located through DWM's caption button bounds): the window stays, one request cancelled.
Keep open, the system menu's Close (from the DragToMoveArea strip): the window stays, a second request cancelled.
Allow, the close button again: the window closes and the app exits with code 0.
The #66 system-menu and #70 snap-layout end-to-end checks still pass on the same build.
Not covered on Windows: Alt+F4 (keyboard) and the taskbar's Close (a click on explorer's window) — both arrive as the same SC_CLOSE / WM_CLOSE path as the close button, but were not driven here.
Still open for this issue: the real close button on macOS and on Linux (GNOME), and quitting from the Dock / app menu on macOS.
GNOME verified, and a Linux core bug found and fixed on the way.
Bug (fixed in e791090): on Linux, WindowManager stored a window's ID on its GdkWindow only, and a Window wrapper made afterwards found it there but left the GtkWindow without one. The close gate and the per-window event subscription check the ID on the GtkWindow, so a window WindowManager saw first — a Flutter app's main window, taken with GetCurrent() — received no events of its own and its close requests could not be cancelled: GNOME's close button closed it regardless of the listener. The widget's ID now wins wherever one is found or allocated and goes on both objects. tests/window_close_manager_first_linux_test reproduces it (no close request, no property event before; all pass after); Linux CTest 26/26.
Real GNOME check (tools/gui/flutter_window_title_bar_close_test_linux.py, libnativeapi/nativeapi@90180e4; Ubuntu 24.04, GNOME 46, Flutter 3.47.6, real input through Mutter RemoteDesktop with the harness's owner check, no keyboard), 3/3 runs:
Keep open: two real clicks on the header bar's close button (found by its accessible name through AT-SPI) leave the window open, two requests cancelled.
Allow: the close button closes the window and the app exits with code 0.
The window menu on GNOME is gnome-shell's, outside the app, so its Close was not driven.
Remaining: the close button and quitting from the Dock / app menu on macOS.
Activity
Add cancellable window close and application quit requests (#65)
lijy91 commentedon Oct 6, 2026
Implemented in 3cc8b3d (all five bindings: libnativeapi/nativeapi@1630105).
EventRequest/EventDecisionfor cancellation and deferred decisions, with retained async delivery and immediate unsubscription.Application::Quit()andWindow::Close()go through confirmation requests; native window close (macOS, Windows, GTK) and native macOS app quit are routed there, keeping host delegates and their decisions.Verified: core CTest 26/26 on macOS. Real Flutter 3.47.6: multi-window ownership (19 checks) and Application/AppLifecycleListener exit (31 checks). Real Node regressions on macOS, Windows and Linux (18 each). The window fixture still prints "Communicating on a dead channel." at engine shutdown, with exit 0.
Still open: checking the real desktop entry points, i.e. the OS title-bar close button, the system-menu close, and app quit from the Dock/menu/taskbar.
lijy91 commentedon Oct 7, 2026
Windows desktop entry points verified in a real Flutter app (libnativeapi/nativeapi@e0ca21a).
flutter_window_title_bar_examplegets a Closing option: Keep open cancels everyWindowCloseRequestedEventthroughevent.request.cancel()and counts it; Allow lets it through.tools/gui/flutter_window_title_bar_close_test.ps1drives it on Windows 11 with owner-guarded real clicks on the example's own window and menu, no keyboard. 3/3 runs, all checks passing:DragToMoveAreastrip): the window stays, a second request cancelled.The #66 system-menu and #70 snap-layout end-to-end checks still pass on the same build.
Not covered on Windows: Alt+F4 (keyboard) and the taskbar's Close (a click on explorer's window) — both arrive as the same
SC_CLOSE/WM_CLOSEpath as the close button, but were not driven here.Still open for this issue: the real close button on macOS and on Linux (GNOME), and quitting from the Dock / app menu on macOS.
Keep one window ID on both GTK objects (#65)
lijy91 commentedon Oct 7, 2026
GNOME verified, and a Linux core bug found and fixed on the way.
Bug (fixed in e791090): on Linux,
WindowManagerstored a window's ID on itsGdkWindowonly, and aWindowwrapper made afterwards found it there but left theGtkWindowwithout one. The close gate and the per-window event subscription check the ID on theGtkWindow, so a windowWindowManagersaw first — a Flutter app's main window, taken withGetCurrent()— received no events of its own and its close requests could not be cancelled: GNOME's close button closed it regardless of the listener. The widget's ID now wins wherever one is found or allocated and goes on both objects.tests/window_close_manager_first_linux_testreproduces it (no close request, no property event before; all pass after); Linux CTest 26/26.Real GNOME check (
tools/gui/flutter_window_title_bar_close_test_linux.py, libnativeapi/nativeapi@90180e4; Ubuntu 24.04, GNOME 46, Flutter 3.47.6, real input through Mutter RemoteDesktop with the harness's owner check, no keyboard), 3/3 runs:The window menu on GNOME is gnome-shell's, outside the app, so its Close was not driven.
Remaining: the close button and quitting from the Dock / app menu on macOS.
Confirm the macOS close button's -__close like performClose: