aboutsummaryrefslogtreecommitdiff
path: root/bundle
diff options
context:
space:
mode:
author_ov4 <ov4@ov4.org>2026-10-27 12:36:06 +0000
committer_ov4 <ov4@ov4.org>2026-10-27 12:36:06 +0000
commit30178981f487c225901f404040c027d4d1f49fea (patch)
tree34c9d0e85cc3b35965d039f2acbf31b339d48915 /bundle
parentc63584c388ea6acb7ad2f244376ae005536b6838 (diff)
fix(bundle): allow windows to close and route quit through document cleanup
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Diffstat (limited to 'bundle')
-rw-r--r--bundle/src-tauri/capabilities/default.json2
-rw-r--r--bundle/src-tauri/src/main.rs11
-rw-r--r--bundle/src/main.js34
3 files changed, 31 insertions, 16 deletions
diff --git a/bundle/src-tauri/capabilities/default.json b/bundle/src-tauri/capabilities/default.json
index a9c7253..4efbe87 100644
--- a/bundle/src-tauri/capabilities/default.json
+++ b/bundle/src-tauri/capabilities/default.json
@@ -2,5 +2,5 @@
"$schema": "../gen/schemas/desktop-schema.json",
"identifier": "main",
"windows": ["*"],
- "permissions": ["core:default", "core:window:allow-set-title", "core:window:allow-close", "dialog:default"]
+ "permissions": ["core:default", "core:window:allow-set-title", "core:window:allow-close", "core:window:allow-destroy", "dialog:default"]
}
diff --git a/bundle/src-tauri/src/main.rs b/bundle/src-tauri/src/main.rs
index c361260..7dbccd9 100644
--- a/bundle/src-tauri/src/main.rs
+++ b/bundle/src-tauri/src/main.rs
@@ -117,7 +117,16 @@ fn main() {
.build(tauri::generate_context!())
.expect("Could not start CPSC Bundle")
.run(|app, event| match event {
- // Also reached when macOS terminates without closing windows, such as Dock Quit.
+ // Dock Quit must run the same document-close flow as the menu and title bar.
+ tauri::RunEvent::ExitRequested { api, code: None, .. } => {
+ let windows = app.webview_windows();
+ if !windows.is_empty() {
+ api.prevent_exit();
+ for window in windows.into_values() {
+ let _ = window.close();
+ }
+ }
+ }
tauri::RunEvent::Exit => {
let runners: Vec<Runner> = app
.state::<Runners>()
diff --git a/bundle/src/main.js b/bundle/src/main.js
index e36b743..6734bc4 100644
--- a/bundle/src/main.js
+++ b/bundle/src/main.js
@@ -17,6 +17,7 @@ const filters = [{ name: 'Pseudocode', extensions: ['cps'] }];
let path = null;
let savedText = '';
let busy = false;
+let actionDone = Promise.resolve();
let closing = false;
let editor;
let running = false;
@@ -26,11 +27,12 @@ function setRunning(value) {
runButton.textContent = value ? 'Stop' : 'Run';
for (const id of ['new', 'open', 'save']) document.getElementById(id).disabled = value;
input.disabled = value;
- editor.updateOptions({ readOnly: value });
+ editor.updateOptions({ readOnly: value || closing });
}
async function runFile() {
if (!await saveFile()) return;
+ if (closing) return;
setRunning(true);
output.textContent = '';
status.textContent = 'Running';
@@ -132,9 +134,12 @@ async function openFile() {
status.textContent = 'Ready';
}
async function action(callback) {
- if (busy || running) return;
+ if (busy || running || closing) return;
busy = true;
- try { await callback(); } catch (error) { report(error); } finally { busy = false; }
+ actionDone = (async () => {
+ try { await callback(); } catch (error) { report(error); } finally { busy = false; }
+ })();
+ await actionDone;
}
function editorAction(id) { editor.focus(); editor.getAction(id).run(); }
// Keyed by the menu item ids in src-tauri/src/menu.rs.
@@ -177,19 +182,20 @@ try {
});
await window.listen('menu', event => commands[event.payload]());
await window.onCloseRequested(async event => {
- if (closing) return;
event.preventDefault();
- if (running) {
- try { await invoke('stop_run'); } catch (error) { report(error); return; }
- // The command drains pipes before completing; let runFile release its UI lock.
- busy = false;
- setRunning(false);
- }
- await action(async () => {
+ if (closing) return;
+ closing = true;
+ editor.updateOptions({ readOnly: true });
+ try {
+ if (running) await invoke('stop_run');
+ // Finish any pending save/open or stopped run before closing the document.
+ await actionDone;
if (!await canReplace()) return;
- closing = true;
- await window.close();
- });
+ await window.destroy();
+ } catch (error) { report(error); } finally {
+ closing = false;
+ editor.updateOptions({ readOnly: running });
+ }
});
editor.focus();
} catch (error) { report(error); }