[gedit] Move menu extension to the app-activatable



commit 1eec261b41589c62eaf98be41dd3684b01dcae51
Author: Paolo Borelli <pborelli gnome org>
Date:   Tue Feb 4 15:30:05 2014 +0100

    Move menu extension to the app-activatable
    
    It is important that the menu-model for the gear menu is a single
    instance shared among all the windows. This makes it consistent
    with the app-menu model and plugins can extend them in the same
    way without causing items to be added multiple times when there
    is more than a window.
    The extension API is thus moved to the app activatable interface
    and the plugins are adapted to use the new api.

 docs/reference/gedit-sections.txt                |    1 +
 gedit/gedit-app-activatable.c                    |   18 ++
 gedit/gedit-app-activatable.h                    |   21 ++-
 gedit/gedit-app.c                                |  134 ++++++++++----
 gedit/gedit-app.h                                |    6 +-
 gedit/gedit-menu.ui                              |  218 ++++++++++++++++++++++
 gedit/gedit-window-activatable.c                 |   57 ------
 gedit/gedit-window-activatable.h                 |   15 --
 gedit/gedit-window-private.h                     |    3 -
 gedit/gedit-window.c                             |   35 +---
 gedit/gedit-window.ui                            |  218 ----------------------
 plugins/docinfo/gedit-docinfo-plugin.c           |   84 +++++++--
 plugins/externaltools/tools/Makefile.am          |    1 +
 plugins/externaltools/tools/__init__.py          |   15 +--
 plugins/externaltools/tools/appactivatable.py    |   99 ++++++++++
 plugins/externaltools/tools/windowactivatable.py |   58 ++-----
 plugins/quickopen/quickopen/__init__.py          |   25 +--
 plugins/snippets/snippets/appactivatable.py      |   20 ++-
 plugins/snippets/snippets/windowactivatable.py   |   21 --
 plugins/sort/gedit-sort-plugin.c                 |   82 +++++++--
 plugins/spell/gedit-spell-app-activatable.c      |   25 ++-
 plugins/spell/gedit-spell-plugin.c               |   19 +--
 plugins/time/gedit-time-plugin.c                 |   84 +++++++--
 23 files changed, 724 insertions(+), 535 deletions(-)
---
diff --git a/docs/reference/gedit-sections.txt b/docs/reference/gedit-sections.txt
index f3194fc..8938fa5 100644
--- a/docs/reference/gedit-sections.txt
+++ b/docs/reference/gedit-sections.txt
@@ -24,6 +24,7 @@ GEDIT_APP_GET_CLASS
 GeditAppActivatable
 gedit_app_activatable_activate
 gedit_app_activatable_deactivate
+gedit_app_activatable_extend_menu
 <SUBSECTION Standard>
 GEDIT_TYPE_APP_ACTIVATABLE
 GEDIT_APP_ACTIVATABLE
diff --git a/gedit/gedit-app-activatable.c b/gedit/gedit-app-activatable.c
index 54a9d39..d7e2e1b 100644
--- a/gedit/gedit-app-activatable.c
+++ b/gedit/gedit-app-activatable.c
@@ -105,3 +105,21 @@ gedit_app_activatable_deactivate (GeditAppActivatable *activatable)
                iface->deactivate (activatable);
        }
 }
+
+GeditMenuExtension *
+gedit_app_activatable_extend_menu (GeditAppActivatable *activatable,
+                                  const gchar *extension_point)
+{
+       GeditApp *app;
+       GeditMenuExtension *ext;
+
+       g_return_val_if_fail (GEDIT_IS_APP_ACTIVATABLE (activatable), NULL);
+
+       g_object_get (G_OBJECT (activatable), "app", &app, NULL);
+       ext = _gedit_app_extend_menu (app, extension_point);
+       g_object_unref (app);
+
+       return ext;
+}
+
+/* ex:set ts=8 noet: */
diff --git a/gedit/gedit-app-activatable.h b/gedit/gedit-app-activatable.h
index 018ed19..d39884f 100644
--- a/gedit/gedit-app-activatable.h
+++ b/gedit/gedit-app-activatable.h
@@ -23,6 +23,7 @@
 #define __GEDIT_APP_ACTIVATABLE_H__
 
 #include <glib-object.h>
+#include <gedit/gedit-menu-extension.h>
 
 G_BEGIN_DECLS
 
@@ -52,9 +53,25 @@ struct _GeditAppActivatableInterface
  */
 GType   gedit_app_activatable_get_type (void)  G_GNUC_CONST;
 
-void    gedit_app_activatable_activate (GeditAppActivatable *activatable);
-void    gedit_app_activatable_deactivate       (GeditAppActivatable *activatable);
+void    gedit_app_activatable_activate                 (GeditAppActivatable *activatable);
+void    gedit_app_activatable_deactivate               (GeditAppActivatable *activatable);
+
+/**
+ * gedit_app_activatable_extend_menu:
+ * @activatable: A #GeditAppActivatable.
+ * @extension_point: the extension point section of the menu to get.
+ *
+ * Gets the #GeditMenuExtension for the menu @extension_point. Note that
+ * the extension point could be in different menus (gear menu, app menu, etc)
+ * depending on the platform.
+ *
+ * Returns: (transfer full): a #GeditMenuExtension for the specific section
+ * or %NULL if not found.
+ */
+GeditMenuExtension     *gedit_app_activatable_extend_menu      (GeditAppActivatable *activatable,
+                                                                const gchar *extension_point);
 
 G_END_DECLS
 
 #endif /* __GEDIT_APP_ACTIVATABLE_H__ */
+/* ex:set ts=8 noet: */
diff --git a/gedit/gedit-app.c b/gedit/gedit-app.c
index 2684bab..f9d10d5 100644
--- a/gedit/gedit-app.c
+++ b/gedit/gedit-app.c
@@ -86,6 +86,8 @@ struct _GeditAppPrivate
        GSettings         *ui_settings;
        GSettings         *window_settings;
 
+       GMenuModel        *window_menu;
+
        PeasExtensionSet  *extensions;
        GNetworkMonitor   *monitor;
 };
@@ -216,6 +218,8 @@ gedit_app_dispose (GObject *object)
 
        g_clear_object (&app->priv->engine);
 
+       g_clear_object (&app->priv->window_menu);
+
        G_OBJECT_CLASS (gedit_app_parent_class)->dispose (object);
 }
 
@@ -414,6 +418,27 @@ extension_removed (PeasExtensionSet *extensions,
        gedit_app_activatable_deactivate (GEDIT_APP_ACTIVATABLE (exten));
 }
 
+static gboolean
+gedit_app_has_app_menu (GeditApp *app)
+{
+       GtkSettings *gtk_settings;
+       gboolean show_app_menu;
+       gboolean show_menubar;
+
+       /* We have three cases:
+        * - GNOME 3: show-app-menu true, show-menubar false -> use the app menu
+        * - Unity, OSX: show-app-menu and show-menubar true -> use the normal menu
+        * - Other WM, Windows: show-app-menu and show-menubar false -> use the normal menu
+        */
+       gtk_settings = gtk_settings_get_default ();
+       g_object_get (G_OBJECT (gtk_settings),
+                     "gtk-shell-shows-app-menu", &show_app_menu,
+                     "gtk-shell-shows-menubar", &show_menubar,
+                     NULL);
+
+       return show_app_menu && !show_menubar;
+}
+
 static void
 gedit_app_startup (GApplication *application)
 {
@@ -428,6 +453,7 @@ gedit_app_startup (GApplication *application)
        GError *error = NULL;
        GFile *css_file;
        GtkCssProvider *provider;
+       GtkBuilder *builder;
 
        G_APPLICATION_CLASS (gedit_app_parent_class)->startup (application);
 
@@ -478,31 +504,35 @@ gedit_app_startup (GApplication *application)
                                         G_N_ELEMENTS (app_entries),
                                         app);
 
-       /* app menu */
-       if (_gedit_app_has_app_menu (app))
+       /* load menu model */
+       builder = gtk_builder_new ();
+       if (!gtk_builder_add_from_resource (builder,
+                                           "/org/gnome/gedit/ui/gedit-menu.ui",
+                                           &error))
+       {
+               g_warning ("loading menu builder file: %s", error->message);
+               g_error_free (error);
+       }
+       else
        {
-               GtkBuilder *builder;
 
-               builder = gtk_builder_new ();
-               if (!gtk_builder_add_from_resource (builder,
-                                                   "/org/gnome/gedit/ui/gedit-menu.ui",
-                                                   &error))
+               if (gedit_app_has_app_menu (app))
                {
-                       g_warning ("loading menu builder file: %s", error->message);
-                       g_error_free (error);
+                       GMenuModel *appmenu;
+
+                       appmenu = G_MENU_MODEL (gtk_builder_get_object (builder, "appmenu"));
+                       gtk_application_set_app_menu (GTK_APPLICATION (application), appmenu);
+
+                       app->priv->window_menu = G_MENU_MODEL (gtk_builder_get_object (builder, 
"gear_menu_withappmenu"));
                }
                else
                {
-                       GMenuModel *app_menu;
-
-                       app_menu = G_MENU_MODEL (gtk_builder_get_object (builder, "appmenu"));
-                       gtk_application_set_app_menu (GTK_APPLICATION (application),
-                                                     app_menu);
+                       app->priv->window_menu = G_MENU_MODEL (gtk_builder_get_object (builder, 
"gear_menu_noappmenu"));
                }
-
-               g_object_unref (builder);
        }
 
+       g_object_unref (builder);
+
        /* Accelerators */
        gtk_application_add_accelerator (GTK_APPLICATION (application),
                                         "<Primary>Q", "app.quit", NULL);
@@ -1570,6 +1600,32 @@ gedit_app_process_window_event (GeditApp    *app,
     return FALSE;
 }
 
+
+static GMenuModel *
+find_extension_point_section (GMenuModel  *model,
+                              const gchar *extension_point)
+{
+       gint i, n_items;
+       GMenuModel *section = NULL;
+
+       n_items = g_menu_model_get_n_items (model);
+
+       for (i = 0; i < n_items && !section; i++)
+       {
+               gchar *id = NULL;
+
+               if (g_menu_model_get_item_attribute (model, i, "id", "s", &id) &&
+                   strcmp (id, extension_point) == 0)
+               {
+                       section = g_menu_model_get_item_link (model, i, G_MENU_LINK_SECTION);
+               }
+
+               g_free (id);
+       }
+
+       return section;
+}
+
 static void
 app_lockdown_changed (GeditApp *app)
 {
@@ -1669,27 +1725,39 @@ _gedit_app_get_settings (GeditApp *app)
        return app->priv->settings;
 }
 
