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



commit a77ea4f75388da833f3b1fcbaf8ca96db6e80352
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).
    * We no longer use the registry as a magical way of passing generators.
    We make a menu with the GActions that can create keys, and they will be
    only shown if that action exists. This means the Registry no longer has
    a concept of generators.
    * Given that it was the easiest way, we removed the GenerateSelect
    dialog for selecting new items in favor of a popover with the actions
    set.
    * 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                 | 418 +++++++++---------------------------
 common/key-manager-store.vala       |   2 +
 common/object.vala                  |   5 -
 data/seahorse.gresource.xml         |   1 -
 gkr/gkr-backend.vala                |  80 +++----
 gkr/gkr-item-add.vala               |  20 +-
 gkr/gkr-keyring-add.vala            |   2 -
 gkr/gkr-keyring.vala                |   4 +-
 libseahorse/seahorse.css            |   4 +
 pgp/seahorse-gpgme-generate.c       | 123 ++++-------
 pgp/seahorse-gpgme-key.c            |   5 -
 pgp/seahorse-pgp-actions.c          | 197 ++++++++---------
 pgp/seahorse-pgp-actions.h          |   6 +-
 pgp/seahorse-pgp-backend.c          |   6 +-
 pkcs11/pkcs11-generate.vala         |  18 --
 pkcs11/seahorse-pkcs11-backend.c    |  43 +++-
 po/POTFILES.in                      |   2 -
 po/POTFILES.skip                    |   1 -
 src/application.vala                |  96 ++++++++-
 src/generate-select.vala            | 129 -----------
 src/key-manager.vala                | 235 ++++++++------------
 src/meson.build                     |   1 -
 src/seahorse-generate-select.ui     |  77 -------
 src/seahorse-key-manager-widgets.ui |  67 +++---
 src/seahorse-key-manager.ui         | 360 ++++++++++++++++++++++++++-----
 ssh/actions.vala                    |  64 +++---
 ssh/backend.vala                    |   3 +-
 ssh/generate.vala                   |  22 +-
 ssh/key.vala                        |   1 -
 31 files changed, 908 insertions(+), 1146 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..f8f9a911 100644
--- a/common/catalog.vala
+++ b/common/catalog.vala
@@ -21,335 +21,131 @@
 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;
-       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);
-               });
-
-               /* 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);
-               var width = this._settings.get_int("width");
-               var height = this._settings.get_int("height");
-               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);
-
-               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);
-       }
-
-       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;
-
-                       int width, height;
-                       this.get_size(out width, out height);
-                       this._settings.set_int("width", width);
-                       this._settings.set_int("height", height);
-               }
-
-               base.dispose();
-       }
-
-       public virtual signal void selection_changed() {
-               bool can_properties = false;
-               bool can_delete = false;
-               bool can_export = false;
-
-               var objects = this.get_selected_objects();
-               foreach (var object in objects) {
-                       if (Exportable.can_export(object))
-                               can_export = true;
-                       if (Deletable.can_delete(object))
-                               can_delete = true;
-                       if (Viewable.can_view(object))
-                               can_properties = true;
-                       if (can_export && can_delete && can_properties)
-                               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();
-       }
+    /* Set by the derived classes */
+    public string ui_name { construct; get; }
+
+    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();
+
+    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);
+        var width = this._settings.get_int("width");
+        var height = this._settings.get_int("height");
+        if (width > 0 && height > 0)
+            this.resize (width, height);
+
+        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");
+
+        add_action_entries (ACTION_ENTRIES, this);
+    }
 
-       public void include_actions(Gtk.ActionGroup group) {
-               this._ui_manager.insert_action_group(group, 10);
+    public override void dispose() {
+        if (!this._disposed) {
+            this._disposed = true;
 
-               if (group is Actions) {
-                       var actions = (Actions)group;
-                       actions.catalog = this;
+            int width, height;
+            this.get_size(out width, out height);
+            this._settings.set_int("width", width);
+            this._settings.set_int("height", height);
+        }
 
-                       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);
-                               }
-                       }
-               }
+        base.dispose();
+    }
 
