[seahorse/wip/nielsdg/gaction-app] Port most uses of Gtk.Action to GLib.Action



commit f360df4232b18c08a125ce6c3ad4597097d99d47
Author: Niels De Graef <nielsdegraef gmail com>
Date:   Mon Dec 31 11:47:14 2018 +0100

    Port most uses of Gtk.Action to GLib.Action
    
    I wasn't planning on doing this in such a huge rework, but given that
    the way the Gtk.ActionGroups were handled was so tightly coupled
    throughout the codebase, I barely had a choice.
    
    A list of the most major changed:
    * Since it was easier to setup (compared to migrating the menubar), we
    now use a popover for our menu (together with a GMenuModel in the
    builder file).
    * A SeahorseBackend's `actions`-property can no longer be null
    * Moved some GActions from KeyManager/Catalog to SeahorseApplication
    where appropriate.
    * Moved the actions that were being registered from the Generate dialogs
    (e.g. Seahorse.Ssh.Generate) to their respective backends.

 common/actions.vala                 |  60 +-------
 common/backend.vala                 |   2 +-
 common/catalog.vala                 | 264 ++++--------------------------------
 common/key-manager-store.vala       |   2 +
 common/object.vala                  |   5 -
 gkr/gkr-backend.vala                |  76 +++++------
 gkr/gkr-keyring.vala                |   6 +-
 pgp/seahorse-gpgme-generate.c       |  52 -------
 pgp/seahorse-gpgme-key.c            |   8 +-
 pgp/seahorse-pgp-actions.c          | 120 ++++++++--------
 pgp/seahorse-pgp-actions.h          |   6 +-
 pgp/seahorse-pgp-backend.c          |   6 +-
 pkcs11/pkcs11-generate.vala         |  18 ---
 pkcs11/seahorse-pkcs11-backend.c    |  55 +++++++-
 src/application.vala                |  96 ++++++++++++-
 src/generate-select.vala            |  69 +++++-----
 src/key-manager.vala                | 193 +++++++++-----------------
 src/seahorse-key-manager-widgets.ui |  67 ++++-----
 src/seahorse-key-manager.ui         | 170 ++++++++++++++++-------
 ssh/actions.vala                    |  66 +++++----
 ssh/backend.vala                    |   3 +-
 ssh/generate.vala                   |  21 ---
 ssh/key.vala                        |   1 -
 23 files changed, 576 insertions(+), 790 deletions(-)
---
diff --git a/common/actions.vala b/common/actions.vala
index 08cd7bb2..b3252c17 100644
--- a/common/actions.vala
+++ b/common/actions.vala
@@ -18,62 +18,12 @@
  * License along with this program; if not, see <http://www.gnu.org/licenses/>.
  */
 