-gboolean
-_gedit_app_has_app_menu (GeditApp *app)
+GMenuModel *
+_gedit_app_get_window_menu (GeditApp *app)
 {
-       GtkSettings *gtk_settings;
-       gboolean show_app_menu;
-       gboolean show_menubar;
+       g_return_val_if_fail (GEDIT_IS_APP (app), NULL);
 
-       g_return_val_if_fail (GEDIT_IS_APP (app), FALSE);
+       return app->priv->window_menu;
+}
 
-       /* We have three cases:
-        * - GNOME 3: show-app-menu true, show-menubar false -> use the app menu
-        * - Unity, OSX: show-app-menu and show-menubar true -> use the normal menu
-        * - Other WM, Windows: show-app-menu and show-menubar false -> use the normal menu
-        */
-       gtk_settings = gtk_settings_get_default ();
-       g_object_get (G_OBJECT (gtk_settings),
-                     "gtk-shell-shows-app-menu", &show_app_menu,
-                     "gtk-shell-shows-menubar", &show_menubar,
-                     NULL);
+GeditMenuExtension *
+_gedit_app_extend_menu (GeditApp    *app,
+                       const gchar *extension_point)
+{
+       GMenuModel *model;
+       GMenuModel *section;
 
-       return show_app_menu && !show_menubar;
+       g_return_val_if_fail (GEDIT_IS_APP (app), NULL);
+       g_return_val_if_fail (extension_point != NULL, NULL);
+
+       /* First look in the window menu */
+       section = find_extension_point_section (app->priv->window_menu, extension_point);
+
+       /* otherwise look in the app menu */
+       if (section == NULL)
+       {
+               model = gtk_application_get_app_menu (GTK_APPLICATION (app));
+
+               if (model != NULL)
+               {
+                       section = find_extension_point_section (model, extension_point);
+               }
+       }
+
+       return section != NULL ? _gedit_menu_extension_new (G_MENU (section)) : NULL;
 }
 
 /* ex:set ts=8 noet: */
diff --git a/gedit/gedit-app.h b/gedit/gedit-app.h
index 5a8cbc9..939bfee 100644
--- a/gedit/gedit-app.h
+++ b/gedit/gedit-app.h
@@ -32,6 +32,7 @@
 #include <gtk/gtk.h>
 
 #include <gedit/gedit-window.h>
+#include <gedit/gedit-menu-extension.h>
 
 G_BEGIN_DECLS
 
@@ -142,7 +143,10 @@ void                        _gedit_app_set_default_print_settings  (GeditApp         
*app,
 
 GObject                        *_gedit_app_get_settings                (GeditApp  *app);
 
-gboolean                _gedit_app_has_app_menu                (GeditApp  *app);
+GMenuModel             *_gedit_app_get_window_menu             (GeditApp  *app);
+
+GeditMenuExtension     *_gedit_app_extend_menu                 (GeditApp    *app,
+                                                                const gchar *extension_point);
 
 G_END_DECLS
 
diff --git a/gedit/gedit-menu.ui b/gedit/gedit-menu.ui
index 9c7288a..2e0901e 100644
--- a/gedit/gedit-menu.ui
+++ b/gedit/gedit-menu.ui
@@ -32,4 +32,222 @@
       </item>
     </section>
   </menu>
+  <menu id="gear_menu_withappmenu">
+    <section>
+      <attribute name="id">ext1</attribute>
+    </section>
+    <section>
+      <attribute name="id">ext2</attribute>
+      <item>
+        <attribute name="label" translatable="yes">_Reload</attribute>
+        <attribute name="action">win.revert</attribute>
+      </item>
+      <item>
+        <attribute name="label" translatable="yes">_Save As…</attribute>
+        <attribute name="action">win.save-as</attribute>
+      </item>
+      <item>
+        <attribute name="label" translatable="yes">Save _All</attribute>
+        <attribute name="action">win.save-all</attribute>
+      </item>
+    </section>
+    <section>
+      <attribute name="id">ext3</attribute>
+    </section>
+    <section>
+      <attribute name="id">ext4</attribute>
+      <item>
+        <attribute name="label" translatable="yes">_Print…</attribute>
+        <attribute name="action">win.print</attribute>
+      </item>
+    </section>
+    <section>
+      <attribute name="id">ext5</attribute>
+    </section>
+    <section>
+      <attribute name="id">ext6</attribute>
+      <item>
+        <attribute name="label" translatable="yes">Side _Panel</attribute>
+        <attribute name="action">win.side-panel</attribute>
+      </item>
+      <item>
+        <attribute name="label" translatable="yes">_Bottom Panel</attribute>
+        <attribute name="action">win.bottom-panel</attribute>
+        <attribute name="hidden-when">action-disabled</attribute>
+      </item>
+      <item>
+        <attribute name="label" translatable="yes">_Fullscreen</attribute>
+        <attribute name="action">win.fullscreen</attribute>
+      </item>
+    </section>
+    <section>
+      <attribute name="id">ext7</attribute>
+    </section>
+    <section>
+      <attribute name="id">ext8</attribute>
+      <item>
+        <attribute name="label" translatable="yes">_Find…</attribute>
+        <attribute name="action">win.find</attribute>
+      </item>
+      <item>
+        <attribute name="label" translatable="yes">_Find and Replace…</attribute>
+        <attribute name="action">win.replace</attribute>
+      </item>
+      <item>
+        <attribute name="label" translatable="yes">_Clear Highlight</attribute>
+        <attribute name="action">win.clear-highlight</attribute>
+      </item>
+      <item>
+        <attribute name="label" translatable="yes">_Go to Line…</attribute>
+        <attribute name="action">win.goto-line</attribute>
+      </item>
+    </section>
+    <section>
+      <attribute name="id">ext9</attribute>
+    </section>
+    <section>
+      <attribute name="id">ext10</attribute>
+      <item>
+        <attribute name="label" translatable="yes">_Highlight Mode…</attribute>
+        <attribute name="action">win.highlight-mode</attribute>
+      </item>
+    </section>
+    <section>
+      <attribute name="id">ext11</attribute>
+    </section>
+    <section>
+      <attribute name="id">ext12</attribute>
+    </section>
+    <section>
+      <attribute name="id">ext13</attribute>
+      <item>
+        <attribute name="label" translatable="yes">_Close All</attribute>
+        <attribute name="action">win.close-all</attribute>
+      </item>
+      <item>
+        <attribute name="label" translatable="yes">_Close</attribute>
+        <attribute name="action">win.close</attribute>
+      </item>
+    </section>
+  </menu>
+  <menu id="gear_menu_noappmenu">
+    <section>
+      <attribute name="id">ext1</attribute>
+    </section>
+    <section>
+      <attribute name="id">ext2</attribute>
+      <item>
+        <attribute name="label" translatable="yes">_Reload</attribute>
+        <attribute name="action">win.revert</attribute>
+      </item>
+      <item>
+        <attribute name="label" translatable="yes">_Save As…</attribute>
+        <attribute name="action">win.save-as</attribute>
+      </item>
+      <item>
+        <attribute name="label" translatable="yes">Save _All</attribute>
+        <attribute name="action">win.save-all</attribute>
+      </item>
+    </section>
+    <section>
+      <attribute name="id">ext3</attribute>
+    </section>
+    <section>
+      <attribute name="id">ext4</attribute>
+      <item>
+        <attribute name="label" translatable="yes">_Print…</attribute>
+        <attribute name="action">win.print</attribute>
+      </item>
+    </section>
+    <section>
+      <attribute name="id">ext5</attribute>
+    </section>
+    <section>
+      <attribute name="id">ext6</attribute>
+      <item>
+        <attribute name="label" translatable="yes">Side _Panel</attribute>
+        <attribute name="action">win.side-panel</attribute>
+      </item>
+      <item>
+        <attribute name="label" translatable="yes">_Bottom Panel</attribute>
+        <attribute name="action">win.bottom-panel</attribute>
+        <attribute name="hidden-when">action-disabled</attribute>
+      </item>
+      <item>
+        <attribute name="label" translatable="yes">_Fullscreen</attribute>
+        <attribute name="action">win.fullscreen</attribute>
+      </item>
+    </section>
+    <section>
+      <attribute name="id">ext7</attribute>
+    </section>
+    <section>
+      <attribute name="id">ext8</attribute>
+      <item>
+        <attribute name="label" translatable="yes">_Find…</attribute>
+        <attribute name="action">win.find</attribute>
+      </item>
+      <item>
+        <attribute name="label" translatable="yes">_Find and Replace…</attribute>
+        <attribute name="action">win.replace</attribute>
+      </item>
+      <item>
+        <attribute name="label" translatable="yes">_Clear Highlight</attribute>
+        <attribute name="action">win.clear-highlight</attribute>
+      </item>
+      <item>
+        <attribute name="label" translatable="yes">_Go to Line…</attribute>
+        <attribute name="action">win.goto-line</attribute>
+      </item>
+    </section>
+    <section>
+      <attribute name="id">ext9</attribute>
+    </section>
+    <section>
+      <attribute name="id">ext10</attribute>
+      <item>
+        <attribute name="label" translatable="yes">_Highlight Mode…</attribute>
+        <attribute name="action">win.highlight-mode</attribute>
+      </item>
+    </section>
+    <section>
+      <attribute name="id">ext11</attribute>
+    </section>
+    <section>
+      <attribute name="id">ext12</attribute>
+    </section>
+    <section>
+      <attribute name="id">appmenuext2</attribute>
+      <item>
+        <attribute name="label" translatable="yes">_Preferences</attribute>
+        <attribute name="action">app.preferences</attribute>
+      </item>
+    </section>
+    <section>
+      <attribute name="id">appmenuext3</attribute>
+      <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>
+    <section>
+      <attribute name="id">ext13</attribute>
+      <item>
+        <attribute name="label" translatable="yes">_Close All</attribute>
+        <attribute name="action">win.close-all</attribute>
+      </item>
+      <item>
+        <attribute name="label" translatable="yes">_Close</attribute>
+        <attribute name="action">win.close</attribute>
+      </item>
+      <item>
+        <attribute name="label" translatable="yes">_Quit</attribute>
+        <attribute name="action">app.quit</attribute>
+      </item>
+    </section>
+  </menu>
 </interface>
diff --git a/gedit/gedit-window-activatable.c b/gedit/gedit-window-activatable.c
index 4fb483d..0f2c7e3 100644
--- a/gedit/gedit-window-activatable.c
+++ b/gedit/gedit-window-activatable.c
@@ -124,61 +124,4 @@ gedit_window_activatable_update_state (GeditWindowActivatable *activatable)
        }
 }
 