-               this._actions.add(group);
-       }
+    public virtual signal void selection_changed() {
+        bool can_properties = false;
+        bool can_delete = false;
+        bool can_export = false;
+
+        var objects = this.get_selected_objects();
+        foreach (var object in objects) {
+            if (Exportable.can_export(object))
+                can_export = true;
+            if (Deletable.can_delete(object))
+                can_delete = true;
+            if (Viewable.can_view(object))
+                can_properties = true;
+            if (can_export && can_delete && can_properties)
+                break;
+        }
 
-       public void show_properties(GLib.Object obj) {
-               Viewable.view(obj, this);
-       }
+        ((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_context_menu(string name, Gdk.Event? event) {
-        var widget = this._ui_manager.get_widget("/%s".printf(name));
+    public void show_properties(GLib.Object obj) {
+        Viewable.view(obj, this);
+    }
 
-        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)
-       {
-               try {
-                       var objects = this.get_selected_objects();
-                       Deletable.delete_with_prompt_wait(objects, this);
-               } catch (GLib.Error err) {
-                       Util.show_error(this, _("Cannot delete"), err.message);
-               }
-       }
-
-       [CCode (instance_pos = -1)]
-       private void on_properties_object(Gtk.Action action) {
-               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);
-       }
-
-       [CCode (instance_pos = -1)]
-       private void on_key_export_file (Gtk.Action action) {
-               try {
-                       Exportable.export_to_prompt_wait(this.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) {
-               uint8[] output;
-               try {
-                       var objects = this.get_selected_objects ();
-                       Exportable.export_to_text_wait (objects, out output);
-               } catch (GLib.Error err) {
-                       Util.show_error(this, _("Couldn’t export data"), err.message);
-                       return;
-               }
-
-               /* TODO: Print message if only partially exported */
+    private void on_object_delete(SimpleAction action, Variant? param) {
+        try {
+            var objects = this.get_selected_objects();
+            Deletable.delete_with_prompt_wait(objects, this);
+        } catch (GLib.Error err) {
+            Util.show_error(this, _("Cannot delete"), err.message);
+        }
+    }
 
-               var board = Gtk.Clipboard.get(Gdk.SELECTION_CLIPBOARD);
-               board.set_text ((string)output, output.length);
-       }
+    private void on_properties_object(SimpleAction action, Variant? param) {
+        var objects = get_selected_objects();
+        if (objects.length() > 0)
+            show_properties(objects.data);
+    }
 
-       [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 void on_key_export_file(SimpleAction action, Variant? param) {
+        try {
+            Exportable.export_to_prompt_wait(get_selected_objects(), this);
+        } catch (GLib.Error err) {
+            Util.show_error(this, _("Couldn’t export keys"), 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 }
-       };
+    private void on_key_export_clipboard (SimpleAction action, Variant? param) {
+        uint8[] output;
+        try {
+            var objects = this.get_selected_objects ();
+            Exportable.export_to_text_wait (objects, out output);
+        } catch (GLib.Error err) {
+            Util.show_error(this, _("Couldn’t export data"), err.message);
+            return;
+        }
 
+        /* TODO: Print message if only partially exported */
 
+        var board = Gtk.Clipboard.get(Gdk.SELECTION_CLIPBOARD);
+        board.set_text ((string)output, output.length);
+    }
 }
 
 }
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/data/seahorse.gresource.xml b/data/seahorse.gresource.xml
index 15122f9b..9b529408 100644
--- a/data/seahorse.gresource.xml
+++ b/data/seahorse.gresource.xml
@@ -11,7 +11,6 @@
 
     <!-- Seahorse -->
     <file alias="seahorse-change-passphrase.ui" 
preprocess="xml-stripblanks">../src/seahorse-change-passphrase.ui</file>
-    <file alias="seahorse-generate-select.ui" 
preprocess="xml-stripblanks">../src/seahorse-generate-select.ui</file>
     <file alias="seahorse-key-manager-widgets.ui" 
preprocess="xml-stripblanks">../src/seahorse-key-manager-widgets.ui</file>
     <file alias="seahorse-key-manager.ui" preprocess="xml-stripblanks">../src/seahorse-key-manager.ui</file>
 
diff --git a/gkr/gkr-backend.vala b/gkr/gkr-backend.vala
index 1abdab52..75445661 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,6 @@ 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;
                base.dispose();
        }
 
@@ -208,14 +207,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 +229,38 @@ 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);
                });
 
                this.backend.notify_property("service");
        }
 
-       private BackendActions(Backend backend) {
-               GLib.Object(name: "KeyringBackend", backend: backend);
-       }
+    private BackendActions(Backend backend) {
+        GLib.Object(
+            prefix: "gkr",
+            backend: backend
+        );
+    }
 
-       private static void on_new_keyring(Gtk.Action action) {
-               new KeyringAdd(Action.get_window(action));
-       }
+    private void on_new_keyring(SimpleAction action, Variant? param) {
+        var dialog = new KeyringAdd(this.catalog);
 
-       private static void on_new_item(Gtk.Action action) {
-               new ItemAdd(Action.get_window(action));
-       }
+        int response = dialog.run();
+        if (response == Gtk.ResponseType.ACCEPT)
+            this.catalog.activate_action("focus-place", "secret-service");
+        dialog.destroy();
+    }
+
+    private void on_new_item(SimpleAction action, Variant? param) {
+        var dialog = new ItemAdd(this.catalog);
+
+        int response = dialog.run();
+        if (response == Gtk.ResponseType.ACCEPT)
+            this.catalog.activate_action("focus-place", "secret-service");
+        dialog.destroy();
+    }
 
