diff --git a/src/Application.vala b/src/Application.vala index ca48a0efa..b10d5f419 100644 --- a/src/Application.vala +++ b/src/Application.vala @@ -199,6 +199,38 @@ namespace Scratch { return windows.length () > 0 ? windows.last ().data as MainWindow : null; } + public async void handle_quit_app () { + unowned List windows; + windows = get_windows (); + //NOTE This yields the last opened window at head of list (may change in future?) + while (windows.length () > 0) { + if (!yield handle_quit_window ((MainWindow) (windows.first ().data))) { + return; + } + + windows = get_windows (); + } + + return; + } + + public async bool handle_quit_window (MainWindow window_to_close) { + unowned List windows = get_windows (); + var n_windows = windows.length (); + if (!yield window_to_close.check_unsaved_changes (n_windows == 1)) { + return false; + } + + if (n_windows == 1) { + window_to_close.before_quit (); // Update settings + } + // Just destroy window - we have already checked whether any docs need saving + // When the last window is removed and destroyed the app quits. + remove_window (window_to_close); + window_to_close.destroy (); + return true; + } + public static int main (string[] args) { // By default, profile whole app when profiling is enabled in meson_options.txt // These conditional statements can be moved to profile sections of code diff --git a/src/MainWindow.vala b/src/MainWindow.vala index bcf37aeb6..9e3a96d37 100644 --- a/src/MainWindow.vala +++ b/src/MainWindow.vala @@ -100,7 +100,8 @@ namespace Scratch { public const string ACTION_TO_UPPER_CASE = "action-to-upper-case"; public const string ACTION_DUPLICATE = "action-duplicate"; public const string ACTION_FULLSCREEN = "action-fullscreen"; - public const string ACTION_QUIT = "action-quit"; + public const string ACTION_QUIT = "action-quit-app"; + public const string ACTION_CLOSE_WINDOW = "action-close-window"; public const string ACTION_ZOOM_DEFAULT = "action-zoom-default"; public const string ACTION_ZOOM_IN = "action-zoom-in"; public const string ACTION_ZOOM_OUT = "action-zoom-out"; @@ -161,7 +162,8 @@ namespace Scratch { { ACTION_TO_UPPER_CASE, action_to_upper_case }, { ACTION_DUPLICATE, action_duplicate }, { ACTION_FULLSCREEN, action_fullscreen }, - { ACTION_QUIT, action_quit }, + { ACTION_QUIT, action_quit_app }, + { ACTION_CLOSE_WINDOW, action_close_window }, { ACTION_ZOOM_DEFAULT, action_set_default_zoom }, { ACTION_ZOOM_IN, action_zoom_in }, { ACTION_ZOOM_OUT, action_zoom_out}, @@ -225,6 +227,7 @@ namespace Scratch { action_accelerators.set (ACTION_DUPLICATE, "d"); action_accelerators.set (ACTION_FULLSCREEN, "F11"); action_accelerators.set (ACTION_QUIT, "q"); + action_accelerators.set (ACTION_CLOSE_WINDOW, "F4"); action_accelerators.set (ACTION_ZOOM_DEFAULT, "0"); action_accelerators.set (ACTION_ZOOM_DEFAULT, "KP_0"); action_accelerators.set (ACTION_ZOOM_IN, "plus"); @@ -722,7 +725,7 @@ namespace Scratch { } protected override bool delete_event (Gdk.EventAny event) { - action_quit (); + action_close_window (); return true; } @@ -810,10 +813,10 @@ namespace Scratch { } // Check that there no unsaved changes and all saves are successful - private async bool check_unsaved_changes () { + public async bool check_unsaved_changes (bool app_closing) { document_view.is_closing = true; foreach (var doc in document_view.docs) { - if (!yield (doc.do_close (true))) { + if (!yield (doc.do_close (app_closing))) { document_view.current_document = doc; return false; } @@ -847,7 +850,7 @@ namespace Scratch { } } - private void update_saved_state () { + private void update_window_state_setting () { // Save window state var state = get_window ().get_state (); if (Gdk.WindowState.MAXIMIZED in state) { @@ -869,14 +872,14 @@ namespace Scratch { // SIGTERM/SIGINT Handling public bool quit_source_func () { - action_quit (); + action_quit_app (); return false; } // For exit cleanup - private void handle_quit () { - document_view.save_opened_files (); - update_saved_state (); + public void before_quit () { + document_view.update_opened_files_setting (); + update_window_state_setting (); } public void set_default_zoom () { @@ -963,13 +966,12 @@ namespace Scratch { preferences_dialog.present (); } - private void action_quit () { - handle_quit (); - check_unsaved_changes.begin ((obj, res) => { - if (check_unsaved_changes.end (res)) { - app.quit (); - } - }); + private void action_close_window () { + app.handle_quit_window.begin (this); + } + + private void action_quit_app () { + app.handle_quit_app.begin (); } private void action_open () { diff --git a/src/Widgets/DocumentView.vala b/src/Widgets/DocumentView.vala index 30fa7f56c..9b572e1ef 100644 --- a/src/Widgets/DocumentView.vala +++ b/src/Widgets/DocumentView.vala @@ -133,7 +133,7 @@ public class Scratch.Widgets.DocumentView : Gtk.Box { var should_close = doc.do_close.end (res); // Ensure removed doc is saved by handling this first if (!is_closing) { - save_opened_files (); + update_opened_files_setting (); } //`page-detached` handler will perform rest of necessary cleanup tab_view.close_page_finish (tab, should_close); @@ -337,7 +337,7 @@ public class Scratch.Widgets.DocumentView : Gtk.Box { if (range != SelectionRange.EMPTY) { Idle.add_full (GLib.Priority.LOW, () => { // This helps ensures new tab is drawn before opening document. current_document.source_view.select_range (range); - save_opened_files (); + update_opened_files_setting (); return false; }); @@ -364,7 +364,7 @@ public class Scratch.Widgets.DocumentView : Gtk.Box { doc.source_view.cursor_position = cursor_position; } - save_opened_files (); + update_opened_files_setting (); } public void next_document () { @@ -399,7 +399,7 @@ public class Scratch.Widgets.DocumentView : Gtk.Box { } } - public void save_opened_files () { + public void update_opened_files_setting () { if (privacy_settings.get_boolean ("remember-recent-files")) { var vb = new VariantBuilder (new VariantType ("a(si)")); docs.foreach ((doc) => { @@ -542,7 +542,7 @@ public class Scratch.Widgets.DocumentView : Gtk.Box { current_document = doc; } - save_opened_files (); + update_opened_files_setting (); } private unowned Hdy.TabView? on_doc_to_new_window (Hdy.TabView tab_view) {