[geary/mjog/account-command-stacks: 5/27] Move per-message action handlers from Controller to MainWindow



commit c017cdb9b4baac6521107634c65ceb3e09d6900a
Author: Michael Gratton <mike vee net>
Date:   Sat Oct 5 11:44:17 2019 +1000

    Move per-message action handlers from Controller to MainWindow

 src/client/application/application-controller.vala | 294 +++++----------------
 src/client/application/geary-application.vala      |   7 +
 src/client/components/main-window.vala             | 207 ++++++++++++++-
 src/client/composer/composer-widget.vala           |   8 +-
 4 files changed, 276 insertions(+), 240 deletions(-)
---
diff --git a/src/client/application/application-controller.vala 
b/src/client/application/application-controller.vala
index f5a31c86..bee2b6d1 100644
--- a/src/client/application/application-controller.vala
+++ b/src/client/application/application-controller.vala
@@ -226,9 +226,6 @@ public class Application.Controller : Geary.BaseObject {
         
main_window.conversation_list_view.visible_conversations_changed.connect(on_visible_conversations_changed);
         main_window.folder_list.folder_selected.connect(on_folder_selected);
         main_window.search_bar.search_text_changed.connect((text) => { do_search(text); });
-        main_window.conversation_viewer.conversation_added.connect(
-            on_conversation_view_added
-        );
         this.main_window.folder_list.set_new_messages_monitor(
             this.plugin_manager.notifications
         );
@@ -343,9 +340,6 @@ public class Application.Controller : Geary.BaseObject {
         this.main_window.conversation_list_view.conversation_activated.disconnect(on_conversation_activated);
         
this.main_window.conversation_list_view.visible_conversations_changed.disconnect(on_visible_conversations_changed);
         this.main_window.folder_list.folder_selected.disconnect(on_folder_selected);
-        this.main_window.conversation_viewer.conversation_added.disconnect(
-            on_conversation_view_added
-        );
 
         // hide window while shutting down, as this can take a few
         // seconds under certain conditions
@@ -469,7 +463,6 @@ public class Application.Controller : Geary.BaseObject {
     public void add_composer(ComposerWidget widget) {
         debug(@"Added composer of type $(widget.compose_type); $(this.composer_widgets.size) composers 
total");
         widget.destroy.connect(this.on_composer_widget_destroy);
-        widget.link_activated.connect((uri) => { open_uri(uri); });
         this.composer_widgets.add(widget);
     }
 
@@ -1421,37 +1414,14 @@ public class Application.Controller : Geary.BaseObject {
         }
     }
 
-    private void on_conversation_viewer_mark_emails(Gee.Collection<Geary.EmailIdentifier> email,
-                                                    Geary.EmailFlags? to_add,
-                                                    Geary.EmailFlags? to_remove) {
-    }
-
-    private void on_attachments_activated(Gee.Collection<Geary.Attachment> attachments) {
-        if (this.application.config.ask_open_attachment) {
-            QuestionDialog ask_to_open = new QuestionDialog.with_checkbox(main_window,
-                _("Are you sure you want to open these attachments?"),
-                _("Attachments may cause damage to your system if opened.  Only open files from trusted 
sources."),
-                Stock._OPEN_BUTTON, Stock._CANCEL, _("Don’t _ask me again"), false);
-            if (ask_to_open.run() != Gtk.ResponseType.OK) {
-                return;
-            }
-            // only save checkbox state if OK was selected
-            this.application.config.ask_open_attachment = !ask_to_open.is_checked;
-        }
-
-        foreach (Geary.Attachment attachment in attachments) {
-            string uri = attachment.file.get_uri();
-            try {
-                this.application.show_uri(uri);
-            } catch (Error err) {
-                message("Unable to open attachment \"%s\": %s", uri, err.message);
-            }
-        }
-    }
+    public async void save_attachment_to_file(Geary.Account account,
+                                              Geary.Attachment attachment,
+                                              string? alt_text) {
+        AccountContext? context = this.accounts.get(account.information);
+        GLib.Cancellable cancellable = (
+            context != null ? context.cancellable : null
+        );
 
-    private async void save_attachment_to_file(Geary.Attachment attachment,
-                                               string? alt_text,
-                                               GLib.Cancellable cancellable) {
         string alt_display_name = Geary.String.is_empty_or_whitespace(alt_text)
             ? Application.Controller.untitled_file_name : alt_text;
         string display_name = yield attachment.get_safe_file_name(
@@ -1472,9 +1442,14 @@ public class Application.Controller : Geary.BaseObject {
         yield this.prompt_save_buffer(display_name, content, cancellable);
     }
 
-    private async void
-        save_attachments_to_file(Gee.Collection<Geary.Attachment> attachments,
-                                 GLib.Cancellable? cancellable) {
+    public async void
+        save_attachments_to_file(Geary.Account account,
+                                 Gee.Collection<Geary.Attachment> attachments) {
+        AccountContext? context = this.accounts.get(account.information);
+        GLib.Cancellable cancellable = (
+            context != null ? context.cancellable : null
+        );
+
         Gtk.FileChooserNative dialog = new_save_chooser(Gtk.FileChooserAction.SELECT_FOLDER);
 
         bool accepted = (dialog.run() == Gtk.ResponseType.ACCEPT);
@@ -1510,6 +1485,53 @@ public class Application.Controller : Geary.BaseObject {
         }
     }
 
+    public async void save_image_extended(Geary.Account account,
+                                          ConversationEmail view,
+                                          string url,
+                                          string? alt_text,
+                                          Geary.Memory.Buffer resource_buf) {
+        AccountContext? context = this.accounts.get(account.information);
+        GLib.Cancellable cancellable = (
+            context != null ? context.cancellable : null
+        );
+
+        // This is going to be either an inline image, or a remote
+        // image, so either treat it as an attachment to assume we'll
+        // have a valid filename in the URL
+        bool handled = false;
+        if (url.has_prefix(ClientWebView.CID_URL_PREFIX)) {
+            string cid = url.substring(ClientWebView.CID_URL_PREFIX.length);
+            Geary.Attachment? attachment = null;
+            try {
+                attachment = view.email.get_attachment_by_content_id(cid);
+            } catch (Error err) {
+                debug("Could not get attachment \"%s\": %s", cid, err.message);
+            }
+            if (attachment != null) {
+                yield this.save_attachment_to_file(
+                    account, attachment, alt_text
+                );
+                handled = true;
+            }
+        }
+
+        if (!handled) {
+            GLib.File source = GLib.File.new_for_uri(url);
+            // Querying the URL-based file for the display name
+            // results in it being looked up, so just get the basename
+            // from it directly. GIO seems to decode any %-encoded
+            // chars anyway.
+            string? display_name = source.get_basename();
+            if (Geary.String.is_empty_or_whitespace(display_name)) {
+                display_name = Controller.untitled_file_name;
+            }
+
+            yield this.prompt_save_buffer(
+                display_name, resource_buf, cancellable
+            );
+        }
+    }
+
     private async void prompt_save_buffer(string display_name,
                                           Geary.Memory.Buffer buffer,
                                           GLib.Cancellable? cancellable) {
@@ -1614,25 +1636,6 @@ public class Application.Controller : Geary.BaseObject {
         return dialog;
     }
 
-    // Opens a link in an external browser.
-    private bool open_uri(string _link) {
-        string link = _link;
-
-        // Support web URLs that omit the protocol.
-        if (!link.contains(":"))
-            link = "http://"; + link;
-
-        bool success = true;
-        try {
-            this.application.show_uri(link);
-        } catch (Error err) {
-            success = false;
-            debug("Unable to open URL: \"%s\" %s", link, err.message);
-        }
-
-        return success;
-    }
-
     internal bool close_composition_windows(bool main_window_only = false) {
         Gee.List<ComposerWidget> composers_to_destroy = new Gee.ArrayList<ComposerWidget>();
         bool quit_cancelled = false;
@@ -1833,76 +1836,6 @@ public class Application.Controller : Geary.BaseObject {
         this.plugin_manager.notifications.email_sent(account, sent);
     }
 
-    private void on_conversation_view_added(ConversationListBox list) {
-        list.email_added.connect(on_conversation_viewer_email_added);
-        list.mark_emails.connect(on_conversation_viewer_mark_emails);
-    }
-
-    private void on_conversation_viewer_email_added(ConversationEmail view) {
-        view.attachments_activated.connect(on_attachments_activated);
-        view.forward_message.connect(on_forward_message);
-        view.load_error.connect(on_email_load_error);
-        view.reply_to_message.connect(on_reply_to_message);
-        view.reply_all_message.connect(on_reply_all_message);
-
-        Geary.App.Conversation conversation = main_window.conversation_viewer.current_list.conversation;
-        bool in_current_folder = (conversation.is_in_base_folder(view.email.id) &&
-            conversation.base_folder == current_folder);
-        bool supports_trash = in_current_folder && current_folder_supports_trash();
-        bool supports_delete = in_current_folder && current_folder is Geary.FolderSupport.Remove;
-        view.trash_message.connect(on_trash_message);
-        view.delete_message.connect(on_delete_message);
-        view.set_folder_actions_enabled(supports_trash, supports_delete);
-        main_window.on_shift_key.connect(view.shift_key_changed);
-
-        view.edit_draft.connect((draft_view) => {
-                create_compose_widget(
-                    ComposerWidget.ComposeType.NEW_MESSAGE,
-                    draft_view.email, null, null, true
-                );
-            });
-        foreach (ConversationMessage msg_view in view) {
-            msg_view.link_activated.connect(on_link_activated);
-            msg_view.save_image.connect((url, alt_text, buf) => {
-                    on_save_image_extended(view, url, alt_text, buf);
-                });
-        }
-        view.save_attachments.connect(on_save_attachments);
-        view.view_source.connect(on_view_source);
-    }
-
-    private void on_trash_message(ConversationEmail target_view) {
-    }
-
-    private void on_delete_message(ConversationEmail target_view) {
-    }
-
-    private void on_view_source(ConversationEmail email_view) {
-        string source = (email_view.email.header.buffer.to_string() +
-                         email_view.email.body.buffer.to_string());
-        string temporary_filename;
-        try {
-            int temporary_handle = FileUtils.open_tmp("geary-message-XXXXXX.txt",
-                                                      out temporary_filename);
-            FileUtils.set_contents(temporary_filename, source);
-            FileUtils.close(temporary_handle);
-
-            // ensure this file is only readable by the user ... this
-            // needs to be done after the file is closed
-            FileUtils.chmod(temporary_filename, (int) (Posix.S_IRUSR | Posix.S_IWUSR));
-
-            string temporary_uri = Filename.to_uri(temporary_filename, null);
-            this.application.show_uri(temporary_uri);
-        } catch (Error error) {
-            ErrorDialog dialog = new ErrorDialog(
-                main_window,
-                _("Failed to open default text editor."),
-                error.message
-            );
-            dialog.run();
-        }
-    }
-
     private SimpleAction get_window_action(string action_name) {
         return (SimpleAction) this.main_window.lookup_action(action_name);
     }
@@ -2218,107 +2151,4 @@ public class Application.Controller : Geary.BaseObject {
         }
     }
 
-    private void on_email_load_error(ConversationEmail view, GLib.Error err) {
-        report_problem(
-            new Geary.ServiceProblemReport(
-                this.current_account.information,
-                this.current_account.information.incoming,
-                err
-            )
-        );
-    }
-
-    private void on_reply_to_message(ConversationEmail target_view) {
-        target_view.get_selection_for_quoting.begin((obj, res) => {
-                string? quote = target_view.get_selection_for_quoting.end(res);
-                create_compose_widget(REPLY, target_view.email, quote);
-            });
-    }
-
-    private void on_reply_all_message(ConversationEmail target_view) {
-        target_view.get_selection_for_quoting.begin((obj, res) => {
-                string? quote = target_view.get_selection_for_quoting.end(res);
-                create_compose_widget(REPLY_ALL, target_view.email, quote);
-            });
-    }
-
-    private void on_forward_message(ConversationEmail target_view) {
-        target_view.get_selection_for_quoting.begin((obj, res) => {
-                string? quote = target_view.get_selection_for_quoting.end(res);
-                create_compose_widget(FORWARD, target_view.email, quote);
-            });
-    }
-
-    private void on_save_attachments(Gee.Collection<Geary.Attachment> attachments) {
-        GLib.Cancellable? cancellable = null;
-        if (this.current_account != null) {
-            cancellable = this.accounts.get(
-                this.current_account.information
-            ).cancellable;
-        }
-        if (attachments.size == 1) {
-            this.save_attachment_to_file.begin(
-                attachments.to_array()[0], null, cancellable
-            );
-        } else {
-            this.save_attachments_to_file.begin(attachments, cancellable);
-        }
-    }
-
-    private void on_link_activated(string uri) {
-        if (uri.down().has_prefix(Geary.ComposedEmail.MAILTO_SCHEME)) {
-            compose(uri);
-        } else {
-            open_uri(uri);
-        }
-    }
-
-    private void on_save_image_extended(ConversationEmail view,
-                                        string url,
-                                        string? alt_text,
-                                        Geary.Memory.Buffer resource_buf) {
-        GLib.Cancellable? cancellable = null;
-        if (this.current_account != null) {
-            cancellable = this.accounts.get(
-                this.current_account.information
-            ).cancellable;
-        }
-
-        // This is going to be either an inline image, or a remote
-        // image, so either treat it as an attachment to assume we'll
-        // have a valid filename in the URL
-        bool handled = false;
-        if (url.has_prefix(ClientWebView.CID_URL_PREFIX)) {
-            string cid = url.substring(ClientWebView.CID_URL_PREFIX.length);
-            Geary.Attachment? attachment = null;
-            try {
-                attachment = view.email.get_attachment_by_content_id(cid);
-            } catch (Error err) {
-                debug("Could not get attachment \"%s\": %s", cid, err.message);
-            }
-            if (attachment != null) {
-                this.save_attachment_to_file.begin(
-                    attachment, alt_text, cancellable
-                );
-                handled = true;
-            }
-        }
-
-        if (!handled) {
-            GLib.File source = GLib.File.new_for_uri(url);
-            // Querying the URL-based file for the display name
-            // results in it being looked up, so just get the basename
-            // from it directly. GIO seems to decode any %-encoded
-            // chars anyway.
-            string? display_name = source.get_basename();
-            if (Geary.String.is_empty_or_whitespace(display_name)) {
-                display_name = Application.Controller.untitled_file_name;
-            }
-
-            this.prompt_save_buffer.begin(
-                display_name, resource_buf, cancellable
-            );
-        }
-    }
-
 }
diff --git a/src/client/application/geary-application.vala b/src/client/application/geary-application.vala
index 3fe307cb..52e5b794 100644
--- a/src/client/application/geary-application.vala
+++ b/src/client/application/geary-application.vala
@@ -636,6 +636,13 @@ public class GearyApplication : Gtk.Application {
 
     /** Displays a URI on the current active window, if any. */
     public void show_uri(string uri) throws Error {
+        string uri_ = uri;
+
+        // Support web URLs that omit the protocol.
+        if (!uri.contains(":")) {
+            uri_ = "http://"; + uri;
+        }
+
         bool success = Gtk.show_uri_on_window(
             get_active_window(), uri, Gdk.CURRENT_TIME
         );
diff --git a/src/client/components/main-window.vala b/src/client/components/main-window.vala
index 337a73e6..74a75602 100644
--- a/src/client/components/main-window.vala
+++ b/src/client/components/main-window.vala
@@ -51,9 +51,9 @@ public class MainWindow : Gtk.ApplicationWindow, Geary.BaseInterface {
         {ACTION_EMPTY_SPAM,            on_empty_spam                   },
         {ACTION_EMPTY_TRASH,           on_empty_trash                  },
         // Message actions
-        {ACTION_REPLY_TO_MESSAGE,      on_reply_to_message     },
-        {ACTION_REPLY_ALL_MESSAGE,     on_reply_all_message    },
-        {ACTION_FORWARD_MESSAGE,       on_forward_message      },
+        {ACTION_REPLY_TO_MESSAGE,      on_reply_conversation },
+        {ACTION_REPLY_ALL_MESSAGE,     on_reply_all_conversation },
+        {ACTION_FORWARD_MESSAGE,       on_forward_conversation },
         {ACTION_ARCHIVE_CONVERSATION,  on_archive_conversation },
         {ACTION_TRASH_CONVERSATION,    on_trash_conversation   },
         {ACTION_DELETE_CONVERSATION,   on_delete_conversation  },
@@ -169,6 +169,7 @@ public class MainWindow : Gtk.ApplicationWindow, Geary.BaseInterface {
             return account;
         }
     }
+
     /** Currently selected folder, null if none selected */
     public Geary.Folder? current_folder { get; private set; default = null; }
 
@@ -539,6 +540,9 @@ public class MainWindow : Gtk.ApplicationWindow, Geary.BaseInterface {
         this.conversation_viewer = new ConversationViewer(
             this.application.config
         );
+        this.conversation_viewer.conversation_added.connect(
+            on_conversation_view_added
+        );
 
         this.main_toolbar = new MainToolbar(config);
         this.main_toolbar.move_folder_menu.folder_selected.connect(on_move_conversation);
@@ -692,6 +696,14 @@ public class MainWindow : Gtk.ApplicationWindow, Geary.BaseInterface {
         );
     }
 
+    private inline void handle_error(Geary.AccountInformation? account,
+                                     GLib.Error error) {
+        Geary.ProblemReport? report = (account != null)
+            ? new Geary.AccountProblemReport(account, error)
+            : new Geary.ProblemReport(error);
+        this.application.controller.report_problem(report);
+    }
+
     private void update_ui() {
         // Only update if we haven't done so within the last while
         int64 now = GLib.get_monotonic_time() / (1000 * 1000);
@@ -1084,7 +1096,44 @@ public class MainWindow : Gtk.ApplicationWindow, Geary.BaseInterface {
         update_command_actions();
     }
 
-    // Action callbacks
+    private void on_conversation_view_added(ConversationListBox list) {
+        list.email_added.connect(on_conversation_viewer_email_added);
+        list.mark_emails.connect(on_conversation_viewer_mark_emails);
+    }
+
+    private void on_conversation_viewer_email_added(ConversationEmail view) {
+        view.load_error.connect(on_email_load_error);
+
+        view.forward_message.connect(on_forward_message);
+        view.reply_all_message.connect(on_reply_all_message);
+        view.reply_to_message.connect(on_reply_to_message);
+        view.edit_draft.connect(on_edit_draft);
+
+        view.attachments_activated.connect(on_attachments_activated);
+        view.save_attachments.connect(on_save_attachments);
+        view.view_source.connect(on_view_source);
+
+        Geary.App.Conversation conversation = this.conversation_viewer.current_list.conversation;
+        bool in_current_folder = (
+            conversation.is_in_base_folder(view.email.id) &&
+            conversation.base_folder == current_folder
+        );
+        bool supports_trash = in_current_folder && current_folder_supports_trash();
+        bool supports_delete = in_current_folder && current_folder is Geary.FolderSupport.Remove;
+        view.trash_message.connect(on_trash_message);
+        view.delete_message.connect(on_delete_message);
+        view.set_folder_actions_enabled(supports_trash, supports_delete);
+        this.on_shift_key.connect(view.shift_key_changed);
+
+        foreach (ConversationMessage msg_view in view) {
+            msg_view.link_activated.connect(on_link_activated);
+            msg_view.save_image.connect((url, alt_text, buf) => {
+                    on_save_image_extended(view, url, alt_text, buf);
+                });
+        }
+    }
+
+    // Window-level action callbacks
 
     private void on_undo() {
         this.application.controller.undo.begin();
@@ -1123,15 +1172,15 @@ public class MainWindow : Gtk.ApplicationWindow, Geary.BaseInterface {
         }
     }
 
-    private void on_reply_to_message() {
+    private void on_reply_conversation() {
         create_composer_from_viewer(REPLY);
     }
 
-    private void on_reply_all_message() {
+    private void on_reply_all_conversation() {
         create_composer_from_viewer(REPLY_ALL);
     }
 
-    private void on_forward_message() {
+    private void on_forward_conversation() {
         create_composer_from_viewer(FORWARD);
     }
 
@@ -1223,6 +1272,150 @@ public class MainWindow : Gtk.ApplicationWindow, Geary.BaseInterface {
     }
 
     private void on_empty_trash() {
+    // Individual message view action callbacks
+
+    private void on_conversation_viewer_mark_emails(Gee.Collection<Geary.EmailIdentifier> email,
+                                                    Geary.EmailFlags? to_add,
+                                                    Geary.EmailFlags? to_remove) {
+    }
+
+    private void on_email_load_error(ConversationEmail view, GLib.Error err) {
+        handle_error(
+            this.current_account != null ? this.current_account.information : null,
+            err
+        );
+    }
+
+    private void on_reply_to_message(ConversationEmail target_view) {
+        target_view.get_selection_for_quoting.begin((obj, res) => {
+                string? quote = target_view.get_selection_for_quoting.end(res);
+                this.application.controller.compose_with_context_email(
+                    REPLY, target_view.email, quote
+                );
+            });
+    }
+
+    private void on_reply_all_message(ConversationEmail target_view) {
+        target_view.get_selection_for_quoting.begin((obj, res) => {
+                string? quote = target_view.get_selection_for_quoting.end(res);
+                this.application.controller.compose_with_context_email(
+                    REPLY_ALL, target_view.email, quote
+                );
+            });
+    }
+
+    private void on_forward_message(ConversationEmail target_view) {
+        target_view.get_selection_for_quoting.begin((obj, res) => {
+                string? quote = target_view.get_selection_for_quoting.end(res);
+                this.application.controller.compose_with_context_email(
+                    FORWARD, target_view.email, quote
+                );
+            });
+    }
+
+    private void on_edit_draft(ConversationEmail target_view) {
+        this.application.controller.compose_with_context_email(
+            NEW_MESSAGE, target_view.email, null
+        );
+    }
+
+    private void on_attachments_activated(Gee.Collection<Geary.Attachment> attachments) {
+        if (this.application.config.ask_open_attachment) {
+            QuestionDialog ask_to_open = new QuestionDialog.with_checkbox(
+                this,
+                _("Are you sure you want to open these attachments?"),
+                _("Attachments may cause damage to your system if opened.  Only open files from trusted 
sources."),
+                Stock._OPEN_BUTTON, Stock._CANCEL, _("Don’t _ask me again"), false);
+            if (ask_to_open.run() != Gtk.ResponseType.OK) {
+                return;
+            }
+            // only save checkbox state if OK was selected
+            this.application.config.ask_open_attachment = !ask_to_open.is_checked;
+        }
+
+        foreach (Geary.Attachment attachment in attachments) {
+            string uri = attachment.file.get_uri();
+            try {
+                this.application.show_uri(uri);
+            } catch (Error err) {
+                message("Unable to open attachment \"%s\": %s", uri, err.message);
+            }
+        }
+    }
+
+    private void on_save_attachments(Gee.Collection<Geary.Attachment> attachments) {
+        if (this.current_account != null) {
+            if (attachments.size == 1) {
+                this.application.controller.save_attachment_to_file.begin(
+                    this.current_account,
+                    attachments.to_array()[0],
+                    null
+                );
+            } else {
+                this.application.controller.save_attachments_to_file.begin(
+                    this.current_account,
+                    attachments
+                );
+            }
+        }
+    }
+
+    private void on_view_source(ConversationEmail email_view) {
+        string source = (email_view.email.header.buffer.to_string() +
+                         email_view.email.body.buffer.to_string());
+        string temporary_filename;
+        try {
+            int temporary_handle = FileUtils.open_tmp("geary-message-XXXXXX.txt",
+                                                      out temporary_filename);
+            FileUtils.set_contents(temporary_filename, source);
+            FileUtils.close(temporary_handle);
+
+            // ensure this file is only readable by the user ... this
+            // needs to be done after the file is closed
+            FileUtils.chmod(temporary_filename, (int) (Posix.S_IRUSR | Posix.S_IWUSR));
+
+            string temporary_uri = Filename.to_uri(temporary_filename, null);
+            this.application.show_uri(temporary_uri);
+        } catch (Error error) {
+            ErrorDialog dialog = new ErrorDialog(
+                this,
+                _("Failed to open default text editor."),
+                error.message
+            );
+            dialog.run();
+        }
+    }
+
+    private void on_save_image_extended(ConversationEmail view,
+                                        string url,
+                                        string? alt_text,
+                                        Geary.Memory.Buffer resource_buf) {
+        if (this.current_account != null) {
+            this.application.controller.save_image_extended.begin(
+                this.current_account, view, url, alt_text, resource_buf
+            );
+        }
+    }
+
+    private void on_trash_message(ConversationEmail target_view) {
+    }
+
+    private void on_delete_message(ConversationEmail target_view) {
+    }
+
+    private void on_link_activated(string uri) {
+        try {
+            if (uri.down().has_prefix(Geary.ComposedEmail.MAILTO_SCHEME)) {
+                this.application.controller.compose(uri);
+            } else {
+                this.application.show_uri(uri);
+            }
+        } catch (GLib.Error err) {
+            handle_error(
+                this.current_account != null ? this.current_account.information : null,
+                err
+            );
+        }
     }
 
 }
diff --git a/src/client/composer/composer-widget.vala b/src/client/composer/composer-widget.vala
index 8585cfa0..de5c70e7 100644
--- a/src/client/composer/composer-widget.vala
+++ b/src/client/composer/composer-widget.vala
@@ -2324,7 +2324,13 @@ public class ComposerWidget : Gtk.EventBox, Geary.BaseInterface {
         popover.link_delete.connect(() => {
                 this.editor.delete_link(selection_id);
             });
-        popover.link_open.connect(() => { link_activated(popover.link_uri); });
+        popover.link_open.connect(() => {
+                try {
+                    this.application.show_uri(popover.link_uri);
+                } catch (GLib.Error err) {
+                    debug("Failed to open URI: %s", err.message);
+                }
+            });
         return popover;
     }
 


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]