User Interface Integration

Warning

This section describes changing Epiphany's user interface. Epiphany developers take pride in Epiphany's simplicity and ease of use: you should continue the trend. UI additions should be simple, minor, and non-intrusive. Carefully plan each addition.

The GtkUIManager functions allow you to add new user interface elements. Epiphany's ephy_window_get_ui_manager will return the appropriate GtkUIManager for an EphyWindow. Use GtkActions to represent actions. For example, an extension could place an action at the bottom of the Go menu of Epiphany. To do so, write the following in ephy-foo-extension.c:

Example 4.4. Adding menu entries

#include <gtk/gtkaction.>
#include <gtk/gtkactiongroup>
#include <gtk/gtkuimanager.h>

#include <glib/gi18n-lib.h> /* see Translation */

#define WINDOW_DATA_KEY "EphyFooExtensionWindowData"

typedef struct
{
	GtkActionGroup *action_group;
	guint ui_id;
} WindowData;

static void my_action_activate_cb (GtkAction *action, EphyWindow *window);

/* ... */

static GtkActionEntry action_entries [] =
{
	{ "MyAction",
	  NULL,
	  N_("Menu Entry Name"),
	  NULL, /* shortcut key */
	  N_("Does Whatever I Want"),
	  G_CALLBACK (my_action_activate_cb) }
};
static const guint n_action_entries = G_N_ELEMENTS (action_entries);

static void my_action_activate_cb (GtkAction *action,
				   EphyWindow *window)
{
	/* Do something */
}

/* ... */

static void
free_window_data (WindowData *data)
{
	g_object_unref (data->action_group);
	g_free (data);
}

static void
impl_attach_window (EphyExtension *extension,
		    EphyWindow *window)
{
	GtkActionGroup *action_group;
	GtkUIManager *manager;
	guint merge_id;
	WindowData *data;

	data = g_new (WindowData, 1);

	manager = GTK_UI_MANAGER (ephy_window_get_ui_manager (window));

	data->action_group = action_group =
		gtk_action_group_new ("EphyFooExtensionActions");

	gtk_action_group_set_translation_domain (action_group, GETTEXT_PACKAGE);
	gtk_action_group_add_actions (action_group, action_entries,
				      n_action_entries, window);

	gtk_ui_manager_insert_action_group (manager, action_group, 0);

	data->ui_id = merge_id = gtk_ui_manager_new_merge_id (manager);

	g_data_set_full (G_OBJECT (window), WINDOW_DATA_KEY, data,
			 (GDestroyNotify) free_window_data);

	gtk_ui_manager_add_ui (manager, merge_id, "/menubar/GoMenu",
			       "MyActionSep1", NULL,
			       GTK_UI_MANAGER_SEPARATOR, FALSE);
	gtk_ui_manager_add_ui (manager, merge_id, "/menubar/GoMenu",
			       "MyAction", "MyAction",
			       GTK_UI_MANAGER_MENUITEM, FALSE);
	gtk_ui_manager_add_ui (manager, merge_id, "/menubar/GoMenu",
			       "MyActionSep2", NULL,
			       GTK_UI_MANAGER_SEPARATOR, FALSE);
}

static void
impl_detach_window (EphyExtension *extension,
		    EphyWindow *window)
{
	GtkUIManager *manager;
	WindowData *data;

	manager = GTK_UI_MANAGER (ephy_window_get_ui_manager (window));

	data = (WindowData *) g_object_get_data (G_OBJECT (window), WINDOW_DATA_KEY);
	g_return_if_fail (data != NULL);

	gtk_ui_manager_remove_ui (manager, data->ui_id);
	gtk_ui_manager_remove_action_group (manager, data->action_group);

	g_object_set_data (G_OBJECT (window), WINDOW_DATA_KEY, NULL);
}

Example 4.5. Adding menu entries (Python)

import gtk

_ui_str = """
<ui>
	<menubar name="menubar">
		<menu name="GoMenu" action="Go">
			<separator/>
			<menuitem name="SampleMenuEntry"
				action="SampleMenuEntry"/>
			<separator/>
		</menu>
	</menubar>
</ui>
"""

def _menu_entry_cb(action, data):
	print data

_actions = [('SampleMenuEntry', None, 'Sample Menu Entry',
	     None, None, _menu_entry_cb)]

def attach_window(window):
	ui_manager = window.get_ui_manager()
	group = gtk.ActionGroup('SampleMenu')
	group.add_actions(_actions, 'Data')
	ui_manager.insert_action_group(group, 0)
	ui_id = ui_manager.add_ui_from_string(_ui_str)

	window._sample_menu_entry_data = (group, ui_id)

def detach_window(window):
	group, ui_id = window._sample_menu_entry_data
	del window._sample_menu_entry_data

	ui_manager = window.get_ui_manager()
	ui_manager.remove_ui(ui_id)
	ui_manager.remove_action_group(group)
	ui_manager.ensure_update()

Tip

The existing epiphany menu hierarchy is described in epiphany/data/ui/epiphany-ui.xml.

Note

Without a placeholder element in epiphany/data/ui/epiphany-ui.xml, extensions can only add menu entries to the top or bottom of menus.

Warning

Remember that extensions may be loaded or unloaded at any point in time. The above procedure detaches from windows nicely. If you decide to modify it, be sure that your extension still loads and unloads successfully.