aboutsummaryrefslogtreecommitdiff
path: root/bundle
diff options
context:
space:
mode:
author_ov4 <ov4@ov4.org>2026-10-22 02:53:04 +0000
committer_ov4 <ov4@ov4.org>2026-10-22 02:53:04 +0000
commit21eb7861f1ca534b39b81a08a49c843c29ee48b6 (patch)
tree406de8332f199b3a50680a329e5eff48c10daaae /bundle
parent68d939ad652c7fca7fe7de7b55e51e0f34374f19 (diff)
fix(bundle): ask about unsaved changes when quitting with Cmd+Q
The predefined macOS Quit terminated the app without closing its windows, so their unsaved-changes prompts never ran. Quit now closes every window and the app exits after the last one. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Diffstat (limited to 'bundle')
-rw-r--r--bundle/AGENTS/DEVELOPMENT.md2
-rw-r--r--bundle/src-tauri/src/main.rs11
-rw-r--r--bundle/src-tauri/src/menu.rs6
3 files changed, 10 insertions, 9 deletions
diff --git a/bundle/AGENTS/DEVELOPMENT.md b/bundle/AGENTS/DEVELOPMENT.md
index 0995c3a..84270e1 100644
--- a/bundle/AGENTS/DEVELOPMENT.md
+++ b/bundle/AGENTS/DEVELOPMENT.md
@@ -30,6 +30,6 @@ The Rust runner launches the packaged compiler directly, using the source direct
After building the compiler, run `cargo test --release --manifest-path src-tauri/Cargo.toml`. The two native tests exercise real compilation, prefilled input, EOF, Unicode, diagnostics, output before process exit, stopping, single-run exclusion and restart, including source paths with spaces. CI runs them on all three native platforms.
-The native menu is defined once in `src-tauri/src/menu.rs` with Tauri's menu API; macOS shows it in the system menu bar, Windows and Linux at the top of each window. Only the macOS application menu is platform-specific. Edit keeps the predefined clipboard and undo items, which macOS needs in the webview. Other platforms have no Quit item because it exits without unsaved-changes prompts. Custom item ids name commands in `src/main.js`; a click emits a `menu` event with the id to the focused window. Run/Stop (F5) toggles like the Run button; its label is fixed because all windows share the menu. Keyboard shortcuts are Monaco `KeyMod.CtrlCmd` keybindings: the editor registers Find and Toggle Line Comment, and the document handler matches the menu's commands with `StandardKeyboardEvent.equals`, so a shortcut runs once whether the webview or the native menu receives the key first. Keep menu accelerators and handler bindings in sync. Never test `ctrlKey`/`metaKey` directly; Monaco resolves CtrlCmd to Cmd on macOS and Ctrl elsewhere.
+The native menu is defined once in `src-tauri/src/menu.rs` with Tauri's menu API; macOS shows it in the system menu bar, Windows and Linux at the top of each window. Only the macOS application menu is platform-specific. Edit keeps the predefined clipboard and undo items, which macOS needs in the webview. macOS Quit (Cmd+Q) is a custom item that closes every window, so each runs its unsaved-changes prompt and the app exits after the last; the predefined Quit terminates without them. Windows and Linux close windows instead. Custom item ids name commands in `src/main.js`; a click emits a `menu` event with the id to the focused window. Run/Stop (F5) toggles like the Run button; its label is fixed because all windows share the menu. Keyboard shortcuts are Monaco `KeyMod.CtrlCmd` keybindings: the editor registers Find and Toggle Line Comment, and the document handler matches the menu's commands with `StandardKeyboardEvent.equals`, so a shortcut runs once whether the webview or the native menu receives the key first. Keep menu accelerators and handler bindings in sync. Never test `ctrlKey`/`metaKey` directly; Monaco resolves CtrlCmd to Cmd on macOS and Ctrl elsewhere.
Use brief English UI labels and messages. Keep one document per window and prefilled stdin. More documents use native OS windows created by the `new_window` command from the configured window; do not add tabs or in-page switching. Before feature commits, run affected plugin tests, build the frontend and check native compilation as appropriate. Do not add a separate UI test framework for routine changes.
diff --git a/bundle/src-tauri/src/main.rs b/bundle/src-tauri/src/main.rs
index 9f63fc5..0da6815 100644
--- a/bundle/src-tauri/src/main.rs
+++ b/bundle/src-tauri/src/main.rs
@@ -93,11 +93,12 @@ fn main() {
.menu(menu::build)
// Menu items act on the focused window, like its keyboard shortcuts.
.on_menu_event(|app, event| {
- let focused = app
- .webview_windows()
- .into_values()
- .find(|window| window.is_focused().unwrap_or(false));
- if let Some(window) = focused {
+ let mut windows = app.webview_windows().into_values();
+ if event.id() == "quit" {
+ // Each window runs its unsaved-changes prompt; the app exits after the last.
+ windows.for_each(|window| drop(window.close()));
+ } else if let Some(window) = windows.find(|window| window.is_focused().unwrap_or(false))
+ {
let _ = window.emit_to(window.label(), "menu", event.id().as_ref());
}
})
diff --git a/bundle/src-tauri/src/menu.rs b/bundle/src-tauri/src/menu.rs
index ab2dd32..dad3779 100644
--- a/bundle/src-tauri/src/menu.rs
+++ b/bundle/src-tauri/src/menu.rs
@@ -39,8 +39,8 @@ pub fn build<R: Runtime>(app: &AppHandle<R>) -> tauri::Result<Menu<R>> {
.maximize()
.build()?;
let menu = MenuBuilder::new(app);
- // macOS shows the first submenu as the application menu. Quit skips unsaved-changes
- // prompts, so other platforms close windows instead.
+ // macOS shows the first submenu as the application menu. The predefined Quit terminates
+ // without closing windows, skipping their unsaved-changes prompts, so "quit" closes them.
#[cfg(target_os = "macos")]
let menu = menu.item(
&SubmenuBuilder::new(app, "CPSC Bundle")
@@ -52,7 +52,7 @@ pub fn build<R: Runtime>(app: &AppHandle<R>) -> tauri::Result<Menu<R>> {
.hide_others()
.show_all()
.separator()
- .quit()
+ .item(&item("quit", "Quit CPSC Bundle", "CmdOrCtrl+Q")?)
.build()?,
);
menu.items(&[&file, &edit, &run, &window]).build()