-static GMenuModel *
-find_extension_point_section (GMenuModel  *model,
-                              const gchar *extension_point)
-{
-       gint i, n_items;
-       GMenuModel *section = NULL;
-
-       n_items = g_menu_model_get_n_items (model);
-
-       for (i = 0; i < n_items && !section; i++)
-       {
-               gchar *id = NULL;
-
-               if (g_menu_model_get_item_attribute (model, i, "id", "s", &id) &&
-                   strcmp (id, extension_point) == 0)
-               {
-                       section = g_menu_model_get_item_link (model, i, G_MENU_LINK_SECTION);
-               }
-
-               g_free (id);
-       }
-
-       return section;
-}
-
-GeditMenuExtension *
-gedit_window_activatable_extend_menu (GeditWindowActivatable *activatable,
-                                      const gchar            *extension_point)
-{
-       GeditWindow *window;
-       GMenuModel *model;
-       GMenuModel *section;
-
-       g_return_val_if_fail (GEDIT_IS_WINDOW_ACTIVATABLE (activatable), NULL);
-       g_return_val_if_fail (extension_point != NULL, NULL);
-
-       /* First look in the gear menu */
-       g_object_get (G_OBJECT (activatable), "window", &window, NULL);
-       model = _gedit_window_get_gear_menu (window);
-       g_object_unref (window);
-
-       section = find_extension_point_section (model, extension_point);
-
-       /* otherwise look in the app menu */
-       if (section == NULL)
-       {
-               model = gtk_application_get_app_menu (GTK_APPLICATION (g_application_get_default ()));
-
-               if (model != NULL)
-               {
-                       section = find_extension_point_section (model, extension_point);
-               }
-       }
-
-       return section != NULL ? _gedit_menu_extension_new (G_MENU (section)) : NULL;
-}
-
 /* ex:set ts=8 noet: */
diff --git a/gedit/gedit-window-activatable.h b/gedit/gedit-window-activatable.h
index 3e13b66..9b3c532 100644
--- a/gedit/gedit-window-activatable.h
+++ b/gedit/gedit-window-activatable.h
@@ -22,7 +22,6 @@
 #define __GEDIT_WINDOW_ACTIVATABLE_H__
 
 #include <glib-object.h>
-#include <gedit/gedit-menu-extension.h>
 
 G_BEGIN_DECLS
 
@@ -57,20 +56,6 @@ void  gedit_window_activatable_activate      (GeditWindowActivatable *activatable);
 void    gedit_window_activatable_deactivate    (GeditWindowActivatable *activatable);
 void    gedit_window_activatable_update_state  (GeditWindowActivatable *activatable);
 
-/**
- * gedit_window_activatable_extend_menu:
- * @activatable: A #GeditWindowActivatable.
- * @extension_point: the extension point section of the menu to get.
- *
- * Gets the #GeditMenuExtension for the menu @extension_point. Note that
- * the extension point could be in different menus (gear menu, app menu, etc)
- * depending on the platform.
- *
- * Returns: (transfer full): a #GeditMenuExtension for the specific section or %NULL if not found.
- */
-GeditMenuExtension *gedit_window_activatable_extend_menu (GeditWindowActivatable *activatable,
-                                                          const gchar            *extension_point);
-
 G_END_DECLS
 
 #endif /* __GEDIT_WINDOW_ACTIVATABLE_H__ */
diff --git a/gedit/gedit-window-private.h b/gedit/gedit-window-private.h
index 9e07e89..93df749 100644
--- a/gedit/gedit-window-private.h
+++ b/gedit/gedit-window-private.h
@@ -90,9 +90,6 @@ struct _GeditWindowPrivate
        GtkWidget      *open_button;
        GtkWidget      *open_menu;
        GtkMenuButton  *gear_button;
-       GMenuModel     *gear_menu;
-       GMenuModel     *gear_menu_win;
-       GMenuModel     *gear_menu_app;
 
        /* recent files */
 
diff --git a/gedit/gedit-window.c b/gedit/gedit-window.c
index c21f593..7507158 100644
--- a/gedit/gedit-window.c
+++ b/gedit/gedit-window.c
@@ -425,8 +425,6 @@ gedit_window_class_init (GeditWindowClass *klass)
        gtk_widget_class_bind_template_child_private (widget_class, GeditWindow, headerbar);
        gtk_widget_class_bind_template_child_private (widget_class, GeditWindow, open_menu);
        gtk_widget_class_bind_template_child_private (widget_class, GeditWindow, gear_button);
-       gtk_widget_class_bind_template_child_private (widget_class, GeditWindow, gear_menu_win);
-       gtk_widget_class_bind_template_child_private (widget_class, GeditWindow, gear_menu_app);
        gtk_widget_class_bind_template_child_private (widget_class, GeditWindow, hpaned);
        gtk_widget_class_bind_template_child_private (widget_class, GeditWindow, side_panel);
        gtk_widget_class_bind_template_child_private (widget_class, GeditWindow, vpaned);
@@ -2953,6 +2951,7 @@ static void
 gedit_window_init (GeditWindow *window)
 {
        GtkTargetList *tl;
+       GMenuModel *gear_menu;
 
        gedit_debug (DEBUG_WINDOW);
 
@@ -2998,19 +2997,9 @@ gedit_window_init (GeditWindow *window)
 
        setup_headerbar_open_button (window);
 
-       if (_gedit_app_has_app_menu (GEDIT_APP (g_application_get_default ())))
-       {
-               window->priv->gear_menu = window->priv->gear_menu_win;
-       }
-       else
-       {
-               window->priv->gear_menu = window->priv->gear_menu_app;
-       }
-
-       gtk_menu_button_set_menu_model (window->priv->gear_button,
-                                       window->priv->gear_menu);
-       gtk_menu_button_set_menu_model (window->priv->fullscreen_gear_button,
-                                       window->priv->gear_menu);
+       gear_menu = _gedit_app_get_window_menu (GEDIT_APP (g_application_get_default ())),
+       gtk_menu_button_set_menu_model (window->priv->gear_button, gear_menu);
+       gtk_menu_button_set_menu_model (window->priv->fullscreen_gear_button, gear_menu);
 
        /* Setup status bar */
        setup_statusbar (window);
@@ -3840,20 +3829,4 @@ gedit_window_get_message_bus (GeditWindow *window)
        return window->priv->message_bus;
 }
 
-/**
- * _gedit_window_get_gear_menu:
- * @window: a #GeditWindow.
- *
- * Gets the gear menu.
- *
- * Returns: (transfer none): the #GMenuModel of the gear menu button.
- */
-GMenuModel *
-_gedit_window_get_gear_menu (GeditWindow *window)
-{
-       g_return_val_if_fail (GEDIT_IS_WINDOW (window), NULL);
-
-       return window->priv->gear_menu;
-}
-
 /* ex:set ts=8 noet: */
diff --git a/gedit/gedit-window.ui b/gedit/gedit-window.ui
index 50bc38f..09ddc83 100644
--- a/gedit/gedit-window.ui
+++ b/gedit/gedit-window.ui
@@ -1,224 +1,6 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <interface>
   <!-- interface-requires gtk+ 3.8 -->
