diff --git a/src/client/application/geary-application.vala b/src/client/application/geary-application.vala index 5638da87..37ed88b8 100644 --- a/src/client/application/geary-application.vala +++ b/src/client/application/geary-application.vala @@ -60,6 +60,8 @@ public class GearyApplication : Gtk.Application { public const string ACTION_HELP = "help"; public const string ACTION_MAILTO = "mailto"; public const string ACTION_PREFERENCES = "preferences"; + public const string ACTION_SHOW_EMAIL = "show-email"; + public const string ACTION_SHOW_FOLDER = "show-folder"; public const string ACTION_QUIT = "quit"; // Local-only command line options @@ -89,6 +91,8 @@ public class GearyApplication : Gtk.Application { {ACTION_MAILTO, on_activate_mailto, "s"}, {ACTION_PREFERENCES, on_activate_preferences}, {ACTION_QUIT, on_activate_quit}, + {ACTION_SHOW_EMAIL, on_activate_show_email, "(svv)"}, + {ACTION_SHOW_FOLDER, on_activate_show_folder, "(sv)"} }; // This is also the order in which they are presented to the user, @@ -727,6 +731,25 @@ public class GearyApplication : Gtk.Application { } } + private Geary.Folder? get_folder_from_action_target(GLib.Variant target) { + Geary.Folder? folder = null; + string account_id = (string) target.get_child_value(0); + try { + Geary.AccountInformation? account_config = + this.engine.get_account(account_id); + Geary.Account? account = + this.engine.get_account_instance(account_config); + Geary.FolderPath? path = + account.to_folder_path( + target.get_child_value(1).get_variant() + ); + folder = account.get_folder(path); + } catch (GLib.Error err) { + debug("Could not find account/folder %s", err.message); + } + return folder; + } + private void on_activate_about() { Gtk.show_about_dialog(get_active_window(), "program-name", NAME, @@ -783,6 +806,41 @@ public class GearyApplication : Gtk.Application { exit(); } + private void on_activate_show_email(GLib.SimpleAction action, + GLib.Variant? target) { + if (target != null) { + // Target is a (account_id,folder_path,email_id) tuple + Geary.Folder? folder = get_folder_from_action_target(target); + Geary.EmailIdentifier? email_id = null; + if (folder != null) { + try { + email_id = folder.account.to_email_identifier( + target.get_child_value(2).get_variant() + ); + } catch (GLib.Error err) { + debug("Could not find email id: %s", err.message); + } + + if (email_id != null) { + this.controller.main_window.present(); + this.controller.main_window.show_email(folder, email_id); + } + } + } + } + + private void on_activate_show_folder(GLib.SimpleAction action, + GLib.Variant? target) { + if (target != null) { + // Target is a (account_id,folder_path) tuple + Geary.Folder? folder = get_folder_from_action_target(target); + if (folder != null) { + this.controller.main_window.present(); + this.controller.main_window.show_folder(folder); + } + } + } + private void on_activate_help() { try { if (is_installed()) { diff --git a/src/client/components/main-window.vala b/src/client/components/main-window.vala index 4b53422e..db91981e 100644 --- a/src/client/components/main-window.vala +++ b/src/client/components/main-window.vala @@ -174,6 +174,30 @@ public class MainWindow : Gtk.ApplicationWindow, Geary.BaseInterface { update_infobar_frame(); } + /** Selects the given account and folder. */ + public void show_folder(Geary.Folder folder) { + this.folder_list.select_folder(folder); + } + + /** Selects the given account, folder and email. */ + public void show_email(Geary.Folder folder, Geary.EmailIdentifier id) { + // XXX this is broken in the case of the email's folder not + // being currently selected and loaded, since changing folders + // and loading the email in the conversation monitor won't + // have completed until well after is it obtained + // below. However, it should work in the only case where this + // currently used, that is when a user clicks on a + // notification for new mail in the current folder. + show_folder(folder); + Geary.App.ConversationMonitor? conversations = + this.application.controller.current_conversations; + Geary.App.Conversation? conversation = + conversations.get_by_email_identifier(id); + if (conversation != null) { + this.conversation_list_view.select_conversation(conversation); + } + } + /** Displays and focuses the search bar for the window. */ public void show_search_bar(string? text = null) { this.search_bar.give_search_focus(); diff --git a/src/client/notification/notification-desktop.vala b/src/client/notification/notification-desktop.vala index 961fcd21..356a6010 100644 --- a/src/client/notification/notification-desktop.vala +++ b/src/client/notification/notification-desktop.vala @@ -18,10 +18,8 @@ public class Notification.Desktop : Geary.BaseObject { private weak NewMessagesMonitor monitor; private weak GearyApplication application; - private GLib.Notification? current_notification = null; + private GLib.Notification? arrived_notification = null; private GLib.Notification? error_notification = null; - private Geary.Folder? folder = null; - private Geary.Email? email = null; private GLib.Cancellable load_cancellable; @@ -43,7 +41,7 @@ public class Notification.Desktop : Geary.BaseObject { public void clear_arrived_notification() { this.application.withdraw_notification(ARRIVED_ID); - this.current_notification = null; + this.arrived_notification = null; } public void set_error_notification(string summary, string body) { @@ -52,7 +50,7 @@ public class Notification.Desktop : Geary.BaseObject { // but it means in the future, a more robust system will be needed.) if (this.error_notification == null) { this.error_notification = issue_notification( - ERROR_ID, summary, body + ERROR_ID, summary, body, null, null ); } } @@ -79,10 +77,6 @@ public class Notification.Desktop : Geary.BaseObject { } private void notify_new_mail(Geary.Folder folder, int added) { - // don't pass email if invoked - this.folder = null; - this.email = null; - if (this.application.config.show_notifications && this.monitor.should_notify_new_messages(folder)) { string body = ngettext( @@ -101,8 +95,8 @@ public class Notification.Desktop : Geary.BaseObject { ).printf(body, total); } - issue_current_notification( - this.folder.account.information.display_name, body + issue_arrived_notification( + folder.account.information.display_name, body, folder, null ); } } @@ -111,10 +105,6 @@ public class Notification.Desktop : Geary.BaseObject { Geary.Email email, GLib.Cancellable? cancellable) throws GLib.Error { - // used if notification is invoked - this.folder = folder; - this.email = email; - Geary.RFC822.MailboxAddress? originator = Util.Email.get_primary_originator(email); if (this.application.config.show_notifications && @@ -140,32 +130,62 @@ public class Notification.Desktop : Geary.BaseObject { ); } - issue_current_notification( + issue_arrived_notification( contact.is_trusted ? contact.display_name : originator.to_short_display(), - body + body, + folder, + email.id ); } else { notify_new_mail(folder, 1); } } - private void issue_current_notification(string summary, string body) { + private void issue_arrived_notification(string summary, + string body, + Geary.Folder folder, + Geary.EmailIdentifier? id) { // only one outstanding notification at a time clear_arrived_notification(); + + string? action = null; + GLib.Variant[] target_param = new GLib.Variant[] { + folder.account.information.id, + new GLib.Variant.variant(folder.path.to_variant()) + }; + + if (id == null) { + action = GearyApplication.ACTION_SHOW_FOLDER; + } else { + action = GearyApplication.ACTION_SHOW_EMAIL; + target_param += new GLib.Variant.variant(id.to_variant()); + } + this.arrived_notification = issue_notification( - ARRIVED_ID, summary, body + ARRIVED_ID, + summary, + body, + "app." + action, + new GLib.Variant.tuple(target_param) ); } private GLib.Notification issue_notification(string id, string summary, - string body) { + string body, + string? action, + GLib.Variant? action_target) { GLib.Notification notification = new GLib.Notification(summary); notification.set_body(body); notification.set_icon( new GLib.ThemedIcon("%s-symbolic".printf(GearyApplication.APP_ID)) ); + if (action != null) { + notification.set_default_action_and_target_value( + action, action_target + ); + } this.application.send_notification(id, notification); return notification; }