-       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 },
-       };
-
-       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 const string BACKEND_UI =
-               """"<ui>
-                       <popup name='SeahorseGkrBackend'>
-                               <menuitem action='keyring-new'/>
-                       </popup>
-               </ui>""";
-
-       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-item-add.vala b/gkr/gkr-item-add.vala
index f130c5ac..f27146d4 100644
--- a/gkr/gkr-item-add.vala
+++ b/gkr/gkr-item-add.vala
@@ -65,8 +65,6 @@ public class Seahorse.Gkr.ItemAdd : Gtk.Dialog {
             transient_for: parent,
             use_header_bar: 1
         );
-        show();
-        present();
     }
 
     [GtkCallback]
@@ -75,10 +73,8 @@ public class Seahorse.Gkr.ItemAdd : Gtk.Dialog {
     }
 
     public override void response(int resp) {
-        if (resp != Gtk.ResponseType.ACCEPT) {
-            this.destroy();
+        if (resp != Gtk.ResponseType.ACCEPT)
             return;
-        }
 
         Gtk.TreeIter iter;
         if (!this.item_keyring_combo.get_active_iter(out iter))
@@ -90,11 +86,13 @@ public class Seahorse.Gkr.ItemAdd : Gtk.Dialog {
         var keyring = (Keyring) collection;
         var cancellable = new Cancellable();
         var interaction = new Interaction(this);
+        var item_buffer = this.item_entry.buffer;
+        var secret_buffer = this.password_entry.buffer;
 
         keyring.unlock.begin(interaction, cancellable, (obj, res) => {
             try {
                 if (keyring.unlock.end(res)) {
-                    create_secret(collection);
+                    create_secret(item_buffer, secret_buffer, collection);
                 }
             } catch (Error e) {
                 Util.show_error(this, _("Couldn’t unlock"), e.message);
@@ -102,8 +100,10 @@ public class Seahorse.Gkr.ItemAdd : Gtk.Dialog {
         });
     }
 
-    private void create_secret(Secret.Collection collection) {
-        var secret = new Secret.Value(this.password_entry.text, -1, "text/plain");
+    private void create_secret(Gtk.EntryBuffer item_buffer,
+                               Gtk.EntryBuffer secret_buffer,
+                               Secret.Collection collection) {
+        var secret = new Secret.Value(secret_buffer.text, -1, "text/plain");
         var cancellable = Dialog.begin_request(this);
         var attributes = new HashTable<string, string>(GLib.str_hash, GLib.str_equal);
 
@@ -111,7 +111,7 @@ public class Seahorse.Gkr.ItemAdd : Gtk.Dialog {
         var schema = new Secret.Schema("org.gnome.keyring.Note", Secret.SchemaFlags.NONE);
 
         Secret.Item.create.begin(collection, schema, attributes,
-                                 this.item_entry.text, secret, Secret.ItemCreateFlags.NONE,
+                                 item_buffer.text, secret, Secret.ItemCreateFlags.NONE,
                                  cancellable, (obj, res) => {
             try {
                 /* Clear the operation without cancelling it since it is complete */
@@ -121,8 +121,6 @@ public class Seahorse.Gkr.ItemAdd : Gtk.Dialog {
             } catch (GLib.Error err) {
                 Util.show_error(this, _("Couldn’t add item"), err.message);
             }
-
-            this.destroy();
         });
     }
 }
diff --git a/gkr/gkr-keyring-add.vala b/gkr/gkr-keyring-add.vala
index aaf55622..4e92a520 100644
--- a/gkr/gkr-keyring-add.vala
+++ b/gkr/gkr-keyring-add.vala
@@ -31,8 +31,6 @@ public class Seahorse.Gkr.KeyringAdd : Gtk.Dialog {
             transient_for: parent,
             use_header_bar: 1
         );
-        show();
-        present();
     }
 
     public override void response(int resp) {
diff --git a/gkr/gkr-keyring.vala b/gkr/gkr-keyring.vala
index 096bb0ae..49f94f95 100644
--- a/gkr/gkr-keyring.vala
+++ b/gkr/gkr-keyring.vala
@@ -163,7 +163,7 @@ 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 = null;
                var service = this.service;
 
                service.set_alias.begin("default", this, null, (obj, res) => {
@@ -178,7 +178,7 @@ 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 = null;
                var service = this.service;
                service.get_connection().call.begin(service.get_name(),
                                                    service.get_object_path(),
diff --git a/libseahorse/seahorse.css b/libseahorse/seahorse.css
index 94a6e179..b44b7f83 100644
--- a/libseahorse/seahorse.css
+++ b/libseahorse/seahorse.css
@@ -5,6 +5,10 @@
     border-radius: 0;
 }
 
+.new-item-list {
+    background-color: transparent;
+}
+
 .pane-separator {
     border-width: 1px 1px 0 0;
     border-style: solid;
diff --git a/pgp/seahorse-gpgme-generate.c b/pgp/seahorse-gpgme-generate.c
index 466b2b9f..cd44502c 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
  */
@@ -172,10 +120,19 @@ on_generate_key_complete (GObject *source,
                           GAsyncResult *result,
                           gpointer user_data)
 {
-       GError *error = NULL;
+    SeahorseCatalog *catalog = SEAHORSE_CATALOG (user_data);
+    GError *error = NULL;
 
-       if (!seahorse_gpgme_key_op_generate_finish (SEAHORSE_GPGME_KEYRING (source), result, &error))
-               seahorse_util_handle_error (&error, NULL, _("Couldn’t generate PGP key"));
+    if (!seahorse_gpgme_key_op_generate_finish (SEAHORSE_GPGME_KEYRING (source), result, &error)) {
+        seahorse_util_handle_error (&error,
+                                    GTK_WINDOW (catalog),
+                                    _("Couldn’t generate PGP key"));
+        return;
+    }
+
+    g_action_group_activate_action (G_ACTION_GROUP (catalog),
+                                    "focus-place",
+                                    g_variant_new_string ("gnupg"));
 }
 
 /**
@@ -203,34 +160,34 @@ seahorse_gpgme_generate_key (SeahorseGpgmeKeyring *keyring,
                              time_t expires,
                              GtkWindow *parent)
 {
-       GCancellable *cancellable;
-       const gchar *pass;
-       SeahorsePassphrasePrompt *dialog;
-       const gchar *notice;
-
-       dialog = seahorse_passphrase_prompt_show_dialog (_("Passphrase for New PGP Key"),
-                                                 _("Enter the passphrase for your new key twice."),
-                                                 NULL, NULL, TRUE);
-       gtk_window_set_transient_for (GTK_WINDOW (dialog), parent);
-       if (gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_ACCEPT) {
-               pass = seahorse_passphrase_prompt_get_text (dialog);
-               cancellable = g_cancellable_new ();
-               seahorse_gpgme_key_op_generate_async (keyring, name, email, comment,
-                                                     pass, type, bits, expires,
-                                                     cancellable, on_generate_key_complete,
-                                                     NULL);
-
-               /* Has line breaks because GtkLabel is completely broken WRT wrapping */
-               notice = _("When creating a key we need to generate a lot of\n"
-                          "random data and we need you to help. It’s a good\n"
-                          "idea to perform some other action like typing on\n"
-                          "the keyboard, moving the mouse, using applications.\n"
-                          "This gives the system the random data that it needs.");
-               seahorse_progress_show_with_notice (cancellable, _("Generating key"), notice, FALSE);
-               g_object_unref (cancellable);
-       }
-
-       gtk_widget_destroy (GTK_WIDGET (dialog));
+    GCancellable *cancellable;
+    const gchar *pass;
+    SeahorsePassphrasePrompt *dialog;
+    const gchar *notice;
+
+    dialog = seahorse_passphrase_prompt_show_dialog (_("Passphrase for New PGP Key"),
+                                              _("Enter the passphrase for your new key twice."),
+                                              NULL, NULL, TRUE);
+    gtk_window_set_transient_for (GTK_WINDOW (dialog), parent);
+    if (gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_ACCEPT) {
+        pass = seahorse_passphrase_prompt_get_text (dialog);
+        cancellable = g_cancellable_new ();
+        seahorse_gpgme_key_op_generate_async (keyring, name, email, comment,
+                                              pass, type, bits, expires,
+                                              cancellable, on_generate_key_complete,
+                                              parent);
+
+        /* Has line breaks because GtkLabel is completely broken WRT wrapping */
+        notice = _("When creating a key we need to generate a lot of\n"
+                   "random data and we need you to help. It’s a good\n"
+                   "idea to perform some other action like typing on\n"
+                   "the keyboard, moving the mouse, using applications.\n"
+                   "This gives the system the random data that it needs.");
+        seahorse_progress_show_with_notice (cancellable, _("Generating key"), notice, FALSE);
+        g_object_unref (cancellable);
+    }
+
+    gtk_widget_destroy (GTK_WIDGET (dialog));
 }
 
 
diff --git a/pgp/seahorse-gpgme-key.c b/pgp/seahorse-gpgme-key.c
index ac52c2a9..8c2802a3 100644
--- a/pgp/seahorse-gpgme-key.c
+++ b/pgp/seahorse-gpgme-key.c
@@ -27,7 +27,6 @@
 #include "seahorse-gpgme-keyring.h"
 #include "seahorse-gpgme-secret-deleter.h"
 #include "seahorse-gpgme-uid.h"
-#include "seahorse-pgp-actions.h"
 #include "seahorse-pgp-backend.h"
 #include "seahorse-pgp-key.h"
 
@@ -308,7 +307,6 @@ void
 seahorse_gpgme_key_realize (SeahorseGpgmeKey *self)
 {
        SeahorseUsage usage;
-       GtkActionGroup *actions;
        guint flags;
 
        if (!self->pv->pubkey)
@@ -359,13 +357,10 @@ seahorse_gpgme_key_realize (SeahorseGpgmeKey *self)
                usage = SEAHORSE_USAGE_PUBLIC_KEY;
        }
 
-       actions = seahorse_gpgme_key_actions_instance ();
        g_object_set (self,
                      "usage", usage,
                      "object-flags", flags,
-                     "actions", actions,
                      NULL);
-       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..a39e2653 100644
--- a/pgp/seahorse-pgp-actions.c
+++ b/pgp/seahorse-pgp-actions.c
@@ -47,91 +47,100 @@ 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);
-       SeahorseGpgmeKeyring *keyring;
-       SeahorseCatalog *catalog;
-       GList *objects = NULL;
-       GList *keys = NULL;
-       GList *l;
-
-       catalog = seahorse_actions_get_catalog (actions);
-       if (catalog != NULL) {
-               objects = seahorse_catalog_get_selected_objects (catalog);
-               for (l = objects; l != NULL; l = g_list_next (l)) {
-                       if (SEAHORSE_PGP_IS_KEY (l->data))
-                               keys = g_list_prepend (keys, l->data);
-               }
-               g_list_free (objects);
-       }
-       g_object_unref (catalog);
-
-       if (keys == NULL) {
-               keyring = seahorse_pgp_backend_get_default_keyring (NULL);
-               keys = gcr_collection_get_objects (GCR_COLLECTION (keyring));
-       }
-
-       seahorse_keyserver_sync_show (keys, seahorse_action_get_window (action));
-       g_list_free (keys);
+  SeahorseActionGroup *actions = SEAHORSE_ACTION_GROUP (user_data);
+  SeahorseGpgmeKeyring *keyring;
+  SeahorseCatalog *catalog;
+  GList *objects = NULL;
+  GList *keys = NULL;
+  GList *l;
+
+  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)) {
+      if (SEAHORSE_PGP_IS_KEY (l->data))
+        keys = g_list_prepend (keys, l->data);
+    }
+    g_list_free (objects);
+  }
+  g_object_unref (catalog);
+
+  if (keys == NULL) {
+    keyring = seahorse_pgp_backend_get_default_keyring (NULL);
+    keys = gcr_collection_get_objects (GCR_COLLECTION (keyring));
+  }
+
+  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);
+
+    g_action_map_add_action_entries (action_map,
+                                     ACTION_ENTRIES,
+                                     G_N_ELEMENTS (ACTION_ENTRIES),
+                                     self);
 }
 
 static void
