Welcome to a new installment of the plugins tutorial! Todays issue will cover menu modifications. This allows you to add new menu options for features you introduce with your plugin.

GTK menu concepts

Before diving into the example code we need to cover some theory. GTK3 provides several APIs to build menus but for Liferea plugins only one of them is exposed: the GtkUIManager. In short the GtkUIManager allows adding UI elements (menus ,toolbars, accelerators) using XML like this:
<ui>
  <menubar>
    <menu name="FileMenu" action="FileMenuAction">
      <menuitem name="New" action="New2Action" />
    </menu>
</ui>
The above snippet defines an menu item that you can merged into the UI by calling a method like gtk_ui_manager_add_ui_from_string(). Note that above definition only says that there ought to be a menu action with internal action name "New2Action". So we still have to define this active and bind a callback.

Extending a menu in PyGI

Now how do we extend a Liferea menu? First we get the GtkUIManager:
self._ui_manager = self.shell.get_property("ui-manager")
Now we can add an XML snippet describing a menu
self._ui_manager.add_ui_from_string(
    """<ui>
         <menubar name='MainwindowMenubar'>
           <menu action='ToolsMenu'>
             <menuitem action='MyPluginMenuEntry'/>
           </menu>
        </menubar>
      </ui>"""
)
Please note that the GtkUIManager property is only exposed starting with Liferea version 1.12.2! And as said above we need to add an action for this menu item. As actions can only be added in groups using a GtkActionGroup we need to create one first, insert the action and finally tell the GtkUIManager about the action group:
self._action = Gtk.Action('MyPluginMenuEntry', 'Awesome Function', 'Run a really awesome function', None)
self._action.connect("activate", self._do_action)

self._actiongroup = Gtk.ActionGroup("MyPluginActions")
self._actiongroup.add_action(self._action)

self._ui_manager.insert_action_group(self._actiongroup)

Available Menus

You probably noticed the "ToolsMenu" and "MainwindowMenubar" ids in the XML snippet above. Here is a list of all menu ids in 1.12 which also can be found in src/ui/liferea_shell.c.
Name Description
FeedMenuAll actions regarding subscriptions and the feed list
ItemMenuAll actions regarding the item list
ViewMenuAll actions controlling reading layout
ToolsMenuThe menu to access preferences and update status
SearchMenuAll actions for finding stuff
HelpMenuThe place to go for help

Complete Solution

Everything put together in a plugin could look like this:
import gi

gi.require_version('Gtk', '3.0')

from gi.repository import GObject, Liferea, Gtk

class AppActivatable(GObject.Object, Liferea.ShellActivatable):
    __gtype_name__ = "MyPluginAppActivatable"

    shell = GObject.property(type=Liferea.Shell)

    def __init__(self):
        GObject.Object.__init__(self)

    def do_activate(self):
        self._action = Gtk.Action('MyPluginMenuEntry', 'Awesome Function', 'Run a really awesome function', None)
        self._action.connect("activate", self._do_action)

        self._actiongroup = Gtk.ActionGroup("MyPluginActions")
        self._actiongroup.add_action(self._action)

        self._ui_manager = self.shell.get_property("ui-manager")
        self._ui_manager.insert_action_group(self._actiongroup)
        self._ui_manager.add_ui_from_string(
             """<ui>
                  <menubar name='MainwindowMenubar'>
                    <menu action='ToolsMenu'>
                      <menuitem action='MyPluginMenuEntry'/>
                    </menu>
                 </menubar>
               </ui>"""
        )

   def _do_action(self, action, data=None):
        print("Action triggered")
For a real world example have a look at https://github.com/lwindolf/liferea/blob/master/plugins/plugin-installer.py

Related

Also check out the previous plugin tutorial posts