-  <menu id="gear_menu_win">
-    <section>
-      <attribute name="id">ext1</attribute>
-    </section>
-    <section>
-      <attribute name="id">ext2</attribute>
-      <item>
-        <attribute name="label" translatable="yes">_Reload</attribute>
-        <attribute name="action">win.revert</attribute>
-      </item>
-      <item>
-        <attribute name="label" translatable="yes">_Save As…</attribute>
-        <attribute name="action">win.save-as</attribute>
-      </item>
-      <item>
-        <attribute name="label" translatable="yes">Save _All</attribute>
-        <attribute name="action">win.save-all</attribute>
-      </item>
-    </section>
-    <section>
-      <attribute name="id">ext3</attribute>
-    </section>
-    <section>
-      <attribute name="id">ext4</attribute>
-      <item>
-        <attribute name="label" translatable="yes">_Print…</attribute>
-        <attribute name="action">win.print</attribute>
-      </item>
-    </section>
-    <section>
-      <attribute name="id">ext5</attribute>
-    </section>
-    <section>
-      <attribute name="id">ext6</attribute>
-      <item>
-        <attribute name="label" translatable="yes">Side _Panel</attribute>
-        <attribute name="action">win.side-panel</attribute>
-      </item>
-      <item>
-        <attribute name="label" translatable="yes">_Bottom Panel</attribute>
-        <attribute name="action">win.bottom-panel</attribute>
-        <attribute name="hidden-when">action-disabled</attribute>
-      </item>
-      <item>
-        <attribute name="label" translatable="yes">_Fullscreen</attribute>
-        <attribute name="action">win.fullscreen</attribute>
-      </item>
-    </section>
-    <section>
-      <attribute name="id">ext7</attribute>
-    </section>
-    <section>
-      <attribute name="id">ext8</attribute>
-      <item>
-        <attribute name="label" translatable="yes">_Find…</attribute>
-        <attribute name="action">win.find</attribute>
-      </item>
-      <item>
-        <attribute name="label" translatable="yes">_Find and Replace…</attribute>
-        <attribute name="action">win.replace</attribute>
-      </item>
-      <item>
-        <attribute name="label" translatable="yes">_Clear Highlight</attribute>
-        <attribute name="action">win.clear-highlight</attribute>
-      </item>
-      <item>
-        <attribute name="label" translatable="yes">_Go to Line…</attribute>
-        <attribute name="action">win.goto-line</attribute>
-      </item>
-    </section>
-    <section>
-      <attribute name="id">ext9</attribute>
-    </section>
-    <section>
-      <attribute name="id">ext10</attribute>
-      <item>
-        <attribute name="label" translatable="yes">_Highlight Mode…</attribute>
-        <attribute name="action">win.highlight-mode</attribute>
-      </item>
-    </section>
-    <section>
-      <attribute name="id">ext11</attribute>
-    </section>
-    <section>
-      <attribute name="id">ext12</attribute>
-    </section>
-    <section>
-      <attribute name="id">ext13</attribute>
-      <item>
-        <attribute name="label" translatable="yes">_Close All</attribute>
-        <attribute name="action">win.close-all</attribute>
-      </item>
-      <item>
-        <attribute name="label" translatable="yes">_Close</attribute>
-        <attribute name="action">win.close</attribute>
-      </item>
-    </section>
-  </menu>
-  <menu id="gear_menu_app">
-    <section>
-      <attribute name="id">ext1</attribute>
-    </section>
-    <section>
-      <attribute name="id">ext2</attribute>
-      <item>
-        <attribute name="label" translatable="yes">_Reload</attribute>
-        <attribute name="action">win.revert</attribute>
-      </item>
-      <item>
-        <attribute name="label" translatable="yes">_Save As…</attribute>
-        <attribute name="action">win.save-as</attribute>
-      </item>
-      <item>
-        <attribute name="label" translatable="yes">Save _All</attribute>
-        <attribute name="action">win.save-all</attribute>
-      </item>
-    </section>
-    <section>
-      <attribute name="id">ext3</attribute>
-    </section>
-    <section>
-      <attribute name="id">ext4</attribute>
-      <item>
-        <attribute name="label" translatable="yes">_Print…</attribute>
-        <attribute name="action">win.print</attribute>
-      </item>
-    </section>
-    <section>
-      <attribute name="id">ext5</attribute>
-    </section>
-    <section>
-      <attribute name="id">ext6</attribute>
-      <item>
-        <attribute name="label" translatable="yes">Side _Panel</attribute>
-        <attribute name="action">win.side-panel</attribute>
-      </item>
-      <item>
-        <attribute name="label" translatable="yes">_Bottom Panel</attribute>
-        <attribute name="action">win.bottom-panel</attribute>
-        <attribute name="hidden-when">action-disabled</attribute>
-      </item>
-      <item>
-        <attribute name="label" translatable="yes">_Fullscreen</attribute>
-        <attribute name="action">win.fullscreen</attribute>
-      </item>
-    </section>
-    <section>
-      <attribute name="id">ext7</attribute>
-    </section>
-    <section>
-      <attribute name="id">ext8</attribute>
-      <item>
-        <attribute name="label" translatable="yes">_Find…</attribute>
-        <attribute name="action">win.find</attribute>
-      </item>
-      <item>
-        <attribute name="label" translatable="yes">_Find and Replace…</attribute>
-        <attribute name="action">win.replace</attribute>
-      </item>
-      <item>
-        <attribute name="label" translatable="yes">_Clear Highlight</attribute>
-        <attribute name="action">win.clear-highlight</attribute>
-      </item>
-      <item>
-        <attribute name="label" translatable="yes">_Go to Line…</attribute>
-        <attribute name="action">win.goto-line</attribute>
-      </item>
-    </section>
-    <section>
-      <attribute name="id">ext9</attribute>
-    </section>
-    <section>
-      <attribute name="id">ext10</attribute>
-      <item>
-        <attribute name="label" translatable="yes">_Highlight Mode…</attribute>
-        <attribute name="action">win.highlight-mode</attribute>
-      </item>
-    </section>
-    <section>
-      <attribute name="id">ext11</attribute>
-    </section>
-    <section>
-      <attribute name="id">ext12</attribute>
-    </section>
-    <section>
-      <attribute name="id">appmenuext2</attribute>
-      <item>
-        <attribute name="label" translatable="yes">_Preferences</attribute>
-        <attribute name="action">app.preferences</attribute>
-      </item>
-    </section>
-    <section>
-      <attribute name="id">appmenuext3</attribute>
-      <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>
-    <section>
-      <attribute name="id">ext13</attribute>
-      <item>
-        <attribute name="label" translatable="yes">_Close All</attribute>
-        <attribute name="action">win.close-all</attribute>
-      </item>
-      <item>
-        <attribute name="label" translatable="yes">_Close</attribute>
-        <attribute name="action">win.close</attribute>
-      </item>
-      <item>
-        <attribute name="label" translatable="yes">_Quit</attribute>
-        <attribute name="action">app.quit</attribute>
-      </item>
-    </section>
-  </menu>
   <template class="GeditWindow" parent="GtkWindow">
     <property name="can_focus">False</property>
     <property name="has_focus">False</property>
diff --git a/plugins/docinfo/gedit-docinfo-plugin.c b/plugins/docinfo/gedit-docinfo-plugin.c
index 97539bf..10ab10a 100644
--- a/plugins/docinfo/gedit-docinfo-plugin.c
+++ b/plugins/docinfo/gedit-docinfo-plugin.c
@@ -30,18 +30,19 @@
 #include <pango/pango-break.h>
 #include <gmodule.h>
 
+#include <gedit/gedit-app.h>
 #include <gedit/gedit-window.h>
-#include <gedit/gedit-window-activatable.h>
 #include <gedit/gedit-debug.h>
 #include <gedit/gedit-utils.h>
 #include <gedit/gedit-menu-extension.h>
+#include <gedit/gedit-app-activatable.h>
+#include <gedit/gedit-window-activatable.h>
 
 struct _GeditDocinfoPluginPrivate
 {
        GeditWindow *window;
 
        GSimpleAction *action;
-       GeditMenuExtension *menu;
 
        GtkWidget *dialog;
        GtkWidget *file_name_label;
@@ -62,20 +63,27 @@ struct _GeditDocinfoPluginPrivate
        GtkWidget *selected_chars_label;
        GtkWidget *selected_chars_ns_label;
        GtkWidget *selected_bytes_label;
+
+       GeditApp  *app;
+       GeditMenuExtension *menu_ext;
 };
 
 enum
 {
        PROP_0,
-       PROP_WINDOW
+       PROP_WINDOW,
+       PROP_APP
 };
 
+static void gedit_app_activatable_iface_init (GeditAppActivatableInterface *iface);
 static void gedit_window_activatable_iface_init (GeditWindowActivatableInterface *iface);
 
 G_DEFINE_DYNAMIC_TYPE_EXTENDED (GeditDocinfoPlugin,
                                gedit_docinfo_plugin,
                                PEAS_TYPE_EXTENSION_BASE,
                                0,
+                               G_IMPLEMENT_INTERFACE_DYNAMIC (GEDIT_TYPE_APP_ACTIVATABLE,
+                                                              gedit_app_activatable_iface_init)
                                G_IMPLEMENT_INTERFACE_DYNAMIC (GEDIT_TYPE_WINDOW_ACTIVATABLE,
                                                               gedit_window_activatable_iface_init))
 
@@ -437,8 +445,9 @@ gedit_docinfo_plugin_dispose (GObject *object)
        gedit_debug_message (DEBUG_PLUGINS, "GeditDocinfoPlugin dispose");
 
        g_clear_object (&plugin->priv->action);
-       g_clear_object (&plugin->priv->menu);
        g_clear_object (&plugin->priv->window);
+       g_clear_object (&plugin->priv->menu_ext);
+       g_clear_object (&plugin->priv->app);
 
        G_OBJECT_CLASS (gedit_docinfo_plugin_parent_class)->dispose (object);
 }
@@ -465,7 +474,9 @@ gedit_docinfo_plugin_set_property (GObject      *object,
                case PROP_WINDOW:
                        plugin->priv->window = GEDIT_WINDOW (g_value_dup_object (value));
                        break;
-
+               case PROP_APP:
+                       plugin->priv->app = GEDIT_APP (g_value_dup_object (value));
+                       break;
                default:
                        G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
                        break;
@@ -485,7 +496,9 @@ gedit_docinfo_plugin_get_property (GObject    *object,
                case PROP_WINDOW:
                        g_value_set_object (value, plugin->priv->window);
                        break;
-
+               case PROP_APP:
+                       g_value_set_object (value, plugin->priv->app);
+                       break;
                default:
                        G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
                        break;
@@ -515,7 +528,7 @@ update_ui (GeditDocinfoPlugin *plugin)
 }
 
 static void
-gedit_docinfo_plugin_activate (GeditWindowActivatable *activatable)
+gedit_docinfo_plugin_app_activate (GeditAppActivatable *activatable)
 {
        GeditDocinfoPluginPrivate *priv;
        GMenuItem *item;
@@ -524,23 +537,47 @@ gedit_docinfo_plugin_activate (GeditWindowActivatable *activatable)
 
        priv = GEDIT_DOCINFO_PLUGIN (activatable)->priv;
 
+       priv->menu_ext = gedit_app_activatable_extend_menu (activatable,
+                                                           "ext9");
+       item = g_menu_item_new (_("_Document Statistics"), "win.docinfo");
+       gedit_menu_extension_append_menu_item (priv->menu_ext, item);
+       g_object_unref (item);
+
+       update_ui (GEDIT_DOCINFO_PLUGIN (activatable));
+}
+
+static void
+gedit_docinfo_plugin_app_deactivate (GeditAppActivatable *activatable)
+{
+       GeditDocinfoPluginPrivate *priv;
+
+       gedit_debug (DEBUG_PLUGINS);
+
+       priv = GEDIT_DOCINFO_PLUGIN (activatable)->priv;
+
+       g_clear_object (&priv->menu_ext);
+}
+
+static void
+gedit_docinfo_plugin_window_activate (GeditWindowActivatable *activatable)
+{
+       GeditDocinfoPluginPrivate *priv;
+
+       gedit_debug (DEBUG_PLUGINS);
+
+       priv = GEDIT_DOCINFO_PLUGIN (activatable)->priv;
+
        priv->action = g_simple_action_new ("docinfo", NULL);
        g_signal_connect (priv->action, "activate",
                          G_CALLBACK (docinfo_cb), activatable);
        g_action_map_add_action (G_ACTION_MAP (priv->window),
                                 G_ACTION (priv->action));
 
-       priv->menu = gedit_window_activatable_extend_menu (activatable,
-                                                          "ext9");
-       item = g_menu_item_new (_("_Document Statistics"), "win.docinfo");
-       gedit_menu_extension_append_menu_item (priv->menu, item);
-       g_object_unref (item);
-
        update_ui (GEDIT_DOCINFO_PLUGIN (activatable));
 }
 
 static void
-gedit_docinfo_plugin_deactivate (GeditWindowActivatable *activatable)
+gedit_docinfo_plugin_window_deactivate (GeditWindowActivatable *activatable)
 {
        GeditDocinfoPluginPrivate *priv;
 
@@ -552,7 +589,7 @@ gedit_docinfo_plugin_deactivate (GeditWindowActivatable *activatable)
 }
 
 static void
-gedit_docinfo_plugin_update_state (GeditWindowActivatable *activatable)
+gedit_docinfo_plugin_window_update_state (GeditWindowActivatable *activatable)
 {
        gedit_debug (DEBUG_PLUGINS);
 
@@ -570,16 +607,24 @@ gedit_docinfo_plugin_class_init (GeditDocinfoPluginClass *klass)
        object_class->get_property = gedit_docinfo_plugin_get_property;
 
        g_object_class_override_property (object_class, PROP_WINDOW, "window");
+       g_object_class_override_property (object_class, PROP_APP, "app");
 
        g_type_class_add_private (klass, sizeof (GeditDocinfoPluginPrivate));
 }
 
 static void
+gedit_app_activatable_iface_init (GeditAppActivatableInterface *iface)
+{
+       iface->activate = gedit_docinfo_plugin_app_activate;
+       iface->deactivate = gedit_docinfo_plugin_app_deactivate;
+}
+
+static void
 gedit_window_activatable_iface_init (GeditWindowActivatableInterface *iface)
 {
-       iface->activate = gedit_docinfo_plugin_activate;
-       iface->deactivate = gedit_docinfo_plugin_deactivate;
-       iface->update_state = gedit_docinfo_plugin_update_state;
+       iface->activate = gedit_docinfo_plugin_window_activate;
+       iface->deactivate = gedit_docinfo_plugin_window_deactivate;
+       iface->update_state = gedit_docinfo_plugin_window_update_state;
 }
 
 static void
@@ -594,6 +639,9 @@ peas_register_types (PeasObjectModule *module)
        gedit_docinfo_plugin_register_type (G_TYPE_MODULE (module));
 
        peas_object_module_register_extension_type (module,
+                                                   GEDIT_TYPE_APP_ACTIVATABLE,
+                                                   GEDIT_TYPE_DOCINFO_PLUGIN);
+       peas_object_module_register_extension_type (module,
                                                    GEDIT_TYPE_WINDOW_ACTIVATABLE,
                                                    GEDIT_TYPE_DOCINFO_PLUGIN);
 }