-namespace Seahorse {
+public class Seahorse.ActionGroup : SimpleActionGroup {
 
-public class Action {
-       public static void pre_activate(Gtk.Action action,
-                                       Catalog? catalog,
-                                       Gtk.Window? window) {
-               action.set_data("seahorse-action-window", window);
-               action.set_data("seahorse-action-catalog", catalog);
-       }
+    public string prefix { get; construct set; }
 
-       public static void activate_with_window(Gtk.Action action,
-                                               Catalog? catalog,
-                                               Gtk.Window? window) {
-               pre_activate(action, catalog, window);
-               action.activate();
-               post_activate(action);
-       }
-
-       public static void post_activate(Gtk.Action action) {
-               action.set_data("seahorse-action-window", null);
-               action.set_data("seahorse-action-catalog", null);
-       }
-
-       public static Gtk.Window? get_window(Gtk.Action action) {
-               Gtk.Window? window = action.get_data("seahorse-action-window");
-               return window;
-       }
-
-       public static Catalog? get_catalog(Gtk.Action action) {
-               Catalog? catalog = action.get_data("seahorse-action-catalog");
-               return catalog;
-       }
-}
-
-public class Actions : Gtk.ActionGroup {
-       public Catalog? catalog {
-               owned get { return (Catalog)this._catalog.get(); }
-               set { this._catalog.set(value); }
-       }
-
-       public string? definition {
-               get { return this._definition; }
-       }
-
-       private unowned string? _definition;
-       private WeakRef _catalog;
-
-       public Actions(string name) {
-               GLib.Object(
-                       name: name
-               );
-       }
-
-       public void register_definition (string definition) {
-               this._definition = definition;
-       }
-}
+    public Catalog catalog { owned get; set; }
 
+    public virtual void set_actions_for_selected_objects(List<GLib.Object> objects) {
+    }
 }
diff --git a/common/backend.vala b/common/backend.vala
index 9f245ecb..ec0508cc 100644
--- a/common/backend.vala
+++ b/common/backend.vala
@@ -22,7 +22,7 @@ public interface Backend : Gcr.Collection {
        public abstract string name { get; }
        public abstract string label { get; }
        public abstract string description { get; }
-       public abstract Gtk.ActionGroup? actions { owned get; }
+       public abstract ActionGroup actions { owned get; }
        public abstract bool loaded { get; }
 
        public abstract Place? lookup_place(string uri);
diff --git a/common/catalog.vala b/common/catalog.vala
index c61a56fc..f9c35565 100644
--- a/common/catalog.vala
+++ b/common/catalog.vala
@@ -21,43 +21,26 @@
 namespace Seahorse {
 
 public abstract class Catalog : Gtk.ApplicationWindow {
-       public const string MENU_OBJECT = "ObjectPopup";
 
        /* Set by the derived classes */
        public string ui_name { construct; get; }
 
-       private Gtk.UIManager _ui_manager;
-       private GLib.GenericSet<Gtk.ActionGroup> _actions;
-       private Gtk.Action _edit_delete;
-       private Gtk.Action _properties_object;
-       private Gtk.Action _file_export;
-       private Gtk.Action _edit_copy;
-       private GLib.List<Gtk.ActionGroup> _selection_actions;
+    protected MenuModel context_menu;
        private bool _disposed;
        private GLib.Settings _settings;
 
        public abstract GLib.List<weak Backend> get_backends();
        public abstract Place? get_focused_place();
        public abstract GLib.List<GLib.Object> get_selected_objects();
-       protected abstract void add_menu(Gtk.Widget menu);
 
-       construct {
-               this._actions = new GLib.GenericSet<Gtk.ActionGroup>(GLib.direct_hash, GLib.direct_equal);
-               this._ui_manager = new Gtk.UIManager();
-
-               this._ui_manager.add_widget.connect((widget) => {
-                       if (widget is Gtk.MenuBar)
-                               add_menu(widget);
-               });
-
-               this._ui_manager.pre_activate.connect((action) => {
-                       Action.pre_activate(action, this, this);
-               });
-
-               this._ui_manager.post_activate.connect((action) => {
-                       Action.post_activate(action);
-               });
+    private const ActionEntry[] ACTION_ENTRIES = {
+        { "file-export",         on_key_export_file },
+        { "copy",                on_key_export_clipboard },
+        { "edit-delete",         on_object_delete },
+        { "properties-object",   on_properties_object },
+    };
 
+       construct {
                /* Load window size for windows that aren't dialogs */
                var key = "/apps/seahorse/windows/%s/".printf(this.ui_name);
                this._settings = new GLib.Settings.with_path("org.gnome.seahorse.window", key);
@@ -66,43 +49,15 @@ public abstract class Catalog : Gtk.ApplicationWindow {
                if (width > 0 && height > 0)
                        this.resize (width, height);
 
-               /* The widgts get added in an idle loop later */
-               try {
-                       var path = "/org/gnome/Seahorse/seahorse-%s-widgets.ui".printf(this.ui_name);
-                       this._ui_manager.add_ui_from_resource(path);
-               } catch (GLib.Error err) {
-                       GLib.warning("couldn't load ui description for '%s': %s",
-                                    this.ui_name, err.message);
-               }
-
-               this.add_accel_group (this._ui_manager.get_accel_group());
-
-               var actions = new Gtk.ActionGroup("main");
-               actions.set_translation_domain(Config.GETTEXT_PACKAGE);
-               actions.add_actions(UI_ENTRIES, this);
+        Gtk.Builder builder = new Gtk.Builder.from_resource(
+            "/org/gnome/Seahorse/seahorse-%s-widgets.ui".printf(this.ui_name)
+        );
+        this.context_menu = (MenuModel) builder.get_object("context_menu");
 
-               var action = actions.get_action("app-preferences");
-               action.set_visible (Prefs.available());
-               this._edit_delete = actions.get_action("edit-delete");
-               this._properties_object = actions.get_action("properties-object");
-               this._edit_copy = actions.get_action("edit-export-clipboard");
-               this._file_export = actions.get_action("file-export");
-               this._ui_manager.insert_action_group (actions, 0);
+        add_action_entries (ACTION_ENTRIES, this);
        }
 
        public override void dispose() {
-               this._edit_copy = null;
-               this._edit_delete = null;
-               this._file_export = null;
-               this._properties_object = null;
-
-               foreach (var group in this._selection_actions)
-                       this._ui_manager.remove_action_group(group);
-               this._selection_actions = null;
-
-               this._ui_manager = null;
-               this._actions.remove_all();
-
                if (!this._disposed) {
                        this._disposed = true;
 
@@ -132,140 +87,28 @@ public abstract class Catalog : Gtk.ApplicationWindow {
                                break;
                }
 
-               this._properties_object.sensitive = can_properties;
-               this._edit_delete.sensitive = can_delete;
-               this._edit_copy.sensitive = can_export;
-               this._file_export.sensitive = can_export;
-
-               foreach (var group in this._selection_actions)
-                       group.visible = false;
-               this._selection_actions = lookup_actions_for_objects(objects);
-               foreach (var group in this._selection_actions)
-                       group.visible = true;
-       }
-
-       public void ensure_updated() {
-               this._ui_manager.ensure_update();
-       }
-
-       public void include_actions(Gtk.ActionGroup group) {
-               this._ui_manager.insert_action_group(group, 10);
-
-               if (group is Actions) {
-                       var actions = (Actions)group;
-                       actions.catalog = this;
-
-                       var definition = actions.definition;
-                       if (definition != null) {
-                               try {
-                                       this._ui_manager.add_ui_from_string (definition, -1);
-                               } catch (GLib.Error err) {
-                                       GLib.warning ("couldn't add ui defintion for action group: %s: %s",
-                                                     actions.name, definition);
-                               }
-                       }
-               }
-
-               this._actions.add(group);
-       }
+        ((SimpleAction) lookup_action("properties-object")).set_enabled(can_properties);
+        ((SimpleAction) lookup_action("edit-delete")).set_enabled(can_delete);;
+        ((SimpleAction) lookup_action("copy")).set_enabled(can_export);
+        ((SimpleAction) lookup_action("file-export")).set_enabled(can_export);
+    }
 
        public void show_properties(GLib.Object obj) {
                Viewable.view(obj, this);
        }
 
-    public void show_context_menu(string name, Gdk.Event? event) {
-        var widget = this._ui_manager.get_widget("/%s".printf(name));
-
-        Gtk.Menu? menu = widget as Gtk.Menu;
-        if (menu == null) {
-            warning("the object /%s isn't a menu", name);
-            return;
+    public void show_context_menu(Gdk.Event? event) {
+        Gtk.Menu menu = new Gtk.Menu.from_model(this.context_menu);
+        menu.insert_action_group("win", this);
+        foreach (weak Backend backend in get_backends()) {
+            ActionGroup actions = backend.actions;
+            menu.insert_action_group(actions.prefix, actions);
         }
         menu.popup_at_pointer(event);
         menu.show();
     }
 
-       private GLib.List<Gtk.ActionGroup> lookup_actions_for_objects (GLib.List<GLib.Object> objects) {
-               var table = new GLib.HashTable<Gtk.ActionGroup, weak Gtk.ActionGroup>(GLib.direct_hash, 
GLib.direct_equal);
-               foreach (var object in objects) {
-                       Gtk.ActionGroup? actions = null;
-                       object.get("actions", out actions, null);
-                       if (actions == null)
-                               continue;
-                       if (!this._actions.contains(actions))
-                               this.include_actions(actions);
-                       this._actions.add(actions);
-               }
-
-               var iter = GLib.HashTableIter<Gtk.ActionGroup, weak Gtk.ActionGroup>(table);
-               var results = new GLib.List<Gtk.ActionGroup>();
-               Gtk.ActionGroup group;
-               while (iter.next(out group, null))
-                       results.prepend(group);
-
-               return results;
-       }
-
-       [CCode (instance_pos = -1)]
-       private void on_app_preferences (Gtk.Action action) {
-        Prefs prefs_dialog = new Prefs(this);
-        prefs_dialog.run();
-        prefs_dialog.destroy();
-       }
-
-       private const string[] AUTHORS = {
-               "Jacob Perkins <jap1 users sourceforge net>",
-               "Jose Carlos Garcia Sogo <jsogo users sourceforge net>",
-               "Jean Schurger <yshark schurger org>",
-               "Stef Walter <stef memberwebs com>",
-               "Adam Schreiber <sadam clemson edu>",
-               "Niels De Graef <nielsdegraef gmail com>",
-               "",
-               N_("Contributions:"),
-               "Albrecht Dreß <albrecht dress arcor de>",
-               "Jim Pharis <binbrain gmail com>",
-               null
-       };
-
-       private const string[] DOCUMENTERS = {
-               "Jacob Perkins <jap1 users sourceforge net>",
-               "Adam Schreiber <sadam clemson edu>",
-               "Milo Casagrande <milo_casagrande yahoo it>",
-               null
-       };
-
-       private const string[] ARTISTS = {
-               "Jacob Perkins <jap1 users sourceforge net>",
-               "Stef Walter <stef memberwebs com>",
-               null
-       };
-
-       [CCode (instance_pos = -1)]
-       private void on_app_about(Gtk.Action action) {
-               var about = new Gtk.AboutDialog();
-               about.set_artists(ARTISTS);
-               about.set_authors(AUTHORS);
-               about.set_documenters(DOCUMENTERS);
-               about.set_version(Config.VERSION);
-               about.set_comments(_("Passwords and Keys"));
-               about.set_copyright("© 2002 - 2018 Seahorse Contributors");
-               about.set_translator_credits(_("translator-credits"));
-               about.set_logo_icon_name("seahorse");
-               about.set_website("https://wiki.gnome.org/Apps/Seahorse";);
-               about.set_website_label(_("Seahorse Project Homepage"));
-
-               about.response.connect((response) => {
-                       about.hide();
-               });
-
-               about.set_transient_for(this);
-               about.run();
-               about.destroy();
-       }
-
-       [CCode (instance_pos = -1)]
-       private void on_object_delete(Gtk.Action action)
-       {
+       private void on_object_delete(SimpleAction action, Variant? param) {
                try {
                        var objects = this.get_selected_objects();
                        Deletable.delete_with_prompt_wait(objects, this);
@@ -274,31 +117,21 @@ public abstract class Catalog : Gtk.ApplicationWindow {
                }
        }
 
-       [CCode (instance_pos = -1)]
-       private void on_properties_object(Gtk.Action action) {
+       private void on_properties_object(SimpleAction action, Variant? param) {
                var objects = get_selected_objects();
                if (objects.length() > 0)
-                       this.show_properties(objects.data);
-       }
-
-       [CCode (instance_pos = -1)]
-       private void on_properties_place (Gtk.Action action) {
-               var place = this.get_focused_place ();
-               if (place != null)
-                       this.show_properties (place);
+                       show_properties(objects.data);
        }
 
-       [CCode (instance_pos = -1)]
-       private void on_key_export_file (Gtk.Action action) {
+       private void on_key_export_file(SimpleAction action, Variant? param) {
                try {
-                       Exportable.export_to_prompt_wait(this.get_selected_objects(), this);
+                       Exportable.export_to_prompt_wait(get_selected_objects(), this);
                } catch (GLib.Error err) {
                        Util.show_error(this, _("Couldn’t export keys"), err.message);
                }
        }
 
-       [CCode (instance_pos = -1)]
-       private void on_key_export_clipboard (Gtk.Action action) {
+       private void on_key_export_clipboard (SimpleAction action, Variant? param) {
                uint8[] output;
                try {
                        var objects = this.get_selected_objects ();
@@ -313,43 +146,6 @@ public abstract class Catalog : Gtk.ApplicationWindow {
                var board = Gtk.Clipboard.get(Gdk.SELECTION_CLIPBOARD);
                board.set_text ((string)output, output.length);
        }
-
-       [CCode (instance_pos = -1)]
-       private void on_help_show(Gtk.Action action) {
-               try {
-                       var document = "help:%s".printf(Config.PACKAGE);
-                       GLib.AppInfo.launch_default_for_uri(document, null);
-               } catch (GLib.Error err) {
-                       Util.show_error(this, _("Could not display help: %s"), err.message);
-               }
-       }
-
-       private const Gtk.ActionEntry[] UI_ENTRIES = {
-               /* Top menu items */
-               { "file-menu", null, N_("_File") },
-               { "file-export", null, N_("E_xport…"), null,
-          N_("Export to a file"), on_key_export_file },
-               { "edit-menu", null, N_("_Edit") },
-               { "edit-export-clipboard", null, N_("_Copy"), "<control>C",
-                 N_("Copy to the clipboard"), on_key_export_clipboard },
-               /*Translators: This text refers to deleting an item from its type's backing store*/
-               { "edit-delete", null, N_("_Delete"), null,
-                 N_("Delete selected items"), on_object_delete },
-               { "properties-object", null, N_("_Properties"), null,
-                 N_("Show the properties of this item"), on_properties_object },
-               { "properties-keyring", null, N_("_Properties"), null,
-                 N_("Show the properties of this keyring"), on_properties_place },
-               { "app-preferences", null, N_("Prefere_nces"), null,
-                 N_("Change preferences for this program"), on_app_preferences },
-               { "view-menu", null, N_("_View") },
-               { "help-menu", null, N_("_Help") },
-               { "app-about", null, N_("_About"), null,
-                 N_("About this program"), on_app_about },
-               { "help-show", null, N_("_Contents"), "F1",
-                 N_("Show Seahorse help"), on_help_show }
-       };
-
-
 }
 
 }
diff --git a/common/key-manager-store.vala b/common/key-manager-store.vala
index 16a811ae..d7e7aa9a 100644
--- a/common/key-manager-store.vala
+++ b/common/key-manager-store.vala
@@ -49,12 +49,14 @@ public class Seahorse.KeyManagerStore : Gcr.CollectionModel {
             switch (str) {
                 case null:
                 case "":
+                case "any":
                     return ShowFilter.ANY;
                 case "personal":
                     return ShowFilter.PERSONAL;
                 case "trusted":
                     return ShowFilter.TRUSTED;
                 default:
+                    critical ("Got unknown ShowFilter string: %s", str);
                     assert_not_reached();
             }
         }
diff --git a/common/object.vala b/common/object.vala
index 52f4435a..4fa7bfc1 100644
--- a/common/object.vala
+++ b/common/object.vala
@@ -31,11 +31,6 @@ public class Seahorse.Object : GLib.Object {
      */
     public weak Place place { get; set; default = null; }
 
-    /**
-     * Actions for the object
-     */
-    public Gtk.ActionGroup? actions { get; set; default = null; }
-
     /**
      * Stock ID for this Object.
      */
diff --git a/gkr/gkr-backend.vala b/gkr/gkr-backend.vala
index 1abdab52..6d74ac1c 100644
--- a/gkr/gkr-backend.vala
+++ b/gkr/gkr-backend.vala
@@ -47,9 +47,9 @@ public class Backend: GLib.Object , Gcr.Collection, Seahorse.Backend {
                get { return _("Stored personal passwords, credentials and secrets"); }
        }
 
-       public Gtk.ActionGroup? actions {
-               owned get { return this._actions; }
-       }
+    public ActionGroup actions {
+        owned get { return this._actions; }
+    }
 
        public GLib.HashTable<string, string> aliases {
                get { return this._aliases; }
@@ -68,7 +68,7 @@ public class Backend: GLib.Object , Gcr.Collection, Seahorse.Backend {
        private Secret.Service _service;
        private GLib.HashTable<string, Keyring> _keyrings;
        private GLib.HashTable<string, string> _aliases;
-       private Gtk.ActionGroup _actions;
+       private ActionGroup _actions;
 
        construct {
                return_val_if_fail(_instance == null, null);
@@ -100,7 +100,7 @@ public class Backend: GLib.Object , Gcr.Collection, Seahorse.Backend {
        public override void dispose() {
                this._aliases.remove_all();
                this._keyrings.remove_all();
-               this._actions.sensitive = false;
+               /* this._actions.sensitive = false; */
                base.dispose();
        }
 
@@ -208,14 +208,18 @@ public class Backend: GLib.Object , Gcr.Collection, Seahorse.Backend {
        }
 }
 
-public class BackendActions : Seahorse.Actions {
+public class BackendActions : Seahorse.ActionGroup {
        public Backend backend { construct; get; }
        private static WeakRef _instance;
        private bool _initialized;
 
+       private const ActionEntry[] BACKEND_ACTIONS = {
+               { "keyring-new",      on_new_keyring },
+               { "keyring-item-new", on_new_item },
+       };
+
        construct {
                this._initialized = false;
-               this.set_translation_domain(Config.GETTEXT_PACKAGE);
 
                this.backend.notify.connect_after((pspec) => {
                        if (pspec.name == "service")
@@ -226,53 +230,41 @@ public class BackendActions : Seahorse.Actions {
                                        return;
 
                        this._initialized = true;
-                       this.add_actions(BACKEND_ACTIONS, null);
-                       this.register_definition(BACKEND_UI);
-
-                       /* Register another set of actions as a generator */
-                       var actions = new Gtk.ActionGroup("gkr-generate");
-                       actions.set_translation_domain(Config.GETTEXT_PACKAGE);
-                       actions.add_actions(ENTRIES_NEW, null);
-                       Registry.register_object(actions, "generator");
+                       add_action_entries(BACKEND_ACTIONS, this);
+                       register_generator_actions();
                });
 
                this.backend.notify_property("service");
        }
 
        private BackendActions(Backend backend) {
-               GLib.Object(name: "KeyringBackend", backend: backend);
-       }
-
-       private static void on_new_keyring(Gtk.Action action) {
-               new KeyringAdd(Action.get_window(action));
+               GLib.Object(
+                       prefix: "gkr",
+                       backend: backend
+               );
        }
 
-       private static void on_new_item(Gtk.Action action) {
-               new ItemAdd(Action.get_window(action));
-       }
+    public void register_generator_actions() {
+        var new_keyring_action = lookup_action("keyring-new");
+        new_keyring_action.set_data("label", _("Password keyring"));
+        new_keyring_action.set_data("description", _("Used to store application and network passwords"));
+               Registry.register_object(new_keyring_action, "generator");
 
-       private const Gtk.ActionEntry[] BACKEND_ACTIONS = {
-               { "keyring-new", null, N_("New password keyring"), "",
-                 N_("Used to store application and network passwords"), on_new_keyring },
-               { "keyring-item-new", null, N_("New password…"), "",
-                 N_("Safely store a password or secret."), on_new_item },
-       };
+        var new_pw_action = lookup_action("keyring-item-new");
+        new_pw_action.set_data("label", _("Password"));
+        new_pw_action.set_data("description", _("Safely store a password or secret."));
+               Registry.register_object(new_pw_action, "generator");
+    }
 
-       private const Gtk.ActionEntry[] ENTRIES_NEW = {
-               { "keyring-new", "folder", N_("Password Keyring"), "",
-                 N_("Used to store application and network passwords"), on_new_keyring },
-               { "keyring-item-new", ICON_PASSWORD, N_("Stored Password"), "",
-                 N_("Safely store a password or secret."), on_new_item }
-       };
+       private void on_new_keyring(SimpleAction action, Variant? param) {
+               new KeyringAdd(this.catalog);
+       }
 
-       private const string BACKEND_UI =
-               """"<ui>
-                       <popup name='SeahorseGkrBackend'>
-                               <menuitem action='keyring-new'/>
-                       </popup>
-               </ui>""";
+       private void on_new_item(SimpleAction action, Variant? param) {
+               new ItemAdd(this.catalog);
+       }
 
-       public static Gtk.ActionGroup instance(Backend backend) {
+       public static ActionGroup instance(Backend backend) {
                BackendActions? actions = (BackendActions?)_instance.get();
                if (actions != null)
                        return actions;
diff --git a/gkr/gkr-keyring.vala b/gkr/gkr-keyring.vala
index 096bb0ae..306c6a19 100644
--- a/gkr/gkr-keyring.vala
+++ b/gkr/gkr-keyring.vala
@@ -163,7 +163,8 @@ public class Keyring : Secret.Collection, Gcr.Collection, Place, Deletable, Lock
 
        [CCode (instance_pos = -1)]
        public void on_keyring_default(Gtk.Action? action) {
-               var parent = (action != null)? Action.get_window(action) : null;
+               /* var parent = (action != null)? Action.get_window(action) : null; */
+               var parent = null;
                var service = this.service;
 
                service.set_alias.begin("default", this, null, (obj, res) => {
@@ -178,7 +179,8 @@ public class Keyring : Secret.Collection, Gcr.Collection, Place, Deletable, Lock
 
        [CCode (instance_pos = -1)]
        public void on_keyring_password (Gtk.Action? action) {
-               var parent = (action != null)? Action.get_window(action) : null;
+               /* var parent = (action != null)? Action.get_window(action) : null; */
+               var parent = null;
                var service = this.service;
                service.get_connection().call.begin(service.get_name(),
                                                    service.get_object_path(),
diff --git a/pgp/seahorse-gpgme-generate.c b/pgp/seahorse-gpgme-generate.c
index 466b2b9f..abcf6a82 100644
--- a/pgp/seahorse-gpgme-generate.c
+++ b/pgp/seahorse-gpgme-generate.c
@@ -60,58 +60,6 @@ void           on_gpgme_generate_expires_toggled             (GtkToggleButton *b
 void           on_gpgme_generate_algorithm_changed           (GtkComboBox *combo,
                                                               gpointer user_data);
 
-/* --------------------------------------------------------------------------
- * ACTIONS
- */
-
-/**
- * on_pgp_generate_key:
- * @action: verified to be an action, not more
- * @unused: not used
- *
- * Calls the function that displays the key creation dialog
- *
- */
-static void
-on_pgp_generate_key (GtkAction *action, gpointer unused)
-{
-       SeahorseGpgmeKeyring* keyring;
-
-       g_return_if_fail (GTK_IS_ACTION (action));
-
-       keyring = seahorse_pgp_backend_get_default_keyring (NULL);
-       g_return_if_fail (keyring != NULL);
-
-       seahorse_gpgme_generate_show (keyring,
-                                     seahorse_action_get_window (action),
-                                     NULL, NULL, NULL);
-}
-
-static const GtkActionEntry ACTION_ENTRIES[] = {
-       { "pgp-generate-key", GCR_ICON_KEY_PAIR, N_ ("PGP Key"), "",
-         N_("Used to encrypt email and files"), G_CALLBACK (on_pgp_generate_key) }
-};
-
-/**
- * seahorse_gpgme_generate_register:
- *
- * Registers the action group for the pgp key creation dialog
- *
- */
-void
-seahorse_gpgme_generate_register (void)
-{
-       GtkActionGroup *actions;
-       
-       actions = gtk_action_group_new ("gpgme-generate");
-
-       gtk_action_group_set_translation_domain (actions, GETTEXT_PACKAGE);
-       gtk_action_group_add_actions (actions, ACTION_ENTRIES, G_N_ELEMENTS (ACTION_ENTRIES), NULL);
-       
-       /* Register this as a generator */
-       seahorse_registry_register_object (G_OBJECT (actions), "generator");
-}
-
 /* --------------------------------------------------------------------------
  * DIALOGS
  */
diff --git a/pgp/seahorse-gpgme-key.c b/pgp/seahorse-gpgme-key.c
index ac52c2a9..69807de5 100644
--- a/pgp/seahorse-gpgme-key.c
+++ b/pgp/seahorse-gpgme-key.c
@@ -308,7 +308,7 @@ void
 seahorse_gpgme_key_realize (SeahorseGpgmeKey *self)
 {
        SeahorseUsage usage;
-       GtkActionGroup *actions;
+       /* GtkActionGroup *actions; */
        guint flags;
 
        if (!self->pv->pubkey)
@@ -359,13 +359,13 @@ seahorse_gpgme_key_realize (SeahorseGpgmeKey *self)
                usage = SEAHORSE_USAGE_PUBLIC_KEY;
        }
 
-       actions = seahorse_gpgme_key_actions_instance ();
+       /* actions = seahorse_gpgme_key_actions_instance (); */
        g_object_set (self,
                      "usage", usage,
                      "object-flags", flags,
-                     "actions", actions,
+                     /* "actions", actions, */
                      NULL);
-       g_object_unref (actions);
+       /* g_object_unref (actions); */
 
        seahorse_pgp_key_realize (SEAHORSE_PGP_KEY (self));
 }
diff --git a/pgp/seahorse-pgp-actions.c b/pgp/seahorse-pgp-actions.c
index 3bffb92d..dd17b437 100644
--- a/pgp/seahorse-pgp-actions.c
+++ b/pgp/seahorse-pgp-actions.c
@@ -47,48 +47,43 @@ GType   seahorse_pgp_backend_actions_get_type         (void) G_GNUC_CONST;
 #define SEAHORSE_PGP_BACKEND_ACTIONS_GET_CLASS(obj)   (G_TYPE_INSTANCE_GET_CLASS ((obj), 
SEAHORSE_PGP_TYPE_BACKEND_ACTIONS, SeahorsePgpBackendActionsClass))
 
 typedef struct {
-       SeahorseActions parent_instance;
+       SeahorseActionGroup parent_instance;
 } SeahorsePgpBackendActions;
 
 typedef struct {
-       SeahorseActionsClass parent_class;
+       SeahorseActionGroupClass parent_class;
 } SeahorsePgpBackendActionsClass;
 
-G_DEFINE_TYPE (SeahorsePgpBackendActions, seahorse_pgp_backend_actions, SEAHORSE_TYPE_ACTIONS);
+G_DEFINE_TYPE (SeahorsePgpBackendActions, seahorse_pgp_backend_actions, SEAHORSE_TYPE_ACTION_GROUP);
 
 #ifdef WITH_KEYSERVER
 
-static const gchar* BACKEND_DEFINITION = ""\
-"<ui>"\
-"      <menubar>"\
-"              <placeholder name='RemoteMenu'>"\
-"                      <menu name='Remote' action='remote-menu'>"\
-"                              <menuitem action='remote-find'/>"\
-"                              <menuitem action='remote-sync'/>"\
-"                      </menu>"\
-"              </placeholder>"\
-"      </menubar>"\
-"</ui>";
-
 static void
-on_remote_find (GtkAction* action,
+on_remote_find (GSimpleAction *action,
+                GVariant *param,
                 gpointer user_data)
 {
-       seahorse_keyserver_search_show (seahorse_action_get_window (action));
+       SeahorseActionGroup *actions = SEAHORSE_ACTION_GROUP (user_data);
+       SeahorseCatalog *catalog;
+
+       catalog = seahorse_action_group_get_catalog (actions);
+       seahorse_keyserver_search_show (GTK_WINDOW (catalog));
+       g_clear_object (&catalog);
 }
 
 static void
-on_remote_sync (GtkAction* action,
+on_remote_sync (GSimpleAction *action,
+                GVariant *param,
                 gpointer user_data)
 {
-       SeahorseActions *actions = SEAHORSE_ACTIONS (user_data);
+       SeahorseActionGroup *actions = SEAHORSE_ACTION_GROUP (user_data);
        SeahorseGpgmeKeyring *keyring;
        SeahorseCatalog *catalog;
        GList *objects = NULL;
        GList *keys = NULL;
        GList *l;
 
-       catalog = seahorse_actions_get_catalog (actions);
+       catalog = seahorse_action_group_get_catalog (actions);
        if (catalog != NULL) {
                objects = seahorse_catalog_get_selected_objects (catalog);
                for (l = objects; l != NULL; l = g_list_next (l)) {
@@ -104,34 +99,59 @@ on_remote_sync (GtkAction* action,
                keys = gcr_collection_get_objects (GCR_COLLECTION (keyring));
        }
 
-       seahorse_keyserver_sync_show (keys, seahorse_action_get_window (action));
+       seahorse_keyserver_sync_show (keys, GTK_WINDOW (catalog));
        g_list_free (keys);
 }
 
-static const GtkActionEntry FIND_ACTIONS[] = {
-       { "remote-find", GTK_STOCK_FIND, N_("_Find Remote Keys…"), "",
-         N_("Search for keys on a key server"), G_CALLBACK (on_remote_find) },
-};
+#endif /* WITH_KEYSERVER */
 
-static const GtkActionEntry SYNC_ACTIONS[] = {
-       { "remote-sync", GTK_STOCK_REFRESH, N_("_Sync and Publish Keys…"), "",
-         N_("Publish and/or synchronize your keys with those online."), G_CALLBACK (on_remote_sync) }
-};
+static void
+on_pgp_generate_key (GSimpleAction *action,
+                     GVariant *param,
+                     gpointer user_data)
+{
+       SeahorseActionGroup *actions = SEAHORSE_ACTION_GROUP (user_data);
+       SeahorseGpgmeKeyring* keyring;
+       SeahorseCatalog *catalog;
+
+       keyring = seahorse_pgp_backend_get_default_keyring (NULL);
+       g_return_if_fail (keyring != NULL);
+
+       catalog = seahorse_action_group_get_catalog (actions);
+       seahorse_gpgme_generate_show (keyring,
+                                  GTK_WINDOW (catalog),
+                                     NULL, NULL, NULL);
+       g_clear_object (&catalog);
+}
 
+static const GActionEntry ACTION_ENTRIES[] = {
+    { "pgp-generate-key", on_pgp_generate_key },
+#ifdef WITH_KEYSERVER
+    { "remote-sync",      on_remote_sync },
+    { "remote-find",      on_remote_find }
 #endif /* WITH_KEYSERVER */
+};
 
 static void
 seahorse_pgp_backend_actions_init (SeahorsePgpBackendActions *self)
 {
-#ifdef WITH_KEYSERVER
-       GtkActionGroup *actions = GTK_ACTION_GROUP (self);
-       gtk_action_group_set_translation_domain (actions, GETTEXT_PACKAGE);
-       gtk_action_group_add_actions (actions, FIND_ACTIONS,
-                                     G_N_ELEMENTS (FIND_ACTIONS), NULL);
-       gtk_action_group_add_actions (actions, SYNC_ACTIONS,
-                                     G_N_ELEMENTS (SYNC_ACTIONS), self);
-       seahorse_actions_register_definition (SEAHORSE_ACTIONS (self), BACKEND_DEFINITION);
-#endif
+    GActionMap *action_map = G_ACTION_MAP (self);
+    GAction *generator_action = NULL;
+
+    g_action_map_add_action_entries (action_map,
+                                     ACTION_ENTRIES,
+                                     G_N_ELEMENTS (ACTION_ENTRIES),
+                                     self);
+
+    /* Register generator actions */
+    generator_action = g_action_map_lookup_action (action_map,
+                                                   "pgp-generate-key");
+    g_object_set_data (G_OBJECT (generator_action),
+                       "label", _("PGP Key"));
+    g_object_set_data (G_OBJECT (generator_action),
+                       "description", _("Used to encrypt email and files"));
+    seahorse_registry_register_object (G_OBJECT (generator_action),
+                                       "generator");
 }
 
 static void
@@ -140,14 +160,14 @@ seahorse_pgp_backend_actions_class_init (SeahorsePgpBackendActionsClass *klass)
 
 }
 
-GtkActionGroup *
+SeahorseActionGroup *
 seahorse_pgp_backend_actions_instance (void)
 {
-       static GtkActionGroup *actions = NULL;
+       static SeahorseActionGroup *actions = NULL;
 
        if (actions == NULL) {
                actions = g_object_new (SEAHORSE_PGP_TYPE_BACKEND_ACTIONS,
-                                       "name", "pgp-backend",
+                                       "prefix", "pgp",
                                        NULL);
                g_object_add_weak_pointer (G_OBJECT (actions),
                                           (gpointer *)&actions);
@@ -167,24 +187,18 @@ GType   seahorse_gpgme_key_actions_get_type       (void) G_GNUC_CONST;
 #define seahorse_gpgme_key_actions_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), 
SEAHORSE_PGP_TYPE_ACTIONS, SeahorseGpgmeKeyActionsClass))
 
 typedef struct {
-       SeahorseActions parent_instance;
+       SeahorseActionGroup parent_instance;
 } SeahorseGpgmeKeyActions;
 
 typedef struct {
-       SeahorseActionsClass parent_class;
+       SeahorseActionGroupClass parent_class;
 } SeahorseGpgmeKeyActionsClass;
 
-G_DEFINE_TYPE (SeahorseGpgmeKeyActions, seahorse_gpgme_key_actions, SEAHORSE_TYPE_ACTIONS);
+G_DEFINE_TYPE (SeahorseGpgmeKeyActions, seahorse_gpgme_key_actions, SEAHORSE_TYPE_ACTION_GROUP);
 
 static void
 seahorse_gpgme_key_actions_init (SeahorseGpgmeKeyActions *self)
 {
-#ifdef WITH_KEYSERVER
-       GtkActionGroup *actions = GTK_ACTION_GROUP (self);
-       gtk_action_group_set_translation_domain (actions, GETTEXT_PACKAGE);
-       gtk_action_group_add_actions (actions, SYNC_ACTIONS,
-                                     G_N_ELEMENTS (SYNC_ACTIONS), NULL);
-#endif
 }
 
 static void
@@ -193,14 +207,14 @@ seahorse_gpgme_key_actions_class_init (SeahorseGpgmeKeyActionsClass *klass)
 
 }
 
-GtkActionGroup *
+SeahorseActionGroup *
 seahorse_gpgme_key_actions_instance (void)
 {
-       static GtkActionGroup *actions = NULL;
+       static SeahorseActionGroup *actions = NULL;
 
        if (actions == NULL) {
                actions = g_object_new (SEAHORSE_TYPE_GPGME_KEY_ACTIONS,
-                                       "name", "gpgme-key",
+                                       "prefix", "gpgme",
                                        NULL);
                g_object_add_weak_pointer (G_OBJECT (actions),
                                           (gpointer *)&actions);
diff --git a/pgp/seahorse-pgp-actions.h b/pgp/seahorse-pgp-actions.h
index 2e131442..12370321 100644
--- a/pgp/seahorse-pgp-actions.h
+++ b/pgp/seahorse-pgp-actions.h
@@ -21,8 +21,8 @@
 
 #pragma once
 
-#include <gtk/gtk.h>
+#include <seahorse-common.h>
 
-GtkActionGroup *      seahorse_pgp_backend_actions_instance    (void);
+SeahorseActionGroup * seahorse_pgp_backend_actions_instance    (void);
 
-GtkActionGroup *      seahorse_gpgme_key_actions_instance      (void);
+SeahorseActionGroup * seahorse_gpgme_key_actions_instance      (void);
diff --git a/pgp/seahorse-pgp-backend.c b/pgp/seahorse-pgp-backend.c
index fa190cd3..a525b1c1 100644
--- a/pgp/seahorse-pgp-backend.c
+++ b/pgp/seahorse-pgp-backend.c
@@ -54,7 +54,7 @@ struct _SeahorsePgpBackend {
     SeahorseDiscovery *discovery;
     SeahorseUnknownSource *unknown;
     GHashTable *remotes;
-    GtkActionGroup *actions;
+    SeahorseActionGroup *actions;
     gboolean loaded;
 };
 
@@ -77,8 +77,6 @@ seahorse_pgp_backend_init (SeahorsePgpBackend *self)
                                               g_free, g_object_unref);
 
        self->actions = seahorse_pgp_backend_actions_instance ();
-
-       seahorse_gpgme_generate_register ();
 }
 
 #ifdef WITH_KEYSERVER
@@ -195,7 +193,7 @@ seahorse_pgp_backend_get_description (SeahorseBackend *backend)
        return _("PGP keys are for encrypting email or files");
 }
 
-static GtkActionGroup *
+static SeahorseActionGroup *
 seahorse_pgp_backend_get_actions (SeahorseBackend *backend)
 {
        SeahorsePgpBackend *self = SEAHORSE_PGP_BACKEND (backend);
diff --git a/pkcs11/pkcs11-generate.vala b/pkcs11/pkcs11-generate.vala
index 8e72cd72..adb575aa 100644
--- a/pkcs11/pkcs11-generate.vala
+++ b/pkcs11/pkcs11-generate.vala
@@ -273,22 +273,4 @@ public class Seahorse.Pkcs11.Generate : Gtk.Dialog {
         publi.clear();
         priva.clear();
     }
-
-    private static void on_generate_activate(Gtk.Action action) {
-        Generate dialog = new Generate(null);
-        dialog.run();
-        dialog.destroy();
-    }
-
-    private const Gtk.ActionEntry ACTION_ENTRIES[] = {
-        { "pkcs11-generate-key", Gcr.ICON_KEY_PAIR, N_ ("Private key"), "",
-          N_("Used to request a certificate"), on_generate_activate }
-    };
-
-    public static void register () {
-        Gtk.ActionGroup actions = new Gtk.ActionGroup("pkcs11-generate");
-        actions.set_translation_domain(Config.GETTEXT_PACKAGE);
-        actions.add_actions(ACTION_ENTRIES, null);
-        Registry.register_object(actions, "generator");
-    }
 }
diff --git a/pkcs11/seahorse-pkcs11-backend.c b/pkcs11/seahorse-pkcs11-backend.c
index fe907635..15318040 100644
--- a/pkcs11/seahorse-pkcs11-backend.c
+++ b/pkcs11/seahorse-pkcs11-backend.c
@@ -49,6 +49,7 @@ static SeahorsePkcs11Backend *pkcs11_backend = NULL;
 
 struct _SeahorsePkcs11Backend {
        GObject parent;
+       SeahorseActionGroup *actions;
        GList *tokens;
        GList *blacklist;
        gboolean loaded;
@@ -65,6 +66,13 @@ static const char *token_blacklist[] = {
        NULL
 };
 
+static void
+on_generate_activate (GSimpleAction *action, GVariant *param, gpointer user_data);
+
+static const GActionEntry ACTION_ENTRIES[] = {
+    { "pkcs11-generate-key", on_generate_activate  }
+};
+
 static void         seahorse_pkcs11_backend_iface            (SeahorseBackendIface *iface);
 
 static void         seahorse_pkcs11_backend_collection_init  (GcrCollectionIface *iface);
@@ -74,6 +82,30 @@ G_DEFINE_TYPE_WITH_CODE (SeahorsePkcs11Backend, seahorse_pkcs11_backend, G_TYPE_
                          G_IMPLEMENT_INTERFACE (SEAHORSE_TYPE_BACKEND, seahorse_pkcs11_backend_iface);
 );
 
+static void
+init_actions (SeahorsePkcs11Backend *self)
+{
+    GAction *generator_action;
+
+    self->actions = g_object_new (SEAHORSE_TYPE_ACTION_GROUP,
+                                  "prefix", "pkcs11",
+                                  NULL);
+    g_action_map_add_action_entries (G_ACTION_MAP (self->actions),
+                                     ACTION_ENTRIES,
+                                     G_N_ELEMENTS (ACTION_ENTRIES),
+                                     self->actions);
+
+    /* Register the generator actions */
+    generator_action = g_action_map_lookup_action(G_ACTION_MAP (self->actions),
+                                                  "pkcs11-generate-key");
+    g_object_set_data (G_OBJECT (generator_action),
+                       "label", _("Private key"));
+    g_object_set_data (G_OBJECT (generator_action),
+                       "description", _("Used to request a certificate"));
+    seahorse_registry_register_object (G_OBJECT (generator_action),
+                                       "generator");
+}
+
 static void
 seahorse_pkcs11_backend_init (SeahorsePkcs11Backend *self)
 {
@@ -93,7 +125,7 @@ seahorse_pkcs11_backend_init (SeahorsePkcs11Backend *self)
                self->blacklist = g_list_prepend (self->blacklist, uri);
        }
 
-       seahorse_pkcs11_generate_register ();
+    init_actions (self);
 }
 
 static gboolean
@@ -201,10 +233,10 @@ seahorse_pkcs11_backend_get_loaded (SeahorseBackend *backend)
        return SEAHORSE_PKCS11_BACKEND (backend)->loaded;
 }
 
-static GtkActionGroup *
+static SeahorseActionGroup *
 seahorse_pkcs11_backend_get_actions (SeahorseBackend *backend)
 {
-       return NULL;
+       return g_object_ref (SEAHORSE_PKCS11_BACKEND (backend)->actions);
 }
 
 static void
@@ -254,6 +286,7 @@ seahorse_pkcs11_backend_finalize (GObject *obj)
        SeahorsePkcs11Backend *self = SEAHORSE_PKCS11_BACKEND (obj);
 
        g_list_free_full (self->blacklist, (GDestroyNotify)gck_uri_data_free);
+       g_clear_object (&self->actions);
        g_assert (self->tokens == NULL);
        g_return_if_fail (pkcs11_backend == self);
        pkcs11_backend = NULL;
@@ -404,3 +437,19 @@ seahorse_pkcs11_backend_get_writable_tokens (SeahorsePkcs11Backend *self,
                                                        on_filter_writable,
                                                        mechanism, NULL);
 }
+
+static void
+on_generate_activate (GSimpleAction *action,
+                      GVariant *param,
+                      gpointer user_data)
+{
+    SeahorseActionGroup *actions = SEAHORSE_ACTION_GROUP (user_data);
+       SeahorseCatalog *catalog;
+    SeahorsePkcs11Generate *dialog;
+
+       catalog = seahorse_action_group_get_catalog (actions);
+    dialog = seahorse_pkcs11_generate_new (GTK_WINDOW (catalog));
+    gtk_dialog_run (GTK_DIALOG (dialog));
+    gtk_widget_destroy (GTK_WIDGET (dialog));
+       g_clear_object (&catalog);
+}
diff --git a/src/application.vala b/src/application.vala
index e4762670..102a4e94 100644
--- a/src/application.vala
+++ b/src/application.vala
@@ -25,6 +25,42 @@ public class Seahorse.Application : Gtk.Application {
     private SearchProvider? search_provider;
     private uint search_provider_dbus_id = 0;
 
+    private KeyManager? key_mgr = null;
+
+    private const string[] AUTHORS = {
+        "Jacob Perkins <jap1 users sourceforge net>",
+        "Jose Carlos Garcia Sogo <jsogo users sourceforge net>",
+        "Jean Schurger <yshark schurger org>",
+        "Stef Walter <stef memberwebs com>",
+        "Adam Schreiber <sadam clemson edu>",
+        "Niels De Graef <nielsdegraef gmail com>",
+        "",
+        N_("Contributions:"),
+        "Albrecht Dreß <albrecht dress arcor de>",
+        "Jim Pharis <binbrain gmail com>",
+        null
+    };
+
+    private const string[] DOCUMENTERS = {
+        "Jacob Perkins <jap1 users sourceforge net>",
+        "Adam Schreiber <sadam clemson edu>",
+        "Milo Casagrande <milo_casagrande yahoo it>",
+        null
+    };
+
+    private const string[] ARTISTS = {
+        "Jacob Perkins <jap1 users sourceforge net>",
+        "Stef Walter <stef memberwebs com>",
+        null
+    };
+
+    private const GLib.ActionEntry[] action_entries = {
+         { "quit",            quit                  },
+         { "help",            on_app_help           },
+         { "about",           on_app_about          },
+         { "preferences",     on_app_preferences    },
+    };
+
     const OptionEntry[] cmd_options = {
         { "version", 'v', 0, OptionArg.NONE, null, N_("Version of this application"), null },
         { null }
@@ -36,9 +72,25 @@ public class Seahorse.Application : Gtk.Application {
             flags: ApplicationFlags.FLAGS_NONE
         );
         this.search_provider = new SearchProvider(this);
+
+        add_action_entries(action_entries, this);
+        var pref_action = lookup_action("preferences") as SimpleAction;
+        pref_action.set_enabled(Prefs.available());
+        add_action_accelerators();
+
         add_main_option_entries(cmd_options);
     }
 
+    private void add_action_accelerators() {
+        set_accels_for_action ("app.help",        {"F1"});
+        set_accels_for_action ("app.quit",        {"<control>Q"});
+
+        set_accels_for_action ("win.new-item",    { "<control>N" });
+        set_accels_for_action ("win.import-file", { "<control>I" });
+        set_accels_for_action ("win.copy",        { "<control>C" });
+        set_accels_for_action ("win.paste",       { "<control>V" });
+    }
+
     public override void startup() {
         base.startup();
 
@@ -57,12 +109,10 @@ public class Seahorse.Application : Gtk.Application {
     }
 
     public override void activate() {
-        var key_mgr = get_active_window();
-
-        if (key_mgr == null)
-            key_mgr = new Seahorse.KeyManager(this);
+        if (get_active_window() == null)
+            this.key_mgr = new Seahorse.KeyManager(this);
 
-        key_mgr.present();
+        this.key_mgr.present();
     }
 
     public override int handle_local_options (VariantDict options) {
@@ -97,4 +147,40 @@ public class Seahorse.Application : Gtk.Application {
     public void initialize_search () {
         this.search_provider.load.begin();
     }
+
+    private void on_app_about(SimpleAction action, Variant? param) {
+        var about = new Gtk.AboutDialog();
+        about.set_artists(ARTISTS);
+        about.set_authors(AUTHORS);
+        about.set_documenters(DOCUMENTERS);
+        about.set_version(Config.VERSION);
+        about.set_comments(_("Passwords and Keys"));
+        about.set_copyright("© 2002 - 2018 Seahorse Contributors");
+        about.set_translator_credits(_("translator-credits"));
+        about.set_logo_icon_name("seahorse");
+        about.set_website("https://wiki.gnome.org/Apps/Seahorse";);
+        about.set_website_label(_("Seahorse Project Homepage"));
+
+        about.response.connect((response) => {
+            about.hide();
+        });
+
+        about.set_transient_for(this.key_mgr);
+        about.run();
+        about.destroy();
+    }
+
+    private void on_app_help(SimpleAction action, Variant? param) {
+        try {
+          Gtk.show_uri_on_window(this.key_mgr, "help:seahorse", Gtk.get_current_event_time ());
+        } catch (GLib.Error err) {
+          warning("Error showing help: %s", err.message);
+        }
+    }
+
+    private void on_app_preferences(SimpleAction action, Variant? param) {
+        Prefs prefs_dialog = new Prefs(this.key_mgr);
+        prefs_dialog.run();
+        prefs_dialog.destroy();
+    }
 }
diff --git a/src/generate-select.vala b/src/generate-select.vala
index 9bd42b0a..3c6e80b4 100644
--- a/src/generate-select.vala
+++ b/src/generate-select.vala
@@ -30,6 +30,8 @@ public class Seahorse.GenerateSelect : Gtk.Dialog {
     [GtkChild]
     private Gtk.ListBox generate_list;
 
+    private SimpleActionGroup action_group = new SimpleActionGroup();
+
     public GenerateSelect(Gtk.Window? parent) {
         GLib.Object(
             use_header_bar: 1,
@@ -37,19 +39,16 @@ public class Seahorse.GenerateSelect : Gtk.Dialog {
             modal: true
         );
 
-        ListStore store = new ListStore(typeof(Gtk.Action));
+        ListStore store = new ListStore(typeof(Action));
         this.generate_list.bind_model(store, on_create_row);
 
-        // Fill up the model
-        var action_groups = (List<Gtk.ActionGroup>) Registry.object_instances("generator");
-        foreach (var action_group in action_groups) {
-            action_group.post_activate.connect(this.switch_view);
-            foreach (var action in action_group.list_actions())
-                store.append(action);
+        // Fetch and process the generator actions
+        var actions = (List<Action>) Registry.object_instances("generator");
+        foreach (var action in actions) {
+            this.action_group.add_action(action);
+            store.insert_sorted(action, compare_generator_actions);
         }
-        store.sort((a, b) => {
-            return ((Gtk.Action) a).label.collate(((Gtk.Action) b).label);
-        });
+        insert_action_group("gen", action_group);
 
         // Select first item (and grab focus, so user can use the keyboard immediately)
         weak Gtk.ListBoxRow? row = this.generate_list.get_row_at_index(0);
@@ -59,20 +58,19 @@ public class Seahorse.GenerateSelect : Gtk.Dialog {
         }
     }
 
+    private int compare_generator_actions(GLib.Object a, GLib.Object b) {
+        unowned string? a_label = a.get_data("label");
+        unowned string? b_label = b.get_data("label");
+        return a_label.collate(b_label);
+    }
+
     private void switch_view(Gtk.Action action) {
         string target = action.action_group.name.split("-", 2)[0];
         ((KeyManager) this.transient_for).set_focused_place(target);
     }
 
     private Gtk.ListBoxRow on_create_row(GLib.Object item) {
-        return new GenerateSelectRow((Gtk.Action) item);
-    }
-
-    [GtkCallback]
-    private void on_row_activated(Gtk.ListBoxRow row) {
-        Gtk.Action action = ((GenerateSelectRow) row).action;
-        Action.activate_with_window(action, null, this.transient_for);
-        destroy();
+        return new GenerateSelectRow((Action) item);
     }
 
     public override void response(int response)  {
@@ -83,16 +81,24 @@ public class Seahorse.GenerateSelect : Gtk.Dialog {
         if (row == null)
             return;
 
-        Action.activate_with_window(row.action, null, this.transient_for);
+        row.activate();
+    }
+
+    [GtkCallback]
+    private void on_row_activated(Gtk.ListBox listbox, Gtk.ListBoxRow row) {
+        var generate_row = (GenerateSelectRow) row;
+        this.action_group.activate_action(generate_row.action_name, null);
+        destroy();
     }
 }
 
 private class Seahorse.GenerateSelectRow : Gtk.ListBoxRow {
-    private Gtk.Image icon;
     private Gtk.Label title;
     private Gtk.Label description;
 
-    public Gtk.Action action { get; private set; }
+    // Note that we can't use the actual "action-name" property,
+    // or the row-activated signal doesn't get emitted for some reason
+    public unowned string? action_name;
 
     construct {
         var grid = new Gtk.Grid();
@@ -100,29 +106,22 @@ private class Seahorse.GenerateSelectRow : Gtk.ListBoxRow {
         grid.margin = 3;
         add(grid);
 
-        this.icon = new Gtk.Image();
-        this.icon.icon_size = Gtk.IconSize.DND;
-        grid.attach(this.icon, 0, 0, 1, 2);
-
         this.title = new Gtk.Label(null);
         this.title.halign = Gtk.Align.START;
-        grid.attach(this.title, 1, 0);
+        grid.attach(this.title, 0, 0);
 
         this.description = new Gtk.Label(null);
         this.description.get_style_context().add_class("dim-label");
-        grid.attach(this.description, 1, 1);
+        grid.attach(this.description, 0, 1);
     }
 
-    public GenerateSelectRow(Gtk.Action action) {
-        this.action = action;
+    public GenerateSelectRow(Action action) {
+        this.action_name = action.name;
 
-        this.title.set_markup("<b>%s</b>".printf(action.label));
-        this.description.label = action.tooltip;
+        unowned string? label = action.get_data<string?>("label");
 
-        if (action.gicon != null)
-            this.icon.gicon = action.gicon;
-        else if (action.icon_name != null)
-            this.icon.icon_name = action.icon_name;
+        this.title.set_markup("<b>%s</b>".printf(label));
+        this.description.label = action.get_data<string?>("description");
 
         show_all();
     }
diff --git a/src/key-manager.vala b/src/key-manager.vala
index 25870b1d..40d31866 100644
--- a/src/key-manager.vala
+++ b/src/key-manager.vala
@@ -24,56 +24,32 @@
 public class Seahorse.KeyManager : Catalog {
 
     [GtkChild]
-    private Gtk.Container menu_placeholder;
-    [GtkChild]
-    private Gtk.TreeView key_list;
+    private Gtk.SearchEntry filter_entry;
+
     [GtkChild]
     private Gtk.Paned sidebar_panes;
     [GtkChild]
-    private Gtk.Button import_button;
-    [GtkChild]
-    private Gtk.Button new_button;
-    [GtkChild]
-    private Gtk.Button new_item_button;
-    [GtkChild]
-    private Gtk.SearchEntry filter_entry;
-    [GtkChild]
     private Gtk.Container sidebar_area;
     private Sidebar sidebar;
 
-    private Gtk.ActionGroup view_actions;
-    private Gtk.RadioAction show_action;
-
+    [GtkChild]
+    private Gtk.TreeView key_list;
     private Gcr.Collection collection;
     private KeyManagerStore store;
 
     private GLib.Settings settings;
-    private int sidebar_width;
-    private uint sidebar_width_sig;
 
     private enum DndTarget { // Drag 'n Drop target type
         PLAIN,
         URIS
     }
 
-    private const Gtk.ActionEntry[] GENERAL_ACTIONS = {
-        // TRANSLATORS: The "Remote" menu contains key operations on remote systems.
-        { "remote-menu", null, N_("_Remote") },
-        { "new-menu", null, N_("_New") },
-        { "app-quit", null, N_("_Quit"), "<control>Q", N_("Close this program") },
-        { "file-new", null, N_("_New…"), "<control>N", N_("Create a new key or item") },
-        { "file-import", null, N_("_Import…"), "<control>I", N_("Import from a file") },
-        { "edit-import-clipboard", null, N_("_Paste"), "<control>V", N_("Import from the clipboard") }
-    };
-
-    private const Gtk.ToggleActionEntry[] SIDEBAR_ACTIONS = {
-        { "view-sidebar", null, N_("By _Keyring"), null, N_("Show sidebar listing keyrings"), null, false },
-    };
-
-    private const Gtk.RadioActionEntry[] VIEW_RADIO_ACTIONS = {
-        { "view-personal", null, N_("Show _Personal"), null, N_("Only show personal keys, certificates and 
passwords"), KeyManagerStore.ShowFilter.PERSONAL },
-        { "view-trusted", null, N_("Show _Trusted"), null, N_("Only show trusted keys, certificates and 
passwords"), KeyManagerStore.ShowFilter.TRUSTED },
-        { "view-any", null, N_("Show _Any"), null, N_("Show all keys, certificates and passwords"), 
KeyManagerStore.ShowFilter.ANY },
+    private const GLib.ActionEntry[] action_entries = {
+         { "new-item",           on_new_item                                                     },
+         { "filter-items",       on_filter_items,              "s",                      "'any'" },
+         { "import-file",        on_import_file                                                  },
+         { "combine-keyrings",   on_toggle_action,  null,  "false",  on_combine_keyrings_toggled },
+         { "paste",              on_paste,                                                       },
     };
 
     public KeyManager(Application app) {
@@ -106,18 +82,8 @@ public class Seahorse.KeyManager : Catalog {
         this.settings.changed["item-filter"].connect(on_item_filter_changed);
         on_item_filter_changed(this.settings, "item-filter");
 
-        // first time signals
-        this.import_button.clicked.connect(on_keymanager_import_button);
-        this.new_button.clicked.connect(on_keymanager_new_button);
-
-        // Flush all updates
-        ensure_updated();
-
-        // The toolbar
-        this.new_item_button.clicked.connect(on_keymanager_new_button);
-        on_filter_changed(this.filter_entry);
-
         // For the filtering
+        on_filter_changed(this.filter_entry);
         this.filter_entry.search_changed.connect(on_filter_changed);
         this.key_list.start_interactive_search.connect(() => {
             this.filter_entry.grab_focus();
@@ -128,9 +94,6 @@ public class Seahorse.KeyManager : Catalog {
         this.key_list.grab_focus();
         selection_changed();
 
-        // To avoid flicker
-        show();
-
         // Setup drops
         Gtk.drag_dest_set(this, Gtk.DestDefaults.ALL, {}, Gdk.DragAction.COPY);
         Gtk.TargetList targets = new Gtk.TargetList(null);
@@ -144,42 +107,8 @@ public class Seahorse.KeyManager : Catalog {
         this.key_list.popup_menu.connect(on_keymanager_key_list_popup_menu);
     }
 
-    ~KeyManager() {
-        if (this.sidebar_width_sig != 0) {
-            Source.remove(this.sidebar_width_sig);
-            this.sidebar_width_sig = 0;
-        }
-    }
-
     private void init_actions() {
-        // General actions
-        Gtk.ActionGroup actions = new Gtk.ActionGroup("general");
-        actions.set_translation_domain(Config.GETTEXT_PACKAGE);
-        actions.add_actions(GENERAL_ACTIONS, null);
-        actions.get_action("app-quit").activate.connect(on_app_quit);
-        actions.get_action("file-new").activate.connect(on_file_new);
-        actions.get_action("file-import").activate.connect(on_key_import_file);
-        actions.get_action("edit-import-clipboard").activate.connect(on_key_import_clipboard);
-        include_actions(actions);
-
-        // View actions
-        this.view_actions = new Gtk.ActionGroup("view");
-        this.view_actions.set_translation_domain(Config.GETTEXT_PACKAGE);
-        this.view_actions.add_radio_actions(VIEW_RADIO_ACTIONS, -1, () => {
-            this.settings.set_string("item-filter", update_view_filter());
-        });
-        this.show_action = (Gtk.RadioAction) this.view_actions.get_action("view-personal");
-        include_actions(this.view_actions);
-
-        // Make sure import is only available with clipboard content
-        Gtk.Clipboard clipboard = Gtk.Clipboard.get(Gdk.SELECTION_PRIMARY);
-        clipboard.owner_change.connect((c, e) => update_clipboard_state(c, e, actions));
-        update_clipboard_state(clipboard, null, actions);
-    }
-
-    protected override void add_menu(Gtk.Widget menu) {
-        this.menu_placeholder.add(menu);
-        menu.show();
+        add_action_entries (action_entries, this);
     }
 
     private void on_view_selection_changed(Gtk.TreeSelection selection) {
@@ -191,6 +120,14 @@ public class Seahorse.KeyManager : Catalog {
         });
     }
 
+    public override void selection_changed() {
+        base.selection_changed();
+
+        var objects = get_selected_objects();
+        foreach (weak Backend backend in get_backends())
+            backend.actions.set_actions_for_selected_objects(objects);
+    }
+
     private void on_keymanager_row_activated(Gtk.TreeView key_list, Gtk.TreePath? path, Gtk.TreeViewColumn 
column) {
         if (path == null)
             return;
@@ -202,7 +139,7 @@ public class Seahorse.KeyManager : Catalog {
 
     private bool on_keymanager_key_list_button_pressed(Gdk.EventButton event) {
         if (event.button == 3) {
-            show_context_menu(Catalog.MENU_OBJECT, event);
+            show_context_menu(event);
             GLib.List<GLib.Object> objects = get_selected_objects();
             if (objects.length() > 1) {
                 return true;
@@ -215,20 +152,29 @@ public class Seahorse.KeyManager : Catalog {
     private bool on_keymanager_key_list_popup_menu() {
         GLib.List<GLib.Object> objects = get_selected_objects();
         if (objects != null)
-            show_context_menu(Catalog.MENU_OBJECT, null);
+            show_context_menu(null);
         return false;
     }
 
-    private void on_file_new(Gtk.Action action) {
+    private void on_new_item(SimpleAction action, GLib.Variant? param) {
         GenerateSelect dialog = new GenerateSelect(this);
         dialog.run();
         dialog.destroy();
     }
 
-    private void on_keymanager_new_button(Gtk.Button button) {
-        GenerateSelect dialog = new GenerateSelect(this);
-        dialog.run();
-        dialog.destroy();
+    private void on_toggle_action(SimpleAction action, GLib.Variant? param) {
+        action.change_state(!action.state.get_boolean());
+    }
+
+    private void on_combine_keyrings_toggled(SimpleAction action, GLib.Variant? new_state) {
+        bool combined = new_state.get_boolean();
+        action.set_state(combined);
+
+        this.sidebar.combined = combined;
+
+        /* Don't show the sidebar if everyhing is combined */
+        this.sidebar_area.visible = !combined;
+        this.settings.set_boolean("sidebar-visible", !combined);
     }
 
     private void on_filter_changed(Gtk.Editable entry) {
@@ -242,7 +188,7 @@ public class Seahorse.KeyManager : Catalog {
         dialog.destroy();
     }
 
-    private void import_prompt() {
+    private void on_import_file(SimpleAction action, GLib.Variant? parameter) {
         Gtk.FileChooserDialog dialog =
             new Gtk.FileChooserDialog(_("Import Key"), this,
                                       Gtk.FileChooserAction.OPEN,
@@ -305,14 +251,6 @@ public class Seahorse.KeyManager : Catalog {
         }
     }
 
-    private void on_key_import_file(Gtk.Action action) {
-        import_prompt();
-    }
-
-    private void on_keymanager_import_button(Gtk.Button button) {
-        import_prompt();
-    }
-
     private void import_text(string? display_name, string? text) {
         ImportDialog dialog = new ImportDialog(this);
         dialog.add_text(display_name, text);
@@ -336,9 +274,14 @@ public class Seahorse.KeyManager : Catalog {
         }
     }
 
-    private void update_clipboard_state(Gtk.Clipboard clipboard, Gdk.Event? event, Gtk.ActionGroup group) {
-        Gtk.Action action = group.get_action("edit-import-clipboard");
-        action.set_sensitive(clipboard.wait_is_text_available());
+    private void on_paste(SimpleAction action, Variant? param) {
+        Gdk.Atom atom = Gdk.Atom.intern("CLIPBOARD", false);
+        Gtk.Clipboard clipboard = Gtk.Clipboard.get(atom);
+
+        if (clipboard.wait_is_text_available())
+            return;
+
+        clipboard.request_text(on_clipboard_received);
     }
 
     private void on_clipboard_received(Gtk.Clipboard board, string? text) {
@@ -353,26 +296,26 @@ public class Seahorse.KeyManager : Catalog {
                 import_text(_("Clipboard text"), text);
     }
 
-    private void on_key_import_clipboard(Gtk.Action action) {
-        Gdk.Atom atom = Gdk.Atom.intern("CLIPBOARD", false);
-        Gtk.Clipboard clipboard = Gtk.Clipboard.get(atom);
-        clipboard.request_text(on_clipboard_received);
-    }
+    private void update_view_filter(string filter_str, bool update_settings = true) {
+        // Update the setting
+        if (update_settings)
+            this.settings.set_string("item-filter", filter_str);
 
-    private void on_app_quit(Gtk.Action action) {
-        this.application.quit();
-    }
+        // Update the action
+        SimpleAction action = lookup_action("filter-items") as SimpleAction;
+        action.set_state(filter_str);
 
-    private unowned string update_view_filter() {
-        this.store.showfilter = (KeyManagerStore.ShowFilter) this.show_action.current_value;
+        // Update the store
+        this.store.showfilter = KeyManagerStore.ShowFilter.from_string(filter_str);
         this.store.refilter();
-        return this.store.showfilter.to_string();
+    }
+
+    private void on_filter_items(SimpleAction action, Variant? param) {
+        update_view_filter (param.get_string());
     }
 
     private void on_item_filter_changed(GLib.Settings settings, string? key) {
-        int radio = KeyManagerStore.ShowFilter.from_string(settings.get_string(key));
-        this.show_action.set_current_value(radio);
-        update_view_filter();
+        update_view_filter(settings.get_string("item-filter"), false);
     }
 
     public override GLib.List<GLib.Object> get_selected_objects() {
@@ -406,9 +349,7 @@ public class Seahorse.KeyManager : Catalog {
         this.sidebar = new Sidebar();
         sidebar.hexpand = true;
 
-        this.sidebar_width = this.settings.get_int("sidebar-width");
-
-        this.sidebar_panes.position = this.sidebar_width;
+        this.sidebar_panes.position = this.settings.get_int("sidebar-width");
         this.sidebar_panes.realize.connect(() =>   { this.sidebar_panes.position = 
this.settings.get_int("sidebar-width"); });
         this.sidebar_panes.unrealize.connect(() => { this.settings.set_int("sidebar-width", 
this.sidebar_panes.position);  });
 
@@ -416,22 +357,14 @@ public class Seahorse.KeyManager : Catalog {
         this.sidebar_panes.get_child2().set_size_request(150, -1);
 
         foreach (weak Backend backend in get_backends()) {
-            if (backend.actions != null)
-                include_actions(backend.actions);
+            ActionGroup actions = backend.actions;
+            actions.catalog = this;
+            insert_action_group(actions.prefix, actions);
         }
 
         this.sidebar_area.add(this.sidebar);
         this.sidebar.show();
 
-        Gtk.ActionGroup actions = new Gtk.ActionGroup("sidebar");
-        actions.set_translation_domain(Config.GETTEXT_PACKAGE);
-        actions.add_toggle_actions(SIDEBAR_ACTIONS, null);
-        Gtk.Action action = actions.get_action("view-sidebar");
-        this.settings.bind("sidebar-visible", action, "active", SettingsBindFlags.DEFAULT);
-        action.bind_property("active", this.sidebar_area, "visible", BindingFlags.SYNC_CREATE);
-        action.bind_property("active", this.sidebar, "combined", BindingFlags.INVERT_BOOLEAN | 
BindingFlags.SYNC_CREATE);
-        include_actions(actions);
-
         this.settings.bind("keyrings-selected", this.sidebar, "selected-uris", SettingsBindFlags.DEFAULT);
 
         return this.sidebar.collection;
diff --git a/src/seahorse-key-manager-widgets.ui b/src/seahorse-key-manager-widgets.ui
index 97d15fc8..9c861740 100644
--- a/src/seahorse-key-manager-widgets.ui
+++ b/src/seahorse-key-manager-widgets.ui
@@ -1,38 +1,29 @@
-<ui>
-       <menubar>
-               <menu name="File" action="file-menu">
-                       <menuitem action="file-new"/>
-                       <menuitem action="file-import"/>
-                       <menuitem action="file-export"/>
-                       <separator/>
-                       <menuitem action="app-quit"/>
-               </menu>
-               <menu name="Edit" action="edit-menu">
-                       <menuitem action="edit-export-clipboard"/>
-                       <menuitem action="edit-import-clipboard"/>
-                       <menuitem action="edit-delete"/>
-                       <separator/>
-                       <menuitem action="app-preferences"/>
-               </menu>
-               <placeholder name="RemoteMenu">
-               </placeholder>
-               <menu name="View" action="view-menu">
-                       <menuitem action="view-sidebar"/>
-                       <separator/>
-                       <menuitem action="view-personal"/>
-                       <menuitem action="view-trusted"/>
-                       <menuitem action="view-any"/>
-               </menu>
-               <menu name="Help" action="help-menu">
-                       <menuitem action="help-show"/>
-                       <menuitem action="app-about"/>
-               </menu>
-
-       </menubar>
-
-       <popup name="ObjectPopup">
-               <menuitem action="edit-delete"/>
-               <separator/>
-               <menuitem action="properties-object"/>
-       </popup>
-</ui>
+<?xml version="1.0" encoding="UTF-8"?>
+<interface>
+  <menu id="context_menu">
+    <section>
+      <item>
+        <attribute name="label" translatable="yes">Export…</attribute>
+        <attribute name="action">win.file-export</attribute>
+        <attribute name="hidden-when">action-disabled</attribute>
+      </item>
+      <item>
+        <!-- Translators: This text refers to deleting an item from its type's backing store -->
+        <attribute name="label" translatable="yes">Delete</attribute>
+        <attribute name="action">win.edit-delete</attribute>
+        <attribute name="hidden-when">action-disabled</attribute>
+      </item>
+    </section>
+    <section>
+      <item>
+        <attribute name="label" translatable="yes">Properties</attribute>
+        <attribute name="action">win.properties-object</attribute>
+      </item>
+      <item>
+        <attribute name="label" translatable="yes">Configure Key for Secure Shell……</attribute>
+        <attribute name="action">ssh.remote-upload</attribute>
+        <attribute name="hidden-when">action-disabled</attribute>
+      </item>
+    </section>
+  </menu>
+</interface>
diff --git a/src/seahorse-key-manager.ui b/src/seahorse-key-manager.ui
index e98c1d90..2467804d 100644
--- a/src/seahorse-key-manager.ui
+++ b/src/seahorse-key-manager.ui
@@ -1,31 +1,128 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <interface>
   <requires lib="gtk+" version="3.22"/>
+  <menu id="main_menu">
+    <section>
+      <attribute name="label" translatable="yes">Filter items:</attribute>
+      <item>
+        <attribute name="label" translatable="yes">Show personal</attribute>
+        <attribute name="action">win.filter-items</attribute>
+        <attribute name="target">personal</attribute>
+      </item>
+      <item>
+        <attribute name="label" translatable="yes">Show trusted</attribute>
+        <attribute name="action">win.filter-items</attribute>
+        <attribute name="target">trusted</attribute>
+      </item>
+      <item>
+        <attribute name="label" translatable="yes">Show any</attribute>
+        <attribute name="action">win.filter-items</attribute>
+        <attribute name="target">any</attribute>
+      </item>
+    </section>
+    <section>
+      <item>
+        <attribute name="label" translatable="yes">Combine all keyrings</attribute>
+        <attribute name="action">win.combine-keyrings</attribute>
+      </item>
+    </section>
+    <section>
+      <item>
+        <attribute name="label" translatable="yes">Import from file…</attribute>
+        <attribute name="action">win.import-file</attribute>
+      </item>
+      <item>
+        <attribute name="label" translatable="yes">Find remote keys…</attribute>
+        <attribute name="action">pgp.remote-find</attribute>
+        <attribute name="hidden-when">action-missing</attribute>
+      </item>
+      <item>
+        <attribute name="label" translatable="yes">Sync and publish keys…</attribute>
+        <attribute name="action">pgp.remote-sync</attribute>
+        <attribute name="hidden-when">action-missing</attribute>
+      </item>
+    </section>
+    <section>
+      <item>
+        <attribute name="label" translatable="yes">Preferences</attribute>
+        <attribute name="action">app.preferences</attribute>
+        <attribute name="hidden-when">action-disabled</attribute>
+      </item>
+      <item>
+        <attribute name="label" translatable="yes">Help</attribute>
+        <attribute name="action">app.help</attribute>
+      </item>
+      <item>
+        <attribute name="label" translatable="yes">About</attribute>
+        <attribute name="action">app.about</attribute>
+      </item>
+    </section>
+  </menu>
   <template class="SeahorseKeyManager" parent="SeahorseCatalog">
-    <property name="title" translatable="yes">Passwords and Keys</property>
-    <child>
-      <object class="GtkBox">
+    <child type="titlebar">
+      <object class="GtkHeaderBar">
         <property name="visible">True</property>
-        <property name="orientation">vertical</property>
-        <property name="can_focus">False</property>
+        <property name="show-close-button">True</property>
+        <property name="title" translatable="yes">Passwords and Keys</property>
+        <child>
+          <object class="GtkButton" id="new_item_button">
+            <property name="visible">True</property>
+            <property name="hexpand">True</property>
+            <property name="halign">start</property>
+            <property name="tooltip_text" translatable="yes">Add a new key or item</property>
+            <property name="action-name">win.new-item</property>
+            <child>
+              <object class="GtkImage">
+                <property name="visible">True</property>
+                <property name="icon_name">list-add-symbolic</property>
+              </object>
+            </child>
+          </object>
+        </child>
         <child>
-          <object class="GtkBox" id="menu_placeholder">
+          <object class="GtkMenuButton" id="main_menu_button">
             <property name="visible">True</property>
-            <property name="orientation">vertical</property>
-            <property name="can_focus">False</property>
+            <property name="can_focus">True</property>
+            <property name="focus_on_click">False</property>
+            <property name="menu-model">main_menu</property>
             <child>
-              <placeholder/>
+              <object class="GtkImage">
+                <property name="visible">True</property>
+                <property name="can_focus">False</property>
+                <property name="icon_name">open-menu-symbolic</property>
+              </object>
             </child>
           </object>
           <packing>
-            <property name="expand">False</property>
-            <property name="fill">True</property>
-            <property name="position">0</property>
+            <property name="pack_type">end</property>
           </packing>
         </child>
+        <child>
+          <object class="GtkToggleButton" id="show_search_button">
+            <property name="visible">True</property>
+            <property name="tooltip_text" translatable="yes">Search for a key or password</property>
+            <child>
+              <object class="GtkImage">
+                <property name="visible">True</property>
+                <property name="icon_name">edit-find-symbolic</property>
+              </object>
+            </child>
+          </object>
+          <packing>
+            <property name="pack_type">end</property>
+          </packing>
+        </child>
+      </object>
+    </child>
+    <child>
+      <object class="GtkBox">
+        <property name="visible">True</property>
+        <property name="orientation">vertical</property>
+        <property name="can_focus">False</property>
         <child>
           <object class="GtkPaned" id="sidebar_panes">
             <property name="visible">True</property>
+            <property name="vexpand">True</property>
             <property name="can_focus">True</property>
             <child>
               <object class="GtkBox" id="sidebar_area">
@@ -35,43 +132,17 @@
                   <placeholder/>
                 </child>
               </object>
-              <packing>
-                <property name="resize">False</property>
-                <property name="shrink">False</property>
-              </packing>
             </child>
             <child>
-              <object class="GtkBox" id="box1">
+              <object class="GtkBox">
                 <property name="visible">True</property>
                 <property name="can_focus">False</property>
                 <property name="orientation">vertical</property>
                 <child>
-                  <object class="GtkBox">
+                  <object class="GtkSearchBar">
                     <property name="visible">True</property>
-                    <property name="orientation">horizontal</property>
+                    <property name="search-mode-enabled" bind-source="show_search_button" 
bind-property="active" bind-flags="bidirectional|sync-create" />
                     <property name="can_focus">False</property>
-                    <property name="margin_start">12</property>
-                    <property name="margin_end">12</property>
-                    <property name="margin_top">6</property>
-                    <property name="margin_bottom">6</property>
-                    <child>
-                      <object class="GtkButton" id="new_item_button">
-                        <property name="visible">True</property>
-                        <property name="hexpand">True</property>
-                        <property name="halign">start</property>
-                        <property name="tooltip_text" translatable="yes">Add a new key or item</property>
-                        <child>
-                          <object class="GtkImage">
-                            <property name="visible">True</property>
-                            <property name="icon_name">list-add</property>
-                          </object>
-                        </child>
-                      </object>
-                      <packing>
-                        <property name="expand">False</property>
-                        <property name="fill">True</property>
-                      </packing>
-                    </child>
                     <child>
                       <object class="GtkSearchEntry" id="filter_entry">
                         <property name="visible">True</property>
@@ -89,8 +160,10 @@
                       <object class="GtkTreeView" id="key_list">
                         <property name="visible">True</property>
                         <property name="can_focus">True</property>
-                        <property name="margin_left">12</property>
-                        <property name="margin_right">12</property>
+                        <property name="margin-top">12</property>
+                        <property name="margin-bottom">12</property>
+                        <property name="margin-left">18</property>
+                        <property name="margin-right">18</property>
                         <property name="rules_hint">True</property>
                         <child internal-child="selection">
                           <object class="GtkTreeSelection" id="treeview-selection"/>
@@ -199,6 +272,7 @@
                                 <property name="can_default">True</property>
                                 <property name="receives_default">True</property>
                                 <property name="use_action_appearance">False</property>
+                                <property name="action-name">win.import-file</property>
                                 <child>
                                   <object class="GtkAlignment" id="alignment6">
                                     <property name="visible">True</property>
@@ -266,6 +340,7 @@
                                 <property name="receives_default">True</property>
                                 <property name="use_action_appearance">False</property>
                                 <property name="use_stock">True</property>
+                                <property name="action-name">win.new-item</property>
                               </object>
                               <packing>
                                 <property name="top_attach">2</property>
@@ -284,17 +359,8 @@
                   </object>
                 </child>
               </object>
-              <packing>
-                <property name="resize">True</property>
-                <property name="shrink">False</property>
-              </packing>
             </child>
           </object>
-          <packing>
-            <property name="expand">True</property>
-            <property name="fill">True</property>
-            <property name="position">1</property>
-          </packing>
         </child>
       </object>
     </child>
diff --git a/ssh/actions.vala b/ssh/actions.vala
index 71770d68..b721e169 100644
--- a/ssh/actions.vala
+++ b/ssh/actions.vala
@@ -20,49 +20,55 @@
  * <http://www.gnu.org/licenses/>.
  */
 
-public class Seahorse.Ssh.Actions : Seahorse.Actions {
+public class Seahorse.Ssh.Actions : ActionGroup {
 
-    private const Gtk.ActionEntry KEYS_ACTIONS[] = {
-        { "remote-ssh-upload", null, N_("Configure Key for _Secure Shell…"), null,
-            N_("Send public Secure Shell key to another machine, and enable logins using that key."),
-            on_ssh_upload }
+    private const ActionEntry KEYS_ACTIONS[] = {
+        { "generate-key",    on_ssh_generate_key },
+        { "remote-upload",   on_ssh_upload       },
     };
 
-    public const string UI_DEFINITION = """
-    <ui>
-      <menubar>
-        <placeholder name="RemoteMenu">
-          <menu name="Remote" action="remote-menu">
-            <menuitem action="remote-ssh-upload"/>
-          </menu>
-        </placeholder>
-      </menubar>
-      <popup name="ObjectPopup">
-        <menuitem action="remote-ssh-upload"/>
-      </popup>
-    </ui>""";
-
     construct {
-        set_translation_domain(Config.GETTEXT_PACKAGE);
-        add_actions(KEYS_ACTIONS, this);
-        register_definition(UI_DEFINITION);
+        add_action_entries(KEYS_ACTIONS, this);
+
+               // Register generator action
+               var action = lookup_action("generate-key");
+        action.set_data("label", _("Secure Shell Key"));
+        action.set_data("description", _("Used to access other computers (eg: via a terminal)"));
+               Registry.register_object(action, "generator");
     }
 
-    private Actions(string name) {
-        base(name);
+    private Actions() {
+        GLib.Object(prefix: "ssh");
     }
 
     private static Actions _instance = null;
-
     public static unowned Actions instance() {
-        if (_instance == null) {
-            _instance = new Actions("SshKey");
-        }
+        if (_instance == null)
+            _instance = new Actions();
 
         return _instance;
     }
 
-    private void on_ssh_upload (Gtk.Action action) {
+    public override void set_actions_for_selected_objects(List<GLib.Object> objects) {
+        bool is_ssh_key = false;
+
+        foreach (var object in objects) {
+            if (object is Ssh.Key) {
+                is_ssh_key = true;
+                break;
+            }
+        }
+
+        ((SimpleAction) lookup_action("remote-upload")).set_enabled(is_ssh_key);
+    }
+
+    private void on_ssh_generate_key(SimpleAction action, Variant? param) {
+        Generate generate_dialog = new Generate(Backend.instance.get_dot_ssh(),
+                                                this.catalog);
+        generate_dialog.show();
+    }
+
+    private void on_ssh_upload(SimpleAction action, Variant? param) {
         List<Key> keys = new List<Key>();
 
         if (this.catalog != null) {
@@ -73,6 +79,6 @@ public class Seahorse.Ssh.Actions : Seahorse.Actions {
             }
         }
 
-        Upload.prompt(keys, Seahorse.Action.get_window(action));
+        Upload.prompt(keys, this.catalog);
     }
 }
diff --git a/ssh/backend.vala b/ssh/backend.vala
index 4865070a..84ea529a 100644
--- a/ssh/backend.vala
+++ b/ssh/backend.vala
@@ -26,7 +26,7 @@ public class Seahorse.Ssh.Backend : GLib.Object, Gcr.Collection, Seahorse.Backen
     public string name { get { return SEAHORSE_SSH_NAME; } }
     public string label { get { return _("Secure Shell"); } }
     public string description { get { return _("Keys used to connect securely to other computers"); } }
-    public Gtk.ActionGroup? actions { owned get { return null; } }
+    public ActionGroup actions { owned get { return Ssh.Actions.instance(); } }
 
     private bool _loaded;
     public bool loaded { get { return _loaded; } }
@@ -73,7 +73,6 @@ public class Seahorse.Ssh.Backend : GLib.Object, Gcr.Collection, Seahorse.Backen
 
     public static void initialize() {
         instance = new Backend();
-        Generate.register();
     }
 
     public Source get_dot_ssh() {
diff --git a/ssh/generate.vala b/ssh/generate.vala
index 9d0ed390..f52cb136 100644
--- a/ssh/generate.vala
+++ b/ssh/generate.vala
@@ -24,11 +24,6 @@ public class Seahorse.Ssh.Generate : Gtk.Dialog {
     public const int DEFAULT_DSA_SIZE = 1024;
     public const int DEFAULT_RSA_SIZE = 2048;
 
-    private const Gtk.ActionEntry ACTION_ENTRIES[] = {
-        { "ssh-generate-key", Gcr.ICON_KEY_PAIR, N_ ("Secure Shell Key"), "",
-          N_("Used to access other computers (eg: via a terminal)"), on_ssh_generate_key }
-    };
-
     private Source source;
 
     [GtkChild]
@@ -58,22 +53,6 @@ public class Seahorse.Ssh.Generate : Gtk.Dialog {
         algorithm_combo_box.set_active(0);
     }
 
-    private static void on_ssh_generate_key(Gtk.Action action) {
-        Generate generate_dialog = new Generate(Backend.instance.get_dot_ssh(),
-                                                Action.get_window(action));
-        generate_dialog.show();
-    }
-
-    public static void register() {
-        Gtk.ActionGroup actions = new Gtk.ActionGroup("ssh-generate");
-
-        actions.set_translation_domain(Config.GETTEXT_PACKAGE);
-        actions.add_actions(ACTION_ENTRIES, null);
-
-        // Register this as a generator
-        Seahorse.Registry.register_object(actions, "generator");
-    }
-
     [GtkCallback]
     private void on_algo_changed(Gtk.ComboBox combo) {
         string t = algorithm_combo_box.get_active_text();
diff --git a/ssh/key.vala b/ssh/key.vala
index 3ee6c761..1b1bf8ee 100644
--- a/ssh/key.vala
+++ b/ssh/key.vala
@@ -140,7 +140,6 @@ public class Seahorse.Ssh.Key : Seahorse.Object, Seahorse.Exportable, Seahorse.D
         this.markup = Markup.printf_escaped("%s<span size='small' rise='0' foreground='#555555'>\n%s</span>",
                                             this.label, filename);
 
-        this.actions = Actions.instance();
         this.identifier = calc_identifier(this.key_data.fingerprint);
     }
 


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