diff options
Diffstat (limited to 'e-util/e-popup.c')
-rw-r--r-- | e-util/e-popup.c | 840 |
1 files changed, 0 insertions, 840 deletions
diff --git a/e-util/e-popup.c b/e-util/e-popup.c deleted file mode 100644 index 31c3bd0866..0000000000 --- a/e-util/e-popup.c +++ /dev/null @@ -1,840 +0,0 @@ -/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ -/* - * Authors: Michael Zucchi <notzed@ximian.com> - * - * Copyright 2004 Ximian, Inc. (www.ximian.com) - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * 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 General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Street #330, Boston, MA 02111-1307, USA. - * - */ - -#ifdef HAVE_CONFIG_H -#include <config.h> -#endif - -#include <string.h> -#include <stdlib.h> - -#include <glib.h> - -#include <gtk/gtkmenu.h> -#include <gtk/gtkmenuitem.h> -#include <gtk/gtkimagemenuitem.h> -#include <gtk/gtkcheckmenuitem.h> -#include <gtk/gtkradiomenuitem.h> -#include <gtk/gtkseparatormenuitem.h> -#include <gtk/gtklabel.h> -#include <gtk/gtkimage.h> - -#include "e-popup.h" - -#include <e-util/e-icon-factory.h> - -#include <libgnome/gnome-i18n.h> - -struct _EPopupFactory { - struct _EPopupFactory *next, *prev; - - char *menuid; - EPopupFactoryFunc factory; - void *factory_data; -}; - -/* Used for the "activate" signal callback data to re-map to the api */ -struct _item_node { - struct _item_node *next; - - EPopupItem *item; - struct _menu_node *menu; -}; - -/* Stores all the items added */ -struct _menu_node { - struct _menu_node *next, *prev; - - EPopup *popup; - - GSList *menu; - EPopupItemsFunc freefunc; - void *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); - - /* free item activate callback data */ - inode = mnode->items; - while (inode) { - struct _item_node *nnode = inode->next; - - 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) -{ - 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 char *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 char *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. - * @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, EPopupItemsFunc freefunc, void *data) -{ - struct _menu_node *node; - - node = g_malloc0(sizeof(*node)); - node->menu = items; - 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 int -ep_cmp(const void *ap, const void *bp) -{ - struct _item_node *a = *((void **)ap); - struct _item_node *b = *((void **)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); -} - -/** - * 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(""); - GtkMenu *topmenu; - GHashTable *menu_hash = g_hash_table_new(g_str_hash, g_str_equal), - *group_hash = g_hash_table_new(g_str_hash, g_str_equal); - int i; - - emp->target = target; - ep_add_static_items(emp); - - if (target && mask == 0) - mask = target->mask; - - /* 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 = g_malloc0(sizeof(*inode)); - - inode->item = l->data; - inode->menu = mnode; - inode->next = mnode->items; - mnode->items = inode; - - g_ptr_array_add(items, inode); - } - mnode = nnode; - nnode = nnode->next; - } - - qsort(items->pdata, items->len, sizeof(items->pdata[0]), ep_cmp); - - topmenu = (GtkMenu *)gtk_menu_new(); - for (i=0;i<items->len;i++) { - GtkWidget *label; - struct _item_node *inode = items->pdata[i]; - struct _EPopupItem *item = inode->item; - GtkMenu *thismenu; - GtkMenuItem *menuitem; - char *tmp; - - /* for bar's, the mask is exclusive or */ - if (item->visible) { - if ((item->type & E_POPUP_TYPE_MASK) == E_POPUP_BAR) { - if ((item->visible & mask) == item->visible) - continue; - } else if (item->visible & mask) - continue; - } - - g_string_truncate(ppath, 0); - tmp = strrchr(item->path, '/'); - if (tmp) { - g_string_append_len(ppath, item->path, tmp-item->path); - thismenu = g_hash_table_lookup(menu_hash, ppath->str); - g_assert(thismenu != NULL); - } else { - thismenu = topmenu; - } - - switch (item->type & E_POPUP_TYPE_MASK) { - case E_POPUP_ITEM: - if (item->image) { - GdkPixbuf *pixbuf; - GtkWidget *image; - - /* work-around e-icon-factory not doing GTK_STOCK stuff */ - if (strncmp((char *)item->image, "gtk-", 4) == 0) { - image = gtk_image_new_from_stock((char *)item->image, GTK_ICON_SIZE_MENU); - } else { - pixbuf = e_icon_factory_get_icon((char *)item->image, E_ICON_SIZE_MENU); - image = gtk_image_new_from_pixbuf(pixbuf); - g_object_unref(pixbuf); - } - - 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(); - gtk_check_menu_item_set_active((GtkCheckMenuItem *)menuitem, item->type & E_POPUP_ACTIVE); - break; - case E_POPUP_RADIO: - menuitem = (GtkMenuItem *)gtk_radio_menu_item_new(g_hash_table_lookup(group_hash, ppath->str)); - /* FIXME: need to strdup the string */ - g_hash_table_insert(group_hash, ppath->str, 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 = (GtkMenu *)gtk_menu_new(); - - g_hash_table_insert(menu_hash, item->path, submenu); - menuitem = (GtkMenuItem *)gtk_menu_item_new(); - gtk_menu_item_set_submenu(menuitem, (GtkWidget *)submenu); - break; } - case E_POPUP_BAR: - /* TODO: double-bar, end-bar stuff? */ - menuitem = (GtkMenuItem *)gtk_separator_menu_item_new(); - break; - default: - continue; - } - - if (item->label) { - label = gtk_label_new_with_mnemonic(_(item->label)); - gtk_misc_set_alignment((GtkMisc *)label, 0.0, 0.5); - gtk_widget_show(label); - gtk_container_add((GtkContainer *)menuitem, label); - } - - if (item->activate) - g_signal_connect(menuitem, "activate", G_CALLBACK(ep_activate), inode); - - gtk_menu_shell_append((GtkMenuShell *)thismenu, (GtkWidget *)menuitem); - - if (item->enable & mask) - gtk_widget_set_sensitive((GtkWidget *)menuitem, FALSE); - - gtk_widget_show((GtkWidget *)menuitem); - } - - g_string_free(ppath, TRUE); - g_ptr_array_free(items, TRUE); - g_hash_table_destroy(menu_hash); - g_hash_table_destroy(group_hash); - - return topmenu; -} - -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 char *menuid, EPopupFactoryFunc func, void *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. - **/ -void *e_popup_target_new(EPopup *ep, int type, size_t size) -{ - EPopupTarget *t; - - g_assert(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, void *o) -{ - EPopupTarget *t = o; - - ((EPopupClass *)G_OBJECT_GET_CLASS(ep))->target_free(ep, t); -} - -/* ********************************************************************** */ - -/* Popup menu plugin handler */ - -/* -<e-plugin - class="com.ximian.mail.plugin.popup:1.0" - id="com.ximian.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="com.ximian.mail.popupMenu:1.0" - handler="HandlePopup"> - <menu id="any" target="select"> - <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 void *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 }, - { 0 } -}; - -static void -emph_popup_activate(EPopup *ep, EPopupItem *item, void *data) -{ - EPopupHook *hook = data; - - e_plugin_invoke(hook->hook.plugin, (char *)item->user_data, ep->target); -} - -static void -emph_popup_factory(EPopup *emp, void *data) -{ - struct _EPopupHookMenu *menu = data; - - 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, NULL, menu->hook); -} - -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->id); - g_free(menu); -} - -static struct _EPopupItem * -emph_construct_item(EPluginHook *eph, EPopupHookMenu *menu, xmlNodePtr root, EPopupHookTargetMap *map) -{ - struct _EPopupItem *item; - - 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; - - printf(" path=%s\n", item->path); - printf(" label=%s\n", item->label); - - return item; -error: - 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); - char *tmp; - - printf(" loading menu\n"); - menu = g_malloc0(sizeof(*menu)); - menu->hook = (EPopupHook *)eph; - - tmp = xmlGetProp(root, "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"); - node = root->children; - while (node) { - if (0 == strcmp(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 int -emph_construct(EPluginHook *eph, EPlugin *ep, xmlNodePtr root) -{ - xmlNodePtr node; - EPopupClass *klass; - - 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(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 = "com.ximian.evolution.popup:1.0"; - - 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, (void *)map->type, (void *)map); -} |