@@ -140,22 +149,22 @@ seahorse_pgp_backend_actions_class_init (SeahorsePgpBackendActionsClass *klass)
 
 }
 
-GtkActionGroup *
+SeahorseActionGroup *
 seahorse_pgp_backend_actions_instance (void)
 {
-       static GtkActionGroup *actions = NULL;
-
-       if (actions == NULL) {
-               actions = g_object_new (SEAHORSE_PGP_TYPE_BACKEND_ACTIONS,
-                                       "name", "pgp-backend",
-                                       NULL);
-               g_object_add_weak_pointer (G_OBJECT (actions),
-                                          (gpointer *)&actions);
-       } else {
-               g_object_ref (actions);
-       }
-
-       return actions;
+    static SeahorseActionGroup *actions = NULL;
+
+    if (actions == NULL) {
+        actions = g_object_new (SEAHORSE_PGP_TYPE_BACKEND_ACTIONS,
+                                "prefix", "pgp",
+                                NULL);
+        g_object_add_weak_pointer (G_OBJECT (actions),
+                                   (gpointer *)&actions);
+    } else {
+        g_object_ref (actions);
+    }
+
+    return actions;
 }
 
 GType   seahorse_gpgme_key_actions_get_type       (void) G_GNUC_CONST;
@@ -167,24 +176,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,20 +196,20 @@ seahorse_gpgme_key_actions_class_init (SeahorseGpgmeKeyActionsClass *klass)
 
 }
 
