From 6b4d05716794b1e8305c486d293bcc082859cc79 Mon Sep 17 00:00:00 2001 From: Sophie Herold Date: Mon, 22 Jun 2026 14:45:51 +0200 Subject: [PATCH] Trigger save dialog via close_request This simplifies the code and fixes that unsaved changes were only saved for the active window and dropped for all others. Part-of: --- src/application.rs | 51 +++----------------------------------- src/widgets/edit_window.rs | 50 ++++++++++++++++++++++++++----------- src/widgets/window.rs | 21 ++++++++++++++++ 3 files changed, 60 insertions(+), 62 deletions(-) diff --git a/src/application.rs b/src/application.rs index fa6ecb6..060a333 100644 --- a/src/application.rs +++ b/src/application.rs @@ -20,7 +20,6 @@ // // SPDX-License-Identifier: GPL-3.0-or-later -use crate::util::gettext::*; use adw::prelude::*; use adw::subclass::prelude::*; @@ -135,53 +134,9 @@ impl LpApplication { .build(), gio::ActionEntryBuilder::new("quit") .activate(|app: &Self, _, _| { - if let Some(win) = app.active_window() { - if let Some(lp_window) = win.downcast_ref::() { - if let Some(edit_window) = lp_window.edit_window() { - if edit_window.has_unsaved_changes() { - let dialog = adw::AlertDialog::new( - Some(&gettext("Unsaved Changes")), - Some(&gettext( - "Changes which are not lost will be permanently lost", - )), - ); - - dialog.add_response("cancel", &gettext("Cancel")); - dialog.add_response("discard", &gettext("Discard")); - dialog.add_response("save", &gettext("Save")); - - let app_clone = app.clone(); - let win_clone = win.clone(); - let edit_window_clone = edit_window.clone(); - let dialog_clone = dialog.clone(); - - dialog.set_response_appearance( - "discard", - adw::ResponseAppearance::Destructive, - ); - - glib::MainContext::default().spawn_local(async move { - let res = - dialog_clone.choose_future(Some(&win_clone)).await; - - match res.as_str() { - "cancel" => {} - "discard" => { - app_clone.quit(); - } - "save" => { - edit_window_clone - .save_as_and_quit(app_clone.clone()); - } - _ => {} - } - }); - - return; - } - } - } - app.quit(); + // Give all windows the chance to handle close-request + for win in app.windows() { + win.close(); } }) .build(), diff --git a/src/widgets/edit_window.rs b/src/widgets/edit_window.rs index 395701d..6935c5d 100644 --- a/src/widgets/edit_window.rs +++ b/src/widgets/edit_window.rs @@ -25,7 +25,6 @@ use glycin::Operations; use super::LpImage; use super::edit::LpEditCrop; -use crate::LpApplication; use crate::deps::*; use crate::util::ErrorType; use crate::util::gettext::*; @@ -490,19 +489,6 @@ impl LpEditWindow { self.imp().is_save_sensitive() } - pub fn save_as_and_quit(&self, app: LpApplication) { - glib::spawn_future_local(glib::clone!( - #[weak(rename_to=win)] - self, - #[strong] - app, - async move { - win.imp().save_overwrite().await; - app.quit() - } - )); - } - pub fn add_operation(&self, operation: glycin::Operation) { let imp = self.imp(); @@ -517,4 +503,40 @@ impl LpEditWindow { self.set_operations(Some(Arc::new(Operations::new(operations)))); } + + /// Returns if the window should proceed with closing + pub async fn ensure_saved(&self) -> glib::Propagation { + if self.has_unsaved_changes() { + let dialog = adw::AlertDialog::new( + Some(&gettext("Unsaved Changes")), + Some(&gettext( + "Changes which are not lost will be permanently lost", + )), + ); + + dialog.add_response("cancel", &gettext("Cancel")); + dialog.add_response("discard", &gettext("Discard")); + dialog.add_response("save", &gettext("Save")); + + dialog.set_response_appearance("discard", adw::ResponseAppearance::Destructive); + + let res = dialog.choose_future(Some(self)).await; + + match res.as_str() { + "cancel" => glib::Propagation::Stop, + "close" => glib::Propagation::Stop, + "discard" => glib::Propagation::Proceed, + "save" => { + self.imp().save_overwrite().await; + glib::Propagation::Proceed + } + res => { + tracing::error!("Invalid dialog result: {res}"); + glib::Propagation::Stop + } + } + } else { + glib::Propagation::Proceed + } + } } diff --git a/src/widgets/window.rs b/src/widgets/window.rs index fa835f9..0a228f7 100644 --- a/src/widgets/window.rs +++ b/src/widgets/window.rs @@ -129,6 +129,11 @@ mod imp { // and keeps the others usable gtk::WindowGroup::new().add_window(&*obj); + obj.connect_close_request(|win| { + win.imp().close_request(); + glib::Propagation::Stop + }); + glib::timeout_add_local_once( std::time::Duration::from_millis(SHOW_WINDOW_AFTER), glib::clone!( @@ -151,6 +156,22 @@ mod imp { impl WindowImpl for LpWindow {} impl ApplicationWindowImpl for LpWindow {} impl AdwApplicationWindowImpl for LpWindow {} + + impl LpWindow { + pub fn close_request(&self) { + let obj = self.obj().to_owned(); + glib::MainContext::default().spawn_local(async move { + if let Some(edit_window) = obj.edit_window() { + if matches!(edit_window.ensure_saved().await, glib::Propagation::Proceed) { + obj.destroy(); + } + } else { + // Without editing window, we can always close + obj.destroy(); + } + }); + } + } } glib::wrapper! {