aboutsummaryrefslogtreecommitdiffstats
path: root/e-util/e-popup.c
diff options
context:
space:
mode:
Diffstat (limited to 'e-util/e-popup.c')
-rw-r--r--e-util/e-popup.c953
1 files changed, 0 insertions, 953 deletions
diff --git a/e-util/e-popup.c b/e-util/e-popup.c
deleted file mode 100644
index 4cbe221ea8..0000000000
--- a/e-util/e-popup.c
+++ /dev/null
@@ -1,953 +0,0 @@
-/*
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) version 3.
- *
- * 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
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with the program; if not, see <http://www.gnu.org/licenses/>
- *
- *
- * Authors:
- * Michael Zucchi <notzed@ximian.com>
- *
- * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
- *
- */
-
-#ifdef HAVE_CONFIG_H
-#include <config.h>
-#endif
-
-#include <string.h>
-#include <stdlib.h>
-
-#include <gtk/gtk.h>
-
-#include "e-popup.h"
-
-#include <glib/gi18n.h>
-
-#define d(x)
-
-struct _EPopupFactory {
- struct _EPopupFactory *next, *prev;
-
- gchar *menuid;
- EPopupFactoryFunc factory;
- gpointer factory_data;
-};
-
-/* Used for the "activate" signal callback data to re-map to the api */
-struct _item_node {
- struct _item_node *next; /* tree pointers */
- struct _item_node *prev;
- struct _item_node *parent;
- EDList children;
-
- struct _item_node *link; /* for freeing */
-
- EPopupItem *item;
- struct _menu_node *menu;
-};
-
-/* Stores all the items added */
-struct _menu_node {
- struct _menu_node *next, *prev;
-
- EPopup *popup;
-
- GSList *menu;
- gchar *domain;
- EPopupItemsFunc freefunc;
- gpointer data;
-
- struct _item_node *items;
-};
-
-struct _EPopupPrivate {
- EDList menus;
-};
-
-static GObjectClass *ep_parent;
-
-static void
-ep_init(GObject *o)
-{
- EPopup *emp = (EPopup *)o;
- struct _EPopupPrivate *p;
-
- p = emp->priv = g_malloc0(sizeof(struct _EPopupPrivate));
-
- e_dlist_init(&p->menus);
-}
-
-static void
-ep_finalise(GObject *o)
-{
- EPopup *emp = (EPopup *)o;
- struct _EPopupPrivate *p = emp->priv;
- struct _menu_node *mnode, *nnode;
-
- mnode = (struct _menu_node *)p->menus.head;
- nnode = mnode->next;
- while (nnode) {
- struct _item_node *inode;
-
- if (mnode->freefunc)
- mnode->freefunc(emp, mnode->menu, mnode->data);
-
- g_free(mnode->domain);
-
- /* free item activate callback data */
- inode = mnode->items;
- while (inode) {
- /* This was declared as _menu_node above already */
- struct _item_node *nnode = inode->link;
-
- g_free(inode);
- inode = nnode;
- }
-
- g_free(mnode);
- mnode = nnode;
- nnode = nnode->next;
- }
-
- if (emp->target)
- e_popup_target_free(emp, emp->target);
-
- g_free(emp->menuid);
-
- g_free(p);
-
- ((GObjectClass *)ep_parent)->finalize(o);
-}
-
-static void
-ep_target_free(EPopup *ep, EPopupTarget *t)
-{
- g_free(t);
- g_object_unref(ep);
-}
-
-static void
-ep_class_init(GObjectClass *klass)
-{
- d(printf("EPopup class init %p '%s'\n", klass, g_type_name(((GObjectClass *)klass)->g_type_class.g_type)));
-
- klass->finalize = ep_finalise;
- ((EPopupClass *)klass)->target_free = ep_target_free;
-}
-
-static void
-ep_base_init(GObjectClass *klass)
-{
- e_dlist_init(&((EPopupClass *)klass)->factories);
-}
-
-/**
- * e_popup_get_type:
- *
- * Standard GObject type function.
- *
- * Return value: The EPopup object type.
- **/
-GType
-e_popup_get_type(void)
-{
- static GType type = 0;
-
- if (type == 0) {
- static const GTypeInfo info = {
- sizeof(EPopupClass),
- (GBaseInitFunc)ep_base_init, NULL,
- (GClassInitFunc)ep_class_init, NULL, NULL,
- sizeof(EPopup), 0,
- (GInstanceInitFunc)ep_init
- };
- ep_parent = g_type_class_ref(G_TYPE_OBJECT);
- type = g_type_register_static(G_TYPE_OBJECT, "EPopup", &info, 0);
- }
-
- return type;
-}
-
-/**
- * e_popup_new - Create an targetless popup menu manager.
- * @menuid: Unique ID for this menu.
- *
- * Create a targetless popup menu object. This can be used as a
- * helper for creating popup menu's with no target. Such popup menu's
- * wont be very pluggable.
- *
- * Return value: A new EPopup.
- **/
-EPopup *e_popup_new(const gchar *menuid)
-{
- EPopup *ep = g_object_new(e_popup_get_type(), NULL);
-
- e_popup_construct(ep, menuid);
-
- return ep;
-}
-
-/**
- * e_popup_construct:
- * @ep: An instantiated but uninitialised EPopup.
- * @menuid: The menu identifier.
- *
- * Construct the base popup instance with standard parameters.
- *
- * Return value: Returns @ep.
- **/
-EPopup *e_popup_construct(EPopup *ep, const gchar *menuid)
-{
- ep->menuid = g_strdup(menuid);
-
- return ep;
-}
-
-/**
- * e_popup_add_items:
- * @emp: An EPopup derived object.
- * @items: A list of EPopupItem's to add to the current popup menu.
- * @domain: Translation domain for translating labels.
- * @freefunc: A function which will be called when the items are no
- * longer needed.
- * @data: user-data passed to @freefunc, and passed to all activate
- * methods.
- *
- * Add new EPopupItems to the menus. Any with the same path
- * will override previously defined menu items, at menu building
- * time. This may be called any number of times before the menu is
- * built to create a complex heirarchy of menus.
- **/
-void
-e_popup_add_items(EPopup *emp, GSList *items, const gchar *domain, EPopupItemsFunc freefunc, gpointer data)
-{
- struct _menu_node *node;
-
- node = g_malloc0(sizeof(*node));
- node->menu = items;
- node->domain = g_strdup(domain);
- node->freefunc = freefunc;
- node->data = data;
- node->popup = emp;
-
- e_dlist_addtail(&emp->priv->menus, (EDListNode *)node);
-}
-
-static void
-ep_add_static_items(EPopup *emp)
-{
- struct _EPopupFactory *f;
- EPopupClass *klass = (EPopupClass *)G_OBJECT_GET_CLASS(emp);
-
- if (emp->menuid == NULL || emp->target == NULL)
- return;
-
- /* setup the menu itself */
- f = (struct _EPopupFactory *)klass->factories.head;
- while (f->next) {
- if (f->menuid == NULL
- || !strcmp(f->menuid, emp->menuid)) {
- f->factory(emp, f->factory_data);
- }
- f = f->next;
- }
-}
-
-static gint
-ep_cmp(gconstpointer ap, gconstpointer bp)
-{
- struct _item_node *a = *((gpointer *)ap);
- struct _item_node *b = *((gpointer *)bp);
-
- return strcmp(a->item->path, b->item->path);
-}
-
-static void
-ep_activate(GtkWidget *w, struct _item_node *inode)
-{
- EPopupItem *item = inode->item;
- guint32 type = item->type & E_POPUP_TYPE_MASK;
-
- /* this is a bit hackish, use the item->type to transmit the
- active state, presumes we can write to this memory ... The
- alternative is the EMenu idea of different callbacks, but
- thats painful for breaking type-safety on callbacks */
-
- if (type == E_POPUP_TOGGLE || type == E_POPUP_RADIO) {
- if (gtk_check_menu_item_get_active((GtkCheckMenuItem *)w))
- item->type |= E_POPUP_ACTIVE;
- else
- item->type &= ~E_POPUP_ACTIVE;
- }
-
- item->activate(inode->menu->popup, item, inode->menu->data);
-}
-
-static void
-ep_prune_tree(EDList *head)
-{
- struct _item_node *inode, *nnode;
-
- /* need to do two scans, first to find out if the subtree's
- * are empty, then to remove any unecessary bars which may
- * become unecessary after the first scan */
-
- inode = (struct _item_node *)head->head;
- nnode = inode->next;
- while (nnode) {
- struct _EPopupItem *item = inode->item;
-
- ep_prune_tree(&inode->children);
-
- if ((item->type & E_POPUP_TYPE_MASK) == E_POPUP_SUBMENU) {
- if (e_dlist_empty(&inode->children))
- e_dlist_remove((EDListNode *)inode);
- }
-
- inode = nnode;
- nnode = nnode->next;
- }
-
- inode = (struct _item_node *)head->head;
- nnode = inode->next;
- while (nnode) {
- struct _EPopupItem *item = inode->item;
-
- if ((item->type & E_POPUP_TYPE_MASK) == E_POPUP_BAR) {
- if (inode->prev->prev == NULL
- || nnode->next == NULL
- || (nnode->item->type & E_POPUP_TYPE_MASK) == E_POPUP_BAR)
- e_dlist_remove((EDListNode *)inode);
- }
-
- inode = nnode;
- nnode = nnode->next;
- }
-}
-
-static GtkMenu *
-ep_build_tree(struct _item_node *inode, guint32 mask)
-{
- struct _item_node *nnode;
- GtkMenu *topmenu;
- GHashTable *group_hash = g_hash_table_new(g_str_hash, g_str_equal);
-
- topmenu = (GtkMenu *)gtk_menu_new();
-
- nnode = inode->next;
- while (nnode) {
- GtkWidget *label;
- struct _EPopupItem *item = inode->item;
- GtkMenuItem *menuitem;
-
- switch (item->type & E_POPUP_TYPE_MASK) {
- case E_POPUP_ITEM:
- if (item->image) {
- GtkWidget *image;
-
- image = gtk_image_new_from_icon_name (
- (gchar *) item->image, GTK_ICON_SIZE_MENU);
- gtk_widget_show(image);
- menuitem = (GtkMenuItem *)gtk_image_menu_item_new();
- gtk_image_menu_item_set_image((GtkImageMenuItem *)menuitem, image);
- } else {
- menuitem = (GtkMenuItem *)gtk_menu_item_new();
- }
- break;
- case E_POPUP_TOGGLE:
- menuitem = (GtkMenuItem *)gtk_check_menu_item_new();
- if (item->type & E_POPUP_INCONSISTENT)
- gtk_check_menu_item_set_inconsistent (GTK_CHECK_MENU_ITEM (menuitem), TRUE);
- else
- gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (menuitem), item->type & E_POPUP_ACTIVE);
-
- if (item->image)
- gtk_widget_show (item->image);
- break;
- case E_POPUP_RADIO: {
- gchar *ppath = inode->parent?inode->parent->item->path:NULL;
-
- menuitem = (GtkMenuItem *)gtk_radio_menu_item_new(g_hash_table_lookup(group_hash, ppath));
- g_hash_table_insert(group_hash, ppath, gtk_radio_menu_item_get_group((GtkRadioMenuItem *)menuitem));
- gtk_check_menu_item_set_active((GtkCheckMenuItem *)menuitem, item->type & E_POPUP_ACTIVE);
- break; }
- case E_POPUP_IMAGE:
- menuitem = (GtkMenuItem *)gtk_image_menu_item_new();
- gtk_image_menu_item_set_image((GtkImageMenuItem *)menuitem, item->image);
- break;
- case E_POPUP_SUBMENU: {
- GtkMenu *submenu = ep_build_tree((struct _item_node *)inode->children.head, mask);
-
- menuitem = (GtkMenuItem *)gtk_menu_item_new();
- gtk_menu_item_set_submenu(menuitem, (GtkWidget *)submenu);
- break; }
- case E_POPUP_BAR:
- menuitem = (GtkMenuItem *)gtk_separator_menu_item_new();
- break;
- default:
- continue;
- }
-
- if (item->label) {
- label = gtk_label_new_with_mnemonic(dgettext(inode->menu->domain, item->label));
- gtk_misc_set_alignment((GtkMisc *)label, 0.0, 0.5);
- gtk_widget_show(label);
- if (item->image && (item->type & E_POPUP_TYPE_MASK) == E_POPUP_TOGGLE) {
- GtkWidget *hbox = gtk_hbox_new (FALSE, 4);
-
- gtk_box_pack_start (GTK_BOX (hbox), item->image, FALSE, FALSE, 0);
- gtk_box_pack_start (GTK_BOX (hbox), label, TRUE, TRUE, 0);
- gtk_widget_show (hbox);
- gtk_container_add (GTK_CONTAINER (menuitem), hbox);
- } else
- gtk_container_add((GtkContainer *)menuitem, label);
- } else if (item->image && (item->type & E_POPUP_TYPE_MASK) == E_POPUP_TOGGLE) {
- gtk_container_add (GTK_CONTAINER (menuitem), item->image);
- }
-
- if (item->activate)
- g_signal_connect(menuitem, "activate", G_CALLBACK(ep_activate), inode);
-
- gtk_menu_shell_append((GtkMenuShell *)topmenu, (GtkWidget *)menuitem);
-
- if (item->enable & mask)
- gtk_widget_set_sensitive((GtkWidget *)menuitem, FALSE);
-
- gtk_widget_show((GtkWidget *)menuitem);
-
- inode = nnode;
- nnode = nnode->next;
- }
-
- g_hash_table_destroy(group_hash);
-
- return topmenu;
-}
-
-/**
- * e_popup_create:
- * @emp: An EPopup derived object.
- * @target: popup target, if set, then factories will be invoked.
- * This is then owned by the menu.
- * @mask: If supplied, overrides the target specified mask or provides
- * a mask if no target is supplied. Used to enable or show menu
- * items.
- *
- * All of the menu items registered on @emp are sorted by path, and
- * then converted into a menu heirarchy.
- *
- *
- * Return value: A GtkMenu which can be popped up when ready.
- **/
-GtkMenu *
-e_popup_create_menu(EPopup *emp, EPopupTarget *target, guint32 mask)
-{
- struct _EPopupPrivate *p = emp->priv;
- struct _menu_node *mnode, *nnode;
- GPtrArray *items = g_ptr_array_new();
- GSList *l;
- GString *ppath = g_string_new("");
- GHashTable *tree_hash = g_hash_table_new(g_str_hash, g_str_equal);
- EDList head = E_DLIST_INITIALISER(head);
- gint i;
-
- emp->target = target;
- ep_add_static_items(emp);
-
- if (target && mask == 0)
- mask = target->mask;
-
- /* Note: This code vastly simplifies memory management by
- * keeping a linked list of all temporary tree nodes on the
- * menu's tree until the epopup is destroyed */
-
- /* FIXME: need to override old ones with new names */
- mnode = (struct _menu_node *)p->menus.head;
- nnode = mnode->next;
- while (nnode) {
- for (l=mnode->menu; l; l = l->next) {
- struct _item_node *inode;
- struct _EPopupItem *item = l->data;
-
- /* we calculate bar/submenu visibility based on calculated set */
- if (item->visible) {
- if ((item->type & E_POPUP_TYPE_MASK) != E_POPUP_BAR
- && (item->type & E_POPUP_TYPE_MASK) != E_POPUP_SUBMENU
- && item->visible & mask) {
- d(printf("%s not visible\n", item->path));
- continue;
- }
- }
-
- inode = g_malloc0(sizeof(*inode));
- inode->item = l->data;
- inode->menu = mnode;
- e_dlist_init(&inode->children);
- inode->link = mnode->items;
- mnode->items = inode;
-
- g_ptr_array_add(items, inode);
- }
- mnode = nnode;
- nnode = nnode->next;
- }
-
- /* this makes building the tree in the right order easier */
- qsort(items->pdata, items->len, sizeof(items->pdata[0]), ep_cmp);
-
- /* create tree structure */
- for (i=0;i<items->len;i++) {
- struct _item_node *inode = items->pdata[i], *pnode;
- struct _item_node *nextnode = (i + 1 < items->len) ? items->pdata[i+1] : NULL;
- struct _EPopupItem *item = inode->item;
- const gchar *tmp;
-
- if (nextnode && !strcmp (nextnode->item->path, item->path)) {
- d(printf ("skipping item %s\n", item->path));
- continue;
- }
-
- g_string_truncate(ppath, 0);
- tmp = strrchr(item->path, '/');
- if (tmp) {
- g_string_append_len(ppath, item->path, tmp-item->path);
- pnode = g_hash_table_lookup(tree_hash, ppath->str);
- if (pnode == NULL) {
- g_warning("No parent defined for node '%s'", item->path);
- e_dlist_addtail(&head, (EDListNode *)inode);
- } else {
- e_dlist_addtail(&pnode->children, (EDListNode *)inode);
- inode->parent = pnode;
- }
- } else {
- e_dlist_addtail(&head, (EDListNode *)inode);
- }
-
- if ((item->type & E_POPUP_TYPE_MASK) == E_POPUP_SUBMENU)
- g_hash_table_insert(tree_hash, item->path, inode);
- }
-
- g_string_free(ppath, TRUE);
- g_ptr_array_free(items, TRUE);
- g_hash_table_destroy(tree_hash);
-
- /* prune unnecessary items */
- ep_prune_tree(&head);
-
- /* & build it */
- return ep_build_tree((struct _item_node *)head.head, mask);
-}
-
-static void
-ep_popup_done(GtkWidget *w, EPopup *emp)
-{
- gtk_widget_destroy(w);
- if (emp->target) {
- e_popup_target_free(emp, emp->target);
- emp->target = NULL;
- }
- g_object_unref(emp);
-}
-
-/**
- * e_popup_create_menu_once:
- * @emp: EPopup, once the menu is shown, this cannot be
- * considered a valid pointer.
- * @target: If set, the target of the selection. Static menu
- * items will be added. The target will be freed once complete.
- * @mask: Enable/disable and visibility mask.
- *
- * Like popup_create_menu, but automatically sets up the menu
- * so that it is destroyed once a selection takes place, and
- * the EPopup is unreffed. This is the normal entry point as it
- * automates most memory management for popup menus.
- *
- * Return value: A menu, to popup.
- **/
-GtkMenu *
-e_popup_create_menu_once(EPopup *emp, EPopupTarget *target, guint32 mask)
-{
- GtkMenu *menu;
-
- menu = e_popup_create_menu(emp, target, mask);
-
- g_signal_connect(menu, "selection_done", G_CALLBACK(ep_popup_done), emp);
-
- return menu;
-}
-
-/* ********************************************************************** */
-
-/**
- * e_popup_class_add_factory:
- * @klass: The EPopup derived class which you're interested in.
- * @menuid: The identifier of the menu you're interested in, or NULL
- * to be called for all menus on this class.
- * @func: The factory called when the menu @menuid is being created.
- * @data: User-data for the factory callback.
- *
- * This is a class-static method used to register factory callbacks
- * against specific menu's.
- *
- * The factory method will be invoked before the menu is created.
- * This way, the factory may add any additional menu items it wishes
- * based on the context supplied in the @target.
- *
- * Return value: A handle to the factory which can be used to remove
- * it later.
- **/
-EPopupFactory *
-e_popup_class_add_factory(EPopupClass *klass, const gchar *menuid, EPopupFactoryFunc func, gpointer data)
-{
- struct _EPopupFactory *f = g_malloc0(sizeof(*f));
-
- f->menuid = g_strdup(menuid);
- f->factory = func;
- f->factory_data = data;
- e_dlist_addtail(&klass->factories, (EDListNode *)f);
-
- return f;
-}
-
-/**
- * e_popup_class_remove_factory:
- * @klass: The EPopup derived class.
- * @f: The factory handle returned by e_popup_class_add_factory().
- *
- * Remove a popup menu factory. If it has not been added, or it has
- * already been removed, then the result is undefined (i.e. it will
- * crash).
- *
- * Generally factories are static for the life of the application, and
- * so do not need to be removed.
- **/
-void
-e_popup_class_remove_factory(EPopupClass *klass, EPopupFactory *f)
-{
- e_dlist_remove((EDListNode *)f);
- g_free(f->menuid);
- g_free(f);
-}
-
-/**
- * e_popup_target_new:
- * @ep: An EPopup derived object.
- * @type: type, defined by the implementing class.
- * @size: The size of memory to allocate for the target. It must be
- * equal or greater than the size of EPopupTarget.
- *
- * Allocate a new popup target suitable for this popup type.
- **/
-gpointer e_popup_target_new(EPopup *ep, gint type, gsize size)
-{
- EPopupTarget *t;
-
- if (size < sizeof(EPopupTarget)) {
- g_warning ("Size is less than the size of EPopupTarget\n");
- size = sizeof(EPopupTarget);
- }
-
- t = g_malloc0(size);
- t->popup = ep;
- g_object_ref(ep);
- t->type = type;
-
- return t;
-}
-
-/**
- * e_popup_target_free:
- * @ep: An EPopup derived object.
- * @o: The target, previously allocated by e_popup_target_new().
- *
- * Free the target against @ep. Note that targets are automatically
- * freed if they are passed to the menu creation functions, so this is
- * only required if you are using the target for other purposes.
- **/
-void
-e_popup_target_free(EPopup *ep, gpointer o)
-{
- EPopupTarget *t = o;
-
- ((EPopupClass *)G_OBJECT_GET_CLASS(ep))->target_free(ep, t);
-}
-
-/* ********************************************************************** */
-
-/* Popup menu plugin handler */
-
-/*
-<e-plugin
- class="org.gnome.mail.plugin.popup:1.0"
- id="org.gnome.mail.plugin.popup.item:1.0"
- type="shlib"
- location="/opt/gnome2/lib/camel/1.0/libcamelimap.so"
- name="imap"
- description="IMAP4 and IMAP4v1 mail store">
- <hook class="org.gnome.mail.popupMenu:1.0"
- handler="HandlePopup">
- <menu id="any" target="select" factory="funcspec"?>
- <item
- type="item|toggle|radio|image|submenu|bar"
- active
- path="foo/bar"
- label="label"
- icon="foo"
- visible="select_one"
- activate="ep_view_emacs"/> *
- </menu>
- </extension>
-
-*/
-
-static gpointer emph_parent_class;
-#define emph ((EPopupHook *)eph)
-
-/* must have 1:1 correspondence with e-popup types in order */
-static const EPluginHookTargetKey emph_item_types[] = {
- { "item", E_POPUP_ITEM },
- { "toggle", E_POPUP_TOGGLE },
- { "radio", E_POPUP_RADIO },
- { "image", E_POPUP_IMAGE },
- { "submenu", E_POPUP_SUBMENU },
- { "bar", E_POPUP_BAR },
- { NULL }
-};
-
-static void
-emph_popup_activate(EPopup *ep, EPopupItem *item, gpointer data)
-{
- EPopupHook *hook = data;
-
- e_plugin_invoke(hook->hook.plugin, (gchar *)item->user_data, ep->target);
-}
-
-static void
-emph_popup_factory(EPopup *emp, gpointer data)
-{
- struct _EPopupHookMenu *menu = data;
-
- d(printf("popup factory called %s mask %08x\n", menu->id?menu->id:"all menus", emp->target->mask));
-
- /* If we're disabled, then don't add the menu's. */
- if (emp->target->type != menu->target_type
- || !menu->hook->hook.plugin->enabled)
- return;
-
- if (menu->items)
- e_popup_add_items(emp, menu->items, menu->hook->hook.plugin->domain, NULL, menu->hook);
-
- if (menu->factory)
- e_plugin_invoke(menu->hook->hook.plugin, menu->factory, emp->target);
-}
-
-static void
-emph_free_item(struct _EPopupItem *item)
-{
- g_free(item->path);
- g_free(item->label);
- g_free(item->image);
- g_free(item->user_data);
- g_free(item);
-}
-
-static void
-emph_free_menu(struct _EPopupHookMenu *menu)
-{
- g_slist_foreach(menu->items, (GFunc)emph_free_item, NULL);
- g_slist_free(menu->items);
-
- g_free(menu->factory);
- g_free(menu->id);
- g_free(menu);
-}
-
-static struct _EPopupItem *
-emph_construct_item(EPluginHook *eph, EPopupHookMenu *menu, xmlNodePtr root, EPopupHookTargetMap *map)
-{
- struct _EPopupItem *item;
-
- d(printf(" loading menu item\n"));
- item = g_malloc0(sizeof(*item));
- if ((item->type = e_plugin_hook_id(root, emph_item_types, "type")) == -1
- || item->type == E_POPUP_IMAGE)
- goto error;
- item->path = e_plugin_xml_prop(root, "path");
- item->label = e_plugin_xml_prop_domain(root, "label", eph->plugin->domain);
- item->image = e_plugin_xml_prop(root, "icon");
- item->visible = e_plugin_hook_mask(root, map->mask_bits, "visible");
- item->enable = e_plugin_hook_mask(root, map->mask_bits, "enable");
- item->user_data = e_plugin_xml_prop(root, "activate");
-
- item->activate = emph_popup_activate;
-
- if (item->user_data == NULL)
- goto error;
-
- d(printf(" path=%s\n", item->path));
- d(printf(" label=%s\n", item->label));
-
- return item;
-error:
- d(printf("error!\n"));
- emph_free_item(item);
- return NULL;
-}
-
-static struct _EPopupHookMenu *
-emph_construct_menu(EPluginHook *eph, xmlNodePtr root)
-{
- struct _EPopupHookMenu *menu;
- xmlNodePtr node;
- EPopupHookTargetMap *map;
- EPopupHookClass *klass = (EPopupHookClass *)G_OBJECT_GET_CLASS(eph);
- gchar *tmp;
-
- d(printf(" loading menu\n"));
- menu = g_malloc0(sizeof(*menu));
- menu->hook = (EPopupHook *)eph;
-
- tmp = (gchar *)xmlGetProp(root, (const guchar *)"target");
- if (tmp == NULL)
- goto error;
- map = g_hash_table_lookup(klass->target_map, tmp);
- xmlFree(tmp);
- if (map == NULL)
- goto error;
-
- menu->target_type = map->id;
- menu->id = e_plugin_xml_prop(root, "id");
- if (menu->id == NULL) {
- g_warning("Plugin '%s' missing 'id' field in popup for '%s'\n", eph->plugin->name,
- ((EPluginHookClass *)G_OBJECT_GET_CLASS(eph))->id);
- goto error;
- }
-
- menu->factory = e_plugin_xml_prop(root, "factory");
-
- node = root->children;
- while (node) {
- if (0 == strcmp((gchar *)node->name, "item")) {
- struct _EPopupItem *item;
-
- item = emph_construct_item(eph, menu, node, map);
- if (item)
- menu->items = g_slist_append(menu->items, item);
- }
- node = node->next;
- }
-
- return menu;
-error:
- emph_free_menu(menu);
- return NULL;
-}
-
-static gint
-emph_construct(EPluginHook *eph, EPlugin *ep, xmlNodePtr root)
-{
- xmlNodePtr node;
- EPopupClass *klass;
-
- d(printf("loading popup hook\n"));
-
- if (((EPluginHookClass *)emph_parent_class)->construct(eph, ep, root) == -1)
- return -1;
-
- klass = ((EPopupHookClass *)G_OBJECT_GET_CLASS(eph))->popup_class;
-
- node = root->children;
- while (node) {
- if (strcmp((gchar *)node->name, "menu") == 0) {
- struct _EPopupHookMenu *menu;
-
- menu = emph_construct_menu(eph, node);
- if (menu) {
- e_popup_class_add_factory(klass, menu->id, emph_popup_factory, menu);
- emph->menus = g_slist_append(emph->menus, menu);
- }
- }
- node = node->next;
- }
-
- eph->plugin = ep;
-
- return 0;
-}
-
-static void
-emph_finalise(GObject *o)
-{
- EPluginHook *eph = (EPluginHook *)o;
-
- g_slist_foreach(emph->menus, (GFunc)emph_free_menu, NULL);
- g_slist_free(emph->menus);
-
- ((GObjectClass *)emph_parent_class)->finalize(o);
-}
-
-static void
-emph_class_init(EPluginHookClass *klass)
-{
- ((GObjectClass *)klass)->finalize = emph_finalise;
- klass->construct = emph_construct;
-
- /* this is actually an abstract implementation but list it anyway */
- klass->id = "org.gnome.evolution.popup:1.0";
-
- d(printf("EPopupHook: init class %p '%s'\n", klass, g_type_name(((GObjectClass *)klass)->g_type_class.g_type)));
-
- ((EPopupHookClass *)klass)->target_map = g_hash_table_new(g_str_hash, g_str_equal);
- ((EPopupHookClass *)klass)->popup_class = g_type_class_ref(e_popup_get_type());
-}
-
-/**
- * e_popup_hook_get_type:
- *
- * Standard GObject function to get the object type. Used to subclass
- * EPopupHook.
- *
- * Return value: The type of the popup hook class.
- **/
-GType
-e_popup_hook_get_type(void)
-{
- static GType type = 0;
-
- if (!type) {
- static const GTypeInfo info = {
- sizeof(EPopupHookClass), NULL, NULL, (GClassInitFunc) emph_class_init, NULL, NULL,
- sizeof(EPopupHook), 0, (GInstanceInitFunc) NULL,
- };
-
- emph_parent_class = g_type_class_ref(e_plugin_hook_get_type());
- type = g_type_register_static(e_plugin_hook_get_type(), "EPopupHook", &info, 0);
- }
-
- return type;
-}
-
-/**
- * e_popup_hook_class_add_target_map:
- * @klass: The derived EPopupHook class.
- * @map: A map used to describe a single EPopupTarget type for this
- * class.
- *
- * Add a target map to a concrete derived class of EPopup. The target
- * map enumerates a single target type and the enable mask bit names,
- * so that the type can be loaded automatically by the EPopup class.
- **/
-void e_popup_hook_class_add_target_map(EPopupHookClass *klass, const EPopupHookTargetMap *map)
-{
- g_hash_table_insert(klass->target_map, (gpointer)map->type, (gpointer)map);
-}