diff --git a/plugins/externaltools/tools/Makefile.am b/plugins/externaltools/tools/Makefile.am
index 6ce758c..3a6c9fe 100644
--- a/plugins/externaltools/tools/Makefile.am
+++ b/plugins/externaltools/tools/Makefile.am
@@ -8,6 +8,7 @@ externaltools_PYTHON =                                          \
        plugins/externaltools/tools/outputpanel.py              \
        plugins/externaltools/tools/filelookup.py               \
        plugins/externaltools/tools/linkparsing.py              \
+       plugins/externaltools/tools/appactivatable.py   \
        plugins/externaltools/tools/windowactivatable.py
 
 externaltools_uidir = $(GEDIT_PLUGINS_DATA_DIR)/externaltools/ui
diff --git a/plugins/externaltools/tools/__init__.py b/plugins/externaltools/tools/__init__.py
index 87af9cf..e2ef029 100644
--- a/plugins/externaltools/tools/__init__.py
+++ b/plugins/externaltools/tools/__init__.py
@@ -16,20 +16,7 @@
 #    along with this program; if not, write to the Free Software
 #    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 
-from gi.repository import GObject, Gedit
+from .appactivatable import AppActivatable
 from .windowactivatable import WindowActivatable
-from .library import ToolLibrary
-import os
-
-class AppActivatable(GObject.Object, Gedit.AppActivatable):
-    __gtype_name__ = "ExternalToolsAppActivatable"
-
-    app = GObject.property(type=Gedit.App)
-
-    def __init__(self):
-        GObject.Object.__init__(self)
-
-    def do_activate(self):
-        ToolLibrary().set_locations(os.path.join(self.plugin_info.get_data_dir(), 'tools'))
 
 # ex:ts=4:et:
diff --git a/plugins/externaltools/tools/appactivatable.py b/plugins/externaltools/tools/appactivatable.py
new file mode 100644
index 0000000..20aa739
--- /dev/null
+++ b/plugins/externaltools/tools/appactivatable.py
@@ -0,0 +1,99 @@
+# -*- coding: UTF-8 -*-
+#    Gedit External Tools plugin
+#    Copyright (C) 2005-2006  Steve Frécinaux <steve istique net>
+#
+#    This program is free software; you can redistribute it and/or modify
+#    it under the terms of the GNU General Public License as published by
+#    the Free Software Foundation; either version 2 of the License, or
+#    (at your option) any later version.
+#
+#    This program is distributed in the hope that it will be useful,
+#    but WITHOUT ANY WARRANTY; without even the implied warranty of
+#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+#    GNU General Public License for more details.
+#
+#    You should have received a copy of the GNU General Public License
+#    along with this program; if not, write to the Free Software
+#    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+
+from gi.repository import GLib, Gio, GObject, Gtk, Gedit
+from .library import ToolLibrary
+import os
+
+class ToolMenu(object):
+    def __init__(self, library, menu):
+        super(ToolMenu, self).__init__()
+        self._library = library
+        self._menu = menu
+        self._action_tools = {}
+
+        self.update()
+
+    def deactivate(self):
+        self.remove()
+
+    def remove(self):
+        self._menu.remove_all()
+
+        for name, tool in self._action_tools.items():
+            if tool.shortcut:
+                app = Gio.Application.get_default()
+                app.remove_accelerator(tool.shortcut)
+
+    def _insert_directory(self, directory, menu):
+        for d in sorted(directory.subdirs, key=lambda x: x.name.lower()):
+            submenu = Gio.Menu()
+            menu.append_submenu(d.name.replace('_', '__'), submenu)
+            section = Gio.Menu()
+            submenu.append_section(None, section)
+
+            self._insert_directory(d, section)
+
+        for tool in sorted(directory.tools, key=lambda x: x.name.lower()):
+            # FIXME: find a better way to share the action name
+            action_name = 'external-tool_%X_%X' % (id(tool), id(tool.name))
+            item = Gio.MenuItem.new(tool.name.replace('_', '__'), "win.%s" % action_name)
+            item.set_attribute_value("hidden-when", GLib.Variant.new_string("action-disabled"))
+            menu.append_item(item)
+
+            if tool.shortcut:
+                app = Gio.Application.get_default()
+                app.add_accelerator(tool.shortcut, "win.%s" % action_name, None)
+
+    def update(self):
+        self.remove()
+        self._insert_directory(self._library.tree, self._menu)
+
+
+class AppActivatable(GObject.Object, Gedit.AppActivatable):
+    __gtype_name__ = "ExternalToolsAppActivatable"
+
+    app = GObject.property(type=Gedit.App)
+
+    def __init__(self):
+        GObject.Object.__init__(self)
+        self.menu = None
+
+    def do_activate(self):
+        self._library = ToolLibrary()
+        self._library.set_locations(os.path.join(self.plugin_info.get_data_dir(), 'tools'))
+
+        self.menu_ext = self.extend_menu("appmenuext2")
+        item = Gio.MenuItem.new(_("Manage _External Tools..."), "win.manage-tools")
+        self.menu_ext.append_menu_item(item)
+
+        self.submenu_ext = self.extend_menu("ext9")
+        external_tools_submenu = Gio.Menu()
+        item = Gio.MenuItem.new_submenu(_("External _Tools"), external_tools_submenu)
+        self.submenu_ext.append_menu_item(item)
+        external_tools_submenu_section = Gio.Menu()
+        external_tools_submenu.append_section(None, external_tools_submenu_section)
+
+        self.menu = ToolMenu(self._library, external_tools_submenu_section)
+
+    def do_deactivate(self):
+        self.menu.deactivate()
+        self.menu_ext = None
+        self.submenu_ext = None
+
+# ex:ts=4:et:
diff --git a/plugins/externaltools/tools/windowactivatable.py 
b/plugins/externaltools/tools/windowactivatable.py
index f409d30..9aa89c8 100644
--- a/plugins/externaltools/tools/windowactivatable.py
+++ b/plugins/externaltools/tools/windowactivatable.py
@@ -25,13 +25,12 @@ from .outputpanel import OutputPanel
 from .capture import Capture
 from .functions import *
 
-class ToolMenu(object):
-    def __init__(self, library, window, panel, menu):
-        super(ToolMenu, self).__init__()
+class ToolActions(object):
+    def __init__(self, library, window, panel):
+        super(ToolActions, self).__init__()
         self._library = library
         self._window = window
         self._panel = panel
-        self._menu = menu
         self._action_tools = {}
 
         self.update()
@@ -40,25 +39,11 @@ class ToolMenu(object):
         self.remove()
 
     def remove(self):
-        self._menu.remove_all()
-
         for name, tool in self._action_tools.items():
             self._window.remove_action(name)
-
-            if tool.shortcut:
-                app = Gio.Application.get_default()
-                app.remove_accelerator(tool.shortcut)
         self._action_tools = {}
 
-    def _insert_directory(self, directory, menu):
-        for d in sorted(directory.subdirs, key=lambda x: x.name.lower()):
-            submenu = Gio.Menu()
-            menu.append_submenu(d.name.replace('_', '__'), submenu)
-            section = Gio.Menu()
-            submenu.append_section(None, section)
-
-            self._insert_directory(d, section)
-
+    def _insert_directory(self, directory):
         for tool in sorted(directory.tools, key=lambda x: x.name.lower()):
             action_name = 'external-tool_%X_%X' % (id(tool), id(tool.name))
             self._action_tools[action_name] = tool
@@ -67,17 +52,9 @@ class ToolMenu(object):
             action.connect('activate', capture_menu_action, self._window, self._panel, tool)
             self._window.add_action(action)
 
-            item = Gio.MenuItem.new(tool.name.replace('_', '__'), "win.%s" % action_name)
-            item.set_attribute_value("hidden-when", GLib.Variant.new_string("action-disabled"))
-            menu.append_item(item)
-
-            if tool.shortcut:
-                app = Gio.Application.get_default()
-                app.add_accelerator(tool.shortcut, "win.%s" % action_name, None)
-
     def update(self):
         self.remove()
-        self._insert_directory(self._library.tree, self._menu)
+        self._insert_directory(self._library.tree)
         self.filter(self._window.get_active_document())
 
     def filter_language(self, language, item):
