Keep Open and Save asynchronous to prevent macOS resize crashes (#1127)
Open and Save use parented AsyncFileDialog sheets; their answers run on the UI thread in a later frame, so resizing the window while a picker is open no longer re-enters winit and aborts. Editors, tab changes, Close/Quit and model-changing control requests wait for the answer; the local library Open and Export in the Appearance dialog use the same flow. Fixes #1088.
This commit is contained in:
1 parent
f425089983
commit
37547f8eba
18 files changed
+564
-137
No files matched your search
@@ -337,9 +337,11 @@ fn file_menu(app: &mut SolveApp, ctx: &egui::Context) {
|
||||
close = true;
|
||||
}
|
||||
if item(ui, &format!("{}…", app.tr("ui.open")), "Ctrl+O") {
|
||||
if let Some(p) = app.services.pick_open.as_ref().and_then(|f| f()) {
|
||||
app.open_path_async(&p);
|
||||
}
|
||||
app.pick_open(|app, path| {
|
||||
if let Some(path) = path {
|
||||
app.open_path_async(&path);
|
||||
}
|
||||
});
|
||||
close = true;
|
||||
}
|
||||
ui.menu_button(app.tr("ui.open_recent"), |ui| {
|
||||
@@ -455,9 +457,12 @@ fn save_as(app: &mut SolveApp) {
|
||||
|
||||
fn save_as_with_extension(app: &mut SolveApp, extension: &str) {
|
||||
let name = format!("{}.{extension}", app.session.doc.name);
|
||||
if let Some(p) = app.services.pick_save.as_ref().and_then(|f| f(&name, &[solidcraft_engine::io::DESIGN_EXT, "json"])) {
|
||||
let _ = app.run("file.save_as", json!({"path": p}));
|
||||
}
|
||||
app.pick_save(&name, &[solidcraft_engine::io::DESIGN_EXT, "json"], |app, path| {
|
||||
if let Some(path) = path {
|
||||
let _ = app.run("file.save_as", json!({"path": path}));
|
||||
}
|
||||
crate::documents::saved_for_close(app);
|
||||
});
|
||||
}
|
||||
|
||||
fn export(app: &mut SolveApp, ext: &str) {
|
||||
@@ -467,14 +472,17 @@ fn export(app: &mut SolveApp, ext: &str) {
|
||||
/// Export to a file with extension `ext`, in `format` when the extension alone doesn't name it.
|
||||
fn export_as(app: &mut SolveApp, ext: &str, format: Option<&str>) {
|
||||
let name = format!("{}.{ext}", app.session.doc.name);
|
||||
let Some(p) = app.services.pick_save.as_ref().and_then(|f| f(&name, &[ext])) else { return };
|
||||
let params = match format {
|
||||
Some(f) => json!({"path": p, "format": f}),
|
||||
None => json!({"path": p}),
|
||||
};
|
||||
if app.run("file.export", params).is_ok() {
|
||||
app.set_status(format!("Exported {p}"), false);
|
||||
}
|
||||
let format = format.map(str::to_string);
|
||||
app.pick_save(&name, &[ext], move |app, path| {
|
||||
let Some(path) = path else { return };
|
||||
let mut params = json!({"path": path});
|
||||
if let Some(format) = format {
|
||||
params["format"] = json!(format);
|
||||
}
|
||||
if app.run("file.export", params).is_ok() {
|
||||
app.set_status(format!("Exported {path}"), false);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
pub fn toolbar(app: &mut SolveApp, ui: &mut egui::Ui) {
|
||||
@@ -1152,9 +1160,11 @@ pub fn shortcuts(app: &mut SolveApp, ctx: &egui::Context) {
|
||||
Key::N => crate::documents::new_design(app),
|
||||
Key::Comma => crate::prefs::open_at(app, 0),
|
||||
Key::O => {
|
||||
if let Some(p) = app.services.pick_open.as_ref().and_then(|f| f()) {
|
||||
app.open_path_async(&p);
|
||||
}
|
||||
app.pick_open(|app, path| {
|
||||
if let Some(path) = path {
|
||||
app.open_path_async(&path);
|
||||
}
|
||||
});
|
||||
}
|
||||
_ if !shown => {}
|
||||
Key::Z => drop(app.run("edit.undo", json!({}))),
|
||||
@@ -1215,7 +1225,8 @@ mod header_report_tests {
|
||||
let mut h = crate::scenario::Harness::new();
|
||||
h.app.run("solid.box", json!({"length":2,"width":3,"height":4})).unwrap();
|
||||
let dir = h.dir.clone();
|
||||
h.app.services.pick_save = Some(Box::new(move |name, _extensions| Some(dir.join(name).to_string_lossy().into_owned())));
|
||||
h.app.services.pick_save =
|
||||
Some(Box::new(move |name, _extensions| Box::pin(std::future::ready(Some(dir.join(name).to_string_lossy().into_owned())))));
|
||||
h.frames(3);
|
||||
h.step(&json!({"click":{"handle":"appbar:folder"}})).unwrap();
|
||||
h.step(&json!({"widget":"Save As JSON…"})).unwrap();
|
||||
|
||||
Reference in new issue
Block a user