diff --git a/src/client/application/application-controller.vala b/src/client/application/application-controller.vala index c46a2a91..5d8cd1c7 100644 --- a/src/client/application/application-controller.vala +++ b/src/client/application/application-controller.vala @@ -1550,7 +1550,7 @@ public class Application.Controller : Geary.BaseObject { this.waiting_to_close.add(composer); composer.close.begin(); } else { - switch (composer.confirm_close()) { + switch (composer.conditional_close(true, true)) { case Composer.Widget.CloseStatus.PENDING: this.waiting_to_close.add(composer); break; @@ -1637,7 +1637,7 @@ public class Application.Controller : Geary.BaseObject { // new one. Replies must open inline in the main window, // so we need to ensure there are no composers open there // first. - if (!this.main_window.close_composer()) { + if (!this.main_window.close_composer(true)) { return; } } diff --git a/src/client/components/main-window.vala b/src/client/components/main-window.vala index 7faf45c8..50bbfb70 100644 --- a/src/client/components/main-window.vala +++ b/src/client/components/main-window.vala @@ -618,16 +618,16 @@ public class MainWindow : Gtk.ApplicationWindow, Geary.BaseInterface { } /** - * Closes any open composers after prompting the user. + * Closes any open composers, after prompting the user if requested. * * Returns true if none were open or the user approved closing * them. */ - public bool close_composer() { + public bool close_composer(bool should_prompt, bool is_shutdown = false) { bool closed = true; Composer.Widget? composer = this.conversation_viewer.current_composer; if (composer != null && - composer.confirm_close() == CANCELLED) { + composer.conditional_close(should_prompt, is_shutdown) == CANCELLED) { closed = false; } return closed; @@ -1598,11 +1598,13 @@ public class MainWindow : Gtk.ApplicationWindow, Geary.BaseInterface { [GtkCallback] private bool on_delete_event() { if (this.application.config.startup_notifications) { - if (close_composer()) { + if (close_composer(true, false)) { hide(); } } else { - this.application.exit(); + if (close_composer(true, false)) { + this.application.exit(); + } } return Gdk.EVENT_STOP; } diff --git a/src/client/composer/composer-widget.vala b/src/client/composer/composer-widget.vala index a3c0e4eb..b4e61b1f 100644 --- a/src/client/composer/composer-widget.vala +++ b/src/client/composer/composer-widget.vala @@ -119,8 +119,7 @@ public class Composer.Widget : Gtk.EventBox, Geary.BaseInterface { private const string ACTION_INSERT_LINK = "insert-link"; private const string ACTION_COMPOSE_AS_HTML = "compose-as-html"; private const string ACTION_SHOW_EXTENDED_HEADERS = "show-extended-headers"; - private const string ACTION_CLOSE_AND_SAVE = "close-and-save"; - private const string ACTION_CLOSE_AND_DISCARD = "close-and-discard"; + private const string ACTION_DISCARD = "discard"; private const string ACTION_DETACH = "detach"; private const string ACTION_SEND = "send"; private const string ACTION_ADD_ATTACHMENT = "add-attachment"; @@ -168,8 +167,7 @@ public class Composer.Widget : Gtk.EventBox, Geary.BaseInterface { { ACTION_ADD_ATTACHMENT, on_add_attachment }, { ACTION_ADD_ORIGINAL_ATTACHMENTS, on_pending_attachments }, { ACTION_CLOSE, on_close }, - { ACTION_CLOSE_AND_DISCARD, on_close_and_discard }, - { ACTION_CLOSE_AND_SAVE, on_close_and_save }, + { ACTION_DISCARD, on_discard }, { ACTION_COMPOSE_AS_HTML, on_toggle_action, null, "true", on_compose_as_html_toggled }, { ACTION_DETACH, on_detach }, { ACTION_OPEN_INSPECTOR, on_open_inspector }, @@ -179,7 +177,7 @@ public class Composer.Widget : Gtk.EventBox, Geary.BaseInterface { }; public static void add_accelerators(GearyApplication application) { - application.add_window_accelerators(ACTION_CLOSE, { "Escape" } ); + application.add_window_accelerators(ACTION_DISCARD, { "Escape" } ); application.add_window_accelerators(ACTION_ADD_ATTACHMENT, { "t" } ); application.add_window_accelerators(ACTION_DETACH, { "d" } ); @@ -757,63 +755,63 @@ public class Composer.Widget : Gtk.EventBox, Geary.BaseInterface { * closed, if it was already being closed, or the prompt was * cancelled by a human. */ - public CloseStatus confirm_close() { + public CloseStatus conditional_close(bool should_prompt, + bool is_shutdown = false) { CloseStatus status = PENDING; - if (this.is_blank) { - this.close.begin(); - } - - if (!this.is_closing && !this.is_blank) { - present(); - - if (this.can_save) { - var dialog = new TernaryConfirmationDialog( - this.container.top_window, - // Translators: This dialog text is displayed to the - // user when closing a composer where the options are - // Keep, Discard or Cancel. - _("Do you want to keep or discard this draft message?"), - null, - Stock._KEEP, - Stock._DISCARD, Gtk.ResponseType.CLOSE, - "", - "destructive-action", - Gtk.ResponseType.OK // Default == Keep - ); - Gtk.ResponseType response = dialog.run(); - if (response == CANCEL || - response == DELETE_EVENT) { - // Cancel - status = CANCELLED; - } else if (response == OK) { - // Keep - if (!this.is_draft_saved) { - this.save_and_exit_async.begin(); + if (!this.is_closing) { + if (this.is_blank) { + this.close.begin(); + } else if (should_prompt) { + present(); + if (this.can_save) { + var dialog = new TernaryConfirmationDialog( + this.container.top_window, + // Translators: This dialog text is displayed to the + // user when closing a composer where the options are + // Keep, Discard or Cancel. + _("Do you want to keep or discard this draft message?"), + null, + Stock._KEEP, + Stock._DISCARD, Gtk.ResponseType.CLOSE, + "", + is_shutdown ? "destructive-action" : "", + Gtk.ResponseType.OK // Default == Keep + ); + Gtk.ResponseType response = dialog.run(); + if (response == CANCEL || + response == DELETE_EVENT) { + // Cancel + status = CANCELLED; + } else if (response == OK) { + // Keep + this.save_and_close.begin(); } else { - this.close.begin(); + // Discard + this.discard_and_close.begin(); } } else { - // Discard - this.discard_and_exit_async.begin(); + AlertDialog dialog = new ConfirmationDialog( + container.top_window, + // Translators: This dialog text is displayed to the + // user when closing a composer where the options are + // only Discard or Cancel. + _("Do you want to discard this draft message?"), + null, + Stock._DISCARD, + "" + ); + Gtk.ResponseType response = dialog.run(); + if (response == OK) { + this.discard_and_close.begin(); + } else { + status = CANCELLED; + } } + } else if (this.can_save) { + this.save_and_close.begin(); } else { - AlertDialog dialog = new ConfirmationDialog( - container.top_window, - // Translators: This dialog text is displayed to the - // user when closing a composer where the options are - // only Discard or Cancel. - _("Do you want to discard this draft message?"), - null, - Stock._DISCARD, - "destructive-action" - ); - Gtk.ResponseType response = dialog.run(); - if (response == OK) { - this.discard_and_exit_async.begin(); - } else { - status = CANCELLED; - } + this.discard_and_close.begin(); } } @@ -1099,7 +1097,6 @@ public class Composer.Widget : Gtk.EventBox, Geary.BaseInterface { ); } - get_action(ACTION_CLOSE_AND_SAVE).set_enabled(false); get_action(Action.Edit.UNDO).set_enabled(false); get_action(Action.Edit.REDO).set_enabled(false); @@ -1450,6 +1447,7 @@ public class Composer.Widget : Gtk.EventBox, Geary.BaseInterface { // Used internally by on_send() private async void on_send_async() { + this.is_closing = true; set_enabled(false); try { @@ -1517,7 +1515,6 @@ public class Composer.Widget : Gtk.EventBox, Geary.BaseInterface { this.draft_manager = new_manager; update_draft_state(); - get_action(ACTION_CLOSE_AND_SAVE).set_enabled(true); this.header.show_save_and_close = true; } @@ -1538,12 +1535,9 @@ public class Composer.Widget : Gtk.EventBox, Geary.BaseInterface { private async void close_draft_manager(GLib.Cancellable? cancellable) throws GLib.Error { - this.draft_status_text = ""; - - get_action(ACTION_CLOSE_AND_SAVE).set_enabled(false); - Geary.App.DraftManager old_manager = this.draft_manager; this.draft_manager = null; + this.draft_status_text = ""; old_manager.notify[Geary.App.DraftManager.PROP_DRAFT_STATE] .disconnect(on_draft_state_changed); @@ -1618,11 +1612,11 @@ public class Composer.Widget : Gtk.EventBox, Geary.BaseInterface { yield this.draft_manager.discard(null); } - private async void save_and_exit_async() { + private async void save_and_close() { this.is_closing = true; set_enabled(false); - if (!is_blank) { + if (this.should_save) { try { yield save_draft(); } catch (GLib.Error error) { @@ -1632,20 +1626,17 @@ public class Composer.Widget : Gtk.EventBox, Geary.BaseInterface { ) ); } - - // Pass on to the controller so the draft can be re-opened - // on undo - if (this.container != null) { - this.container.close(); - } - yield this.application.controller.save_composed_email(this); - } else { - // The composer is blank, so drop the mic and walk away - yield close(); } + + // Pass on to the controller so the draft can be re-opened + // on undo + if (this.container != null) { + this.container.close(); + } + yield this.application.controller.save_composed_email(this); } - private async void discard_and_exit_async() { + private async void discard_and_close() { this.is_closing = true; set_enabled(false); @@ -1662,17 +1653,12 @@ public class Composer.Widget : Gtk.EventBox, Geary.BaseInterface { } } - if (!is_blank) { - // Pass on to the controller so the discarded email can be - // re-opened on undo - if (this.container != null) { - this.container.close(); - } - yield this.application.controller.discard_composed_email(this); - } else { - // The composer is blank, so drop the mic and walk away - yield close(); + // Pass on to the controller so the discarded email can be + // re-opened on undo + if (this.container != null) { + this.container.close(); } + yield this.application.controller.discard_composed_email(this); } private void update_attachments_view() { @@ -2719,22 +2705,18 @@ public class Composer.Widget : Gtk.EventBox, Geary.BaseInterface { update_cursor_actions(); } - private void on_close(SimpleAction action, Variant? param) { - confirm_close(); + private void on_close() { + conditional_close(this.container is Window); } - private void on_close_and_save(SimpleAction action, Variant? param) { - if (this.should_save) { - save_and_exit_async.begin(); + private void on_discard() { + if (this.container is Window) { + conditional_close(true); } else { - this.close.begin(); + this.discard_and_close.begin(); } } - private void on_close_and_discard(SimpleAction action, Variant? param) { - discard_and_exit_async.begin(); - } - private void on_draft_timeout() { var current_account = this.account; this.save_draft.begin( diff --git a/src/client/composer/composer-window.vala b/src/client/composer/composer-window.vala index da2fd72c..9ca8699b 100644 --- a/src/client/composer/composer-window.vala +++ b/src/client/composer/composer-window.vala @@ -115,13 +115,13 @@ public class Composer.Window : Gtk.ApplicationWindow, Container { } public override bool delete_event(Gdk.EventAny event) { - bool ret = Gdk.EVENT_PROPAGATE; - // Use the child instead of the `composer` property so we don't check - // with the composer if it has already been removed from the - // container. + // Use the child instead of the `composer` property so we + // don't check with the composer if it has already been + // removed from the container. Widget? child = get_child() as Widget; + bool ret = Gdk.EVENT_PROPAGATE; if (child != null && - child.confirm_close() == CANCELLED) { + child.conditional_close(true) == CANCELLED) { ret = Gdk.EVENT_STOP; } return ret; diff --git a/src/client/conversation-list/conversation-list-view.vala b/src/client/conversation-list/conversation-list-view.vala index d489429f..7eb3dcb7 100644 --- a/src/client/conversation-list/conversation-list-view.vala +++ b/src/client/conversation-list/conversation-list-view.vala @@ -297,7 +297,7 @@ public class ConversationListView : Gtk.TreeView, Geary.BaseInterface { if (event.type == Gdk.EventType.BUTTON_PRESS && !get_selection().path_is_selected(path)) { MainWindow? parent = get_toplevel() as MainWindow; - if (parent != null && !parent.close_composer()) { + if (parent != null && !parent.close_composer(false)) { return true; } } diff --git a/src/client/folder-list/folder-list-tree.vala b/src/client/folder-list/folder-list-tree.vala index 80b31c81..69e05d50 100644 --- a/src/client/folder-list/folder-list-tree.vala +++ b/src/client/folder-list/folder-list-tree.vala @@ -59,7 +59,7 @@ public class FolderList.Tree : Sidebar.Tree, Geary.BaseInterface { bool can_switch = true; MainWindow? parent = get_toplevel() as MainWindow; if (parent != null) { - can_switch = parent.close_composer(); + can_switch = parent.close_composer(false); } return can_switch; } diff --git a/ui/composer-headerbar.ui b/ui/composer-headerbar.ui index 52ec320c..fb672ae1 100644 --- a/ui/composer-headerbar.ui +++ b/ui/composer-headerbar.ui @@ -229,7 +229,7 @@ False False Discard and Close - cmh.close-and-discard + cmh.discard True @@ -253,7 +253,7 @@ False False Save and Close - cmh.close-and-save + cmh.close True