** 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
This commit is contained in:
committed by
Matthew Barnes
parent
3986fb032a
commit
116ed5dcc7
@ -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
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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 \
|
||||
|
||||
443
e-util/e-plugin-ui.c
Normal file
443
e-util/e-plugin-ui.c
Normal file
@ -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);
|
||||
}
|
||||
74
e-util/e-plugin-ui.h
Normal file
74
e-util/e-plugin-ui.h
Normal file
@ -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 */
|
||||
@ -696,6 +696,27 @@ e_plugin_invoke(EPlugin *ep, const char *name, void *data)
|
||||
return ((EPluginClass *)G_OBJECT_GET_CLASS(ep))->invoke(ep, name, 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:
|
||||
@ -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";
|
||||
|
||||
@ -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);
|
||||
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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 = \
|
||||
|
||||
@ -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;
|
||||
}
|
||||
|
||||
@ -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>
|
||||
|
||||
@ -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>
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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();
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user