diff options
author | Matthew Barnes <mbarnes@redhat.com> | 2008-05-09 02:11:40 +0800 |
---|---|---|
committer | Matthew Barnes <mbarnes@src.gnome.org> | 2008-05-09 02:11:40 +0800 |
commit | 116ed5dcc7bc07fc9a2e78aef4231bfe25fa9d0a (patch) | |
tree | 49a7516e812c322167681a65bfdca0285b336733 | |
parent | 3986fb032adb5b40ae86624f209524b3273d0148 (diff) | |
download | gsoc2013-evolution-116ed5dcc7bc07fc9a2e78aef4231bfe25fa9d0a.tar.gz 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/ChangeLog | 10 | ||||
-rw-r--r-- | composer/e-msg-composer.c | 41 | ||||
-rw-r--r-- | e-util/ChangeLog | 23 | ||||
-rw-r--r-- | e-util/Makefile.am | 2 | ||||
-rw-r--r-- | e-util/e-plugin-ui.c | 443 | ||||
-rw-r--r-- | e-util/e-plugin-ui.h | 74 | ||||
-rw-r--r-- | e-util/e-plugin.c | 36 | ||||
-rw-r--r-- | e-util/e-plugin.h | 2 | ||||
-rw-r--r-- | plugins/face/ChangeLog | 16 | ||||
-rw-r--r-- | plugins/face/Makefile.am | 4 | ||||
-rw-r--r-- | plugins/face/face.c | 36 | ||||
-rw-r--r-- | plugins/face/org-gnome-face-ui.xml | 12 | ||||
-rw-r--r-- | plugins/face/org-gnome-face.eplug.xml | 32 | ||||
-rw-r--r-- | shell/ChangeLog | 6 | ||||
-rw-r--r-- | shell/main.c | 2 |
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(); } |