OS taskbar/dock "Close N windows" sends a per-window WM_CLOSE instead of a single quit signal, causing a race in the last-window close path
Categories
(Firefox :: Tabbed Browser, defect)
Tracking
()
People
(Reporter: jporter, Unassigned, NeedInfo)
References
(Blocks 1 open bug)
Details
Platforms Affected
Windows and Linux. macOS sends a single quit-application-requested signal and is unaffected.
Description
When a user invokes the OS-level "Close all windows" / "Quit N windows" action from the taskbar or dock, the window manager delivers a close signal to each window rather than issuing a single application-quit request. macOS is unaffected because it dispatches one quit-application-requested signal. Since each window is torn down independently, the per-window "last window closing" check does not always trigger. The specific race window is widened when the topmost window to close has a heavier page loaded and takes slightly longer to shut down, so the window(s) underneath will continue to detect it in their last-window check.
- A window's
.closedflag does not flip until after its close handler returns. CanCloseWindow->browser.permitUnload()performs synchronous IPC that spins the event loop, allowing the next window's window-close handler to dispatch and run to completion before the first window's handler returns.- As a result, multiple closing windows each observe the others as still open, none of them concludes it is the "last window," and the
application-quitbranch is skipped entirely.
This issue was discovered when working on Enterprise Firefox, so I'll be including some of that detail here, but this issue is not enterprise-specific. Rather it is another symptom of this underlying bug, surfaced because we implemented a custom signout/close dialog when the last browser window is closed or the application is quit. I found some related bugs that are the result of Windows/Linux closing the windows separately such as:
- Bug 1818971: session restore loses windows
- Bug 1858782:
browser.tabs.warnOnCloseprompts show on every window that is closed - Bug 2040447: Enterprise signout prompt is not shown since no window detects it's the last window closing
More detail and logs on the Enterprise-specific symptom and debugging can be viewed in bug 2040447.
Based on my debugging and the various related bugs, the proposed fix by :dao seems like a sound way of resolving this.
Comment 1•21 days ago
|
||
The bug describes a race condition when the OS (Windows taskbar "Close N windows", Linux/GNOME dock equivalent) sends individual close requests to each browser window instead of a unified quit signal (macOS is unaffected, as it sends a single quit-application-requested).
This breaks the "last window" detection logic:
• warnAboutClosingWindow() / browser-lastwindow-close-* observers (in browser/base/content/browser.js).
• CanCloseWindow() + browser.permitUnload() (synchronous IPC that spins the event loop).
• The .closed flag + otherWindowExists checks that decide between per-window close vs. "treat as quit" (session restore, prompts, Enterprise signout, etc.).
• Related effects: session restore losing windows (bug 1818971), warnOnClose prompting per-window (bug 1858782), and the Enterprise prompt not appearing (bug 2040447, which this blocks).
The core logic lives in the tabbed browser front-end:
• browser/base/content/browser.js (CanCloseWindow, WindowIsClosing, warnAboutClosingWindow, closeWindow).
• browser/components/BrowserGlue.sys.mjs (observers for browser-lastwindow-close-requested/granted and quit integration).
• browser/components/sessionstore/SessionStore.sys.mjs.
• Supporting pieces in browser/modules/BrowserDOMWindow.sys.mjs and xpfe/appshell/AppWindow.cpp (the platform RequestWindowClose path that feeds into this).
Platform widget code (e.g., widget/windows/nsWindow.cpp for WM_CLOSE, GTK equivalent) just delivers the per-window closes—the bug and the race are in how the browser layer handles them.
Comment 2•13 days ago
|
||
The severity field is not set for this bug.
:dao, could you have a look please?
For more information, please visit BugBot documentation.
Description
•