@@ -127,10 +104,10 @@ class WindowActivatable(GObject.Object, Gedit.WindowActivatable):
         GObject.Object.__init__(self)
         self._manager = None
         self._manager_default_size = None
-        self.menu = None
+        self.actions = None
 
     def do_activate(self):
-        # Ugly hack... we need to get access to the activatable to update the menuitems
+        # Ugly hack... we need to get access to the activatable to update the menu actions
         self.window._external_tools_window_activatable = self
         self._library = ToolLibrary()
 
@@ -138,32 +115,21 @@ class WindowActivatable(GObject.Object, Gedit.WindowActivatable):
         action.connect("activate", lambda action, parameter: self.open_dialog())
         self.window.add_action(action)
 
-        self.menu_ext = self.extend_menu("appmenuext2")
-        item = Gio.MenuItem.new(_("Manage _External Tools..."), "win.manage-tools")
-        self.menu_ext.append_menu_item(item)
-
-        self.submenu_ext = self.extend_menu("ext9")
-        external_tools_submenu = Gio.Menu()
-        item = Gio.MenuItem.new_submenu(_("External _Tools"), external_tools_submenu)
-        self.submenu_ext.append_menu_item(item)
-        external_tools_submenu_section = Gio.Menu()
-        external_tools_submenu.append_section(None, external_tools_submenu_section)
-
         # Create output console
         self._output_buffer = OutputPanel(self.plugin_info.get_data_dir(), self.window)
 
-        self.menu = ToolMenu(self._library, self.window, self._output_buffer, external_tools_submenu_section)
+        self.actions = ToolActions(self._library, self.window, self._output_buffer)
 
         bottom = self.window.get_bottom_panel()
         bottom.add_titled(self._output_buffer.panel, "GeditExternalToolsShellOutput", _("Tool Output"))
 
     def do_update_state(self):
-        if self.menu is not None:
-            self.menu.filter(self.window.get_active_document())
+        if self.actions is not None:
+            self.actions.filter(self.window.get_active_document())
 
     def do_deactivate(self):
         self.window._external_tools_window_activatable = None
-        self.menu.deactivate()
+        self.actions.deactivate()
         self.window.remove_action("manage-tools")
 
         bottom = self.window.get_bottom_panel()
@@ -194,6 +160,6 @@ class WindowActivatable(GObject.Object, Gedit.WindowActivatable):
 
     def on_manager_tools_updated(self, manager):
         for window in Gio.Application.get_default().get_windows():
-            window._external_tools_window_activatable.menu.update()
+            window._external_tools_window_activatable.actions.update()
 
 # ex:ts=4:et:
diff --git a/plugins/quickopen/quickopen/__init__.py b/plugins/quickopen/quickopen/__init__.py
index e110156..8026028 100644
--- a/plugins/quickopen/quickopen/__init__.py
+++ b/plugins/quickopen/quickopen/__init__.py
@@ -30,6 +30,10 @@ class QuickOpenAppActivatable(GObject.Object, Gedit.AppActivatable):
     def do_activate(self):
         self.app.add_accelerator("<Primary><Alt>O", "win.quickopen", None)
 
+        self.menu_ext = self.extend_menu("ext2")
+        item = Gio.MenuItem.new(_("Quick Open..."), "win.quickopen")
+        self.menu_ext.prepend_menu_item(item)
+
     def do_deactivate(self):
         self.app.remove_accelerator("win.quickopen", None)
 
@@ -44,10 +48,13 @@ class QuickOpenPlugin(GObject.Object, Gedit.WindowActivatable):
     def do_activate(self):
         self._popup_size = (450, 300)
         self._popup = None
-        self._install_menu()
+
+        action = Gio.SimpleAction(name="quickopen")
+        action.connect('activate', self.on_quick_open_activate)
+        self.window.add_action(action)
 
     def do_deactivate(self):
-        self._uninstall_menu()
+        self.window.remove_action("quickopen")
 
     def get_popup_size(self):
         return self._popup_size
@@ -55,20 +62,6 @@ class QuickOpenPlugin(GObject.Object, Gedit.WindowActivatable):
     def set_popup_size(self, size):
         self._popup_size = size
 
-    def _uninstall_menu(self):
-        self.window.remove_action("quickopen")
-
-    def _install_menu(self):
-        action = Gio.SimpleAction(name="quickopen")
-        action.connect('activate', self.on_quick_open_activate)
-        self.window.add_action(action)
-
-        item = Gio.MenuItem.new(_("Quick Open..."), "win.quickopen")
-        item.set_attribute_value("accel", GLib.Variant.new_string("<Primary><Alt>O"))
-
-        self.menu = self.extend_menu("ext2")
-        self.menu.prepend_menu_item(item)
-
     def _create_popup(self):
         paths = []
 
diff --git a/plugins/snippets/snippets/appactivatable.py b/plugins/snippets/snippets/appactivatable.py
index 9c33426..332daa7 100644
--- a/plugins/snippets/snippets/appactivatable.py
+++ b/plugins/snippets/snippets/appactivatable.py
@@ -19,11 +19,12 @@ import sys
 import os
 import shutil
 
-from gi.repository import Gedit, GLib, GObject, Gtk
+from gi.repository import Gedit, Gtk, GObject, Gio, GLib
 import platform
 
 from .library import Library
 from .manager import Manager
+from .shareddata import SharedData
 
 class AppActivatable(GObject.Object, Gedit.AppActivatable):
         __gtype_name__ = "GeditSnippetsAppActivatable"
@@ -44,6 +45,17 @@ class AppActivatable(GObject.Object, Gedit.AppActivatable):
 
                 library.set_dirs(snippetsdir, self.system_dirs())
 
+                action = Gio.SimpleAction(name="snippets")
+                action.connect('activate', self.on_action_snippets_activate)
+                self.app.add_action(action)
+
+                item = Gio.MenuItem.new(_("Manage _Snippets..."), "app.snippets")
+                self.menu = self.extend_menu("appmenuext2")
+                self.menu.append_menu_item(item)
+
+        def do_deactivate(self):
+                self.window.remove_action("snippets")
+
         def system_dirs(self):
                 if platform.system() != 'Windows':
                         if 'XDG_DATA_DIRS' in os.environ:
@@ -72,4 +84,10 @@ class AppActivatable(GObject.Object, Gedit.AppActivatable):
 
                 return ret
 
+        def create_configure_dialog(self):
+                SharedData().show_manager(self.app.get_active_window(), self.plugin_info.get_data_dir())
+
+        def on_action_snippets_activate(self, action, parameter):
+                self.create_configure_dialog()
+
 # vi:ex:ts=8:et
diff --git a/plugins/snippets/snippets/windowactivatable.py b/plugins/snippets/snippets/windowactivatable.py
index 54521c8..4ae9c5d 100644
--- a/plugins/snippets/snippets/windowactivatable.py
+++ b/plugins/snippets/snippets/windowactivatable.py
@@ -48,7 +48,6 @@ class WindowActivatable(GObject.Object, Gedit.WindowActivatable, Signals):
                 self.current_language_accel_group = None
 
         def do_activate(self):
-                self.insert_menu()
                 self.register_messages()
 
                 library = Library()
@@ -73,7 +72,6 @@ class WindowActivatable(GObject.Object, Gedit.WindowActivatable, Signals):
 
                 self.accel_group = None
 
-                self.remove_menu()
                 self.unregister_messages()
 
                 library = Library()
@@ -145,18 +143,6 @@ class WindowActivatable(GObject.Object, Gedit.WindowActivatable, Signals):
 
                 controller.parse_and_run_snippet(message.props.snippet, iter)
 
-        def insert_menu(self):
-                action = Gio.SimpleAction(name="snippets")
-                action.connect('activate', self.on_action_snippets_activate)
-                self.window.add_action(action)
-
-                item = Gio.MenuItem.new(_("Manage _Snippets..."), "win.snippets")
-                self.menu = self.extend_menu("appmenuext2")
-                self.menu.append_menu_item(item)
-
-        def remove_menu(self):
-                self.window.remove_action("snippets")
-
         def find_snippet(self, snippets, tag):
                 result = []
 
@@ -192,13 +178,6 @@ class WindowActivatable(GObject.Object, Gedit.WindowActivatable, Signals):
         def on_active_tab_changed(self, window, tab):
                 self.update_language(SharedData().get_controller(tab.get_view()))
 
-        # Callbacks
-        def create_configure_dialog(self):
-                SharedData().show_manager(self.window, self.plugin_info.get_data_dir())
-
-        def on_action_snippets_activate(self, action, parameter):
-                self.create_configure_dialog()
-
         def accelerator_activated(self, group, obj, keyval, mod):
                 if obj == self.window:
                         controller = SharedData().get_active_controller(self.window)
diff --git a/plugins/sort/gedit-sort-plugin.c b/plugins/sort/gedit-sort-plugin.c
index fb8bcc6..3a99b89 100644
--- a/plugins/sort/gedit-sort-plugin.c
+++ b/plugins/sort/gedit-sort-plugin.c
@@ -31,16 +31,20 @@
 #include <gedit/gedit-utils.h>
 #include <gedit/gedit-app.h>
 #include <gedit/gedit-window.h>
+#include <gedit/gedit-app-activatable.h>
 #include <gedit/gedit-window-activatable.h>
 
 #define GEDIT_SORT_PLUGIN_GET_PRIVATE(object)(G_TYPE_INSTANCE_GET_PRIVATE ((object), GEDIT_TYPE_SORT_PLUGIN, 
GeditSortPluginPrivate))
 
+static void gedit_app_activatable_iface_init (GeditAppActivatableInterface *iface);
 static void gedit_window_activatable_iface_init (GeditWindowActivatableInterface *iface);
 
 G_DEFINE_DYNAMIC_TYPE_EXTENDED (GeditSortPlugin,
                                gedit_sort_plugin,
                                PEAS_TYPE_EXTENSION_BASE,
                                0,
+                               G_IMPLEMENT_INTERFACE_DYNAMIC (GEDIT_TYPE_APP_ACTIVATABLE,
+                                                              gedit_app_activatable_iface_init)
                                G_IMPLEMENT_INTERFACE_DYNAMIC (GEDIT_TYPE_WINDOW_ACTIVATABLE,
                                                               gedit_window_activatable_iface_init))
 
@@ -49,14 +53,15 @@ struct _GeditSortPluginPrivate
        GeditWindow *window;
 
        GSimpleAction *action;
