aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMatthew Barnes <mbarnes@redhat.com>2008-05-09 02:11:40 +0800
committerMatthew Barnes <mbarnes@src.gnome.org>2008-05-09 02:11:40 +0800
commit116ed5dcc7bc07fc9a2e78aef4231bfe25fa9d0a (patch)
tree49a7516e812c322167681a65bfdca0285b336733
parent3986fb032adb5b40ae86624f209524b3273d0148 (diff)
downloadgsoc2013-evolution-116ed5dcc7bc07fc9a2e78aef4231bfe25fa9d0a.tar
gsoc2013-evolution-116ed5dcc7bc07fc9a2e78aef4231bfe25fa9d0a.tar.gz
gsoc2013-evolution-116ed5dcc7bc07fc9a2e78aef4231bfe25fa9d0a.tar.bz2
gsoc2013-evolution-116ed5dcc7bc07fc9a2e78aef4231bfe25fa9d0a.tar.lz
gsoc2013-evolution-116ed5dcc7bc07fc9a2e78aef4231bfe25fa9d0a.tar.xz
gsoc2013-evolution-116ed5dcc7bc07fc9a2e78aef4231bfe25fa9d0a.tar.zst
gsoc2013-evolution-116ed5dcc7bc07fc9a2e78aef4231bfe25fa9d0a.zip
** Fixes bug #525241 (EPluginUI)
2008-05-08 Matthew Barnes <mbarnes@redhat.com> ** Fixes bug #525241 (EPluginUI) * e-util/Makefile.am: Add e-plugin-ui.[ch]. * e-util/e-plugin.h (EPluginClass): Add a "get_symbol" method for extracting arbitrary symbols from an EPlugin. Implementation of the method is optional. * e-util/e-plugin.c (e_plugin_get_symbol): New function invokes the new "get_symbol" EPlugin method. * e-util/e-plugin.c (epl_get_symbol): New function implements the new "get_symbol" EPlugin method. It extracts the given symbol name from the GModule. * e-util/e-plugin-ui.[ch]: New EPluginHook subclass that allows plugins to extend menus, toolbars, and popups that are managed by GtkUIManager instead of BonoboUI. Should eventually replace EMenu/EPopup. * shell/main.c (main): Register the EPluginUIHook type. * composer/e-msg-composer.c (msg_composer_destroy), (msg_composer_init): Rip out the EMenu logic. * composer/e-msg-composer.c (msg_composer_init): Register the GtkUIManager with EPluginUI. * plugins/face/Makefile.am: * plugins/face/org-gnome-face-ui.xml: Remove org-gnome-face-ui.xml (obsolete). * plugins/face/face.c (e_plugin_ui_init): Initialization callback for EPluginUI. Adds a "face" action to the EMsgComposer instance's "composer" action group. * plugins/face/org-gnome-face.eplug.xml: Replace the "bonobomenu" hook definition with a new one for EPluginUI. Include the UI definition inline. svn path=/trunk/; revision=35485
-rw-r--r--composer/ChangeLog10
-rw-r--r--composer/e-msg-composer.c41
-rw-r--r--e-util/ChangeLog23
-rw-r--r--e-util/Makefile.am2
-rw-r--r--e-util/e-plugin-ui.c443
-rw-r--r--e-util/e-plugin-ui.h74
-rw-r--r--e-util/e-plugin.c36
-rw-r--r--e-util/e-plugin.h2
-rw-r--r--plugins/face/ChangeLog16
-rw-r--r--plugins/face/Makefile.am4
-rw-r--r--plugins/face/face.c36
-rw-r--r--plugins/face/org-gnome-face-ui.xml12
-rw-r--r--plugins/face/org-gnome-face.eplug.xml32
-rw-r--r--shell/ChangeLog6
-rw-r--r--shell/main.c2
15 files changed, 671 insertions, 68 deletions
diff --git a/composer/ChangeLog b/composer/ChangeLog
index 6622aec517..d1fa8ef034 100644
--- a/composer/ChangeLog
+++ b/composer/ChangeLog
@@ -1,3 +1,13 @@
+2008-05-08 Matthew Barnes <mbarnes@redhat.com>
+
+ ** Fixes part of bug #525241 (EPluginUI)
+
+ * e-msg-composer.c (msg_composer_destroy), (msg_composer_init):
+ Rip out the EMenu logic.
+
+ * e-msg-composer.c (msg_composer_init):
+ Register the GtkUIManager with EPluginUI.
+
2008-05-06 Matthew Barnes <mbarnes@redhat.com>
** Fixes part of bug #424744
diff --git a/composer/e-msg-composer.c b/composer/e-msg-composer.c
index 2aaffba0d4..2dbfcc92d4 100644
--- a/composer/e-msg-composer.c
+++ b/composer/e-msg-composer.c
@@ -69,6 +69,7 @@
#include "misc/e-charset-picker.h"
#include "misc/e-expander.h"
#include "e-util/e-error.h"
+#include "e-util/e-plugin-ui.h"
#include "e-util/e-util-private.h"
#include "e-util/e-util.h"
#include <mail/em-event.h>
@@ -2183,14 +2184,6 @@ msg_composer_destroy (GtkObject *object)
all_composers = g_slist_remove (all_composers, object);
-#if 0 /* GTKHTML-EDITOR */
- if (composer->priv->menu) {
- e_menu_update_target ((EMenu *)composer->priv->menu, NULL);
- g_object_unref (composer->priv->menu);
- composer->priv->menu = NULL;
- }
-#endif
-
if (composer->priv->address_dialog != NULL) {
gtk_widget_destroy (composer->priv->address_dialog);
composer->priv->address_dialog = NULL;
@@ -2724,17 +2717,18 @@ static void
msg_composer_init (EMsgComposer *composer)
{
EComposerHeaderTable *table;
-#if 0 /* GTKHTML-EDITOR */
- EMMenuTargetWidget *target;
-#endif
+ GtkUIManager *manager;
+ GtkhtmlEditor *editor;
GtkHTML *html;
composer->priv = E_MSG_COMPOSER_GET_PRIVATE (composer);
e_composer_private_init (composer);
+ editor = GTKHTML_EDITOR (composer);
+ html = gtkhtml_editor_get_html (editor);
+ manager = gtkhtml_editor_get_ui_manager (editor);
all_composers = g_slist_prepend (all_composers, composer);
- html = gtkhtml_editor_get_html (GTKHTML_EDITOR (composer));
table = E_COMPOSER_HEADER_TABLE (composer->priv->header_table);
gtk_window_set_title (GTK_WINDOW (composer), _("Compose Message"));
@@ -2751,24 +2745,6 @@ msg_composer_init (EMsgComposer *composer)
html, "drag-data-received",
G_CALLBACK (msg_composer_drag_data_received), NULL);
- /* Plugin Support */
-
-#if 0 /* GTKHTML-EDITOR */
- /** @HookPoint-EMMenu: Main Mail Menu
- * @Id: org.gnome.evolution.mail.composer
- * @Class: org.gnome.evolution.mail.bonobomenu:1.0
- * @Target: EMMenuTargetWidget
- *
- * The main menu of the composer window. The widget of the
- * target will point to the EMsgComposer object.
- */
- composer->priv->menu = em_menu_new ("org.gnome.evolution.mail.composer");
- target = em_menu_target_new_widget (p->menu, (GtkWidget *)composer);
- e_menu_update_target ((EMenu *)p->menu, target);
- e_menu_activate ((EMenu *)p->menu, p->uic, TRUE);
-
-#endif
-
/* Configure Headers */
e_composer_header_table_set_account_list (
@@ -2824,7 +2800,10 @@ msg_composer_init (EMsgComposer *composer)
e_composer_autosave_register (composer);
/* Initialization may have tripped the "changed" state. */
- gtkhtml_editor_set_changed (GTKHTML_EDITOR (composer), FALSE);
+ gtkhtml_editor_set_changed (editor, FALSE);
+
+ e_plugin_ui_register_manager (
+ "org.gnome.evolution.composer", manager, composer);
}
GType
diff --git a/e-util/ChangeLog b/e-util/ChangeLog
index af0027fd51..9d4197b337 100644
--- a/e-util/ChangeLog
+++ b/e-util/ChangeLog
@@ -1,3 +1,26 @@
+2008-05-08 Matthew Barnes <mbarnes@redhat.com>
+
+ ** Fixes part of bug #525241 (EPluginUI)
+
+ * Makefile.am:
+ Add e-plugin-ui.[ch].
+
+ * e-plugin.h (EPluginClass):
+ Add a "get_symbol" method for extracting arbitrary symbols
+ from an EPlugin. Implementation of the method is optional.
+
+ * e-plugin.c (e_plugin_get_symbol):
+ New function invokes the new "get_symbol" EPlugin method.
+
+ * e-plugin.c (epl_get_symbol):
+ New function implements the new "get_symbol" EPlugin method.
+ It extracts the given symbol name from the GModule.
+
+ * e-plugin-ui.[ch]:
+ New EPluginHook subclass that allows plugins to extend menus,
+ toolbars, and popups that are managed by GtkUIManager instead
+ of BonoboUI. Should eventually replace EMenu/EPopup.
+
2008-04-23 Milan Crha <mcrha@redhat.com>
** Fix for bug #529254
diff --git a/e-util/Makefile.am b/e-util/Makefile.am
index 3d4c495b8a..c104de4ddf 100644
--- a/e-util/Makefile.am
+++ b/e-util/Makefile.am
@@ -61,6 +61,7 @@ eutilinclude_HEADERS = \
e-mktemp.h \
e-print.h \
e-plugin.h \
+ e-plugin-ui.h \
e-popup.h \
e-profile-event.h \
e-request.h \
@@ -100,6 +101,7 @@ libeutil_la_SOURCES = \
e-menu.c \
e-mktemp.c \
e-plugin.c \
+ e-plugin-ui.c \
e-popup.c \
e-print.c \
e-profile-event.c \
diff --git a/e-util/e-plugin-ui.c b/e-util/e-plugin-ui.c
new file mode 100644
index 0000000000..16d127a2ef
--- /dev/null
+++ b/e-util/e-plugin-ui.c
@@ -0,0 +1,443 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * Copyright (C) 2008 Novell, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of version 2 of the GNU Lesser General Public
+ * License as published by the Free Software Foundation.
+ *
+ * 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 Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#include "e-plugin-ui.h"
+
+#include <string.h>
+
+/* XXX These should moved to e-plugin.h */
+#define E_TYPE_PLUGIN_HOOK \
+ (e_plugin_hook_get_type ())
+#define E_PLUGIN_HOOK(obj) \
+ (G_TYPE_CHECK_INSTANCE_CAST \
+ ((obj), E_TYPE_PLUGIN_HOOK, EPluginHook))
+#define E_PLUGIN_HOOK_CLASS(cls) \
+ (G_TYPE_CHECK_CLASS_CAST \
+ ((cls), E_TYPE_PLUGIN_HOOK, EPluginHookClass))
+#define E_IS_PLUGIN_HOOK(obj) \
+ (G_TYPE_CHECK_INSTANCE_TYPE \
+ ((obj), E_TYPE_PLUGIN_HOOK))
+#define E_IS_PLUGIN_HOOK_CLASS(cls) \
+ (G_TYPE_CHECK_CLASS_TYPE \
+ ((cls), E_TYPE_PLUGIN_HOOK))
+#define E_PLUGIN_HOOK_GET_CLASS(obj) \
+ (G_TYPE_INSTANCE_GET_CLASS \
+ ((obj), E_TYPE_PLUGIN_HOOK, EPluginHookClass))
+
+
+#define E_PLUGIN_UI_HOOK_GET_PRIVATE(obj) \
+ (G_TYPE_INSTANCE_GET_PRIVATE \
+ ((obj), E_TYPE_PLUGIN_UI_HOOK, EPluginUIHookPrivate))
+
+#define E_PLUGIN_UI_INIT_FUNC "e_plugin_ui_init"
+#define E_PLUGIN_UI_HOOK_CLASS_ID "org.gnome.evolution.ui:1.0"
+#define E_PLUGIN_UI_MANAGER_ID_KEY "e-plugin-ui-manager-id"
+
+struct _EPluginUIHookPrivate {
+
+ /* Table of GtkUIManager ID's to UI definitions.
+ *
+ * For example:
+ *
+ * <ui-manager id="org.gnome.evolution.sample">
+ * ... UI definition ...
+ * </ui-manager>
+ *
+ * Results in:
+ *
+ * g_hash_table_insert (
+ * ui_definitions,
+ * "org.gnome.evolution.sample",
+ * "... UI definition ...");
+ *
+ * See http://library.gnome.org/devel/gtk/unstable/GtkUIManager.html
+ * for more information about UI definitions. Note: the <ui> tag is
+ * optional.
+ */
+ GHashTable *ui_definitions;
+};
+
+/* The registry is a hash table of hash tables. It maps
+ *
+ * EPluginUIHook instance --> GtkUIManager instance --> UI merge id
+ *
+ * GtkUIManager instances are automatically removed when finalized.
+ */
+static GHashTable *registry;
+static gpointer parent_class;
+
+static void
+plugin_ui_registry_remove (EPluginUIHook *hook,
+ GtkUIManager *manager)
+{
+ GHashTable *hash_table;
+
+ /* Note: Manager may already be finalized. */
+
+ hash_table = g_hash_table_lookup (registry, hook);
+ g_return_if_fail (hash_table != NULL);
+
+ g_hash_table_remove (hash_table, manager);
+ if (g_hash_table_size (hash_table) == 0)
+ g_hash_table_remove (registry, hook);
+}
+
+static void
+plugin_ui_registry_insert (EPluginUIHook *hook,
+ GtkUIManager *manager,
+ guint merge_id)
+{
+ GHashTable *hash_table;
+
+ if (registry == NULL)
+ registry = g_hash_table_new_full (
+ g_direct_hash, g_direct_equal,
+ (GDestroyNotify) NULL,
+ (GDestroyNotify) g_hash_table_destroy);
+
+ hash_table = g_hash_table_lookup (registry, hook);
+ if (hash_table == NULL) {
+ hash_table = g_hash_table_new (g_direct_hash, g_direct_equal);
+ g_hash_table_insert (registry, hook, hash_table);
+ }
+
+ g_object_weak_ref (
+ G_OBJECT (manager), (GWeakNotify)
+ plugin_ui_registry_remove, hook);
+
+ g_hash_table_insert (hash_table, manager, GUINT_TO_POINTER (merge_id));
+}
+
+/* Helper for plugin_ui_hook_merge_ui() */
+static void
+plugin_ui_hook_merge_foreach (GtkUIManager *manager,
+ const gchar *ui_definition,
+ GHashTable *hash_table)
+{
+ guint merge_id;
+ GError *error = NULL;
+
+ /* Merge the UI definition into the manager. */
+ merge_id = gtk_ui_manager_add_ui_from_string (
+ manager, ui_definition, -1, &error);
+ gtk_ui_manager_ensure_update (manager);
+ if (error != NULL) {
+ g_warning ("%s", error->message);
+ g_error_free (error);
+ }
+
+ /* Merge ID will be 0 on error, which is what we want. */
+ g_hash_table_insert (hash_table, manager, GUINT_TO_POINTER (merge_id));
+}
+
+static void
+plugin_ui_hook_merge_ui (EPluginUIHook *hook)
+{
+ GHashTable *old_merge_ids;
+ GHashTable *new_merge_ids;
+ GHashTable *intermediate;
+ GList *keys;
+
+ old_merge_ids = g_hash_table_lookup (registry, hook);
+ if (old_merge_ids == NULL)
+ return;
+
+ /* The GtkUIManager instances and UI definitions live in separate
+ * tables, so we need to build an intermediate table that we can
+ * easily iterate over. */
+ keys = g_hash_table_get_keys (old_merge_ids);
+ intermediate = g_hash_table_new (g_direct_hash, g_direct_equal);
+
+ while (keys != NULL) {
+ GtkUIManager *manager = keys->data;
+ gchar *ui_definition;
+
+ ui_definition = g_hash_table_lookup (
+ hook->priv->ui_definitions,
+ e_plugin_ui_get_manager_id (manager));
+
+ g_hash_table_insert (intermediate, manager, ui_definition);
+
+ keys = g_list_delete_link (keys, keys);
+ }
+
+ new_merge_ids = g_hash_table_new (g_direct_hash, g_direct_equal);
+
+ g_hash_table_foreach (
+ intermediate, (GHFunc)
+ plugin_ui_hook_merge_foreach, new_merge_ids);
+
+ g_hash_table_insert (registry, hook, new_merge_ids);
+
+ g_hash_table_destroy (intermediate);
+}
+
+/* Helper for plugin_ui_hook_unmerge_ui() */
+static void
+plugin_ui_hook_unmerge_foreach (GtkUIManager *manager,
+ gpointer value,
+ GHashTable *hash_table)
+{
+ guint merge_id;
+
+ merge_id = GPOINTER_TO_UINT (value);
+ gtk_ui_manager_remove_ui (manager, merge_id);
+
+ g_hash_table_insert (hash_table, manager, GUINT_TO_POINTER (0));
+}
+
+static void
+plugin_ui_hook_unmerge_ui (EPluginUIHook *hook)
+{
+ GHashTable *old_merge_ids;
+ GHashTable *new_merge_ids;
+
+ old_merge_ids = g_hash_table_lookup (registry, hook);
+ if (old_merge_ids == NULL)
+ return;
+
+ new_merge_ids = g_hash_table_new (g_direct_hash, g_direct_equal);
+
+ g_hash_table_foreach (
+ old_merge_ids, (GHFunc)
+ plugin_ui_hook_unmerge_foreach, new_merge_ids);
+
+ g_hash_table_insert (registry, hook, new_merge_ids);
+}
+
+static void
+plugin_ui_hook_register_manager (EPluginUIHook *hook,
+ GtkUIManager *manager,
+ const gchar *ui_definition,
+ gpointer user_data)
+{
+ EPlugin *plugin;
+ EPluginUIInitFunc func;
+ guint merge_id = 0;
+
+ plugin = ((EPluginHook *) hook)->plugin;
+ func = e_plugin_get_symbol (plugin, E_PLUGIN_UI_INIT_FUNC);
+
+ /* Pass the manager and user_data to the plugin's e_plugin_ui_init()
+ * function (if it defined one). The plugin should install whatever
+ * GtkActions and GtkActionGroups are neccessary to implement the
+ * action names in its UI definition. */
+ if (func != NULL && !func (manager, user_data))
+ return;
+
+ if (plugin->enabled) {
+ GError *error = NULL;
+
+ /* Merge the UI definition into the manager. */
+ merge_id = gtk_ui_manager_add_ui_from_string (
+ manager, ui_definition, -1, &error);
+ gtk_ui_manager_ensure_update (manager);
+ if (error != NULL) {
+ g_warning ("%s", error->message);
+ g_error_free (error);
+ }
+ }
+
+ /* Save merge ID's for later use. */
+ plugin_ui_registry_insert (hook, manager, merge_id);
+}
+
+static void
+plugin_ui_hook_finalize (GObject *object)
+{
+ EPluginUIHookPrivate *priv;
+
+ priv = E_PLUGIN_UI_HOOK_GET_PRIVATE (object);
+
+ g_hash_table_destroy (priv->ui_definitions);
+
+ /* Chain up to parent's dispose() method. */
+ G_OBJECT_CLASS (parent_class)->dispose (object);
+}
+
+static gint
+plugin_ui_hook_construct (EPluginHook *hook,
+ EPlugin *plugin,
+ xmlNodePtr node)
+{
+ EPluginUIHookPrivate *priv;
+
+ priv = E_PLUGIN_UI_HOOK_GET_PRIVATE (hook);
+
+ /* XXX The EPlugin should be a property of EPluginHookClass.
+ * Then it could be passed directly to g_object_new() and
+ * we wouldn't have to chain up here. */
+
+ /* Chain up to parent's construct() method. */
+ E_PLUGIN_HOOK_CLASS (parent_class)->construct (hook, plugin, node);
+
+ for (node = node->children; node != NULL; node = node->next) {
+ xmlNodePtr child;
+ xmlBufferPtr buffer;
+ const gchar *content;
+ gchar *id;
+
+ if (strcmp ((gchar *) node->name, "ui-manager") != 0)
+ continue;
+
+ id = e_plugin_xml_prop (node, "id");
+ if (id == NULL) {
+ g_warning ("<ui-manager> requires 'id' property");
+ continue;
+ }
+
+ /* Extract the XML content below <ui-manager> */
+ buffer = xmlBufferCreate ();
+ child = node->children;
+ while (child != NULL && xmlNodeIsText (child))
+ child = child->next;
+ if (child != NULL)
+ xmlNodeDump (buffer, node->doc, child, 2, 1);
+ content = (const gchar *) xmlBufferContent (buffer);
+
+ g_hash_table_insert (
+ priv->ui_definitions,
+ id, g_strdup (content));
+
+ xmlBufferFree (buffer);
+ }
+
+ return 0;
+}
+
+static void
+plugin_ui_hook_enable (EPluginHook *hook,
+ gint state)
+{
+ if (state)
+ plugin_ui_hook_merge_ui (E_PLUGIN_UI_HOOK (hook));
+ else
+ plugin_ui_hook_unmerge_ui (E_PLUGIN_UI_HOOK (hook));
+}
+
+static void
+plugin_ui_hook_class_init (EPluginUIHookClass *class)
+{
+ GObjectClass *object_class;
+ EPluginHookClass *plugin_hook_class;
+
+ parent_class = g_type_class_peek_parent (class);
+ g_type_class_add_private (class, sizeof (EPluginUIHookPrivate));
+
+ object_class = G_OBJECT_CLASS (class);
+ object_class->finalize = plugin_ui_hook_finalize;
+
+ plugin_hook_class = E_PLUGIN_HOOK_CLASS (class);
+ plugin_hook_class->id = E_PLUGIN_UI_HOOK_CLASS_ID;
+ plugin_hook_class->construct = plugin_ui_hook_construct;
+ plugin_hook_class->enable = plugin_ui_hook_enable;
+}
+
+static void
+plugin_ui_hook_init (EPluginUIHook *hook)
+{
+ GHashTable *ui_definitions;
+
+ ui_definitions = g_hash_table_new_full (
+ g_str_hash, g_str_equal,
+ (GDestroyNotify) g_free,
+ (GDestroyNotify) g_free);
+
+ hook->priv = E_PLUGIN_UI_HOOK_GET_PRIVATE (hook);
+ hook->priv->ui_definitions = ui_definitions;
+}
+
+GType
+e_plugin_ui_hook_get_type (void)
+{
+ static GType type = 0;
+
+ if (G_UNLIKELY (type == 0)) {
+ static const GTypeInfo type_info = {
+ sizeof (EPluginUIHookClass),
+ (GBaseInitFunc) NULL,
+ (GBaseFinalizeFunc) NULL,
+ (GClassInitFunc) plugin_ui_hook_class_init,
+ (GClassFinalizeFunc) NULL,
+ NULL, /* class_data */
+ sizeof (EPluginUIHook),
+ 0, /* n_preallocs */
+ (GInstanceInitFunc) plugin_ui_hook_init,
+ NULL /* value_table */
+ };
+
+ type = g_type_register_static (
+ E_TYPE_PLUGIN_HOOK, "EPluginUIHook", &type_info, 0);
+ }
+
+ return type;
+}
+
+void
+e_plugin_ui_register_manager (const gchar *id,
+ GtkUIManager *manager,
+ gpointer user_data)
+{
+ const gchar *key = E_PLUGIN_UI_MANAGER_ID_KEY;
+ GSList *plugin_list;
+
+ g_return_if_fail (id != NULL);
+ g_return_if_fail (GTK_IS_UI_MANAGER (manager));
+
+ g_object_set_data (G_OBJECT (manager), key, (gpointer) id);
+
+ /* Loop over all installed plugins. */
+ plugin_list = e_plugin_list_plugins ();
+ while (plugin_list != NULL) {
+ EPlugin *plugin = plugin_list->data;
+ GSList *iter;
+
+ /* Look for hooks of type EPluginUIHook. */
+ for (iter = plugin->hooks; iter != NULL; iter = iter->next) {
+ EPluginUIHook *hook = iter->data;
+ const gchar *ui_definition;
+
+ if (!E_IS_PLUGIN_UI_HOOK (hook))
+ continue;
+
+ /* Check if the hook has a UI definition
+ * for the GtkUIManager being registered. */
+ ui_definition = g_hash_table_lookup (
+ hook->priv->ui_definitions, id);
+ if (ui_definition == NULL)
+ continue;
+
+ /* Register the manager with the hook. */
+ plugin_ui_hook_register_manager (
+ hook, manager, ui_definition, user_data);
+ }
+
+ plugin_list = g_slist_next (plugin_list);
+ }
+}
+
+const gchar *
+e_plugin_ui_get_manager_id (GtkUIManager *manager)
+{
+ const gchar *key = E_PLUGIN_UI_MANAGER_ID_KEY;
+
+ g_return_val_if_fail (GTK_IS_UI_MANAGER (manager), NULL);
+
+ return g_object_get_data (G_OBJECT (manager), key);
+}
diff --git a/e-util/e-plugin-ui.h b/e-util/e-plugin-ui.h
new file mode 100644
index 0000000000..8bcaaa3d01
--- /dev/null
+++ b/e-util/e-plugin-ui.h
@@ -0,0 +1,74 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * Copyright (C) 2008 Novell, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of version 2 of the GNU Lesser General Public
+ * License as published by the Free Software Foundation.
+ *
+ * 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 Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef E_PLUGIN_UI_H
+#define E_PLUGIN_UI_H
+
+#include <gtk/gtk.h>
+#include "e-plugin.h"
+
+/* Standard GObject macros */
+#define E_TYPE_PLUGIN_UI_HOOK \
+ (e_plugin_ui_hook_get_type ())
+#define E_PLUGIN_UI_HOOK(obj) \
+ (G_TYPE_CHECK_INSTANCE_CAST \
+ ((obj), E_TYPE_PLUGIN_UI_HOOK, EPluginUIHook))
+#define E_PLUGIN_UI_HOOK_CLASS(cls) \
+ (G_TYPE_CHECK_CLASS_CAST \
+ ((cls), E_TYPE_PLUGIN_UI_HOOK, EPluginUIHookClass))
+#define E_IS_PLUGIN_UI_HOOK(obj) \
+ (G_TYPE_CHECK_INSTANCE_TYPE \
+ ((obj), E_TYPE_PLUGIN_UI_HOOK))
+#define E_IS_PLUGIN_UI_HOOK_CLASS(cls) \
+ (G_TYPE_CHECK_CLASS_TYPE \
+ ((cls), E_TYPE_PLUGIN_UI_HOOK))
+#define E_PLUGIN_UI_HOOK_GET_CLASS(obj) \
+ (G_TYPE_INSTANCE_GET_CLASS \
+ ((obj), E_TYPE_PLUGIN_UI_HOOK, EPluginUIHookClass))
+
+G_BEGIN_DECLS
+
+typedef struct _EPluginUIHook EPluginUIHook;
+typedef struct _EPluginUIHookClass EPluginUIHookClass;
+typedef struct _EPluginUIHookPrivate EPluginUIHookPrivate;
+
+struct _EPluginUIHook {
+ EPluginHook parent;
+ EPluginUIHookPrivate *priv;
+};
+
+struct _EPluginUIHookClass {
+ EPluginHookClass parent_class;
+};
+
+/* Plugins with "org.gnome.evolution.ui" hooks should define a
+ * function named e_plugin_ui_init() having this signature. */
+typedef gboolean (*EPluginUIInitFunc) (GtkUIManager *manager,
+ gpointer user_data);
+
+GType e_plugin_ui_hook_get_type (void);
+
+void e_plugin_ui_register_manager (const gchar *id,
+ GtkUIManager *manager,
+ gpointer user_data);
+const gchar * e_plugin_ui_get_manager_id (GtkUIManager *manager);
+
+G_END_DECLS
+
+#endif /* E_PLUGIN_UI_H */
diff --git a/e-util/e-plugin.c b/e-util/e-plugin.c
index d4770915d3..e91169ac67 100644
--- a/e-util/e-plugin.c
+++ b/e-util/e-plugin.c
@@ -697,6 +697,27 @@ e_plugin_invoke(EPlugin *ep, const char *name, void *data)
}
/**
+ * e_plugin_get_symbol:
+ * @ep: an #EPlugin
+ * @name: The name of the symbol to fetch. The format of this name
+ * will depend on the EPlugin type and its language conventions.
+ *
+ * Helper to fetch a symbol name from a plugin.
+ *
+ * Return value: the symbol value, or %NULL if not found
+ **/
+void *
+e_plugin_get_symbol(EPlugin *ep, const char *name)
+{
+ EPluginClass *class;
+
+ class = (EPluginClass *) G_OBJECT_GET_CLASS (ep);
+ g_return_val_if_fail (class->get_symbol != NULL, NULL);
+
+ return class->get_symbol (ep, name);
+}
+
+/**
* e_plugin_enable:
* @ep:
* @state:
@@ -927,6 +948,20 @@ epl_invoke(EPlugin *ep, const char *name, void *data)
return cb(epl, data);
}
+static void *
+epl_get_symbol(EPlugin *ep, const gchar *name)
+{
+ gpointer symbol;
+
+ if (epl_loadmodule(ep) != 0)
+ return NULL;
+
+ if (!g_module_symbol (epl->module, name, &symbol))
+ return NULL;
+
+ return symbol;
+}
+
static int
epl_construct(EPlugin *ep, xmlNodePtr root)
{
@@ -1029,6 +1064,7 @@ epl_class_init(EPluginClass *klass)
((GObjectClass *)klass)->finalize = epl_finalise;
klass->construct = epl_construct;
klass->invoke = epl_invoke;
+ klass->get_symbol = epl_get_symbol;
klass->enable = epl_enable;
klass->get_configure_widget = epl_get_configure_widget;
klass->type = "shlib";
diff --git a/e-util/e-plugin.h b/e-util/e-plugin.h
index fd5955ba38..c20ed81a7f 100644
--- a/e-util/e-plugin.h
+++ b/e-util/e-plugin.h
@@ -86,6 +86,7 @@ struct _EPluginClass {
const char *type;
int (*construct)(EPlugin *, xmlNodePtr root);
+ void *(*get_symbol)(EPlugin *, const char *name);
void *(*invoke)(EPlugin *, const char *name, void *data);
void (*enable)(EPlugin *, int state);
GtkWidget *(*get_configure_widget)(EPlugin *);
@@ -100,6 +101,7 @@ GSList * e_plugin_list_plugins(void);
void e_plugin_register_type(GType type);
+void *e_plugin_get_symbol(EPlugin *ep, const char *name);
void *e_plugin_invoke(EPlugin *ep, const char *name, void *data);
void e_plugin_enable(EPlugin *eph, int state);
diff --git a/plugins/face/ChangeLog b/plugins/face/ChangeLog
index 86a2af2140..c300752828 100644
--- a/plugins/face/ChangeLog
+++ b/plugins/face/ChangeLog
@@ -1,3 +1,19 @@
+2008-05-08 Matthew Barnes <mbarnes@redhat.com>
+
+ ** Fixes part of bug #525241 (EPluginUI)
+
+ * Makefile.am:
+ * org-gnome-face-ui.xml:
+ Remove org-gnome-face-ui.xml (obsolete).
+
+ * face.c (e_plugin_ui_init):
+ Initialization callback for EPluginUI. Adds a "face" action to
+ the EMsgComposer instance's "composer" action group.
+
+ * org-gnome-face.eplug.xml:
+ Replace the "bonobomenu" hook definition with a new one for
+ EPluginUI. Include the UI definition inline.
+
2008-03-11 Matthew Barnes <mbarnes@redhat.com>
** Fixes part of bug #513951
diff --git a/plugins/face/Makefile.am b/plugins/face/Makefile.am
index ec53eee1c2..8a44c94815 100644
--- a/plugins/face/Makefile.am
+++ b/plugins/face/Makefile.am
@@ -13,8 +13,7 @@ INCLUDES = -I. \
@EVO_PLUGIN_RULE@
plugin_DATA = \
- org-gnome-face.eplug \
- org-gnome-face-ui.xml
+ org-gnome-face.eplug
plugin_LTLIBRARIES = liborg-gnome-face.la
@@ -36,7 +35,6 @@ errordir = $(privdatadir)/errors
EXTRA_DIST = \
org-gnome-face.eplug.xml \
- org-gnome-face-ui.xml \
$(error_DATA)
BUILT_SOURCES = \
diff --git a/plugins/face/face.c b/plugins/face/face.c
index 45851bee18..f431bc50f4 100644
--- a/plugins/face/face.c
+++ b/plugins/face/face.c
@@ -33,16 +33,16 @@
#define d(x) x
-void org_gnome_composer_face (EPlugin * ep, EMMenuTargetWidget * target);
-int e_plugin_lib_configure (EPlugin * ep);
+gboolean e_plugin_ui_init (GtkUIManager *manager,
+ EMsgComposer *composer);
-void org_gnome_composer_face (EPlugin * ep, EMMenuTargetWidget * t)
+static void
+action_face_cb (GtkAction *action,
+ EMsgComposer *composer)
{
- EMsgComposer *composer;
gchar *filename, *file_contents;
GError *error = NULL;
- composer = (EMsgComposer *) t->target.widget;
filename = g_build_filename (e_get_user_data_dir (), "faces", NULL);
g_file_get_contents (filename, &file_contents, NULL, &error);
@@ -117,3 +117,29 @@ void org_gnome_composer_face (EPlugin * ep, EMMenuTargetWidget * t)
}
e_msg_composer_modify_header (composer, "Face", file_contents);
}
+
+static GtkActionEntry entries[] = {
+
+ { "face",
+ NULL,
+ N_("_Face"),
+ NULL,
+ NULL,
+ G_CALLBACK (action_face_cb) }
+};
+
+gboolean
+e_plugin_ui_init (GtkUIManager *manager,
+ EMsgComposer *composer)
+{
+ GtkhtmlEditor *editor;
+
+ editor = GTKHTML_EDITOR (composer);
+
+ /* Add actions to the "composer" action group. */
+ gtk_action_group_add_actions (
+ gtkhtml_editor_get_action_group (editor, "composer"),
+ entries, G_N_ELEMENTS (entries), composer);
+
+ return TRUE;
+}
diff --git a/plugins/face/org-gnome-face-ui.xml b/plugins/face/org-gnome-face-ui.xml
index 2bf2a75c65..e69de29bb2 100644
--- a/plugins/face/org-gnome-face-ui.xml
+++ b/plugins/face/org-gnome-face-ui.xml
@@ -1,12 +0,0 @@
-<Root>
- <commands>
- <cmd name="Face" _label="_Face"/>
- </commands>
- <menu>
- <submenu name="Insert">
- <placeholder name="Component">
- <menuitem name="Face" verb="" />
- </placeholder>
- </submenu>
- </menu>
-</Root>
diff --git a/plugins/face/org-gnome-face.eplug.xml b/plugins/face/org-gnome-face.eplug.xml
index cc56aac359..e84b93f809 100644
--- a/plugins/face/org-gnome-face.eplug.xml
+++ b/plugins/face/org-gnome-face.eplug.xml
@@ -1,22 +1,20 @@
<?xml version="1.0"?>
<e-plugin-list>
- <e-plugin id="org.gnome.evolution.face" type="shlib" _name="Face"
- location="@PLUGINDIR@/liborg-gnome-face@SOEXT@">
+ <e-plugin id="org.gnome.evolution.face" type="shlib" _name="Face" location="@PLUGINDIR@/liborg-gnome-face@SOEXT@">
- <author name="Sankar P" email="psankar@novell.com"/>
- <_description>Attach Face header to outgoing messages. First time the user needs to configure a 48*48 png image. It is base64 encoded and stored in ~/.evolution/faces This will be used in messages that are sent further.</_description>
+ <author name="Sankar P" email="psankar@novell.com"/>
+ <_description>Attach Face header to outgoing messages. First time the user needs to configure a 48*48 png image. It is base64 encoded and stored in ~/.evolution/faces This will be used in messages that are sent further.</_description>
- <hook class="org.gnome.evolution.mail.bonobomenu:1.0">
- <menu id="org.gnome.evolution.mail.composer" target="widget">
- <ui file="@PLUGINDIR@/org-gnome-face-ui.xml"/>
- <item
- type="item"
- verb="Face"
- path="/commands/Face"
- activate="org_gnome_composer_face"
- enable="one"
- />
- </menu>
- </hook>
- </e-plugin>
+ <hook class="org.gnome.evolution.ui:1.0">
+ <ui-manager id="org.gnome.evolution.composer">
+ <menubar name='main-menu'>
+ <menu action='insert-menu'>
+ <placeholder name="insert-menu-top">
+ <menuitem action="face"/>
+ </placeholder>
+ </menu>
+ </menubar>
+ </ui-manager>
+ </hook>
+ </e-plugin>
</e-plugin-list>
diff --git a/shell/ChangeLog b/shell/ChangeLog
index b172ffb012..4f9092fe45 100644
--- a/shell/ChangeLog
+++ b/shell/ChangeLog
@@ -1,3 +1,9 @@
+2008-05-08 Matthew Barnes <mbarnes@redhat.com>
+
+ ** Fixes part of bug #525241 (EPluginUI)
+
+ * main.c (main): Register the EPluginUIHook type.
+
2008-05-08 Tor Lillqvist <tml@novell.com>
* main.c (main) [Win32]: If no message catalog is installed for
diff --git a/shell/main.c b/shell/main.c
index 7062ea9a6e..705f57d369 100644
--- a/shell/main.c
+++ b/shell/main.c
@@ -95,6 +95,7 @@
#include <pthread.h>
#include "e-util/e-plugin.h"
+#include "e-util/e-plugin-ui.h"
#define SKIP_WARNING_DIALOG_KEY \
"/apps/evolution/shell/skip_warning_dialog"
@@ -771,6 +772,7 @@ main (int argc, char **argv)
#endif
e_plugin_hook_register_type(e_plugin_type_hook_get_type());
e_plugin_hook_register_type(e_import_hook_get_type());
+ e_plugin_hook_register_type(E_TYPE_PLUGIN_UI_HOOK);
e_plugin_load_plugins();
}