-GtkActionGroup *
+SeahorseActionGroup *
 seahorse_gpgme_key_actions_instance (void)
 {
-       static GtkActionGroup *actions = NULL;
-
-       if (actions == NULL) {
-               actions = g_object_new (SEAHORSE_TYPE_GPGME_KEY_ACTIONS,
-                                       "name", "gpgme-key",
-                                       NULL);
-               g_object_add_weak_pointer (G_OBJECT (actions),
-                                          (gpointer *)&actions);
-       } else {
-               g_object_ref (actions);
-       }
-
-       return actions;
+    static SeahorseActionGroup *actions = NULL;
+
+    if (actions == NULL) {
+        actions = g_object_new (SEAHORSE_TYPE_GPGME_KEY_ACTIONS,
+                                "prefix", "gpgme",
+                                NULL);
+        g_object_add_weak_pointer (G_OBJECT (actions),
+                                   (gpointer *)&actions);
+    } else {
+        g_object_ref (actions);
+    }
+
+    return 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..b7ea21e1 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,18 @@ 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)
+{
+    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);
+}
+
 static void
 seahorse_pkcs11_backend_init (SeahorsePkcs11Backend *self)
 {
@@ -93,7 +113,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 +221,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 +274,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 +425,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/po/POTFILES.in b/po/POTFILES.in
index e7f273ba..24bcdcb8 100644
--- a/po/POTFILES.in
+++ b/po/POTFILES.in
@@ -90,12 +90,10 @@ pkcs11/seahorse-pkcs11-backend.c
 pkcs11/seahorse-pkcs11-generate.ui
 pkcs11/seahorse-pkcs11-request.ui
 src/application.vala
-src/generate-select.vala
 src/import-dialog.vala
 src/key-manager.vala
 src/main.vala
 src/seahorse-change-passphrase.ui
-src/seahorse-generate-select.ui
 src/seahorse-key-manager.ui
 src/seahorse-key-manager-widgets.ui
 src/search-provider.vala
diff --git a/po/POTFILES.skip b/po/POTFILES.skip
index e647ef34..f8b9cebe 100644
--- a/po/POTFILES.skip
+++ b/po/POTFILES.skip
@@ -29,7 +29,6 @@ pkcs11/pkcs11-properties.c
 pkcs11/pkcs11-request.c
 pkcs11/pkcs11-token.c
 src/application.c
-src/generate-select.c
 src/import-dialog.c
 src/key-manager.c
 src/main.c
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/key-manager.vala b/src/key-manager.vala
index 25870b1d..959effea 100644
--- a/src/key-manager.vala
+++ b/src/key-manager.vala
@@ -24,56 +24,36 @@
 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.MenuButton new_item_button;
 
+    [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'" },
+         { "focus-place",        on_focus_place,               "s",           "'secret-service'" },
+         { "import-file",        on_import_file                                                  },
+         { "combine-keyrings",   on_toggle_action,  null,  "false",  on_combine_keyrings_toggled },
+         { "paste",              on_paste,                                                       },
     };
 
     public KeyManager(Application app) {
@@ -91,6 +71,8 @@ public class Seahorse.KeyManager : Catalog {
 
         this.collection = setup_sidebar();
 
+        load_css();
+
         // Init key list & selection settings
         Gtk.TreeSelection selection = this.key_list.get_selection();
         selection.set_mode(Gtk.SelectionMode.MULTIPLE);
@@ -106,18 +88,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 +100,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 +113,26 @@ 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() {
+        add_action_entries (action_entries, this);
     }
 
-    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());
+    private void load_css() {
+        Gtk.CssProvider provider = new Gtk.CssProvider();
+        Gtk.StyleContext.add_provider_for_screen(
+            Gdk.Display.get_default().get_default_screen(),
+            provider, Gtk.STYLE_PROVIDER_PRIORITY_APPLICATION);
+
+        provider.parsing_error.connect((section, error) => {
+            uint start = section.get_start_line();
+            uint end = section.get_end_line();
+            if (start == end)
+                debug("Error parsing css on line %u: %s", start, error.message);
+            else
+                debug("Error parsing css on lines %u-%u: %s", start, end, error.message);
         });
-        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();
+        provider.load_from_resource("/org/gnome/Seahorse/seahorse.css");
     }
 
     private void on_view_selection_changed(Gtk.TreeSelection selection) {
@@ -191,6 +144,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 +163,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 +176,27 @@ 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) {
-        GenerateSelect dialog = new GenerateSelect(this);
-        dialog.run();
-        dialog.destroy();
+    private void on_new_item(SimpleAction action, GLib.Variant? param) {
+        this.new_item_button.activate();
     }
 
-    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 +210,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 +273,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 +296,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,46 +318,34 @@ 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() {
         return KeyManagerStore.get_selected_objects(this.key_list);
     }
 
-    public void set_focused_place(string target) {
-        string? uri_prefix = null;
-        switch(target) {
-            case "ssh":
-            case "pkcs11":
-                uri_prefix = "openssh";
-                break;
-            case "gpgme":
-                uri_prefix = "gnupg";
-                break;
-            case "gkr":
-                uri_prefix = "secret-service";
-                break;
-        }
+    private void on_focus_place(SimpleAction action, Variant? param) {
+        string? uri_prefix = param.get_string();
         if (uri_prefix != null) {
             this.sidebar.set_focused_place(uri_prefix);
         }
@@ -406,9 +359,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 +367,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;
@@ -440,4 +383,10 @@ public class Seahorse.KeyManager : Catalog {
     public override List<weak Backend> get_backends() {
         return this.sidebar.get_backends();
     }
+
+    [GtkCallback]
+    private void on_popover_grab_notify(Gtk.Widget widget, bool was_grabbed) {
+        if (!was_grabbed)
+            widget.hide();
+    }
 }
diff --git a/src/meson.build b/src/meson.build
index 950c3c8d..93a5c13a 100644
--- a/src/meson.build
+++ b/src/meson.build
@@ -6,7 +6,6 @@ search_provider_src = gnome.gdbus_codegen('seahorse-shell-search-provider-genera
 
 seahorse_sources = [
   'application.vala',
-  'generate-select.vala',
   'import-dialog.vala',
   'key-manager.vala',
   'main.vala',
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..e1d4811f 100644
--- a/src/seahorse-key-manager.ui
+++ b/src/seahorse-key-manager.ui
@@ -1,31 +1,324 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <interface>
   <requires lib="gtk+" version="3.22"/>
-  <template class="SeahorseKeyManager" parent="SeahorseCatalog">
-    <property name="title" translatable="yes">Passwords and Keys</property>
+  <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">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>
+  <object class="GtkPopover" id="new_item_menu_popover">
+    <signal name="grab-notify" handler="on_popover_grab_notify" after="yes"/>
     <child>
       <object class="GtkBox">
         <property name="visible">True</property>
         <property name="orientation">vertical</property>
         <property name="can_focus">False</property>
+        <property name="border_width">6</property>
         <child>
-          <object class="GtkBox" id="menu_placeholder">
+          <object class="GtkListBox" id="generate_list">
             <property name="visible">True</property>
-            <property name="orientation">vertical</property>
-            <property name="can_focus">False</property>
+            <property name="selection-mode">none</property>
+            <property name="can_focus">True</property>
+            <property name="has_focus">True</property>
+            <property name="selection-mode">browse</property>
+            <style>
+              <class name="new-item-list"/>
+            </style>
+            <child>
+              <object class="GtkListBoxRow" id="ssh_generate_key_button">
+                <property name="visible" bind-source="ssh_generate_key_button" bind-property="sensitive" />
+                <property name="margin">3</property>
+                <property name="selectable">False</property>
+                <property name="action-name">ssh.generate-key</property>
+                <child>
+                  <object class="GtkGrid">
+                    <property name="visible">True</property>
+                    <property name="orientation">vertical</property>
+                    <child>
+                      <object class="GtkLabel">
+                        <property name="visible">True</property>
+                        <property name="halign">start</property>
+                        <property name="label" translatable="yes">Secure Shell key</property>
+                      </object>
+                    </child>
+                    <child>
+                      <object class="GtkLabel">
+                        <property name="visible">True</property>
+                        <property name="halign">start</property>
+                        <property name="label" translatable="yes">Used to access other computers</property>
+                        <style>
+                          <class name="dim-label"/>
+                        </style>
+                      </object>
+                    </child>
+                  </object>
+                </child>
+              </object>
+            </child>
+            <child>
+              <object class="GtkListBoxRow" id="pgp_generate_key_button">
+                <property name="visible" bind-source="pgp_generate_key_button" bind-property="sensitive" />
+                <property name="margin">3</property>
+                <property name="selectable">False</property>
+                <property name="action-name">pgp.pgp-generate-key</property>
+                <child>
+                  <object class="GtkGrid">
+                    <property name="visible">True</property>
+                    <property name="orientation">vertical</property>
+                    <child>
+                      <object class="GtkLabel">
+                        <property name="visible">True</property>
+                        <property name="halign">start</property>
+                        <property name="label" translatable="yes">GPG key</property>
+                      </object>
+                    </child>
+                    <child>
+                      <object class="GtkLabel">
+                        <property name="visible">True</property>
+                        <property name="halign">start</property>
+                        <property name="label" translatable="yes">Used to encrypt email and files</property>
+                        <style>
+                          <class name="dim-label"/>
+                        </style>
+                      </object>
+                    </child>
+                  </object>
+                </child>
+              </object>
+            </child>
+            <child>
+              <object class="GtkListBoxRow" id="gkr_generate_keyring_button">
+                <property name="visible" bind-source="gkr_generate_keyring_button" bind-property="sensitive" 
/>
+                <property name="margin">3</property>
+                <property name="selectable">False</property>
+                <property name="action-name">gkr.keyring-new</property>
+                <child>
+                  <object class="GtkGrid">
+                    <property name="visible">True</property>
+                    <property name="orientation">vertical</property>
+                    <child>
+                      <object class="GtkLabel">
+                        <property name="visible">True</property>
+                        <property name="halign">start</property>
+                        <property name="label" translatable="yes">Password keyring</property>
+                      </object>
+                    </child>
+                    <child>
+                      <object class="GtkLabel">
+                        <property name="visible">True</property>
+                        <property name="halign">start</property>
+                        <property name="label" translatable="yes">Used to store application and network 
passwords</property>
+                        <style>
+                          <class name="dim-label"/>
+                        </style>
+                      </object>
+                    </child>
+                  </object>
+                </child>
+              </object>
+            </child>
             <child>
-              <placeholder/>
+              <object class="GtkListBoxRow" id="gkr_generate_item_button">
+                <property name="visible" bind-source="gkr_generate_item_button" bind-property="sensitive" />
+                <property name="margin">3</property>
+                <property name="selectable">False</property>
+                <property name="action-name">gkr.keyring-item-new</property>
+                <child>
+                  <object class="GtkGrid">
+                    <property name="visible">True</property>
+                    <property name="orientation">vertical</property>
+                    <child>
+                      <object class="GtkLabel">
+                        <property name="visible">True</property>
+                        <property name="halign">start</property>
+                        <property name="label" translatable="yes">Password</property>
+                      </object>
+                    </child>
+                    <child>
+                      <object class="GtkLabel">
+                        <property name="visible">True</property>
+                        <property name="halign">start</property>
+                        <property name="label" translatable="yes">Safely store a password or 
secret</property>
+                        <style>
+                          <class name="dim-label"/>
+                        </style>
+                      </object>
+                    </child>
+                  </object>
+                </child>
+              </object>
+            </child>
+            <child>
+              <object class="GtkListBoxRow" id="pkcs11_generate_key_button">
+                <property name="visible" bind-source="pkcs11_generate_key_button" bind-property="sensitive" 
/>
+                <property name="margin">3</property>
+                <property name="selectable">False</property>
+                <property name="action-name">pkcs11.pkcs11-generate-key</property>
+                <child>
+                  <object class="GtkGrid">
+                    <property name="visible">True</property>
+                    <property name="orientation">vertical</property>
+                    <child>
+                      <object class="GtkLabel">
+                        <property name="visible">True</property>
+                        <property name="halign">start</property>
+                        <property name="label" translatable="yes">Private key</property>
+                      </object>
+                    </child>
+                    <child>
+                      <object class="GtkLabel">
+                        <property name="visible">True</property>
+                        <property name="halign">start</property>
+                        <property name="label" translatable="yes">Used to request a certificate</property>
+                        <style>
+                          <class name="dim-label"/>
+                        </style>
+                      </object>
+                    </child>
+                  </object>
+                </child>
+              </object>
+            </child>
+            <child>
+              <object class="GtkListBoxRow" id="import_from_file_button">
+                <property name="visible" bind-source="import_from_file_button" bind-property="sensitive" />
+                <property name="margin">6</property>
+                <property name="selectable">False</property>
+                <property name="action-name">win.import-file</property>
+                <child>
+                  <object class="GtkGrid">
+                    <property name="visible">True</property>
+                    <property name="orientation">vertical</property>
+                    <child>
+                      <object class="GtkLabel">
+                        <property name="visible">True</property>
+                        <property name="halign">start</property>
+                        <property name="vexpand">True</property>
+                        <property name="label" translatable="yes">Import from file…</property>
+                      </object>
+                    </child>
+                  </object>
+                </child>
+              </object>
+            </child>
+          </object>
+        </child>
+      </object>
+    </child>
+  </object>
+  <template class="SeahorseKeyManager" parent="SeahorseCatalog">
+    <child type="titlebar">
+      <object class="GtkHeaderBar">
+        <property name="visible">True</property>
+        <property name="show-close-button">True</property>
+        <property name="title" translatable="yes">Passwords and Keys</property>
+        <child>
+          <object class="GtkMenuButton" 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="popover">new_item_menu_popover</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="GtkMenuButton" id="main_menu_button">
+            <property name="visible">True</property>
+            <property name="can_focus">True</property>
+            <property name="focus_on_click">False</property>
+            <property name="menu-model">main_menu</property>
+            <child>
+              <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="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="expand">False</property>
-            <property name="fill">True</property>
-            <property name="position">0</property>
+            <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 +328,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 +356,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 +468,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 +536,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 +555,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..d2c37b1f 100644
--- a/ssh/actions.vala
+++ b/ssh/actions.vala
@@ -20,49 +20,53 @@
  * <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);
     }
 
-    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);
+
+        int response = generate_dialog.run();
+        if (response == Gtk.ResponseType.ACCEPT)
+            this.catalog.activate_action("focus-place", "openssh");
+        generate_dialog.destroy();
+    }
+
+    private void on_ssh_upload(SimpleAction action, Variant? param) {
         List<Key> keys = new List<Key>();
 
         if (this.catalog != null) {
@@ -73,6 +77,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..05b83c96 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();
@@ -121,6 +100,7 @@ public class Seahorse.Ssh.Generate : Gtk.Dialog {
         });
         Seahorse.Progress.show(cancellable, _("Creating Secure Shell Key"), false);
 
+        response(Gtk.ResponseType.ACCEPT);
         destroy();
     }
 
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]