-       GeditMenuExtension *menu;
-
        GtkWidget *dialog;
        GtkWidget *col_num_spinbutton;
        GtkWidget *reverse_order_checkbutton;
        GtkWidget *ignore_case_checkbutton;
        GtkWidget *remove_dups_checkbutton;
 
+       GeditApp *app;
+       GeditMenuExtension *menu_ext;
+
        GtkTextIter start, end; /* selection */
 };
 
@@ -72,7 +77,8 @@ typedef struct
 enum
 {
        PROP_0,
-       PROP_WINDOW
+       PROP_WINDOW,
+       PROP_APP
 };
 
 static void sort_real (GeditSortPlugin *plugin);
@@ -413,7 +419,7 @@ update_ui (GeditSortPlugin *plugin)
 }
 
 static void
-gedit_sort_plugin_activate (GeditWindowActivatable *activatable)
+gedit_sort_plugin_app_activate (GeditAppActivatable *activatable)
 {
        GeditSortPluginPrivate *priv;
        GMenuItem *item;
@@ -422,23 +428,47 @@ gedit_sort_plugin_activate (GeditWindowActivatable *activatable)
 
        priv = GEDIT_SORT_PLUGIN (activatable)->priv;
 
+       priv->menu_ext = gedit_app_activatable_extend_menu (activatable,
+                                                           "ext9");
+       item = g_menu_item_new (_("S_ort..."), "win.sort");
+       gedit_menu_extension_append_menu_item (priv->menu_ext, item);
+       g_object_unref (item);
+
+       update_ui (GEDIT_SORT_PLUGIN (activatable));
+}
+
+static void
+gedit_sort_plugin_app_deactivate (GeditAppActivatable *activatable)
+{
+       GeditSortPluginPrivate *priv;
+
+       gedit_debug (DEBUG_PLUGINS);
+
+       priv = GEDIT_SORT_PLUGIN (activatable)->priv;
+
+       g_clear_object (&priv->menu_ext);
+}
+
+static void
+gedit_sort_plugin_window_activate (GeditWindowActivatable *activatable)
+{
+       GeditSortPluginPrivate *priv;
+
+       gedit_debug (DEBUG_PLUGINS);
+
+       priv = GEDIT_SORT_PLUGIN (activatable)->priv;
+
        priv->action = g_simple_action_new ("sort", NULL);
        g_signal_connect (priv->action, "activate",
                          G_CALLBACK (sort_cb), activatable);
        g_action_map_add_action (G_ACTION_MAP (priv->window),
                                 G_ACTION (priv->action));
 
-       priv->menu = gedit_window_activatable_extend_menu (activatable,
-                                                          "ext9");
-       item = g_menu_item_new (_("S_ort..."), "win.sort");
-       gedit_menu_extension_append_menu_item (priv->menu, item);
-       g_object_unref (item);
-
        update_ui (GEDIT_SORT_PLUGIN (activatable));
 }
 
 static void
-gedit_sort_plugin_deactivate (GeditWindowActivatable *activatable)
+gedit_sort_plugin_window_deactivate (GeditWindowActivatable *activatable)
 {
        GeditSortPluginPrivate *priv;
 
@@ -449,7 +479,7 @@ gedit_sort_plugin_deactivate (GeditWindowActivatable *activatable)
 }
 
 static void
-gedit_sort_plugin_update_state (GeditWindowActivatable *activatable)
+gedit_sort_plugin_window_update_state (GeditWindowActivatable *activatable)
 {
        gedit_debug (DEBUG_PLUGINS);
 
@@ -474,8 +504,9 @@ gedit_sort_plugin_dispose (GObject *object)
        gedit_debug_message (DEBUG_PLUGINS, "GeditSortPlugin disposing");
 
        g_clear_object (&plugin->priv->action);
-       g_clear_object (&plugin->priv->menu);
        g_clear_object (&plugin->priv->window);
+       g_clear_object (&plugin->priv->menu_ext);
+       g_clear_object (&plugin->priv->app);
 
        G_OBJECT_CLASS (gedit_sort_plugin_parent_class)->dispose (object);
 }
@@ -502,7 +533,9 @@ gedit_sort_plugin_set_property (GObject      *object,
                case PROP_WINDOW:
                        plugin->priv->window = GEDIT_WINDOW (g_value_dup_object (value));
                        break;
-
+               case PROP_APP:
+                       plugin->priv->app = GEDIT_APP (g_value_dup_object (value));
+                       break;
                default:
                        G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
                        break;
@@ -522,7 +555,9 @@ gedit_sort_plugin_get_property (GObject    *object,
                case PROP_WINDOW:
                        g_value_set_object (value, plugin->priv->window);
                        break;
-
+               case PROP_APP:
+                       g_value_set_object (value, plugin->priv->app);
+                       break;
                default:
                        G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
                        break;
@@ -540,6 +575,7 @@ gedit_sort_plugin_class_init (GeditSortPluginClass *klass)
        object_class->get_property = gedit_sort_plugin_get_property;
 
        g_object_class_override_property (object_class, PROP_WINDOW, "window");
+       g_object_class_override_property (object_class, PROP_APP, "app");
 
        g_type_class_add_private (klass, sizeof (GeditSortPluginPrivate));
 }
@@ -550,11 +586,18 @@ gedit_sort_plugin_class_finalize (GeditSortPluginClass *klass)
 }
 
 static void
+gedit_app_activatable_iface_init (GeditAppActivatableInterface *iface)
+{
+       iface->activate = gedit_sort_plugin_app_activate;
+       iface->deactivate = gedit_sort_plugin_app_deactivate;
+}
+
+static void
 gedit_window_activatable_iface_init (GeditWindowActivatableInterface *iface)
 {
-       iface->activate = gedit_sort_plugin_activate;
-       iface->deactivate = gedit_sort_plugin_deactivate;
-       iface->update_state = gedit_sort_plugin_update_state;
+       iface->activate = gedit_sort_plugin_window_activate;
+       iface->deactivate = gedit_sort_plugin_window_deactivate;
+       iface->update_state = gedit_sort_plugin_window_update_state;
 }
 
 G_MODULE_EXPORT void
@@ -563,6 +606,9 @@ peas_register_types (PeasObjectModule *module)
        gedit_sort_plugin_register_type (G_TYPE_MODULE (module));
 
        peas_object_module_register_extension_type (module,
+                                                   GEDIT_TYPE_APP_ACTIVATABLE,
+                                                   GEDIT_TYPE_SORT_PLUGIN);
+       peas_object_module_register_extension_type (module,
                                                    GEDIT_TYPE_WINDOW_ACTIVATABLE,
                                                    GEDIT_TYPE_SORT_PLUGIN);
 }
diff --git a/plugins/spell/gedit-spell-app-activatable.c b/plugins/spell/gedit-spell-app-activatable.c
index e926c7e..3b9bf2a 100644
--- a/plugins/spell/gedit-spell-app-activatable.c
+++ b/plugins/spell/gedit-spell-app-activatable.c
@@ -18,16 +18,16 @@
  * along with gedit. If not, see <http://www.gnu.org/licenses/>.
  */
 
-
-#include "gedit-spell-app-activatable.h"
+#include <glib/gi18n.h>
+#include <libpeas/peas-object-module.h>
 #include <gedit/gedit-app-activatable.h>
 #include <gedit/gedit-app.h>
-#include <libpeas/peas-object-module.h>
-
+#include "gedit-spell-app-activatable.h"
 
 typedef struct _GeditSpellAppActivatablePrivate
 {
        GeditApp *app;
+       GeditMenuExtension *menu_ext;
 } GeditSpellAppActivatablePrivate;
 
 enum
@@ -53,6 +53,7 @@ gedit_spell_app_activatable_dispose (GObject *object)
        GeditSpellAppActivatablePrivate *priv = gedit_spell_app_activatable_get_instance_private 
(activatable);
 
        g_clear_object (&priv->app);
+       g_clear_object (&priv->menu_ext);
 
        G_OBJECT_CLASS (gedit_spell_app_activatable_parent_class)->dispose (object);
 }
@@ -126,8 +127,23 @@ gedit_spell_app_activatable_activate (GeditAppActivatable *activatable)
 {
        GeditSpellAppActivatable *app_activatable = GEDIT_SPELL_APP_ACTIVATABLE (activatable);
        GeditSpellAppActivatablePrivate *priv = gedit_spell_app_activatable_get_instance_private 
(app_activatable);
+       GMenuItem *item;
 
        gtk_application_add_accelerator (GTK_APPLICATION (priv->app), "<Shift>F7", "win.check_spell", NULL);
+       priv->menu_ext = gedit_app_activatable_extend_menu (activatable,
+                                                           "ext5");
+
+       item = g_menu_item_new (_("_Check Spelling..."), "win.check_spell");
+       gedit_menu_extension_append_menu_item (priv->menu_ext, item);
+       g_object_unref (item);
+
+       item = g_menu_item_new (_("Set _Language..."), "win.config_spell");
+       gedit_menu_extension_append_menu_item (priv->menu_ext, item);
+       g_object_unref (item);
+
+       item = g_menu_item_new (_("_Highlight Misspelled Words"), "win.auto_spell");
+       gedit_menu_extension_append_menu_item (priv->menu_ext, item);
+       g_object_unref (item);
 }
 
 static void
@@ -137,6 +153,7 @@ gedit_spell_app_activatable_deactivate (GeditAppActivatable *activatable)
        GeditSpellAppActivatablePrivate *priv = gedit_spell_app_activatable_get_instance_private 
(app_activatable);
 
        gtk_application_remove_accelerator (GTK_APPLICATION (priv->app), "win.check_spell", NULL);
+       g_clear_object (&priv->menu_ext);
 }
 
 static void
diff --git a/plugins/spell/gedit-spell-plugin.c b/plugins/spell/gedit-spell-plugin.c
index 53ca966..c89ab67 100644
--- a/plugins/spell/gedit-spell-plugin.c
+++ b/plugins/spell/gedit-spell-plugin.c
@@ -31,6 +31,7 @@
 
 #include <gedit/gedit-debug.h>
 #include <gedit/gedit-statusbar.h>
+#include <gedit/gedit-app.h>
 #include <gedit/gedit-window.h>
 #include <gedit/gedit-window-activatable.h>
 #include <gtksourceview/gtksource.h>
