Skip to content

Quit when the last window closes - #5

Merged
IAmJSD merged 1 commit into
mainfrom
quit-when-last-window-closes
Aug 21, 2026
Merged

Quit when the last window closes#5
IAmJSD merged 1 commit into
mainfrom
quit-when-last-window-closes

Conversation

@IAmJSD

@IAmJSD IAmJSD commented Aug 21, 2026

Copy link
Copy Markdown
Member

Closing Schist's only window on macOS left the app running with nothing on screen — still in the dock, still holding the menu bar that #3 just moved up there, and with no route back to a window, since no menu item opens a second one. AppKit keeps a window-less app alive unless told otherwise, so an on_window_closed observer now quits once cx.windows() is empty.

The observer is macOS-only, for two reasons:

  • The other backends already do this. X11 and Wayland stop their event loop when the last window goes, and the Windows backend posts a quit message from the last close_one_window.
  • Doing it on Linux breaks shutdown. Platform::quit defers to the main queue on macOS and to the foreground executor on Windows, but on Linux it calls with_common straight away, which re-borrows the client state this callback is already being dispatched from. Schist died on RefCell already borrowed (exit 101) instead of shutting down, skipping the rest of the quit path.

It is a cfg! rather than a #[cfg] so the callback stays type-checked wherever Schist builds, matching how native_menu handles the same split.

Testing

  • cargo build -p schist-app.
  • Headless X11 (Xvfb + lavapipe), sending a real WM_DELETE_WINDOW to the app window: exits 0 with no panic, same as before this change. The intermediate ungated version is what turned up the RefCell panic above.
  • The macOS path is reasoned from the backends, not run: closing the window calls Window::on_closeremove_window(), which drops the window from cx.windows before the observers fire, so the emptiness check is accurate, and mac's deferred quit means calling it from inside the observer is safe.

One thing to flag, unchanged by this PR but now easier to hit: there is no unsaved-changes prompt on window close (Workspace registers no should_close handler), so closing the last window discards dirty tabs and quits. Crash-recovery snapshots are still written, exactly as with the existing Quit menu item.

🤖 Generated with Claude Code

Closing Schist's only window on macOS left the app running with nothing
on screen: still in the dock, still holding the menu bar, and with no way
back to a window, since nothing in the menus opens a second one. AppKit
keeps a window-less app alive unless it is told otherwise, so say so.

The other backends already end the process themselves once no window is
left -- X11 and Wayland stop their event loop, Windows posts a quit
message from the last close -- so the observer is macOS-only. That is not
just to avoid a redundant call: `Platform::quit` is asynchronous on macOS
and Windows but synchronous on Linux, where it re-enters the client state
that is already borrowed to dispatch the close, and the process died on a
"RefCell already borrowed" panic rather than shutting down.

The gate is a `cfg!` rather than a `#[cfg]` so the callback keeps being
type-checked wherever Schist builds.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@IAmJSD
IAmJSD merged commit 78be671 into main Aug 21, 2026
3 checks passed
@IAmJSD
IAmJSD deleted the quit-when-last-window-closes branch August 21, 2026 23:55
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