@@ -68,7 +69,6 @@ struct _GeditSpellPluginPrivate
 {
        GeditWindow    *window;
 
-       GeditMenuExtension *menu;
        guint           message_cid;
        gulong          tab_added_id;
        gulong          tab_removed_id;
@@ -137,7 +137,6 @@ gedit_spell_plugin_dispose (GObject *object)
 
        gedit_debug_message (DEBUG_PLUGINS, "GeditSpellPlugin disposing");
 
-       g_clear_object (&plugin->priv->menu);
        g_clear_object (&plugin->priv->window);
 
        G_OBJECT_CLASS (gedit_spell_plugin_parent_class)->dispose (object);
@@ -1118,7 +1117,6 @@ gedit_spell_plugin_activate (GeditWindowActivatable *activatable)
 {
        GeditSpellPlugin *plugin;
        GeditSpellPluginPrivate *priv;
-       GMenuItem *item;
        GList *views, *l;
 
        gedit_debug (DEBUG_PLUGINS);
@@ -1131,21 +1129,6 @@ gedit_spell_plugin_activate (GeditWindowActivatable *activatable)
                                         G_N_ELEMENTS (action_entries),
                                         activatable);
 
-       priv->menu = gedit_window_activatable_extend_menu (activatable,
-                                                          "ext5");
-
-       item = g_menu_item_new (_("_Check Spelling..."), "win.check_spell");
-       gedit_menu_extension_append_menu_item (priv->menu, item);
-       g_object_unref (item);
-
-       item = g_menu_item_new (_("Set _Language..."), "win.config_spell");
-       gedit_menu_extension_append_menu_item (priv->menu, item);
-       g_object_unref (item);
-
-       item = g_menu_item_new (_("_Highlight Misspelled Words"), "win.auto_spell");
-       gedit_menu_extension_append_menu_item (priv->menu, item);
-       g_object_unref (item);
-
        priv->message_cid = gtk_statusbar_get_context_id (GTK_STATUSBAR (gedit_window_get_statusbar 
(priv->window)),
                                                          "spell_plugin_message");
 
diff --git a/plugins/time/gedit-time-plugin.c b/plugins/time/gedit-time-plugin.c
index 8eeb837..66d85a5 100644
--- a/plugins/time/gedit-time-plugin.c
+++ b/plugins/time/gedit-time-plugin.c
@@ -33,6 +33,7 @@
 #include <gedit/gedit-debug.h>
 #include <gedit/gedit-utils.h>
 #include <gedit/gedit-window.h>
+#include <gedit/gedit-app-activatable.h>
 #include <gedit/gedit-window-activatable.h>
 #include <libpeas-gtk/peas-gtk-configurable.h>
 #include <gedit/gedit-app.h>
@@ -44,7 +45,7 @@
 
 /* gsettings keys */
 #define TIME_BASE_SETTINGS     "org.gnome.gedit.plugins.time"
-#define PROMPT_TYPE_KEY                "prompt-type"
+#define PROMPT_TYPE_KEY        "prompt-type"
 #define SELECTED_FORMAT_KEY    "selected-format"
 #define CUSTOM_FORMAT_KEY      "custom-format"
 
@@ -147,18 +148,21 @@ struct _GeditTimePluginPrivate
 {
        GSettings      *settings;
 
+       GSimpleAction  *action;
        GeditWindow    *window;
 
-       GSimpleAction *action;
-       GeditMenuExtension *menu;
+       GeditApp *app;
+       GeditMenuExtension *menu_ext;
 };
 
 enum
 {
        PROP_0,
-       PROP_WINDOW
+       PROP_WINDOW,
+       PROP_APP
 };
 
+static void gedit_app_activatable_iface_init (GeditAppActivatableInterface *iface);
 static void gedit_window_activatable_iface_init (GeditWindowActivatableInterface *iface);
 static void peas_gtk_configurable_iface_init (PeasGtkConfigurableInterface *iface);
 
@@ -166,6 +170,8 @@ G_DEFINE_DYNAMIC_TYPE_EXTENDED (GeditTimePlugin,
                                gedit_time_plugin,
                                PEAS_TYPE_EXTENSION_BASE,
                                0,
+                               G_IMPLEMENT_INTERFACE_DYNAMIC (GEDIT_TYPE_APP_ACTIVATABLE,
+                                                              gedit_app_activatable_iface_init)
                                G_IMPLEMENT_INTERFACE_DYNAMIC (GEDIT_TYPE_WINDOW_ACTIVATABLE,
                                                               gedit_window_activatable_iface_init)
                                G_IMPLEMENT_INTERFACE_DYNAMIC (PEAS_GTK_TYPE_CONFIGURABLE,
@@ -192,8 +198,9 @@ gedit_time_plugin_dispose (GObject *object)
 
        g_clear_object (&plugin->priv->settings);
        g_clear_object (&plugin->priv->action);
-       g_clear_object (&plugin->priv->menu);
        g_clear_object (&plugin->priv->window);
+       g_clear_object (&plugin->priv->menu_ext);
+       g_clear_object (&plugin->priv->app);
 
        G_OBJECT_CLASS (gedit_time_plugin_parent_class)->dispose (object);
 }
@@ -211,7 +218,9 @@ gedit_time_plugin_set_property (GObject      *object,
                case PROP_WINDOW:
                        plugin->priv->window = GEDIT_WINDOW (g_value_dup_object (value));
                        break;
-
+               case PROP_APP:
+                       plugin->priv->app = GEDIT_APP (g_value_dup_object (value));
+                       break;
                default:
                        G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
                        break;
@@ -231,7 +240,9 @@ gedit_time_plugin_get_property (GObject    *object,
                case PROP_WINDOW:
                        g_value_set_object (value, plugin->priv->window);
                        break;
-
+               case PROP_APP:
+                       g_value_set_object (value, plugin->priv->app);
+                       break;
                default:
                        G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
                        break;
@@ -255,7 +266,7 @@ update_ui (GeditTimePlugin *plugin)
 }
 
 static void
-gedit_time_plugin_activate (GeditWindowActivatable *activatable)
+gedit_time_plugin_app_activate (GeditAppActivatable *activatable)
 {
        GeditTimePluginPrivate *priv;
        GMenuItem *item;
@@ -264,23 +275,47 @@ gedit_time_plugin_activate (GeditWindowActivatable *activatable)
 
        priv = GEDIT_TIME_PLUGIN (activatable)->priv;
 
+       priv->menu_ext = gedit_app_activatable_extend_menu (activatable,
+                                                           "ext5");
+       item = g_menu_item_new (_("In_sert Date and Time..."), "win.time");
+       gedit_menu_extension_append_menu_item (priv->menu_ext, item);
+       g_object_unref (item);
+
+       update_ui (GEDIT_TIME_PLUGIN (activatable));
+}
+
+static void
+gedit_time_plugin_app_deactivate (GeditAppActivatable *activatable)
+{
+       GeditTimePluginPrivate *priv;
+
+       gedit_debug (DEBUG_PLUGINS);
+
+       priv = GEDIT_TIME_PLUGIN (activatable)->priv;
+
+       g_clear_object (&priv->menu_ext);
+}
+
+static void
+gedit_time_plugin_window_activate (GeditWindowActivatable *activatable)
+{
+       GeditTimePluginPrivate *priv;
+
+       gedit_debug (DEBUG_PLUGINS);
+
+       priv = GEDIT_TIME_PLUGIN (activatable)->priv;
+
        priv->action = g_simple_action_new ("time", NULL);
        g_signal_connect (priv->action, "activate",
                          G_CALLBACK (time_cb), activatable);
        g_action_map_add_action (G_ACTION_MAP (priv->window),
                                 G_ACTION (priv->action));
 
-       priv->menu = gedit_window_activatable_extend_menu (activatable,
-                                                          "ext5");
-       item = g_menu_item_new (_("In_sert Date and Time..."), "win.time");
-       gedit_menu_extension_append_menu_item (priv->menu, item);
-       g_object_unref (item);
-
        update_ui (GEDIT_TIME_PLUGIN (activatable));
 }
 
 static void
-gedit_time_plugin_deactivate (GeditWindowActivatable *activatable)
+gedit_time_plugin_window_deactivate (GeditWindowActivatable *activatable)
 {
        GeditTimePluginPrivate *priv;
 
@@ -292,7 +327,7 @@ gedit_time_plugin_deactivate (GeditWindowActivatable *activatable)
 }
 
 static void
-gedit_time_plugin_update_state (GeditWindowActivatable *activatable)
+gedit_time_plugin_window_update_state (GeditWindowActivatable *activatable)
 {
        gedit_debug (DEBUG_PLUGINS);
 
@@ -1014,6 +1049,7 @@ gedit_time_plugin_class_init (GeditTimePluginClass *klass)
        object_class->get_property = gedit_time_plugin_get_property;
 
        g_object_class_override_property (object_class, PROP_WINDOW, "window");
+       g_object_class_override_property (object_class, PROP_APP, "app");
 
        g_type_class_add_private (object_class, sizeof (GeditTimePluginPrivate));
 }
@@ -1030,11 +1066,18 @@ peas_gtk_configurable_iface_init (PeasGtkConfigurableInterface *iface)
 }
 
 static void
+gedit_app_activatable_iface_init (GeditAppActivatableInterface *iface)
+{
+       iface->activate = gedit_time_plugin_app_activate;
+       iface->deactivate = gedit_time_plugin_app_deactivate;
+}
+
+static void
 gedit_window_activatable_iface_init (GeditWindowActivatableInterface *iface)
 {
-       iface->activate = gedit_time_plugin_activate;
-       iface->deactivate = gedit_time_plugin_deactivate;
-       iface->update_state = gedit_time_plugin_update_state;
+       iface->activate = gedit_time_plugin_window_activate;
+       iface->deactivate = gedit_time_plugin_window_deactivate;
+       iface->update_state = gedit_time_plugin_window_update_state;
 }
 
 G_MODULE_EXPORT void
@@ -1043,6 +1086,9 @@ peas_register_types (PeasObjectModule *module)
        gedit_time_plugin_register_type (G_TYPE_MODULE (module));
 
        peas_object_module_register_extension_type (module,
+                                                   GEDIT_TYPE_APP_ACTIVATABLE,
+                                                   GEDIT_TYPE_TIME_PLUGIN);
+       peas_object_module_register_extension_type (module,
                                                    GEDIT_TYPE_WINDOW_ACTIVATABLE,
                                                    GEDIT_TYPE_TIME_PLUGIN);
        peas_object_module_register_extension_type (module,


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