diff options
author | Matthew Barnes <mbarnes@redhat.com> | 2009-08-30 13:37:36 +0800 |
---|---|---|
committer | Matthew Barnes <mbarnes@redhat.com> | 2009-08-30 13:40:49 +0800 |
commit | cfb9c32b6657165e4d5e11aa7b47804f679a61f8 (patch) | |
tree | 1f9c8954df7a357b5dc20a13ac82bf31c1112083 /e-util | |
parent | fefeb30f58447f2fa7bcbee16dbe68a9333ce89d (diff) | |
parent | 0f7f4cfe38b3c4cd83efbe9922ae15c5aee00317 (diff) | |
download | gsoc2013-evolution-cfb9c32b6657165e4d5e11aa7b47804f679a61f8.tar gsoc2013-evolution-cfb9c32b6657165e4d5e11aa7b47804f679a61f8.tar.gz gsoc2013-evolution-cfb9c32b6657165e4d5e11aa7b47804f679a61f8.tar.bz2 gsoc2013-evolution-cfb9c32b6657165e4d5e11aa7b47804f679a61f8.tar.lz gsoc2013-evolution-cfb9c32b6657165e4d5e11aa7b47804f679a61f8.tar.xz gsoc2013-evolution-cfb9c32b6657165e4d5e11aa7b47804f679a61f8.tar.zst gsoc2013-evolution-cfb9c32b6657165e4d5e11aa7b47804f679a61f8.zip |
Merge commit 'origin/kill-bonobo'
Diffstat (limited to 'e-util')
38 files changed, 4193 insertions, 4336 deletions
diff --git a/e-util/Makefile.am b/e-util/Makefile.am index 35d254b4eb..e5c0886735 100644 --- a/e-util/Makefile.am +++ b/e-util/Makefile.am @@ -4,7 +4,6 @@ ecpsdir = $(privdatadir)/ecps ruledir = $(privdatadir) if OS_WIN32 -WIN32_BOOTSTRAP_LIBS = $(top_builddir)/win32/libemiscwidgets.la PLATFORM_SOURCES = e-win32-reloc.c endif @@ -39,11 +38,12 @@ AM_CPPFLAGS = \ privsolib_LTLIBRARIES = libeutil.la libeconduit.la eutilinclude_HEADERS = \ + e-account-utils.h \ e-bconf-map.h \ e-binding.h \ e-categories-config.h \ + e-charset.h \ e-config.h \ - e-corba-utils.h \ e-cursor.h \ e-datetime-format.h \ e-dialog-utils.h \ @@ -56,18 +56,18 @@ eutilinclude_HEADERS = \ e-icon-factory.h \ e-import.h \ e-logger.h \ - e-non-intrusive-error-dialog.h \ e-marshal.h \ - e-menu.h \ e-mktemp.h \ + e-module.h \ + e-non-intrusive-error-dialog.h \ e-print.h \ e-plugin.h \ e-plugin-ui.h \ - e-popup.h \ e-profile-event.h \ e-request.h \ e-signature.h \ e-signature-list.h \ + e-signature-utils.h \ e-bit-array.h \ e-sorter.h \ e-sorter-array.h \ @@ -75,16 +75,17 @@ eutilinclude_HEADERS = \ e-text-event-processor-types.h \ e-text-event-processor.h \ e-util.h \ - e-util-labels.h \ + e-unicode.h \ e-xml-utils.h libeutil_la_SOURCES = \ $(eutilinclude_HEADERS) \ + e-account-utils.c \ e-bconf-map.c \ e-binding.c \ e-categories-config.c \ + e-charset.c \ e-config.c \ - e-corba-utils.c \ e-cursor.c \ e-datetime-format.c \ e-dialog-utils.c \ @@ -97,25 +98,25 @@ libeutil_la_SOURCES = \ e-icon-factory.c \ e-import.c \ e-logger.c \ - e-non-intrusive-error-dialog.c \ e-marshal.c \ - e-menu.c \ e-mktemp.c \ - e-plugin.c \ + e-module.c \ + e-non-intrusive-error-dialog.c \ e-plugin-ui.c \ - e-popup.c \ + e-plugin.c \ e-print.c \ e-profile-event.c \ e-request.c \ e-signature.c \ e-signature-list.c \ + e-signature-utils.c \ e-bit-array.c \ e-sorter.c \ e-sorter-array.c \ e-text-event-processor-emacs-like.c \ e-text-event-processor.c \ e-util.c \ - e-util-labels.c \ + e-unicode.c \ e-util-private.h \ e-xml-utils.c \ gconf-bridge.c \ @@ -128,7 +129,6 @@ MARSHAL_GENERATED = e-marshal.c e-marshal.h libeutil_la_LDFLAGS = $(NO_UNDEFINED) libeutil_la_LIBADD = \ - $(WIN32_BOOTSTRAP_LIBS) \ $(ICONV_LIBS) \ $(E_UTIL_LIBS) \ $(GNOME_PILOT_LIBS) \ diff --git a/e-util/e-account-utils.c b/e-util/e-account-utils.c new file mode 100644 index 0000000000..5fdffd8be2 --- /dev/null +++ b/e-util/e-account-utils.c @@ -0,0 +1,96 @@ +/* + * 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/> + * + * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com) + */ + +#include "e-account-utils.h" + +#include <gconf/gconf-client.h> + +static EAccountList *global_account_list; + +EAccountList * +e_get_account_list (void) +{ + if (G_UNLIKELY (global_account_list == NULL)) { + GConfClient *client; + + client = gconf_client_get_default (); + global_account_list = e_account_list_new (client); + g_object_unref (client); + } + + g_return_val_if_fail (global_account_list != NULL, NULL); + + return global_account_list; +} + +EAccount * +e_get_default_account (void) +{ + EAccountList *account_list; + const EAccount *account; + + account_list = e_get_account_list (); + account = e_account_list_get_default (account_list); + + /* XXX EAccountList misuses const. */ + return (EAccount *) account; +} + +void +e_set_default_account (EAccount *account) +{ + EAccountList *account_list; + + g_return_if_fail (E_IS_ACCOUNT (account)); + + account_list = e_get_account_list (); + e_account_list_set_default (account_list, account); +} + +EAccount * +e_get_account_by_name (const gchar *name) +{ + EAccountList *account_list; + const EAccount *account; + e_account_find_t find; + + g_return_val_if_fail (name != NULL, NULL); + + find = E_ACCOUNT_FIND_NAME; + account_list = e_get_account_list (); + account = e_account_list_find (account_list, find, name); + + /* XXX EAccountList misuses const. */ + return (EAccount *) account; +} + +EAccount * +e_get_account_by_uid (const gchar *uid) +{ + EAccountList *account_list; + const EAccount *account; + e_account_find_t find; + + g_return_val_if_fail (uid != NULL, NULL); + + find = E_ACCOUNT_FIND_UID; + account_list = e_get_account_list (); + account = e_account_list_find (account_list, find, uid); + + /* XXX EAccountList misuses const. */ + return (EAccount *) account; +} diff --git a/e-util/e-corba-utils.c b/e-util/e-account-utils.h index 338b88efee..f2ae8fc5dc 100644 --- a/e-util/e-corba-utils.c +++ b/e-util/e-account-utils.h @@ -12,32 +12,24 @@ * 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: - * Ettore Perazzoli <ettore@ximian.com> - * * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com) - * */ -#ifdef HAVE_CONFIG_H -#include <config.h> -#endif +#ifndef E_ACCOUNT_UTILS_H +#define E_ACCOUNT_UTILS_H + +#include <glib.h> +#include <libedataserver/e-account.h> +#include <libedataserver/e-account-list.h> -#include "e-corba-utils.h" +G_BEGIN_DECLS - -const CORBA_char * -e_safe_corba_string (const gchar *s) -{ - if (s == NULL) - return (CORBA_char *) ""; +EAccountList * e_get_account_list (void); +EAccount * e_get_default_account (void); +void e_set_default_account (EAccount *account); +EAccount * e_get_account_by_name (const gchar *name); +EAccount * e_get_account_by_uid (const gchar *uid); - return s; -} +G_END_DECLS -CORBA_char * -e_safe_corba_string_dup (const gchar *s) -{ - return CORBA_string_dup (e_safe_corba_string (s)); -} +#endif /* E_ACCOUNT_UTILS_H */ diff --git a/e-util/e-charset.c b/e-util/e-charset.c new file mode 100644 index 0000000000..329f513ec7 --- /dev/null +++ b/e-util/e-charset.c @@ -0,0 +1,255 @@ +/* + * 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: + * + * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com) + * + */ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include "e-charset.h" + +#include <string.h> +#include <iconv.h> + +#include <glib/gi18n-lib.h> + +typedef enum { + E_CHARSET_UNKNOWN, + E_CHARSET_ARABIC, + E_CHARSET_BALTIC, + E_CHARSET_CENTRAL_EUROPEAN, + E_CHARSET_CHINESE, + E_CHARSET_CYRILLIC, + E_CHARSET_GREEK, + E_CHARSET_HEBREW, + E_CHARSET_JAPANESE, + E_CHARSET_KOREAN, + E_CHARSET_THAI, + E_CHARSET_TURKISH, + E_CHARSET_UNICODE, + E_CHARSET_WESTERN_EUROPEAN, + E_CHARSET_WESTERN_EUROPEAN_NEW +} ECharsetClass; + +static const gchar *classnames[] = { + N_("Unknown"), + N_("Arabic"), + N_("Baltic"), + N_("Central European"), + N_("Chinese"), + N_("Cyrillic"), + N_("Greek"), + N_("Hebrew"), + N_("Japanese"), + N_("Korean"), + N_("Thai"), + N_("Turkish"), + N_("Unicode"), + N_("Western European"), + N_("Western European, New"), +}; + +typedef struct { + const gchar *name; + ECharsetClass class; + const gchar *subclass; +} ECharset; + +/* This list is based on what other mailers/browsers support. There's + * not a lot of point in using, say, ISO-8859-3, if anything that can + * read that can read UTF8 too. + */ +/* To Translators: Character set "Logical Hebrew" */ +static ECharset charsets[] = { + { "ISO-8859-6", E_CHARSET_ARABIC, NULL }, + { "ISO-8859-13", E_CHARSET_BALTIC, NULL }, + { "ISO-8859-4", E_CHARSET_BALTIC, NULL }, + { "ISO-8859-2", E_CHARSET_CENTRAL_EUROPEAN, NULL }, + { "Big5", E_CHARSET_CHINESE, N_("Traditional") }, + { "BIG5HKSCS", E_CHARSET_CHINESE, N_("Traditional") }, + { "EUC-TW", E_CHARSET_CHINESE, N_("Traditional") }, + { "GB18030", E_CHARSET_CHINESE, N_("Simplified") }, + { "GB2312", E_CHARSET_CHINESE, N_("Simplified") }, + { "HZ", E_CHARSET_CHINESE, N_("Simplified") }, + { "ISO-2022-CN", E_CHARSET_CHINESE, N_("Simplified") }, + { "KOI8-R", E_CHARSET_CYRILLIC, NULL }, + { "Windows-1251", E_CHARSET_CYRILLIC, NULL }, + { "KOI8-U", E_CHARSET_CYRILLIC, N_("Ukrainian") }, + { "ISO-8859-5", E_CHARSET_CYRILLIC, NULL }, + { "ISO-8859-7", E_CHARSET_GREEK, NULL }, + { "ISO-8859-8", E_CHARSET_HEBREW, N_("Visual") }, + { "ISO-2022-JP", E_CHARSET_JAPANESE, NULL }, + { "EUC-JP", E_CHARSET_JAPANESE, NULL }, + { "Shift_JIS", E_CHARSET_JAPANESE, NULL }, + { "EUC-KR", E_CHARSET_KOREAN, NULL }, + { "TIS-620", E_CHARSET_THAI, NULL }, + { "ISO-8859-9", E_CHARSET_TURKISH, NULL }, + { "UTF-8", E_CHARSET_UNICODE, NULL }, + { "UTF-7", E_CHARSET_UNICODE, NULL }, + { "ISO-8859-1", E_CHARSET_WESTERN_EUROPEAN, NULL }, + { "ISO-8859-15", E_CHARSET_WESTERN_EUROPEAN_NEW, NULL }, +}; + +/** + * e_charset_add_radio_actions: + * @action_group: a #GtkActionGroup + * @action_prefix: a prefix for action names, or %NULL + * @default_charset: the default character set, or %NULL to use the + * locale character set + * @callback: a callback function for actions in the group, or %NULL + * @user_data: user data to be passed to @callback, or %NULL + * + * Adds a set of #GtkRadioActions for available character sets to + * @action_group. The @default_charset (or locale character set if + * @default_charset is %NULL) will be added first, and selected by + * default (except that ISO-8859-1 will always be used instead of + * US-ASCII). Any other character sets of the same language class as + * the default will be added next, followed by the remaining character + * sets. + **/ +GSList * +e_charset_add_radio_actions (GtkActionGroup *action_group, + const gchar *action_prefix, + const gchar *default_charset, + GCallback callback, + gpointer user_data) +{ + GtkRadioAction *action = NULL; + GSList *group = NULL; + const gchar *locale_charset; + gint def, ii; + + g_return_val_if_fail (GTK_IS_ACTION_GROUP (action_group), NULL); + + if (action_prefix == NULL) + action_prefix = ""; + + g_get_charset (&locale_charset); + if (!g_ascii_strcasecmp (locale_charset, "US-ASCII")) + locale_charset = "ISO-8859-1"; + + if (default_charset == NULL) + default_charset = locale_charset; + for (def = 0; def < G_N_ELEMENTS (charsets); def++) + if (!g_ascii_strcasecmp (charsets[def].name, default_charset)) + break; + + for (ii = 0; ii < G_N_ELEMENTS (charsets); ii++) { + const gchar *charset_name; + gchar *action_name; + gchar *escaped_name; + gchar *charset_label; + gchar **str_array; + + charset_name = charsets[ii].name; + action_name = g_strconcat (action_prefix, charset_name, NULL); + + /* Escape underlines in the character set name so + * they're not treated as GtkLabel mnemonics. */ + str_array = g_strsplit (charset_name, "_", -1); + escaped_name = g_strjoinv ("__", str_array); + g_strfreev (str_array); + + if (charsets[ii].subclass != NULL) + charset_label = g_strdup_printf ( + "%s, %s (%s)", + gettext (classnames[charsets[ii].class]), + gettext (charsets[ii].subclass), + escaped_name); + else if (charsets[ii].class != E_CHARSET_UNKNOWN) + charset_label = g_strdup_printf ( + "%s (%s)", + gettext (classnames[charsets[ii].class]), + escaped_name); + else + charset_label = g_strdup (escaped_name); + + /* XXX Add a tooltip! */ + action = gtk_radio_action_new ( + action_name, charset_label, NULL, NULL, ii); + + /* Character set name is static so no need to free it. */ + g_object_set_data ( + G_OBJECT (action), "charset", + (gpointer) charset_name); + + gtk_radio_action_set_group (action, group); + group = gtk_radio_action_get_group (action); + + if (callback != NULL) + g_signal_connect ( + action, "changed", callback, user_data); + + gtk_action_group_add_action ( + action_group, GTK_ACTION (action)); + + g_object_unref (action); + + g_free (action_name); + g_free (escaped_name); + g_free (charset_label); + } + + if (def == G_N_ELEMENTS (charsets)) { + const gchar *charset_name; + gchar *action_name; + gchar *charset_label; + gchar **str_array; + + charset_name = default_charset; + action_name = g_strconcat (action_prefix, charset_name, NULL); + + /* Escape underlines in the character set name so + * they're not treated as GtkLabel mnemonics. */ + str_array = g_strsplit (charset_name, "_", -1); + charset_label = g_strjoinv ("__", str_array); + g_strfreev (str_array); + + /* XXX Add a tooltip! */ + action = gtk_radio_action_new ( + action_name, charset_label, NULL, NULL, def); + + /* Character set name is static so no need to free it. */ + g_object_set_data ( + G_OBJECT (action), "charset", + (gpointer) charset_name); + + gtk_radio_action_set_group (action, group); + group = gtk_radio_action_get_group (action); + + if (callback != NULL) + g_signal_connect ( + action, "changed", callback, user_data); + + gtk_action_group_add_action ( + action_group, GTK_ACTION (action)); + + g_object_unref (action); + + g_free (action_name); + g_free (charset_label); + } + + /* Any of the actions in the action group will do. */ + if (action != NULL) + gtk_radio_action_set_current_value (action, def); + + return group; +} diff --git a/e-util/e-corba-utils.h b/e-util/e-charset.h index c7527ebe26..57b6976a1f 100644 --- a/e-util/e-corba-utils.h +++ b/e-util/e-charset.h @@ -1,4 +1,5 @@ /* + * * 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 @@ -13,19 +14,23 @@ * License along with the program; if not, see <http://www.gnu.org/licenses/> * * - * Authors: - * Ettore Perazzoli <ettore@ximian.com> - * * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com) * */ -#ifndef E_CORBA_UTILS_H -#define E_CORBA_UTILS_H +#ifndef E_CHARSET_H +#define E_CHARSET_H + +#include <gtk/gtk.h> + +G_BEGIN_DECLS -#include <orbit/orbit.h> +GSList * e_charset_add_radio_actions (GtkActionGroup *action_group, + const gchar *action_prefix, + const gchar *default_charset, + GCallback callback, + gpointer user_data); -const CORBA_char *e_safe_corba_string (const gchar *s); -CORBA_char *e_safe_corba_string_dup (const gchar *s); +G_END_DECLS -#endif +#endif /* E_CHARSET_H */ diff --git a/e-util/e-config.c b/e-util/e-config.c index 412c00b649..9974da72cb 100644 --- a/e-util/e-config.c +++ b/e-util/e-config.c @@ -30,10 +30,6 @@ #include <gtk/gtk.h> #include <glib/gi18n.h> -#include <libgnomeui/gnome-druid.h> -#include <libgnomeui/gnome-druid-page-standard.h> -#include <libgnomeui/gnome-druid-page-edge.h> - #include "e-config.h" #include <glib/gi18n.h> @@ -79,12 +75,19 @@ struct _check_node { gpointer data; }; +struct _finish_page_node { + struct _finish_page_node *next, *prev; + + gchar *pageid; + gboolean is_finish; + gint orig_type; +}; + struct _EConfigPrivate { EDList menus; EDList widgets; EDList checks; - - struct _widget_node *druid_page; /* current druid page if using the druid */ + EDList finish_pages; }; static GObjectClass *ep_parent; @@ -100,6 +103,7 @@ ep_init(GObject *o) e_dlist_init(&p->menus); e_dlist_init(&p->widgets); e_dlist_init(&p->checks); + e_dlist_init(&p->finish_pages); } static void @@ -110,6 +114,7 @@ ep_finalise(GObject *o) struct _menu_node *mnode; struct _widget_node *wn; struct _check_node *cn; + struct _finish_page_node *fp; d(printf("finalising EConfig %p\n", o)); @@ -135,6 +140,11 @@ ep_finalise(GObject *o) g_free(cn); } + while ( (fp = (struct _finish_page_node *) e_dlist_remhead (&p->finish_pages)) ) { + g_free (fp->pageid); + g_free (fp); + } + g_free(p); ((GObjectClass *)ep_parent)->finalize(o); @@ -204,7 +214,7 @@ e_config_get_type(void) * e_config_construct: * @ep: The instance to initialise. * @type: The type of configuration manager, @E_CONFIG_BOOK or - * @E_CONFIG_DRUID. + * @E_CONFIG_ASSISTANT. * @id: The name of the configuration window this manager drives. * * Used by implementing classes to initialise base parameters. @@ -213,7 +223,7 @@ e_config_get_type(void) **/ EConfig *e_config_construct(EConfig *ep, gint type, const gchar *id) { - g_return_val_if_fail (type == E_CONFIG_BOOK || type == E_CONFIG_DRUID, NULL); + g_return_val_if_fail (type == E_CONFIG_BOOK || type == E_CONFIG_ASSISTANT, NULL); ep->type = type; ep->id = g_strdup(id); @@ -269,7 +279,7 @@ e_config_add_items(EConfig *ec, GSList *items, EConfigItemsFunc commitfunc, ECon * is being checked. * * The page check function is used to validate input before allowing - * the druid to continue or the notebook to close. + * the assistant to continue or the notebook to close. **/ void e_config_add_page_check(EConfig *ec, const gchar *pageid, EConfigCheckFunc check, gpointer data) @@ -284,6 +294,48 @@ e_config_add_page_check(EConfig *ec, const gchar *pageid, EConfigCheckFunc check e_dlist_addtail(&ec->priv->checks, (EDListNode *)cn); } +static struct _finish_page_node * +find_page_finish (EConfig *ec, const gchar *pageid) +{ + struct _finish_page_node *fp; + + for (fp = (struct _finish_page_node *) ec->priv->finish_pages.head; fp->next; fp = fp->next) { + if (g_str_equal (fp->pageid, pageid)) + return fp; + } + + return NULL; +} + +/** + * e_config_set_page_is_finish: + * @ec: Initialised implementing instance of EConfig. + * @pageid: pageid to change the value on. + * @can_finish: whether the pageid can finish immediately or not. + * + * With is_finish set on the pageid the page is treated as the last page in an assistant. + **/ +void +e_config_set_page_is_finish (EConfig *ec, const gchar *pageid, gboolean is_finish) +{ + struct _finish_page_node *fp; + + fp = find_page_finish (ec, pageid); + + if (is_finish) { + if (!fp) { + fp = g_malloc0 (sizeof (*fp)); + fp->pageid = g_strdup (pageid); + e_dlist_addtail (&ec->priv->finish_pages, (EDListNode *)fp); + } + + fp->is_finish = TRUE; + } else { + if (fp) + fp->is_finish = FALSE; + } +} + static void ec_add_static_items(EConfig *ec) { @@ -309,83 +361,131 @@ ep_cmp(gconstpointer ap, gconstpointer bp) return strcmp(a->item->path, b->item->path); } +static struct _widget_node * +ec_assistant_find_page (EConfig *ec, GtkWidget *page, gint *page_index) +{ + struct _widget_node *wn; + + g_return_val_if_fail (ec != NULL, NULL); + g_return_val_if_fail (GTK_IS_ASSISTANT (ec->widget), NULL); + g_return_val_if_fail (page != NULL, NULL); + + for (wn = (struct _widget_node *)ec->priv->widgets.head; wn->next; wn = wn->next) { + if (wn->frame == page + && (wn->item->type == E_CONFIG_PAGE + || wn->item->type == E_CONFIG_PAGE_START + || wn->item->type == E_CONFIG_PAGE_FINISH)) + break; + } + + if (wn->frame != page) + wn = NULL; + + if (page_index) { + if (wn) { + GtkAssistant *assistant = GTK_ASSISTANT (ec->widget); + gint index, count = gtk_assistant_get_n_pages (assistant); + + for (index = 0; index < count; index++) { + if (gtk_assistant_get_nth_page (assistant, index) == page) + break; + } + + if (index == count) + index = -1; + *page_index = index; + } else { + *page_index = -1; + } + } + + return wn; +} + static void -ec_druid_check_current(EConfig *ec) +ec_assistant_check_current (EConfig *ec) { - g_return_if_fail(ec->priv->druid_page != NULL); + struct _widget_node *wn; + struct _finish_page_node *fp; + GtkAssistant *assistant; + GtkWidget *page; + gint page_no; - if (e_config_page_check(ec, ec->priv->druid_page->item->path)) { - gtk_widget_set_sensitive(((GnomeDruid *)ec->widget)->next, TRUE); - } else { - gtk_widget_set_sensitive(((GnomeDruid *)ec->widget)->next, FALSE); + g_return_if_fail (GTK_IS_ASSISTANT (ec->widget)); + + assistant = GTK_ASSISTANT (ec->widget); + page_no = gtk_assistant_get_current_page (assistant); + + /* no page selected yet */ + if (page_no == -1) + return; + + page = gtk_assistant_get_nth_page (assistant, page_no); + g_return_if_fail (page != NULL); + + wn = ec_assistant_find_page (ec, page, NULL); + g_return_if_fail (wn != NULL); + + /* this should come first, as the check function can change the finish state of the page */ + gtk_assistant_set_page_complete (assistant, page, e_config_page_check (ec, wn->item->path)); + + fp = find_page_finish (ec, wn->item->path); + if (fp) { + GtkAssistantPageType pt = gtk_assistant_get_page_type (assistant, page); + + if (fp->is_finish && pt != GTK_ASSISTANT_PAGE_CONFIRM) { + if (fp->orig_type == GTK_ASSISTANT_PAGE_CONTENT) + fp->orig_type = pt; + gtk_assistant_set_page_type (assistant, page, GTK_ASSISTANT_PAGE_CONFIRM); + } else if (!fp->is_finish && pt != fp->orig_type) { + gtk_assistant_set_page_type (assistant, page, fp->orig_type); + } } + + gtk_assistant_update_buttons_state (assistant); } static void -ec_druid_cancel(GnomeDruid *druid, struct _widget_node *wn) +ec_assistant_cancel (GtkAssistant *assistant, EConfig *config) { - d(printf("finishing druid, calling abort\n")); - e_config_abort(wn->config); + d(printf("finishing assistant, calling abort\n")); + e_config_abort (config); - if (wn->config->window) - gtk_widget_destroy(wn->config->window); + if (config->window) + gtk_widget_destroy (config->window); } static void -ec_druid_finish(GnomeDruidPage *page, GnomeDruid *druid, struct _widget_node *wn) +ec_assistant_apply (GtkAssistant *assistant, EConfig *config) { - d(printf("finishing druid, calling commit\n")); - e_config_commit(wn->config); + d(printf("finishing assistant, calling commit\n")); + e_config_commit (config); /* TODO: allow the commit to fail? Do we care? */ - if (wn->config->window) - gtk_widget_destroy(wn->config->window); + if (config->window) + gtk_widget_destroy (config->window); } static void -ec_druid_prepare(GnomeDruidPage *page, GnomeDruid *druid, struct _widget_node *wn) +ec_assistant_prepare (GtkAssistant *assistant, GtkWidget *page, EConfig *config) { - d(printf("prepare page '%s'\n", wn->item->path)); - wn->config->priv->druid_page = wn; - ec_druid_check_current(wn->config); + d(printf("prepare page '%p'\n", page)); + ec_assistant_check_current (config); } -static gboolean -ec_druid_prev(GnomeDruidPage *page, GnomeDruid *druid, struct _widget_node *wn) +static gint +ec_assistant_forward (gint current_page, gpointer user_data) { - EConfig *ec = wn->config; - - d(printf("prev page from '%s'\n", wn->item->path)); - if (wn->prev) { - for (wn = wn->prev;wn->prev;wn=wn->prev) { - if (!wn->empty && wn->frame != NULL - && (wn->item->type == E_CONFIG_PAGE - || wn->item->type == E_CONFIG_PAGE_START - || wn->item->type == E_CONFIG_PAGE_FINISH)) - break; - } - } + EConfig *ec = user_data; + struct _widget_node *wn; + gint next_page = current_page; - if (wn->prev) { - d(printf(" is %s\n",wn->item->path)); - gnome_druid_set_page((GnomeDruid *)ec->widget, (GnomeDruidPage *)wn->frame); - ec->priv->druid_page = wn; - } else { - /* do we need to indicate first? */ - ec->priv->druid_page = NULL; - } + d(printf("next page from '%d'\n", current_page)); - return wn->prev != NULL; -} + wn = ec_assistant_find_page (ec, gtk_assistant_get_nth_page (GTK_ASSISTANT (ec->widget), current_page), NULL); -static gboolean -ec_druid_next(GnomeDruidPage *page, GnomeDruid *druid, struct _widget_node *wn) -{ - EConfig *ec = wn->config; - - d(printf("next page from '%s'\n", wn->item->path)); - if (wn->next) { - for (wn = wn->next;wn->next;wn=wn->next) { + if (wn && wn->next) { + for (wn = wn->next; wn->next; wn = wn->next) { if (!wn->empty && wn->frame != NULL && (wn->item->type == E_CONFIG_PAGE || wn->item->type == E_CONFIG_PAGE_START @@ -394,25 +494,23 @@ ec_druid_next(GnomeDruidPage *page, GnomeDruid *druid, struct _widget_node *wn) } } - if (wn->next) { + if (wn && wn->next) { d(printf(" is %s\n",wn->item->path)); - gnome_druid_set_page((GnomeDruid *)ec->widget, (GnomeDruidPage *)wn->frame); - ec->priv->druid_page = wn; - } else { - /* do we need to indicate last? */ - ec->priv->druid_page = NULL; + ec_assistant_find_page (ec, wn->frame, &next_page); } - return wn->next != NULL; + return next_page; } static void -ec_rebuild(EConfig *emp) +ec_rebuild (EConfig *emp) { struct _EConfigPrivate *p = emp->priv; struct _widget_node *wn, *sectionnode = NULL, *pagenode = NULL; - GtkWidget *book = NULL, *page = NULL, *section = NULL, *root = NULL, *druid = NULL; + GtkWidget *book = NULL, *page = NULL, *section = NULL, *root = NULL, *assistant = NULL; gint pageno = 0, sectionno = 0, itemno = 0; + struct _widget_node *last_active_page = NULL; + gboolean is_assistant; d(printf("target changed, rebuilding:\n")); @@ -421,6 +519,15 @@ ec_rebuild(EConfig *emp) * into the two base types, but there would be a lot of code * duplication */ + /* because rebuild destroys pages, and destroying active page causes crashes */ + is_assistant = emp->widget && GTK_IS_ASSISTANT (emp->widget); + if (is_assistant) { + gint page_index = gtk_assistant_get_current_page (GTK_ASSISTANT (emp->widget)); + if (page_index != -1) + last_active_page = ec_assistant_find_page (emp, gtk_assistant_get_nth_page (GTK_ASSISTANT (emp->widget), page_index), NULL); + gtk_assistant_set_current_page (GTK_ASSISTANT (emp->widget), 0); + } + for (wn = (struct _widget_node *)p->widgets.head;wn->next;wn=wn->next) { struct _EConfigItem *item = wn->item; const gchar *translated_label = NULL; @@ -464,35 +571,39 @@ ec_rebuild(EConfig *emp) /* Now process the item */ switch (item->type) { case E_CONFIG_BOOK: - case E_CONFIG_DRUID: - /* Only one of BOOK or DRUID may be define, it + case E_CONFIG_ASSISTANT: + /* Only one of BOOK or ASSISTANT may be define, it is used by the defining code to mark the type of the config window. It is cross-checked with the code's defined type. */ if (root != NULL) { - g_warning("EConfig book/druid redefined at: %s", item->path); + g_warning("EConfig book/assistant redefined at: %s", item->path); break; } if (wn->widget == NULL) { if (item->type != emp->type) { - g_warning("EConfig book/druid type mismatch"); + g_warning("EConfig book/assistant type mismatch"); break; } if (item->factory) { root = item->factory(emp, item, NULL, wn->widget, wn->context->data); } else if (item->type == E_CONFIG_BOOK) { - root = book = gtk_notebook_new(); - gtk_widget_show(book); - } else if (item->type == E_CONFIG_DRUID) { - root = druid = gnome_druid_new(); - gtk_widget_show(druid); + root = gtk_notebook_new(); + gtk_widget_show (root); + } else if (item->type == E_CONFIG_ASSISTANT) { + root = gtk_assistant_new (); } else abort(); - if (item->type == E_CONFIG_DRUID) - g_signal_connect(root, "cancel", G_CALLBACK(ec_druid_cancel), wn); + if (item->type == E_CONFIG_ASSISTANT) { + g_signal_connect (root, "cancel", G_CALLBACK (ec_assistant_cancel), emp); + g_signal_connect (root, "close", G_CALLBACK (ec_assistant_cancel), emp); + g_signal_connect (root, "apply", G_CALLBACK (ec_assistant_apply), emp); + g_signal_connect (root, "prepare", G_CALLBACK (ec_assistant_prepare), emp); + gtk_assistant_set_forward_page_func (GTK_ASSISTANT (root), ec_assistant_forward, emp, NULL); + } emp->widget = root; wn->widget = root; @@ -503,7 +614,7 @@ ec_rebuild(EConfig *emp) if (item->type == E_CONFIG_BOOK) book = root; else - druid = root; + assistant = root; page = NULL; pagenode = NULL; @@ -518,8 +629,8 @@ ec_rebuild(EConfig *emp) g_warning("EConfig page defined before container widget: %s", item->path); break; } - if (emp->type != E_CONFIG_DRUID) { - g_warning("EConfig druid start/finish pages can't be used on E_CONFIG_BOOKs"); + if (emp->type != E_CONFIG_ASSISTANT) { + g_warning("EConfig assistant start/finish pages can't be used on E_CONFIG_BOOKs"); break; } @@ -527,21 +638,41 @@ ec_rebuild(EConfig *emp) if (item->factory) { page = item->factory(emp, item, root, wn->frame, wn->context->data); } else { - page = gnome_druid_page_edge_new(item->type == E_CONFIG_PAGE_START?GNOME_EDGE_START:GNOME_EDGE_FINISH); - gtk_widget_show(page); - gnome_druid_page_edge_set_title((GnomeDruidPageEdge *)page, translated_label); - gnome_druid_insert_page((GnomeDruid *)druid, pagenode?(GnomeDruidPage *)pagenode->frame:NULL, (GnomeDruidPage *)page); - } - if (page) { - if (item->type == E_CONFIG_PAGE_FINISH) { - g_signal_connect(page, "back", G_CALLBACK(ec_druid_prev), wn); - g_signal_connect(page, "finish", G_CALLBACK(ec_druid_finish), wn); - } else - g_signal_connect(page, "next", G_CALLBACK(ec_druid_next), wn); + page = gtk_vbox_new (FALSE, 0); + gtk_container_set_border_width (GTK_CONTAINER (page), 12); + if (pagenode) { + /* put after */ + gint index = -1; + ec_assistant_find_page (emp, pagenode->frame, &index); + gtk_assistant_insert_page (GTK_ASSISTANT (assistant), page, index + 1); + } else { + gtk_assistant_prepend_page (GTK_ASSISTANT (assistant), page); + } + + gtk_assistant_set_page_type (GTK_ASSISTANT (assistant), page, item->type == E_CONFIG_PAGE_START ? GTK_ASSISTANT_PAGE_INTRO : GTK_ASSISTANT_PAGE_CONFIRM); + gtk_assistant_set_page_title (GTK_ASSISTANT (assistant), page, translated_label); + gtk_widget_show_all (page); } + wn->frame = page; wn->widget = page; + + if (page) { + const gchar *empty_xpm_img[] = { + "48 1 2 1", + " c None", + ". c #FFFFFF", + " "}; + + /* left side place with a blue background on a start and finish page */ + GdkPixbuf *spacer = gdk_pixbuf_new_from_xpm_data (empty_xpm_img); + + gtk_assistant_set_page_side_image (GTK_ASSISTANT (assistant), page, spacer); + + g_object_unref (spacer); + } } + pageno++; page = NULL; pagenode = wn; /* need this for previous page linking */ @@ -550,15 +681,12 @@ ec_rebuild(EConfig *emp) sectionno = 1; /* never want to hide these */ break; case E_CONFIG_PAGE: { - gint connect = 0; /* connect druid signals */ - /* CONFIG_PAGEs depend on the config type. E_CONFIG_BOOK: The page is a VBox, stored in the notebook. - E_CONFIG_DRUID - The page is a GnomeDruidPageStandard, - any sections automatically added are added to - the vbox inside it. */ + E_CONFIG_ASSISTANT + The page is a VBox, stored in the GtkAssistant, + any sections automatically added inside it. */ sectionno = 0; if (root == NULL) { g_warning("EConfig page defined before container widget: %s", item->path); @@ -567,15 +695,8 @@ ec_rebuild(EConfig *emp) if (item->factory) { page = item->factory(emp, item, root, wn->frame, wn->context->data); - if (emp->type == E_CONFIG_DRUID) { - if (page) { - if (GNOME_IS_DRUID_PAGE_STANDARD(page)) { - connect = wn->frame != page; - wn->frame = page; - page = ((GnomeDruidPageStandard *)page)->vbox; - } - } else - wn->frame = page; + if (emp->type == E_CONFIG_ASSISTANT) { + wn->frame = page; } else { wn->frame = page; if (page) @@ -584,14 +705,22 @@ ec_rebuild(EConfig *emp) if (page) sectionno = 1; } else if (wn->widget == NULL) { - if (emp->type == E_CONFIG_DRUID) { - w = gnome_druid_page_standard_new(); - gtk_widget_show(w); - gnome_druid_page_standard_set_title((GnomeDruidPageStandard *)w, translated_label); - gnome_druid_insert_page((GnomeDruid *)druid, pagenode?(GnomeDruidPage *)pagenode->frame:NULL, (GnomeDruidPage *)w); - wn->frame = w; - page = ((GnomeDruidPageStandard *)w)->vbox; - connect = TRUE; + if (emp->type == E_CONFIG_ASSISTANT) { + page = gtk_vbox_new (FALSE, 0); + gtk_container_set_border_width (GTK_CONTAINER (page), 12); + if (pagenode) { + /* put after */ + gint index = -1; + ec_assistant_find_page (emp, pagenode->frame, &index); + gtk_assistant_insert_page (GTK_ASSISTANT (assistant), page, index + 1); + } else { + gtk_assistant_prepend_page (GTK_ASSISTANT (assistant), page); + } + gtk_assistant_set_page_type (GTK_ASSISTANT (assistant), page, GTK_ASSISTANT_PAGE_CONTENT); + gtk_assistant_set_page_title (GTK_ASSISTANT (assistant), page, translated_label); + gtk_widget_show_all (page); + + wn->frame = page; } else { w = gtk_label_new_with_mnemonic (translated_label); gtk_widget_show(w); @@ -607,15 +736,8 @@ ec_rebuild(EConfig *emp) d(printf("page %d:%s widget %p\n", pageno, item->path, page)); if (wn->widget && wn->widget != page) { - d(printf("destroy old widget for page '%s'\n", item->path)); - gtk_widget_destroy(wn->widget); - } - - if (connect) { - g_signal_connect(wn->frame, "next", G_CALLBACK(ec_druid_next), wn); - g_signal_connect(wn->frame, "back", G_CALLBACK(ec_druid_prev), wn); - /* GnomeDruid bug, need to connect_after */ - g_signal_connect_after(wn->frame, "prepare", G_CALLBACK(ec_druid_prepare), wn); + d(printf("destroy old widget for page '%s' (%p)\n", item->path, wn->widget)); + gtk_widget_destroy (wn->widget); } pageno++; @@ -629,8 +751,7 @@ ec_rebuild(EConfig *emp) case E_CONFIG_SECTION: case E_CONFIG_SECTION_TABLE: /* The section factory is always called with - the parent vbox object. Even for druid - pages. */ + the parent vbox object. Even for assistant pages. */ if (page == NULL) { /*g_warning("EConfig section '%s' has no parent page", item->path);*/ section = NULL; @@ -768,6 +889,13 @@ ec_rebuild(EConfig *emp) gtk_notebook_set_show_border((GtkNotebook *)book, FALSE); } } + + if (is_assistant && last_active_page) { + gint page_index = -1; + + ec_assistant_find_page (emp, last_active_page->frame, &page_index); + gtk_assistant_set_current_page (GTK_ASSISTANT (emp->widget), page_index); + } } /** @@ -805,7 +933,7 @@ ec_widget_destroy(GtkWidget *w, EConfig *ec) * * Create the widget described by @emp. Only the core widget * appropriate for the given type is created, i.e. a GtkNotebook for - * the E_CONFIG_BOOK type and a GnomeDruid for the E_CONFIG_DRUID + * the E_CONFIG_BOOK type and a GtkAssistant for the E_CONFIG_ASSISTANT * type. * * This object will be self-driving, but will not close itself once @@ -859,6 +987,11 @@ e_config_create_widget(EConfig *emp) /* FIXME: for some reason ec_rebuild puts the widget on page 1, this is just to override that */ if (emp->type == E_CONFIG_BOOK) gtk_notebook_set_current_page((GtkNotebook *)emp->widget, 0); + else { + gtk_assistant_set_current_page (GTK_ASSISTANT (emp->widget), 0); + gtk_window_set_position (GTK_WINDOW (emp->widget), GTK_WIN_POS_CENTER); + gtk_widget_show (emp->widget); + } return emp->widget; } @@ -882,9 +1015,9 @@ ec_dialog_response(GtkWidget *d, gint id, EConfig *ec) * * Create a managed GtkWindow object from @emp. This window will be * fully driven by the EConfig @emp. If @emp.type is - * @E_CONFIG_DRUID, then this will be a toplevel GtkWindow containing - * a GnomeDruid. If it is @E_CONFIG_BOOK then it will be a GtkDialog - * containing a Nnotebook. + * @E_CONFIG_ASSISTANT, then this will be a toplevel GtkWindow containing + * a GtkAssistant. If it is @E_CONFIG_BOOK then it will be a GtkDialog + * containing a Notebook. * * Unless reffed otherwise, the management object @emp will be * finalised when the widget is. @@ -913,11 +1046,9 @@ e_config_create_window(EConfig *emp, GtkWindow *parent, const gchar *title) gtk_box_pack_start((GtkBox *)gtk_dialog_get_content_area (((GtkDialog *)w)), emp->widget, TRUE, TRUE, 0); } else { - /* response is handled directly by the druid stuff */ - w = gtk_window_new(GTK_WINDOW_TOPLEVEL); + /* response is handled directly by the assistant stuff */ + w = emp->widget; gtk_window_set_title ((GtkWindow *)w, title); - gtk_container_add((GtkContainer *)w, emp->widget); - gtk_window_set_type_hint((GtkWindow *)w, GDK_WINDOW_TYPE_HINT_DIALOG); } emp->window = w; @@ -926,17 +1057,11 @@ e_config_create_window(EConfig *emp, GtkWindow *parent, const gchar *title) return w; } -static gboolean -ec_idle_handler_for_rebuild (gpointer data) +static void +ec_call_page_check (EConfig *emp) { - EConfig *emp = (EConfig*) data; - - ec_rebuild (emp); - if (emp->type == E_CONFIG_DRUID) { - if (emp->priv->druid_page) { - gnome_druid_set_page((GnomeDruid *)emp->widget, (GnomeDruidPage *)emp->priv->druid_page->frame); - ec_druid_check_current(emp); - } + if (emp->type == E_CONFIG_ASSISTANT) { + ec_assistant_check_current (emp); } else { if (emp->window) { if (e_config_page_check(emp, NULL)) { @@ -946,6 +1071,16 @@ ec_idle_handler_for_rebuild (gpointer data) } } } +} + +static gboolean +ec_idle_handler_for_rebuild (gpointer data) +{ + EConfig *emp = (EConfig*) data; + + ec_rebuild (emp); + ec_call_page_check (emp); + return FALSE; } @@ -959,29 +1094,15 @@ ec_idle_handler_for_rebuild (gpointer data) * %E_CONFIG_TARGET_CHANGED_REBUILD, then the entire configuration * widget may be recreated based on the changed target. * - * This is used to sensitise Druid next/back buttons and the Apply + * This is used to sensitise Assistant next/back buttons and the Apply * button for the Notebook mode. **/ void e_config_target_changed(EConfig *emp, e_config_target_change_t how) { if (how == E_CONFIG_TARGET_CHANGED_REBUILD) { g_idle_add (ec_idle_handler_for_rebuild, emp); - return; - } - - if (emp->type == E_CONFIG_DRUID) { - if (emp->priv->druid_page) { - gnome_druid_set_page((GnomeDruid *)emp->widget, (GnomeDruidPage *)emp->priv->druid_page->frame); - ec_druid_check_current(emp); - } } else { - if (emp->window) { - if (e_config_page_check(emp, NULL)) { - gtk_dialog_set_response_sensitive((GtkDialog *)emp->window, GTK_RESPONSE_OK, TRUE); - } else { - gtk_dialog_set_response_sensitive((GtkDialog *)emp->window, GTK_RESPONSE_OK, FALSE); - } - } + ec_call_page_check (emp); } /* virtual method/signal? */ @@ -992,7 +1113,7 @@ void e_config_target_changed(EConfig *emp, e_config_target_change_t how) * @ec: * * Signify that the stateful configuration changes must be discarded - * to all listeners. This is used by self-driven druid or notebook, or + * to all listeners. This is used by self-driven assistant or notebook, or * may be used by code using the widget directly. **/ void e_config_abort(EConfig *ec) @@ -1012,7 +1133,7 @@ void e_config_abort(EConfig *ec) * @ec: * * Signify that the stateful configuration changes should be saved. - * This is used by the self-driven druid or notebook, or may be used + * This is used by the self-driven assistant or notebook, or may be used * by code driving the widget directly. **/ void e_config_commit(EConfig *ec) @@ -1046,8 +1167,9 @@ gboolean e_config_page_check(EConfig *ec, const gchar *pageid) if ((pageid == NULL || mnode->pageid == NULL || strcmp(mnode->pageid, pageid) == 0) - && !mnode->check(ec, pageid, mnode->data)) + && !mnode->check(ec, pageid, mnode->data)) { return FALSE; + } return TRUE; } @@ -1060,7 +1182,7 @@ gboolean e_config_page_check(EConfig *ec, const gchar *pageid) * Retrieve the page widget corresponding to @pageid. * * Return value: The page widget. It will be the root GtkNotebook - * container or the GnomeDruidPage object. + * container or the GtkVBox object inside the assistant. **/ GtkWidget *e_config_page_get(EConfig *ec, const gchar *pageid) { @@ -1258,7 +1380,7 @@ static gpointer emph_parent_class; static const EPluginHookTargetKey ech_item_types[] = { { "book", E_CONFIG_BOOK }, - { "druid", E_CONFIG_DRUID }, + { "assistant", E_CONFIG_ASSISTANT }, { "page", E_CONFIG_PAGE }, { "page_start", E_CONFIG_PAGE_START }, diff --git a/e-util/e-config.h b/e-util/e-config.h index e6ff495520..1550f8895c 100644 --- a/e-util/e-config.h +++ b/e-util/e-config.h @@ -76,18 +76,18 @@ enum _e_config_target_change_t { * enum _e_config_t - configuration item type. * * @E_CONFIG_BOOK: A notebook item. Only one of this or - * @E_CONFIG_DRUID may be included in the item list for the entire + * @E_CONFIG_ASSISTANT may be included in the item list for the entire * configuration description. - * @E_CONFIG_DRUID: A druid item. Only one of this or @E_CONFIG_BOOK + * @E_CONFIG_ASSISTANT: An assistant item. Only one of this or @E_CONFIG_BOOK * may be included in the item list for the entire configutation * description. * @E_CONFIG_PAGE: A configuration page. The item @label will be - * either the notebook tab label or the druid page title if no factory + * either the notebook tab label or the assistant page title if no factory * is supplied. - * @E_CONFIG_PAGE_START: A druid start page. Only one of these may be - * supplied for a druid and it should be the first page in the druid. - * @E_CONFIG_PAGE_FINISH: A druid finish page. Only one of these may - * be supplied for a druid and it should be the last page of the druid. + * @E_CONFIG_PAGE_START: An assistant start page. Only one of these may be + * supplied for a assistant and it should be the first page in the assistant. + * @E_CONFIG_PAGE_FINISH: An assistant finish page. Only one of these may + * be supplied for an assistant and it should be the last page of the assistant. * @E_CONFIG_SECTION: A section in the configuration page. A page for * this section must have already been defined. The item @label if * supplied will be setup as a borderless hig-compliant frame title. @@ -109,11 +109,11 @@ enum _e_config_target_change_t { enum _e_config_t { /* use one and only one of these for any given config-window id */ E_CONFIG_BOOK, - E_CONFIG_DRUID, + E_CONFIG_ASSISTANT, E_CONFIG_PAGE, - E_CONFIG_PAGE_START, /* only allowed in druid types */ - E_CONFIG_PAGE_FINISH, /* only allowed in druid types */ + E_CONFIG_PAGE_START, /* only allowed in assistant types */ + E_CONFIG_PAGE_FINISH, /* only allowed in assistant types */ E_CONFIG_SECTION, E_CONFIG_SECTION_TABLE, E_CONFIG_ITEM, @@ -175,7 +175,7 @@ struct _EConfigTarget { * @id: The globally unique identifider for this configuration window, * used for hooking into it. * @target: The current target. - * @widget: The GtkNoteBook or GnomeDruid created after + * @widget: The GtkNoteBook or GtkAssistant created after * :create_widget() is called that represents the merged and combined * configuration window. * @window: If :create_window() is called, then the containing @@ -188,7 +188,7 @@ struct _EConfig { struct _EConfigPrivate *priv; - gint type; /* E_CONFIG_BOOK or E_CONFIG_DRUID */ + gint type; /* E_CONFIG_BOOK or E_CONFIG_ASSISTANT */ gchar *id; @@ -231,6 +231,7 @@ EConfig *e_config_construct(EConfig *, gint type, const gchar *id); void e_config_add_items(EConfig *, GSList *items, EConfigItemsFunc commitfunc, EConfigItemsFunc abortfunc, EConfigItemsFunc freefunc, gpointer data); void e_config_add_page_check(EConfig *, const gchar *pageid, EConfigCheckFunc, gpointer data); +void e_config_set_page_is_finish (EConfig *ec, const gchar *pageid, gboolean is_finish); void e_config_set_target(EConfig *emp, EConfigTarget *target); GtkWidget *e_config_create_widget(EConfig *); diff --git a/e-util/e-dialog-utils.c b/e-util/e-dialog-utils.c index 5bc1bbc685..d02a42572b 100644 --- a/e-util/e-dialog-utils.c +++ b/e-util/e-dialog-utils.c @@ -343,29 +343,29 @@ e_file_dialog_save_folder (const gchar *title) * no signals connected and is not shown. **/ GtkWidget * -e_file_get_save_filesel (GtkWidget *parent, const gchar *title, const gchar *name, GtkFileChooserAction action) +e_file_get_save_filesel (GtkWindow *parent, const gchar *title, const gchar *name, GtkFileChooserAction action) { GtkWidget *filesel; gchar *uri; - filesel = gtk_file_chooser_dialog_new (title, - NULL, - action, - GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, - (action == GTK_FILE_CHOOSER_ACTION_OPEN) ? GTK_STOCK_OPEN:GTK_STOCK_SAVE, GTK_RESPONSE_OK, - NULL); + g_return_val_if_fail (GTK_IS_WINDOW (parent), NULL); + + filesel = gtk_file_chooser_dialog_new ( + title, parent, action, + GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, + (action == GTK_FILE_CHOOSER_ACTION_OPEN) ? + GTK_STOCK_OPEN : GTK_STOCK_SAVE, GTK_RESPONSE_OK, NULL); gtk_dialog_set_default_response (GTK_DIALOG (filesel), GTK_RESPONSE_OK); gtk_file_chooser_set_local_only (GTK_FILE_CHOOSER (filesel), FALSE); - if (parent) - e_dialog_set_transient_for ((GtkWindow *)filesel, parent); - - uri = e_file_get_save_path(); + uri = e_file_get_save_path (); - gtk_file_chooser_set_current_folder_uri (GTK_FILE_CHOOSER (filesel), uri); + gtk_file_chooser_set_current_folder_uri ( + GTK_FILE_CHOOSER (filesel), uri); if (name && name[0]) - gtk_file_chooser_set_current_name (GTK_FILE_CHOOSER (filesel), name); + gtk_file_chooser_set_current_name ( + GTK_FILE_CHOOSER (filesel), name); g_free (uri); diff --git a/e-util/e-dialog-utils.h b/e-util/e-dialog-utils.h index 71c801cbc0..98d85e151d 100644 --- a/e-util/e-dialog-utils.h +++ b/e-util/e-dialog-utils.h @@ -43,7 +43,7 @@ gchar *e_file_dialog_save (const gchar *title, const gchar *fna gchar *e_file_dialog_save_folder (const gchar *title); -GtkWidget * e_file_get_save_filesel (GtkWidget *parent, const gchar *title, const gchar *name, GtkFileChooserAction action); +GtkWidget * e_file_get_save_filesel (GtkWindow *parent, const gchar *title, const gchar *name, GtkFileChooserAction action); gboolean e_file_can_save(GtkWindow *parent, const gchar *uri); gboolean e_file_check_local(const gchar *name); diff --git a/e-util/e-dialog-widgets.c b/e-util/e-dialog-widgets.c index afa680d11b..cdcd52dd26 100644 --- a/e-util/e-dialog-widgets.c +++ b/e-util/e-dialog-widgets.c @@ -320,9 +320,11 @@ e_dialog_radio_get (GtkWidget *widget, const gint *value_map) group = gtk_radio_button_get_group (GTK_RADIO_BUTTON (widget)); for (i = 0, l = group; l; l = l->next, i++) { - widget = GTK_WIDGET (l->data); + GtkToggleButton *toggle_button; - if (GTK_TOGGLE_BUTTON (widget)->active) + toggle_button = GTK_TOGGLE_BUTTON (l->data); + + if (gtk_toggle_button_get_active (toggle_button)) break; } @@ -373,10 +375,9 @@ e_dialog_toggle_set (GtkWidget *widget, gboolean value) gboolean e_dialog_toggle_get (GtkWidget *widget) { - g_return_val_if_fail (widget != NULL, FALSE); g_return_val_if_fail (GTK_IS_TOGGLE_BUTTON (widget), FALSE); - return GTK_TOGGLE_BUTTON (widget)->active; + return gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (widget)); } /** @@ -396,7 +397,7 @@ e_dialog_spin_set (GtkWidget *widget, double value) adj = gtk_spin_button_get_adjustment (GTK_SPIN_BUTTON (widget)); - adj->value = value; + gtk_adjustment_set_value (adj, value); g_signal_emit_by_name (adj, "value_changed", 0); } @@ -417,7 +418,8 @@ e_dialog_spin_get_double (GtkWidget *widget) g_return_val_if_fail (GTK_IS_SPIN_BUTTON (widget), 0.0); adj = gtk_spin_button_get_adjustment (GTK_SPIN_BUTTON (widget)); - return adj->value; + + return gtk_adjustment_get_value (adj); } /** diff --git a/e-util/e-error.c b/e-util/e-error.c index dd5dddf64e..b672e1d17e 100644 --- a/e-util/e-error.c +++ b/e-util/e-error.c @@ -412,6 +412,8 @@ e_error_newv(GtkWindow *parent, const gchar *tag, const gchar *arg0, va_list ap) struct _e_error *e; struct _e_error_button *b; GtkWidget *hbox, *w, *scroll=NULL; + GtkWidget *action_area; + GtkWidget *content_area; gchar *tmp, *domain, *id; GString *out, *oerr; GPtrArray *args; @@ -422,11 +424,14 @@ e_error_newv(GtkWindow *parent, const gchar *tag, const gchar *arg0, va_list ap) ee_load_tables(); dialog = (GtkDialog *)gtk_dialog_new(); + action_area = gtk_dialog_get_action_area (dialog); + content_area = gtk_dialog_get_content_area (dialog); + gtk_dialog_set_has_separator(dialog, FALSE); gtk_widget_ensure_style ((GtkWidget *)dialog); - gtk_container_set_border_width ((GtkContainer *)(dialog->vbox), 0); - gtk_container_set_border_width ((GtkContainer *)(dialog->action_area), 12); + gtk_container_set_border_width (GTK_CONTAINER (action_area), 12); + gtk_container_set_border_width (GTK_CONTAINER (content_area), 0); if (parent == NULL && ee_parent_list) parent = (GtkWindow *)ee_parent_list->data; @@ -454,7 +459,7 @@ e_error_newv(GtkWindow *parent, const gchar *tag, const gchar *arg0, va_list ap) gtk_label_set_markup((GtkLabel *)w, tmp); GTK_WIDGET_UNSET_FLAGS (w, GTK_CAN_FOCUS); gtk_widget_show(w); - gtk_box_pack_start((GtkBox *)dialog->vbox, w, TRUE, TRUE, 12); + gtk_box_pack_start (GTK_BOX (content_area), w, TRUE, TRUE, 12); return (GtkWidget *)dialog; } @@ -557,7 +562,7 @@ e_error_newv(GtkWindow *parent, const gchar *tag, const gchar *arg0, va_list ap) gtk_widget_show_all(hbox); - gtk_box_pack_start((GtkBox *)dialog->vbox, hbox, TRUE, TRUE, 0); + gtk_box_pack_start (GTK_BOX (content_area), hbox, TRUE, TRUE, 0); g_object_set_data_full ((GObject *) dialog, "primary", perr, g_free); g_object_set_data_full ((GObject *) dialog, "secondary", serr, g_free); @@ -645,14 +650,14 @@ e_error_run(GtkWindow *parent, const gchar *tag, const gchar *arg0, ...) guint e_error_count_buttons (GtkDialog *dialog) { - GtkContainer *action_area; + GtkWidget *container; GList *children, *iter; guint n_buttons = 0; g_return_val_if_fail (GTK_DIALOG (dialog), 0); - action_area = GTK_CONTAINER (dialog->action_area); - children = gtk_container_get_children (action_area); + container = gtk_dialog_get_action_area (dialog); + children = gtk_container_get_children (GTK_CONTAINER (container)); /* Iterate over the children looking for buttons. */ for (iter = children; iter != NULL; iter = iter->next) diff --git a/e-util/e-import.c b/e-util/e-import.c index 6f4c5947b4..0c10715ce3 100644 --- a/e-util/e-import.c +++ b/e-util/e-import.c @@ -29,10 +29,6 @@ #include <gtk/gtk.h> -#include <libgnomeui/gnome-druid.h> -#include <libgnomeui/gnome-druid-page-standard.h> -#include <libgnomeui/gnome-druid-page-edge.h> - #include "e-import.h" #include <glib/gi18n.h> diff --git a/e-util/e-import.h b/e-util/e-import.h index 5a3165e117..9e409a30fb 100644 --- a/e-util/e-import.h +++ b/e-util/e-import.h @@ -60,7 +60,7 @@ enum _e_import_target_t { * @type: target type * @priority: Priority of importer. Higher values will be processed first. * @supported: Callback to see if this target is supported by the importer. - * @get_widget: A widget factory for this importer, if it needs any extra information in the druid. It will update the target. + * @get_widget: A widget factory for this importer, if it needs any extra information in the assistant. It will update the target. * @import: Run the import. * @user_data: User data for the callbacks; * diff --git a/e-util/e-logger.c b/e-util/e-logger.c index eac1a8fb06..07571d229a 100644 --- a/e-util/e-logger.c +++ b/e-util/e-logger.c @@ -43,7 +43,7 @@ ((obj), E_TYPE_LOGGER, ELoggerPrivate)) struct _ELoggerPrivate { - gchar *component; + gchar *name; gchar *logfile; FILE *fp; @@ -52,13 +52,13 @@ struct _ELoggerPrivate { enum { PROP_0, - PROP_COMPONENT + PROP_NAME }; static gpointer parent_class; static gboolean -flush_logfile (ELogger *logger) +logger_flush (ELogger *logger) { if (logger->priv->fp) fflush (logger->priv->fp); @@ -68,16 +68,26 @@ flush_logfile (ELogger *logger) } static void -logger_set_component (ELogger *logger, - const gchar *component) +logger_set_dirty (ELogger *logger) +{ + if (logger->priv->timer) + return; + + logger->priv->timer = g_timeout_add ( + TIMEOUT_INTERVAL, (GSourceFunc) logger_flush, logger); +} + +static void +logger_set_name (ELogger *logger, + const gchar *name) { gchar *temp; - g_return_if_fail (logger->priv->component == NULL); + g_return_if_fail (logger->priv->name == NULL); - temp = g_strdup_printf ("%s.log.XXXXXX", component); + temp = g_strdup_printf ("%s.log.XXXXXX", name); - logger->priv->component = g_strdup (component); + logger->priv->name = g_strdup (name); logger->priv->logfile = e_mktemp (temp); logger->priv->fp = g_fopen (logger->priv->logfile, "w"); logger->priv->timer = 0; @@ -95,8 +105,8 @@ logger_set_property (GObject *object, GParamSpec *pspec) { switch (property_id) { - case PROP_COMPONENT: - logger_set_component ( + case PROP_NAME: + logger_set_name ( E_LOGGER (object), g_value_get_string (value)); return; @@ -112,9 +122,9 @@ logger_get_property (GObject *object, GParamSpec *pspec) { switch (property_id) { - case PROP_COMPONENT: + case PROP_NAME: g_value_set_string ( - value, e_logger_get_component ( + value, e_logger_get_name ( E_LOGGER (object))); return; } @@ -129,11 +139,11 @@ logger_finalize (GObject *object) if (logger->priv->timer) g_source_remove (logger->priv->timer); - flush_logfile (logger); + logger_flush (logger); if (logger->priv->fp) fclose (logger->priv->fp); - g_free (logger->priv->component); + g_free (logger->priv->name); g_free (logger->priv->logfile); /* Chain up to parent's finalize() method. */ @@ -155,11 +165,11 @@ logger_class_init (ELoggerClass *class) g_object_class_install_property ( object_class, - PROP_COMPONENT, + PROP_NAME, g_param_spec_string ( - "component", - _("Component"), - _("Name of the component being logged"), + "name", + _("Name"), + _("Name of the logger"), "anonymous", G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY)); @@ -198,34 +208,24 @@ e_logger_get_type (void) } ELogger * -e_logger_create (const gchar *component) +e_logger_new (const gchar *name) { - g_return_val_if_fail (component != NULL, NULL); + g_return_val_if_fail (name != NULL, NULL); - return g_object_new (E_TYPE_LOGGER, "component", component, NULL); + return g_object_new (E_TYPE_LOGGER, "name", name, NULL); } const gchar * -e_logger_get_component (ELogger *logger) +e_logger_get_name (ELogger *logger) { g_return_val_if_fail (E_IS_LOGGER (logger), NULL); - return logger->priv->component; -} - -static void -set_dirty (ELogger *logger) -{ - if (logger->priv->timer) - return; - - logger->priv->timer = g_timeout_add_seconds ( - TIMEOUT_INTERVAL, (GSourceFunc) flush_logfile, logger); + return logger->priv->name; } void e_logger_log (ELogger *logger, - gint level, + ELogLevel level, gchar *primary, gchar *secondary) { @@ -240,13 +240,13 @@ e_logger_log (ELogger *logger, fprintf (logger->priv->fp, "%d:%ld:%s\n", level, t, primary); fprintf (logger->priv->fp, "%d:%ld:%s\n", level, t, secondary); - set_dirty (logger); + logger_set_dirty (logger); } void e_logger_get_logs (ELogger *logger, ELogFunction func, - gpointer data) + gpointer user_data) { FILE *fp; gchar buf[250]; @@ -288,11 +288,11 @@ e_logger_get_logs (ELogger *logger, g_string_append (str, tmp); } - func (str->str, data); + func (str->str, user_data); g_string_free (str, TRUE); } else - func (tmp, data); + func (tmp, user_data); } fclose (fp); diff --git a/e-util/e-logger.h b/e-util/e-logger.h index b3bd4f8919..efb5cd47f1 100644 --- a/e-util/e-logger.h +++ b/e-util/e-logger.h @@ -20,8 +20,8 @@ * */ -#ifndef __E_LOGGER_H__ -#define __E_LOGGER_H__ +#ifndef E_LOGGER_H +#define E_LOGGER_H #include <glib-object.h> @@ -52,34 +52,32 @@ typedef struct _ELoggerPrivate ELoggerPrivate; typedef void (*ELogFunction) (gchar *line, gpointer data); -enum e_log_level_t { +typedef enum { E_LOG_ERROR, - E_LOG_WARNINGS, + E_LOG_WARNING, E_LOG_DEBUG -}; +} ELogLevel; -/* The object */ struct _ELogger { GObject parent; - - struct _ELoggerPrivate *priv; + ELoggerPrivate *priv; }; struct _ELoggerClass { - GObjectClass popup_class; + GObjectClass parent_class; }; GType e_logger_get_type (void); -ELogger * e_logger_create (const gchar *component); -const gchar * e_logger_get_component (ELogger *logger); +ELogger * e_logger_new (const gchar *name); +const gchar * e_logger_get_name (ELogger *logger); void e_logger_log (ELogger *logger, - gint level, + ELogLevel level, gchar *primary, gchar *secondary); void e_logger_get_logs (ELogger *logger, ELogFunction func, - gpointer data); + gpointer user_data); G_END_DECLS -#endif /* __E_LOGGER_H__ */ +#endif /* E_LOGGER_H */ diff --git a/e-util/e-marshal.list b/e-util/e-marshal.list index 366602491b..d6a3f0cb55 100644 --- a/e-util/e-marshal.list +++ b/e-util/e-marshal.list @@ -66,3 +66,5 @@ NONE:STRING,STRING,STRING NONE:STRING,STRING,UINT OBJECT:OBJECT,DOUBLE,DOUBLE,BOOLEAN POINTER:NONE +STRING:NONE + diff --git a/e-util/e-menu.c b/e-util/e-menu.c deleted file mode 100644 index 76c41b62f5..0000000000 --- a/e-util/e-menu.c +++ /dev/null @@ -1,925 +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 <glib.h> - -#include <glib/gi18n.h> -#include <bonobo/bonobo-ui-util.h> - -#include <libedataserver/e-data-server-util.h> - -#include "e-menu.h" -#include "e-icon-factory.h" - -#define d(x) - -struct _EMenuFactory { - struct _EMenuFactory *next, *prev; - - gchar *menuid; - EMenuFactoryFunc factory; - gpointer factory_data; -}; - -struct _item_node { - struct _item_node *next; - - EMenuItem *item; - struct _menu_node *menu; -}; - -struct _menu_node { - struct _menu_node *next, *prev; - - EMenu *parent; - - GSList *items; - GSList *uis; - GSList *pixmaps; - - EMenuItemsFunc freefunc; - gpointer data; - - /* a copy of items wrapped in an item_node, for bonobo - * callback mapping */ - struct _item_node *menu; -}; - -struct _EMenuPrivate { - EDList menus; -}; - -static GObjectClass *em_parent; - -static void -em_init(GObject *o) -{ - EMenu *emp = (EMenu *)o; - struct _EMenuPrivate *p; - - p = emp->priv = g_malloc0(sizeof(struct _EMenuPrivate)); - - e_dlist_init(&p->menus); -} - -static void -em_finalise(GObject *o) -{ - EMenu *em = (EMenu *)o; - struct _EMenuPrivate *p = em->priv; - struct _menu_node *mnode; - - if (em->target) - e_menu_target_free(em, em->target); - g_free(em->menuid); - - while ((mnode = (struct _menu_node *)e_dlist_remhead(&p->menus))) { - struct _item_node *inode; - - if (mnode->freefunc) - mnode->freefunc(em, mnode->items, mnode->uis, mnode->pixmaps, mnode->data); - - inode = mnode->menu; - while (inode) { - struct _item_node *nnode = inode->next; - - g_free(inode); - inode = nnode; - } - - g_free(mnode); - } - - g_free(p); - - ((GObjectClass *)em_parent)->finalize(o); -} - -static void -em_target_free(EMenu *ep, EMenuTarget *t) -{ - g_free(t); - /* look funny but t has a reference to us */ - g_object_unref(ep); -} - -static void -em_class_init(GObjectClass *klass) -{ - d(printf("EMenu class init %p '%s'\n", klass, g_type_name(((GObjectClass *)klass)->g_type_class.g_type))); - - klass->finalize = em_finalise; - ((EMenuClass *)klass)->target_free = em_target_free; -} - -static void -em_base_init(GObjectClass *klass) -{ - /* each class instance must have its own list, it isn't inherited */ - d(printf("%p: list init\n", klass)); - e_dlist_init(&((EMenuClass *)klass)->factories); -} - -/** - * e_menu_get_type: - * - * Standard GObject type function. Used to subclass this type only. - * - * Return value: The EMenu object type. - **/ -GType -e_menu_get_type(void) -{ - static GType type = 0; - - if (type == 0) { - static const GTypeInfo info = { - sizeof(EMenuClass), - (GBaseInitFunc)em_base_init, NULL, - (GClassInitFunc)em_class_init, - NULL, NULL, - sizeof(EMenu), 0, - (GInstanceInitFunc)em_init - }; - em_parent = g_type_class_ref(G_TYPE_OBJECT); - type = g_type_register_static(G_TYPE_OBJECT, "EMenu", &info, 0); - } - - return type; -} - -/** - * e_menu_construct: - * @em: An instantiated but uninitislied EPopup. - * @menuid: The unique identifier for this menu. - * - * Construct the base menu instance based on the parameters. - * - * Return value: Returns @em. - **/ -EMenu *e_menu_construct(EMenu *em, const gchar *menuid) -{ - struct _EMenuFactory *f; - EMenuClass *klass; - - d(printf("constructing menu '%s'\n", menuid)); - - klass = (EMenuClass *)G_OBJECT_GET_CLASS(em); - - d(printf(" class is %p '%s'\n", klass, g_type_name(((GObjectClass *)klass)->g_type_class.g_type))); - - em->menuid = g_strdup(menuid); - - /* setup the menu itself based on factories */ - f = (struct _EMenuFactory *)klass->factories.head; - if (f->next == NULL) { - d(printf("%p no factories registered on menu\n", klass)); - } - - while (f->next) { - if (f->menuid == NULL - || !strcmp(f->menuid, em->menuid)) { - d(printf(" calling factory\n")); - f->factory(em, f->factory_data); - } - f = f->next; - } - - return em; -} - -/** - * e_menu_add_items: - * @emp: An initialised EMenu. - * @items: A list of EMenuItems or derived structures defining a group - * of menu items for this menu. - * @uifiles: A list of EMenuUIFile objects describing all ui files - * associated with the items. - * @pixmaps: A list of EMenuPixmap objects describing all pixmaps - * associated with the menus. - * @freefunc: If supplied, called when the menu items are no longer needed. - * @data: user-data passed to @freefunc and activate callbacks. - * - * Add new EMenuItems to the menu's. This may be called any number of - * times before the menu is first activated to hook onto any of the - * menu items defined for that view. - * - * Return value: A handle that can be passed to remove_items as required. - **/ -gpointer -e_menu_add_items(EMenu *emp, GSList *items, GSList *uifiles, GSList *pixmaps, EMenuItemsFunc freefunc, gpointer data) -{ - struct _menu_node *node; - GSList *l; - - node = g_malloc0(sizeof(*node)); - node->parent = emp; - node->items = items; - node->uis = uifiles; - node->pixmaps = pixmaps; - node->freefunc = freefunc; - node->data = data; - - for (l=items;l;l=g_slist_next(l)) { - struct _item_node *inode = g_malloc0(sizeof(*inode)); - EMenuItem *item = l->data; - - inode->item = item; - inode->menu = node; - inode->next = node->menu; - node->menu = inode; - } - - for (l=pixmaps;l;l=g_slist_next(l)) { - EMenuPixmap *pixmap = l->data; - - if (pixmap->pixmap == NULL) { - GdkPixbuf *pixbuf; - - pixbuf = e_icon_factory_get_icon(pixmap->name, pixmap->size); - if (pixbuf == NULL) { - g_warning("Unable to load icon '%s'", pixmap->name); - } else { - pixmap->pixmap = bonobo_ui_util_pixbuf_to_xml(pixbuf); - g_object_unref(pixbuf); - } - } - } - - e_dlist_addtail(&emp->priv->menus, (EDListNode *)node); - - /* FIXME: add the menu's to a running menu if it is there? */ - - return (gpointer)node; -} - -/** - * e_menu_remove_items: - * @emp: - * @handle: - * - * Remove menu items previously added. - **/ -void -e_menu_remove_items(EMenu *emp, gpointer handle) -{ - struct _menu_node *node = handle; - struct _item_node *inode; - GSList *l; - - e_dlist_remove((EDListNode *)node); - - if (emp->uic) { - for (l = node->items;l;l=g_slist_next(l)) { - EMenuItem *item = l->data; - - bonobo_ui_component_remove_verb(emp->uic, item->verb); - } - } - - if (node->freefunc) - node->freefunc(emp, node->items, node->uis, node->pixmaps, node->data); - - inode = node->menu; - while (inode) { - struct _item_node *nnode = inode->next; - - g_free(inode); - inode = nnode; - } - - g_free(node); -} - -static void -em_activate_toggle(BonoboUIComponent *component, const gchar *path, Bonobo_UIComponent_EventType type, const gchar *state, gpointer data) -{ - struct _item_node *inode = data; - - if (type != Bonobo_UIComponent_STATE_CHANGED) - return; - - ((EMenuToggleActivateFunc)inode->item->activate)(inode->menu->parent, inode->item, state[0] != '0', inode->menu->data); -} - -static void -em_activate(BonoboUIComponent *uic, gpointer data, const gchar *cname) -{ - struct _item_node *inode = data; - - ((EMenuActivateFunc)inode->item->activate)(inode->menu->parent, inode->item, inode->menu->data); -} - -/** - * e_menu_activate: - * @em: An initialised EMenu. - * @uic: The BonoboUI component for this views menu's. - * @act: If %TRUE, then the control is being activated. - * - * This is called by the owner of the component, control, or view to - * pass on the activate or deactivate control signals. If the view is - * being activated then the callbacks and menu items are setup, - * otherwise they are removed. - * - * This should always be called in the strict sequence of activate, then - * deactivate, repeated any number of times. - **/ -void e_menu_activate(EMenu *em, struct _BonoboUIComponent *uic, gint act) -{ - struct _EMenuPrivate *p = em->priv; - struct _menu_node *mw; - GSList *l; - - if (act) { - GArray *verbs; - gint i; - - em->uic = uic; - - verbs = g_array_new(TRUE, FALSE, sizeof(BonoboUIVerb)); - for (mw = (struct _menu_node *)p->menus.head;mw->next;mw=mw->next) { - struct _item_node *inode; - - for (l = mw->uis; l; l = g_slist_next(l)) { - EMenuUIFile *ui = l->data; - - bonobo_ui_util_set_ui(uic, ui->appdir, ui->filename, ui->appname, NULL); - } - - for (l = mw->pixmaps; l; l = g_slist_next(l)) { - EMenuPixmap *pm = l->data; - - if (pm->pixmap) - bonobo_ui_component_set_prop(uic, pm->command, "pixmap", pm->pixmap, NULL); - } - - for (inode = mw->menu; inode; inode=inode->next) { - EMenuItem *item = inode->item; - BonoboUIVerb *verb; - - d(printf("adding menu verb '%s'\n", item->verb)); - - switch (item->type & E_MENU_TYPE_MASK) { - case E_MENU_ITEM: - i = verbs->len; - verbs = g_array_set_size(verbs, i+1); - verb = &((BonoboUIVerb *)verbs->data)[i]; - - verb->cname = item->verb; - verb->cb = em_activate; - verb->user_data = inode; - break; - case E_MENU_TOGGLE: - bonobo_ui_component_set_prop(uic, item->path, "state", item->type & E_MENU_ACTIVE?"1":"0", NULL); - bonobo_ui_component_add_listener(uic, item->verb, em_activate_toggle, inode); - break; - } - } - } - - if (verbs->len) - bonobo_ui_component_add_verb_list(uic, (BonoboUIVerb *)verbs->data); - - g_array_free(verbs, TRUE); - } else { - for (mw = (struct _menu_node *)p->menus.head;mw->next;mw=mw->next) { - for (l = mw->items;l;l=g_slist_next(l)) { - EMenuItem *item = l->data; - - bonobo_ui_component_remove_verb(uic, item->verb); - } - } - - em->uic = NULL; - } -} - -/** - * e_menu_update_target: - * @em: An initialised EMenu. - * @tp: Target, after this call the menu owns the target. - * - * Change the target for the menu. Once the target is changed, the - * sensitivity state of the menu items managed by @em is re-evaluated - * and the physical menu's updated to reflect it. - * - * This is used by the owner of the menu and view to update the menu - * system based on user input or changed system state. - **/ -void e_menu_update_target(EMenu *em, gpointer tp) -{ - struct _EMenuPrivate *p = em->priv; - EMenuTarget *t = tp; - guint32 mask = ~0; - struct _menu_node *mw; - GSList *l; - - if (em->target && em->target != t) - e_menu_target_free(em, em->target); - - /* if we unset the target, should we disable/hide all the menu items? */ - em->target = t; - if (t == NULL) - return; - - mask = t->mask; - - /* canna do any more capt'n */ - if (em->uic == NULL) - return; - - for (mw = (struct _menu_node *)p->menus.head;mw->next;mw=mw->next) { - for (l = mw->items;l;l=g_slist_next(l)) { - EMenuItem *item = l->data; - gint state; - - d(printf("checking item '%s' mask %08x against target %08x\n", item->verb, item->enable, mask)); - - state = (item->enable & mask) == 0; - bonobo_ui_component_set_prop(em->uic, item->path, "sensitive", state?"1":"0", NULL); - /* visible? */ - } - } -} - -/* ********************************************************************** */ - -/** - * e_menu_class_add_factory: - * @klass: An EMenuClass type to which this factory applies. - * @menuid: The identifier of the menu for this factory, or NULL to be - * called on all menus. - * @func: An EMenuFactoryFunc callback. - * @data: Callback data for @func. - * - * Add a menu factory which will be called when the menu @menuid is - * created. The factory is free to add new items as it wishes to the - * menu provided in the callback. - * - * TODO: Make the menuid a pattern? - * - * Return value: A handle to the factory. - **/ -EMenuFactory * -e_menu_class_add_factory(EMenuClass *klass, const gchar *menuid, EMenuFactoryFunc func, gpointer data) -{ - struct _EMenuFactory *f = g_malloc0(sizeof(*f)); - - d(printf("%p adding factory '%s' to class '%s'\n", klass, menuid?menuid:"<all menus>", g_type_name(((GObjectClass *)klass)->g_type_class.g_type))); - - f->menuid = g_strdup(menuid); - f->factory = func; - f->factory_data = data; - e_dlist_addtail(&klass->factories, (EDListNode *)f); - - /* setup the menu itself based on factories */ - { - struct _EMenuFactory *j; - - j = (struct _EMenuFactory *)klass->factories.head; - if (j->next == NULL) { - d(printf("%p no factories registered on menu???\n", klass)); - } - } - - return f; -} - -/** - * e_menu_class_remove_factory: - * @klass: Class on which the factory was originally added. - * @f: Factory handle. - * - * Remove a popup factory. This must only be called once, and must - * only be called using a valid factory handle @f. After this call, - * @f is undefined. - **/ -void -e_menu_class_remove_factory(EMenuClass *klass, EMenuFactory *f) -{ - e_dlist_remove((EDListNode *)f); - g_free(f->menuid); - g_free(f); -} - -/** - * e_menu_target_new: - * @ep: An EMenu to which this target applies. - * @type: Target type, up to implementation. - * @size: Size of memory to allocate. Must be >= sizeof(EMenuTarget). - * - * Allocate a new menu target suitable for this class. @size is used - * to specify the actual target size, which may vary depending on the - * implementing class. - **/ -gpointer e_menu_target_new(EMenu *ep, gint type, gsize size) -{ - EMenuTarget *t; - - if (size < sizeof(EMenuTarget)) { - g_warning ("size less than size of EMenuTarget\n"); - size = sizeof (EMenuTarget); - } - - t = g_malloc0(size); - t->menu = ep; - g_object_ref(ep); - t->type = type; - - return t; -} - -/** - * e_menu_target_free: - * @ep: EMenu on which the target was allocated. - * @o: Tareget to free. - * - * Free a target. - **/ -void -e_menu_target_free(EMenu *ep, gpointer o) -{ - EMenuTarget *t = o; - - ((EMenuClass *)G_OBJECT_GET_CLASS(ep))->target_free(ep, t); -} - -/* ********************************************************************** */ - -/* Main menu plugin handler */ - -/* NB: This has significant overlap with EPopupHook */ - -/* -<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="Main menu plugin"> - <hook class="org.gnome.evolution.bonobomenu:1.0"> - <menu id="any" target="select" view="org.gnome.mail"> - <ui file="ui file1"/> - <ui file="ui file2"/> - <pixmap command="command" pixmap="stockname" size="menu|button|small_toolbar|large_toolbar|dnd|dialog"/> - <item - type="item|toggle" - verb="verb" - enable="select_one" - visible="select_one" - activate="doactivate"/> - </menu> - </hook> - </extension> - -*/ - -static gpointer emph_parent_class; -#define emph ((EMenuHook *)eph) - -/* must have 1:1 correspondence with e-menu types in order */ -static const EPluginHookTargetKey emph_item_types[] = { - { "item", E_MENU_ITEM }, - { "toggle", E_MENU_TOGGLE }, - { "radio", E_MENU_RADIO }, - { NULL } -}; - -/* 1:1 with e-icon-factory sizes */ -static const EPluginHookTargetKey emph_pixmap_sizes[] = { - { "menu", 0 }, - { "button", 1}, - { "small_toolbar", 2}, - { "large_toolbar", 3}, - { "dnd", 4}, - { "dialog", 5}, - { NULL } -}; - -static void -emph_menu_activate(EMenu *em, EMenuItem *item, gpointer data) -{ - EMenuHook *hook = data; - - d(printf("invoking plugin hook '%s' %p\n", (gchar *)item->user_data, em->target)); - - e_plugin_invoke(hook->hook.plugin, item->user_data, em->target); -} - -static void -emph_menu_toggle_activate(EMenu *em, EMenuItem *item, gint state, gpointer data) -{ - EMenuHook *hook = data; - - /* FIXME: where does the toggle state go? */ - d(printf("invoking plugin hook '%s' %p\n", (gchar *)item->user_data, em->target)); - - e_plugin_invoke(hook->hook.plugin, item->user_data, em->target); -} - -static void -emph_menu_factory(EMenu *emp, gpointer data) -{ - struct _EMenuHookMenu *menu = data; - - d(printf("menu factory, adding %d items\n", g_slist_length(menu->items))); - - if (menu->items) - e_menu_add_items(emp, menu->items, menu->uis, menu->pixmaps, NULL, menu->hook); -} - -static void -emph_free_item(struct _EMenuItem *item) -{ - g_free(item->path); - g_free(item->verb); - g_free(item->user_data); - g_free(item); -} - -static void -emph_free_ui(struct _EMenuUIFile *ui) -{ - g_free(ui->appdir); - g_free(ui->appname); - g_free(ui->filename); -} - -static void -emph_free_pixmap(struct _EMenuPixmap *pixmap) -{ - g_free(pixmap->command); - g_free(pixmap->name); - g_free(pixmap->pixmap); - g_free(pixmap); -} - -static void -emph_free_menu(struct _EMenuHookMenu *menu) -{ - g_slist_foreach(menu->items, (GFunc)emph_free_item, NULL); - g_slist_free(menu->items); - g_slist_foreach(menu->uis, (GFunc)emph_free_ui, NULL); - g_slist_free(menu->uis); - g_slist_foreach(menu->pixmaps, (GFunc)emph_free_pixmap, NULL); - g_slist_free(menu->pixmaps); - - g_free(menu->id); - g_free(menu); -} - -static struct _EMenuItem * -emph_construct_item(EPluginHook *eph, EMenuHookMenu *menu, xmlNodePtr root, EMenuHookTargetMap *map) -{ - struct _EMenuItem *item; - - d(printf(" loading menu item\n")); - item = g_malloc0(sizeof(*item)); - item->type = e_plugin_hook_id(root, emph_item_types, "type"); - item->path = e_plugin_xml_prop(root, "path"); - item->verb = e_plugin_xml_prop(root, "verb"); - 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"); - if ((item->type & E_MENU_TYPE_MASK) == E_MENU_TOGGLE) - item->activate = G_CALLBACK(emph_menu_toggle_activate); - else - item->activate = G_CALLBACK(emph_menu_activate); - - if (item->type == -1 || item->user_data == NULL) - goto error; - - d(printf(" path=%s\n", item->path)); - d(printf(" verb=%s\n", item->verb)); - - return item; -error: - d(printf("error!\n")); - emph_free_item(item); - return NULL; -} - -static struct _EMenuPixmap * -emph_construct_pixmap(EPluginHook *eph, EMenuHookMenu *menu, xmlNodePtr root) -{ - struct _EMenuPixmap *pixmap; - - d(printf(" loading menu pixmap\n")); - pixmap = g_malloc0(sizeof(*pixmap)); - pixmap->command = e_plugin_xml_prop(root, "command"); - pixmap->name = e_plugin_xml_prop(root, "pixmap"); - pixmap->size = e_plugin_hook_id(root, emph_pixmap_sizes, "size"); - - if (pixmap->command == NULL || pixmap->name == NULL || pixmap->size == -1) - goto error; - - return pixmap; -error: - d(printf("error!\n")); - emph_free_pixmap(pixmap); - return NULL; -} - -static struct _EMenuHookMenu * -emph_construct_menu(EPluginHook *eph, xmlNodePtr root) -{ - struct _EMenuHookMenu *menu; - xmlNodePtr node; - EMenuHookTargetMap *map; - EMenuHookClass *klass = (EMenuHookClass *)G_OBJECT_GET_CLASS(eph); - gchar *tmp; - - d(printf(" loading menu\n")); - menu = g_malloc0(sizeof(*menu)); - menu->hook = (EMenuHook *)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 menu for '%s'\n", eph->plugin->name, - ((EPluginHookClass *)G_OBJECT_GET_CLASS(eph))->id); - goto error; - } - node = root->children; - while (node) { - if (0 == strcmp((gchar *)node->name, "item")) { - struct _EMenuItem *item; - - item = emph_construct_item(eph, menu, node, map); - if (item) - menu->items = g_slist_append(menu->items, item); - } else if (0 == strcmp((gchar *)node->name, "ui")) { - tmp = (gchar *)xmlGetProp(node, (const guchar *)"file"); - if (tmp) { - EMenuUIFile *ui = g_malloc0(sizeof(*ui)); - - ui->filename = g_strdup(tmp); - xmlFree(tmp); -#ifdef G_OS_WIN32 - { - gchar *mapped_location = - e_util_replace_prefix (EVOLUTION_PREFIX, - e_util_get_prefix (), - ui->filename); - g_free (ui->filename); - ui->filename = mapped_location; - } -#endif - ui->appdir = g_strdup(g_get_tmp_dir()); - ui->appname = g_strdup("Evolution"); - menu->uis = g_slist_append(menu->uis, ui); - } - } else if (0 == strcmp((gchar *)node->name, "pixmap")) { - struct _EMenuPixmap *pixmap; - - pixmap = emph_construct_pixmap(eph, menu, node); - if (pixmap) - menu->pixmaps = g_slist_append(menu->pixmaps, pixmap); - } - node = node->next; - } - - return menu; -error: - d(printf("error loading menu hook\n")); - emph_free_menu(menu); - return NULL; -} - -static gint -emph_construct(EPluginHook *eph, EPlugin *ep, xmlNodePtr root) -{ - xmlNodePtr node; - EMenuClass *klass; - - d(printf("loading menu hook\n")); - - if (!ep->enabled) - return 0; - - if (((EPluginHookClass *)emph_parent_class)->construct(eph, ep, root) == -1) - return -1; - - klass = ((EMenuHookClass *)G_OBJECT_GET_CLASS(eph))->menu_class; - - node = root->children; - while (node) { - if (strcmp((gchar *)node->name, "menu") == 0) { - struct _EMenuHookMenu *menu; - - menu = emph_construct_menu(eph, node); - if (menu) { - d(printf(" plugin adding factory %p\n", klass)); - e_menu_class_add_factory(klass, menu->id, emph_menu_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) -{ - d(printf("EMenuHook class init %p '%s'\n", klass, g_type_name(((GObjectClass *)klass)->g_type_class.g_type))); - - ((GObjectClass *)klass)->finalize = emph_finalise; - klass->construct = emph_construct; - - /* this is actually an abstract implementation but list it anyway */ - klass->id = "org.gnome.evolution.bonobomenu:1.0"; - - ((EMenuHookClass *)klass)->target_map = g_hash_table_new(g_str_hash, g_str_equal); - ((EMenuHookClass *)klass)->menu_class = g_type_class_ref(e_menu_get_type()); -} - -/** - * e_menu_hook_get_type: - * - * Standard GObject function to get the object type. Used to subclass - * EMenuHook. - * - * Return value: The type of the menu hook class. - **/ -GType -e_menu_hook_get_type(void) -{ - static GType type = 0; - - if (!type) { - static const GTypeInfo info = { - sizeof(EMenuHookClass), NULL, NULL, (GClassInitFunc) emph_class_init, NULL, NULL, - sizeof(EMenuHook), 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(), "EMenuHook", &info, 0); - } - - return type; -} - -/** - * e_menu_hook_class_add_target_map: - * @klass: The derived EMenuHook class. - * @map: A map used to describe a single EMenuTarget for this class. - * - * Adds a target map to a concrete derived class of EMenu. The target - * map enumerates a single target type, and the enable mask bit names, - * so that the type can be loaded automatically by the EMenu class. - **/ -void e_menu_hook_class_add_target_map(EMenuHookClass *klass, const EMenuHookTargetMap *map) -{ - g_hash_table_insert(klass->target_map, (gpointer)map->type, (gpointer)map); -} diff --git a/e-util/e-menu.h b/e-util/e-menu.h deleted file mode 100644 index 3b2416e46a..0000000000 --- a/e-util/e-menu.h +++ /dev/null @@ -1,319 +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: - * Michel Zucchi <notzed@ximian.com> - * - * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com) - * - */ - -#ifndef __E_MENU_H__ -#define __E_MENU_H__ - -#include <gtk/gtk.h> -#include <libedataserver/e-msgport.h> - -G_BEGIN_DECLS - -/* This is an abstract popup menu management/merging class. - - To implement your own popup menu system, just create your own - target types and implement the target free method. */ - -typedef struct _EMenu EMenu; -typedef struct _EMenuClass EMenuClass; - -typedef struct _EMenuItem EMenuItem; -typedef struct _EMenuUIFile EMenuUIFile; -typedef struct _EMenuPixmap EMenuPixmap; - -typedef struct _EMenuFactory EMenuFactory; /* anonymous type */ -typedef struct _EMenuTarget EMenuTarget; - -typedef void (*EMenuFactoryFunc)(EMenu *emp, gpointer data); -typedef void (*EMenuActivateFunc)(EMenu *, EMenuItem *, gpointer data); -typedef void (*EMenuToggleActivateFunc)(EMenu *, EMenuItem *, gint state, gpointer data); -typedef void (*EMenuItemsFunc)(EMenu *, GSList *items, GSList *uifiles, GSList *pixmaps, gpointer data); - -/** - * enum _e_menu_t - Menu item type. - * - * @E_MENU_ITEM: Normal menu item. - * @E_MENU_TOGGLE: Toggle menu item. - * @E_MENU_RADIO: unimplemented. - * @E_MENU_TYPE_MASK: Mask used to separate item type from option bits. - * @E_MENU_ACTIVE: Whether a toggle item is active. - * - * The type of menu items which are supported by the menu system. - **/ -enum _e_menu_t { - E_MENU_ITEM = 0, - E_MENU_TOGGLE, - E_MENU_RADIO, - E_MENU_TYPE_MASK = 0xffff, - E_MENU_ACTIVE = 0x10000 -}; - -/** - * struct _EMenuItem - A BonoboUI menu item. - * - * @type: Menu item type. %E_MENU_ITEM or %E_MENU_TOGGLE. - * @path: BonoboUI Path to the menu item. - * @verb: BonoboUI verb for the menu item. - * @activate: Callback when the menu item is selected. This will be a - * EMenuToggleActivateFunc for toggle items or EMenuActivateFunc for - * normal items. - * @user_data: User data for item. - * @visible: Visibility mask, unimplemented. - * @enable: Sensitivity mask, combined with the target mask. - * - * An EMenuItem defines a single menu item. This menu item is used to - * hook onto callbacks from the bonobo menus, but not to build or - * merge the menu itself. - **/ -struct _EMenuItem { - enum _e_menu_t type; - gchar *path; /* full path? can we just create it from verb? */ - gchar *verb; /* command verb */ - GCallback activate; /* depends on type, the bonobo activate callback */ - gpointer user_data; /* up to caller to use */ - guint32 visible; /* is visible mask */ - guint32 enable; /* is enable mask */ -}; - -/** - * struct _EMenuPixmap - A menu icon holder. - * - * @command: The path to the command or verb to which this pixmap belongs. - * @name: The name of the icon. Either an icon-theme name or the full - * pathname of the icon. - * @size: The e-icon-factory icon size. - * @pixmap: The pixmap converted to XML format. If not set, then EMenu will - * create it as required. This must be freed if set in the free function. - * - * Used to track all pixmap items used in menus. These need to be - * supplied separately from the menu definition. - **/ -struct _EMenuPixmap { - gchar *command; - gchar *name; - gint size; - gchar *pixmap; -}; - -/** - * struct _EMenuUIFile - A meu UI file holder. - * - * @appdir: TODO; should this be handled internally. - * @appname: TODO; should this be handled internally. - * @filename: The filename of the BonoboUI XML menu definition. - * - * These values are passed directly to bonobo_ui_util_set_ui() when - * the menu is activated. - **/ -struct _EMenuUIFile { - gchar *appdir; - gchar *appname; - gchar *filename; -}; - -/** - * struct _EMenuTarget - A BonoboUI menu target definition. - * - * @menu: The parent menu object, used for virtual methods on the target. - * @widget: The parent widget where available. In some cases the type - * of this object is part of the published api for the target, in - * others it is merely a GtkWidget from which you can find the - * toplevel widget. - * @type: Target type. This will be defined by the implementation. - * @mask: Target mask. This is used to sensitise show items based on - * their definition in EMenuItem. - * - * An EMenuTarget defines the context for a specific view instance. - * It is used to enable and show menu items, and to provide contextual - * data to menu invocations. - **/ -struct _EMenuTarget { - struct _EMenu *menu; /* used for virtual methods */ - - GtkWidget *widget; /* used if you need a parent toplevel, if available */ - guint32 type; /* for implementors */ - - guint32 mask; /* enable/visible mask */ - - /* implementation fields follow */ -}; - -/** - * struct _EMenu - A BonoboUI menu manager object. - * - * @object: Superclass. - * @priv: Private data. - * @menuid: The id of this menu instance. - * @uic: The current BonoboUIComponent which stores the actual menu - * items this object manages. - * @target: The current target for the view. - * - * The EMenu manager object manages the mappings between EMenuItems - * and the BonoboUI menus loaded from UI files. - **/ -struct _EMenu { - GObject object; - struct _EMenuPrivate *priv; - - gchar *menuid; - struct _BonoboUIComponent *uic; - EMenuTarget *target; -}; - -/** - * struct _EMenuClass - - * - * @object_class: Superclass type. - * @factories: A list of factories for this particular class of main menu. - * @target_free: Virtual method to free the menu target. The base - * class free method frees the allocation and unrefs the EMenu parent - * pointer. - * - * The EMenu class definition. This should be sub-classed for each - * component that wants to provide hookable main menus. The subclass - * only needs to know how to allocate and free the various target - * types it supports. - **/ -struct _EMenuClass { - GObjectClass object_class; - - EDList factories; - - void (*target_free)(EMenu *ep, EMenuTarget *t); -}; - -GType e_menu_get_type(void); - -/* Static class methods */ -EMenuFactory *e_menu_class_add_factory(EMenuClass *klass, const gchar *menuid, EMenuFactoryFunc func, gpointer data); -void e_menu_class_remove_factory(EMenuClass *klass, EMenuFactory *f); - -EMenu *e_menu_construct(EMenu *menu, const gchar *menuid); - -void e_menu_add_ui(EMenu *, const gchar *appdir, const gchar *appname, const gchar *filename); -void e_menu_add_pixmap(EMenu *, const gchar *cmd, const gchar *name, gint size); - -gpointer e_menu_add_items(EMenu *emp, GSList *items, GSList *uifiles, GSList *pixmaps, EMenuItemsFunc freefunc, gpointer data); -void e_menu_remove_items(EMenu *emp, gpointer handle); - -void e_menu_activate(EMenu *, struct _BonoboUIComponent *uic, gint act); -void e_menu_update_target(EMenu *, gpointer ); - -gpointer e_menu_target_new(EMenu *, gint type, gsize size); -void e_menu_target_free(EMenu *, gpointer ); - -/* ********************************************************************** */ - -/* menu plugin, they are closely integrated */ - -/* To implement a basic menu plugin, you just need to subclass - this and initialise the class target type tables */ - -#include "e-util/e-plugin.h" - -typedef struct _EMenuHookPixmap EMenuHookPixmap; -typedef struct _EMenuHookMenu EMenuHookMenu; -typedef struct _EMenuHook EMenuHook; -typedef struct _EMenuHookClass EMenuHookClass; - -typedef struct _EPluginHookTargetMap EMenuHookTargetMap; -typedef struct _EPluginHookTargetKey EMenuHookTargetMask; - -typedef void (*EMenuHookFunc)(struct _EPlugin *plugin, EMenuTarget *target); - -/** - * struct _EMenuHookMenu - A group of items targetting a specific menu. - * - * @hook: Parent pointer. - * @id: The identifier of the menu or view to which these items belong. - * @target_type: The target number of the type of target these menu - * items expect. This will be defined by menu itself. - * @items: A list of EMenuItems. - * @uis: A list of filenames of the BonoboUI files that need to be - * loaded for an active view. - * @pixmaps: A list of EMenuHookPixmap structures for the menus. - * - * This structure is used to keep track of all of the items that a - * plugin wishes to add to specific menu. This is used internally by - * a factory method defined by the EMenuHook to add the right menu - * items to a given view. - **/ -struct _EMenuHookMenu { - struct _EMenuHook *hook; /* parent pointer */ - gchar *id; /* target menu id for these menu items */ - gint target_type; /* target type, not used */ - GSList *items; /* items to add to menu */ - GSList *uis; /* ui files */ - GSList *pixmaps; /* pixmap descriptors */ -}; - -/** - * struct _EMenuHook - A BonoboUI menu hook. - * - * @hook: Superclass. - * @menus: A list of EMenuHookMenus for all menus registered on this - * hook type. - * - * The EMenuHook class loads and manages the meta-data to required to - * map plugin definitions to physical menus. - **/ -struct _EMenuHook { - EPluginHook hook; - - GSList *menus; -}; - -/** - * struct _EMenuHookClass - Menu hook type. - * - * @hook_class: Superclass type. - * @target_map: Table of EluginHookTargetMaps which enumerate the - * target types and enable bits of the implementing class. - * @menu_class: The EMenuClass of the corresponding popup manager for - * implementing the class. - * - * The EMenuHookClass is an empty concrete class. It must be - * subclassed and initialised appropriately to perform useful work. - * - * The EPluginHookClass.id must be set to the name and version of the - * hook handler the implementation defines. The @target_map must be - * initialised with the data required to enumerate the target types - * and enable flags supported by the implementing class. - **/ -struct _EMenuHookClass { - EPluginHookClass hook_class; - - /* EMenuHookTargetMap by .type */ - GHashTable *target_map; - /* the menu class these menus belong to */ - EMenuClass *menu_class; -}; - -GType e_menu_hook_get_type(void); - -/* for implementors */ -void e_menu_hook_class_add_target_map(EMenuHookClass *klass, const EMenuHookTargetMap *); - -G_END_DECLS - -#endif /* __E_MENU_H__ */ diff --git a/e-util/e-module.c b/e-util/e-module.c new file mode 100644 index 0000000000..3919841910 --- /dev/null +++ b/e-util/e-module.c @@ -0,0 +1,318 @@ +/* + * e-module.c + * + * 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/> + * + * + * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com) + * + */ + +#include "e-module.h" + +#include <glib/gi18n.h> + +/* This is the symbol we call when loading a module. */ +#define LOAD_SYMBOL "e_module_load" + +/* This is the symbol we call when unloading a module. */ +#define UNLOAD_SYMBOL "e_module_unload" + +#define E_MODULE_GET_PRIVATE(obj) \ + (G_TYPE_INSTANCE_GET_PRIVATE \ + ((obj), E_TYPE_MODULE, EModulePrivate)) + +struct _EModulePrivate { + GModule *module; + gchar *filename; + + void (*load) (GTypeModule *type_module); + void (*unload) (GTypeModule *type_module); +}; + +enum { + PROP_0, + PROP_FILENAME +}; + +static gpointer parent_class; + +static void +module_set_filename (EModule *module, + const gchar *filename) +{ + g_return_if_fail (module->priv->filename == NULL); + + module->priv->filename = g_strdup (filename); +} + +static void +module_set_property (GObject *object, + guint property_id, + const GValue *value, + GParamSpec *pspec) +{ + switch (property_id) { + case PROP_FILENAME: + module_set_filename ( + E_MODULE (object), + g_value_get_string (value)); + return; + } + + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); +} + +static void +module_get_property (GObject *object, + guint property_id, + GValue *value, + GParamSpec *pspec) +{ + switch (property_id) { + case PROP_FILENAME: + g_value_set_string ( + value, e_module_get_filename ( + E_MODULE (object))); + return; + } + + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); +} + +static void +module_finalize (GObject *object) +{ + EModulePrivate *priv; + + priv = E_MODULE_GET_PRIVATE (object); + + g_free (priv->filename); + + /* Chain up to parent's finalize() method. */ + G_OBJECT_CLASS (parent_class)->finalize (object); +} + +static gboolean +module_load (GTypeModule *type_module) +{ + EModulePrivate *priv; + gpointer symbol; + + priv = E_MODULE_GET_PRIVATE (type_module); + + g_return_val_if_fail (priv->filename != NULL, FALSE); + priv->module = g_module_open (priv->filename, 0); + + if (priv->module == NULL) + goto fail; + + if (!g_module_symbol (priv->module, LOAD_SYMBOL, &symbol)) + goto fail; + + priv->load = symbol; + + if (!g_module_symbol (priv->module, UNLOAD_SYMBOL, &symbol)) + goto fail; + + priv->unload = symbol; + + priv->load (type_module); + + return TRUE; + +fail: + g_warning ("%s", g_module_error ()); + + if (priv->module != NULL) + g_module_close (priv->module); + + return FALSE; +} + +static void +module_unload (GTypeModule *type_module) +{ + EModulePrivate *priv; + + priv = E_MODULE_GET_PRIVATE (type_module); + + priv->unload (type_module); + + g_module_close (priv->module); + priv->module = NULL; + + priv->load = NULL; + priv->unload = NULL; +} + +static void +module_class_init (EModuleClass *class) +{ + GObjectClass *object_class; + GTypeModuleClass *type_module_class; + + parent_class = g_type_class_peek_parent (class); + g_type_class_add_private (class, sizeof (EModulePrivate)); + + object_class = G_OBJECT_CLASS (class); + object_class->set_property = module_set_property; + object_class->get_property = module_get_property; + object_class->finalize = module_finalize; + + type_module_class = G_TYPE_MODULE_CLASS (class); + type_module_class->load = module_load; + type_module_class->unload = module_unload; + + /** + * EModule:filename + * + * The filename of the module. + **/ + g_object_class_install_property ( + object_class, + PROP_FILENAME, + g_param_spec_string ( + "filename", + _("Filename"), + _("The filename of the module"), + NULL, + G_PARAM_READWRITE | + G_PARAM_CONSTRUCT_ONLY)); +} + +static void +module_init (EModule *module) +{ + module->priv = E_MODULE_GET_PRIVATE (module); +} + +GType +e_module_get_type (void) +{ + static GType type = 0; + + if (G_UNLIKELY (type == 0)) { + const GTypeInfo type_info = { + sizeof (EModuleClass), + (GBaseInitFunc) NULL, + (GBaseFinalizeFunc) NULL, + (GClassInitFunc) module_class_init, + (GClassFinalizeFunc) NULL, + NULL, /* class_data */ + sizeof (EModule), + 0, /* n_preallocs */ + (GInstanceInitFunc) module_init, + NULL /* value_table */ + }; + + type = g_type_register_static ( + G_TYPE_TYPE_MODULE, "EModule", &type_info, 0); + } + + return type; +} + +/** + * e_module_new: + * @filename: filename of the shared library module + * + * Creates a new #EModule that will load the specific shared library + * when in use. + * + * Returns: a new #EModule for @filename + **/ +EModule * +e_module_new (const gchar *filename) +{ + g_return_val_if_fail (filename != NULL, NULL); + + return g_object_new (E_TYPE_MODULE, "filename", filename, NULL); +} + +/** + * e_module_get_filename: + * @module: an #EModule + * + * Returns the filename of the shared library for @module. The + * string is owned by @module and should not be modified or freed. + * + * Returns: the filename for @module + **/ +const gchar * +e_module_get_filename (EModule *module) +{ + g_return_val_if_fail (E_IS_MODULE (module), NULL); + + return module->priv->filename; +} + +/** + * e_module_load_all_in_directory: + * @dirname: pathname for a directory containing modules to load + * + * Loads all the modules in the specified directory into memory. If + * you want to unload them (enabling on-demand loading) you must call + * g_type_module_unuse() on all the modules. Free the returned list + * with g_list_free(). + * + * Returns: a list of #EModules loaded from @dirname + **/ +GList * +e_module_load_all_in_directory (const gchar *dirname) +{ + GDir *dir; + const gchar *basename; + GList *loaded_modules = NULL; + GError *error = NULL; + + g_return_val_if_fail (dirname != NULL, NULL); + + if (!g_module_supported ()) + return NULL; + + dir = g_dir_open (dirname, 0, &error); + if (dir == NULL) { + g_warning ("%s", error->message); + g_error_free (error); + return NULL; + } + + while ((basename = g_dir_read_name (dir)) != NULL) { + EModule *module; + gchar *filename; + + if (!g_str_has_suffix (basename, "." G_MODULE_SUFFIX)) + continue; + + filename = g_build_filename (dirname, basename, NULL); + + module = e_module_new (filename); + + if (!g_type_module_use (G_TYPE_MODULE (module))) { + g_printerr ("Failed to load module: %s\n", filename); + g_object_unref (module); + g_free (filename); + continue; + } + + g_free (filename); + + loaded_modules = g_list_prepend (loaded_modules, module); + } + + g_dir_close (dir); + + return loaded_modules; +} diff --git a/e-util/e-module.h b/e-util/e-module.h new file mode 100644 index 0000000000..a8120563d3 --- /dev/null +++ b/e-util/e-module.h @@ -0,0 +1,81 @@ +/* + * e-module.h + * + * 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/> + * + * + * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com) + * + */ + +/** + * SECTION: e-module + * @short_description: generic module loader + * @include: e-util/e-module.h + **/ + +#ifndef E_MODULE_H +#define E_MODULE_H + +#include <gmodule.h> +#include <glib-object.h> + +/* Standard GObject macros */ +#define E_TYPE_MODULE \ + (e_module_get_type ()) +#define E_MODULE(obj) \ + (G_TYPE_CHECK_INSTANCE_CAST \ + ((obj), E_TYPE_MODULE, EModule)) +#define E_MODULE_CLASS(cls) \ + (G_TYPE_CHECK_CLASS_CAST \ + ((cls), E_TYPE_MODULE, EModuleClass)) +#define E_IS_MODULE(obj) \ + (G_TYPE_CHECK_INSTANCE_TYPE \ + ((obj), E_TYPE_MODULE)) +#define E_IS_MODULE_CLASS(cls) \ + (G_TYPE_CHECK_CLASS_TYPE \ + ((cls), E_TYPE_MODULE)) +#define E_MODULE_GET_CLASS(obj) \ + (G_TYPE_INSTANCE_GET_CLASS \ + ((obj), E_TYPE_MODULE, EModuleClass)) + +G_BEGIN_DECLS + +typedef struct _EModule EModule; +typedef struct _EModuleClass EModuleClass; +typedef struct _EModulePrivate EModulePrivate; + +/** + * EModule: + * + * Contains only private data that should be read and manipulated using the + * functions below. + **/ +struct _EModule { + GTypeModule parent; + EModulePrivate *priv; +}; + +struct _EModuleClass { + GTypeModuleClass parent_class; +}; + +GType e_module_get_type (void); +EModule * e_module_new (const gchar *filename); +const gchar * e_module_get_filename (EModule *module); +GList * e_module_load_all_in_directory (const gchar *dirname); + +G_END_DECLS + +#endif /* E_MODULE_H */ diff --git a/e-util/e-non-intrusive-error-dialog.c b/e-util/e-non-intrusive-error-dialog.c index 7831c59f58..e36190fc9a 100644 --- a/e-util/e-non-intrusive-error-dialog.c +++ b/e-util/e-non-intrusive-error-dialog.c @@ -306,4 +306,3 @@ eni_show_logger(ELogger *logger, GtkWidget *top,const gchar *error_timeout_path, gtk_widget_show_all (window); } - diff --git a/e-util/e-non-intrusive-error-dialog.h b/e-util/e-non-intrusive-error-dialog.h index 0adbd0c789..4c38808ea2 100644 --- a/e-util/e-non-intrusive-error-dialog.h +++ b/e-util/e-non-intrusive-error-dialog.h @@ -37,7 +37,7 @@ struct _log_data { GdkPixbuf *pbuf; } ldata [] = { { E_LOG_ERROR, N_("Error"), N_("Errors"), GTK_STOCK_DIALOG_ERROR }, - { E_LOG_WARNINGS, N_("Warning"), N_("Warnings and Errors"), GTK_STOCK_DIALOG_WARNING }, + { E_LOG_WARNING, N_("Warning"), N_("Warnings and Errors"), GTK_STOCK_DIALOG_WARNING }, { E_LOG_DEBUG, N_("Debug"), N_("Error, Warnings and Debug messages"), GTK_STOCK_DIALOG_INFO } }; diff --git a/e-util/e-plugin-ui.c b/e-util/e-plugin-ui.c index 6af3290bb6..4f948fbb2f 100644 --- a/e-util/e-plugin-ui.c +++ b/e-util/e-plugin-ui.c @@ -25,7 +25,6 @@ #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 { @@ -33,9 +32,11 @@ struct _EPluginUIHookPrivate { * * For example: * - * <ui-manager id="org.gnome.evolution.sample"> - * ... UI definition ... - * </ui-manager> + * <hook class="org.gnome.evolution.ui:1.0"> + * <ui-manager id="org.gnome.evolution.sample"> + * ... UI definition ... + * </ui-manager> + * </hook> * * Results in: * @@ -49,197 +50,310 @@ struct _EPluginUIHookPrivate { * optional. */ GHashTable *ui_definitions; + + /* The registry is the heart of EPluginUI. It tracks GtkUIManager + * instances, GtkUIManager IDs, and UI merge IDs as a hash table of + * hash tables: + * + * GtkUIManager instance -> GtkUIManager ID -> UI Merge ID + * + * A GtkUIManager instance and ID form a unique key for looking up + * UI merge IDs. The reason both are needed is because the same + * GtkUIManager instance and be registered under multiple IDs. + * + * This is done primarily to support shell views, which share a + * common GtkUIManager instance for a particular shell window. + * Each shell view registers the same GtkUIManager instance under + * a unique ID: + * + * "org.gnome.evolution.mail" } + * "org.gnome.evolution.contacts" } aliases for a common + * "org.gnome.evolution.calendar" } GtkUIManager instance + * "org.gnome.evolution.memos" } + * "org.gnome.evolution.tasks" } + * + * Note: The shell window also registers the same GtkUIManager + * instance as "org.gnome.evolution.shell". + * + * This way, plugins that extend a shell view's UI will follow the + * merging and unmerging of the shell view automatically. + * + * The presence or absence of GtkUIManager IDs in the registry is + * significant. Presence of a (instance, ID) pair indicates that + * UI manager is active, absence indicates inactive. Furthermore, + * a non-zero merge ID for an active UI manager indicates the + * plugin is enabled. Zero indicates disabled. + * + * Here's a quick scenario to illustrate: + * + * Suppose we have a plugin that extends the mail shell view UI. + * Its EPlugin definition file has this section: + * + * <hook class="org.gnome.evolution.ui:1.0"> + * <ui-manager id="org.gnome.evolution.mail"> + * ... UI definition ... + * </ui-manager> + * </hook> + * + * The plugin is enabled and the active shell view is "mail". + * Let "ManagerA" denote the common GtkUIManager instance for + * this shell window. Here's what happens to the registry as + * the user performs various actions; + * + * - Initial State Merge ID + * V + * { "ManagerA", { "org.gnome.evolution.mail", 3 } } + * + * - User Disables the Plugin + * + * { "ManagerA", { "org.gnome.evolution.mail", 0 } } + * + * - User Enables the Plugin + * + * { "ManagerA", { "org.gnome.evolution.mail", 4 } } + * + * - User Switches to Calendar View + * + * { "ManagerA", { } } + * + * - User Disables the Plugin + * + * { "ManagerA", { } } + * + * - User Switches to Mail View + * + * { "ManagerA", { "org.gnome.evolution.mail", 0 } } + * + * - User Enables the Plugin + * + * { "ManagerA", { "org.gnome.evolution.mail", 5 } } + */ + GHashTable *registry; }; -/* 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 *ui_manager) +plugin_ui_hook_unregister_manager (EPluginUIHook *hook, + GtkUIManager *ui_manager) { - GHashTable *hash_table; + GHashTable *registry; /* 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, ui_manager); - if (g_hash_table_size (hash_table) == 0) - g_hash_table_remove (registry, hook); + registry = hook->priv->registry; + g_hash_table_remove (registry, ui_manager); } static void -plugin_ui_registry_insert (EPluginUIHook *hook, - GtkUIManager *ui_manager, - guint merge_id) +plugin_ui_hook_register_manager (EPluginUIHook *hook, + GtkUIManager *ui_manager, + gpointer user_data) { + EPlugin *plugin; + EPluginUIInitFunc func; + GHashTable *registry; GHashTable *hash_table; - 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); - } + 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 (ui_manager, user_data)) + return; g_object_weak_ref ( G_OBJECT (ui_manager), (GWeakNotify) - plugin_ui_registry_remove, hook); + plugin_ui_hook_unregister_manager, hook); - g_hash_table_insert ( - hash_table, ui_manager, GUINT_TO_POINTER (merge_id)); + registry = hook->priv->registry; + hash_table = g_hash_table_lookup (registry, ui_manager); + + if (hash_table == NULL) { + hash_table = g_hash_table_new_full ( + g_str_hash, g_str_equal, + (GDestroyNotify) g_free, + (GDestroyNotify) NULL); + g_hash_table_insert (registry, ui_manager, hash_table); + } } -/* Helper for plugin_ui_hook_merge_ui() */ -static void -plugin_ui_hook_merge_foreach (GtkUIManager *ui_manager, - const gchar *ui_definition, - GHashTable *hash_table) +static guint +plugin_ui_hook_merge_ui (EPluginUIHook *hook, + GtkUIManager *ui_manager, + const gchar *id) { + GHashTable *hash_table; + const gchar *ui_definition; guint merge_id; GError *error = NULL; - /* Merge the UI definition into the manager. */ + hash_table = hook->priv->ui_definitions; + ui_definition = g_hash_table_lookup (hash_table, id); + g_return_val_if_fail (ui_definition != NULL, 0); + merge_id = gtk_ui_manager_add_ui_from_string ( ui_manager, ui_definition, -1, &error); - gtk_ui_manager_ensure_update (ui_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, ui_manager, GUINT_TO_POINTER (merge_id)); + return merge_id; } static void -plugin_ui_hook_merge_ui (EPluginUIHook *hook) +plugin_ui_enable_manager (EPluginUIHook *hook, + GtkUIManager *ui_manager, + const gchar *id) { - GHashTable *old_merge_ids; - GHashTable *new_merge_ids; - GHashTable *intermediate; + GHashTable *hash_table; + GHashTable *ui_definitions; GList *keys; - old_merge_ids = g_hash_table_lookup (registry, hook); - if (old_merge_ids == NULL) - return; + hash_table = hook->priv->registry; + hash_table = g_hash_table_lookup (hash_table, ui_manager); - /* 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); + if (hash_table == NULL) + return; - while (keys != NULL) { - GtkUIManager *ui_manager = keys->data; - gchar *ui_definition; + if (id != NULL) + keys = g_list_prepend (NULL, (gpointer) id); + else + keys = g_hash_table_get_keys (hash_table); - ui_definition = g_hash_table_lookup ( - hook->priv->ui_definitions, - e_plugin_ui_get_manager_id (ui_manager)); + ui_definitions = hook->priv->ui_definitions; - g_hash_table_insert (intermediate, ui_manager, ui_definition); + while (keys != NULL) { + guint merge_id; + gpointer data; + id = keys->data; keys = g_list_delete_link (keys, keys); - } - new_merge_ids = g_hash_table_new (g_direct_hash, g_direct_equal); + if (g_hash_table_lookup (ui_definitions, id) == NULL) + continue; + + data = g_hash_table_lookup (hash_table, id); + merge_id = GPOINTER_TO_UINT (data); - g_hash_table_foreach ( - intermediate, (GHFunc) - plugin_ui_hook_merge_foreach, new_merge_ids); + if (merge_id > 0) + continue; - g_hash_table_insert (registry, hook, new_merge_ids); + if (((EPluginHook *) hook)->plugin->enabled) + merge_id = plugin_ui_hook_merge_ui ( + hook, ui_manager, id); - g_hash_table_destroy (intermediate); + /* Merge ID will be 0 on error, which is what we want. */ + data = GUINT_TO_POINTER (merge_id); + g_hash_table_insert (hash_table, g_strdup (id), data); + } } -/* Helper for plugin_ui_hook_unmerge_ui() */ static void -plugin_ui_hook_unmerge_foreach (GtkUIManager *ui_manager, - gpointer value, - GHashTable *hash_table) +plugin_ui_disable_manager (EPluginUIHook *hook, + GtkUIManager *ui_manager, + const gchar *id, + gboolean remove) { - guint merge_id; + GHashTable *hash_table; + GHashTable *ui_definitions; + GList *keys; + + hash_table = hook->priv->registry; + hash_table = g_hash_table_lookup (hash_table, ui_manager); + + if (hash_table == NULL) + return; + + if (id != NULL) + keys = g_list_prepend (NULL, (gpointer) id); + else + keys = g_hash_table_get_keys (hash_table); + + ui_definitions = hook->priv->ui_definitions; + + while (keys != NULL) { + guint merge_id; + gpointer data; - merge_id = GPOINTER_TO_UINT (value); - gtk_ui_manager_remove_ui (ui_manager, merge_id); + id = keys->data; + keys = g_list_delete_link (keys, keys); + + if (g_hash_table_lookup (ui_definitions, id) == NULL) + continue; - g_hash_table_insert (hash_table, ui_manager, GUINT_TO_POINTER (0)); + data = g_hash_table_lookup (hash_table, id); + merge_id = GPOINTER_TO_UINT (data); + + /* Merge ID could be 0 if the plugin is disabled. */ + if (merge_id > 0) + gtk_ui_manager_remove_ui (ui_manager, merge_id); + + if (remove) + g_hash_table_remove (hash_table, id); + else + g_hash_table_insert (hash_table, g_strdup (id), NULL); + } } static void -plugin_ui_hook_unmerge_ui (EPluginUIHook *hook) +plugin_ui_enable_hook (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; + GHashTable *hash_table; + GHashTableIter iter; + gpointer key; - new_merge_ids = g_hash_table_new (g_direct_hash, g_direct_equal); + /* Enable all GtkUIManagers for this hook. */ - g_hash_table_foreach ( - old_merge_ids, (GHFunc) - plugin_ui_hook_unmerge_foreach, new_merge_ids); + hash_table = hook->priv->registry; + g_hash_table_iter_init (&iter, hash_table); - g_hash_table_insert (registry, hook, new_merge_ids); + while (g_hash_table_iter_next (&iter, &key, NULL)) { + GtkUIManager *ui_manager = key; + plugin_ui_enable_manager (hook, ui_manager, NULL); + } } static void -plugin_ui_hook_register_manager (EPluginUIHook *hook, - GtkUIManager *ui_manager, - const gchar *ui_definition, - gpointer user_data) +plugin_ui_disable_hook (EPluginUIHook *hook) { - EPlugin *plugin; - EPluginUIInitFunc func; - guint merge_id = 0; + GHashTable *hash_table; + GHashTableIter iter; + gpointer key; - plugin = ((EPluginHook *) hook)->plugin; - func = e_plugin_get_symbol (plugin, E_PLUGIN_UI_INIT_FUNC); + /* Disable all GtkUIManagers for this hook. */ - /* 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 (ui_manager, user_data)) - return; + hash_table = hook->priv->registry; + g_hash_table_iter_init (&iter, hash_table); - if (plugin->enabled) { - GError *error = NULL; - - /* Merge the UI definition into the manager. */ - merge_id = gtk_ui_manager_add_ui_from_string ( - ui_manager, ui_definition, -1, &error); - gtk_ui_manager_ensure_update (ui_manager); - if (error != NULL) { - g_warning ("%s", error->message); - g_error_free (error); - } + while (g_hash_table_iter_next (&iter, &key, NULL)) { + GtkUIManager *ui_manager = key; + plugin_ui_disable_manager (hook, ui_manager, NULL, FALSE); } - - /* Save merge ID's for later use. */ - plugin_ui_registry_insert (hook, ui_manager, merge_id); } static void plugin_ui_hook_finalize (GObject *object) { EPluginUIHookPrivate *priv; + GHashTableIter iter; + gpointer ui_manager; priv = E_PLUGIN_UI_HOOK_GET_PRIVATE (object); + /* Remove weak reference callbacks to GtkUIManagers. */ + g_hash_table_iter_init (&iter, priv->registry); + while (g_hash_table_iter_next (&iter, &ui_manager, NULL)) + g_object_weak_unref ( + G_OBJECT (ui_manager), (GWeakNotify) + plugin_ui_hook_unregister_manager, object); + g_hash_table_destroy (priv->ui_definitions); + g_hash_table_destroy (priv->registry); /* Chain up to parent's dispose() method. */ G_OBJECT_CLASS (parent_class)->dispose (object); @@ -306,9 +420,9 @@ plugin_ui_hook_enable (EPluginHook *hook, gint state) { if (state) - plugin_ui_hook_merge_ui (E_PLUGIN_UI_HOOK (hook)); + plugin_ui_enable_hook (E_PLUGIN_UI_HOOK (hook)); else - plugin_ui_hook_unmerge_ui (E_PLUGIN_UI_HOOK (hook)); + plugin_ui_disable_hook (E_PLUGIN_UI_HOOK (hook)); } static void @@ -327,25 +441,24 @@ plugin_ui_hook_class_init (EPluginUIHookClass *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; - - registry = g_hash_table_new_full ( - g_direct_hash, g_direct_equal, - (GDestroyNotify) NULL, - (GDestroyNotify) g_hash_table_destroy); } static void plugin_ui_hook_init (EPluginUIHook *hook) { GHashTable *ui_definitions; + GHashTable *registry; ui_definitions = g_hash_table_new_full ( g_str_hash, g_str_equal, (GDestroyNotify) g_free, (GDestroyNotify) g_free); + registry = g_hash_table_new (g_direct_hash, g_direct_equal); + hook->priv = E_PLUGIN_UI_HOOK_GET_PRIVATE (hook); hook->priv->ui_definitions = ui_definitions; + hook->priv->registry = registry; } GType @@ -375,17 +488,14 @@ e_plugin_ui_hook_get_type (void) } void -e_plugin_ui_register_manager (const gchar *id, - GtkUIManager *ui_manager, +e_plugin_ui_register_manager (GtkUIManager *ui_manager, + const gchar *id, 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 (ui_manager)); - - g_object_set_data (G_OBJECT (ui_manager), key, (gpointer) id); + g_return_if_fail (id != NULL); /* Loop over all installed plugins. */ plugin_list = e_plugin_list_plugins (); @@ -393,36 +503,84 @@ e_plugin_ui_register_manager (const gchar *id, EPlugin *plugin = plugin_list->data; GSList *iter; + plugin_list = g_slist_next (plugin_list); + /* Look for hooks of type EPluginUIHook. */ for (iter = plugin->hooks; iter != NULL; iter = iter->next) { EPluginUIHook *hook = iter->data; - const gchar *ui_definition; + GHashTable *hash_table; if (!E_IS_PLUGIN_UI_HOOK (hook)) continue; + hash_table = hook->priv->ui_definitions; + /* 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) + if (g_hash_table_lookup (hash_table, id) == NULL) continue; /* Register the manager with the hook. */ plugin_ui_hook_register_manager ( - hook, ui_manager, ui_definition, user_data); + hook, ui_manager, user_data); } + } +} + +void +e_plugin_ui_enable_manager (GtkUIManager *ui_manager, + const gchar *id) +{ + GSList *plugin_list; + + g_return_if_fail (GTK_IS_UI_MANAGER (ui_manager)); + g_return_if_fail (id != NULL); + + /* Loop over all installed plugins. */ + plugin_list = e_plugin_list_plugins (); + while (plugin_list != NULL) { + EPlugin *plugin = plugin_list->data; + GSList *iter; plugin_list = g_slist_next (plugin_list); + + /* Look for hooks of type EPluginUIHook. */ + for (iter = plugin->hooks; iter != NULL; iter = iter->next) { + EPluginUIHook *hook = iter->data; + + if (!E_IS_PLUGIN_UI_HOOK (hook)) + continue; + + plugin_ui_enable_manager (hook, ui_manager, id); + } } } -const gchar * -e_plugin_ui_get_manager_id (GtkUIManager *ui_manager) +void +e_plugin_ui_disable_manager (GtkUIManager *ui_manager, + const gchar *id) { - const gchar *key = E_PLUGIN_UI_MANAGER_ID_KEY; + GSList *plugin_list; + + g_return_if_fail (GTK_IS_UI_MANAGER (ui_manager)); + g_return_if_fail (id != NULL); + + /* Loop over all installed plugins. */ + plugin_list = e_plugin_list_plugins (); + while (plugin_list != NULL) { + EPlugin *plugin = plugin_list->data; + GSList *iter; - g_return_val_if_fail (GTK_IS_UI_MANAGER (ui_manager), NULL); + plugin_list = g_slist_next (plugin_list); + + /* Look for hooks of type EPluginUIHook. */ + for (iter = plugin->hooks; iter != NULL; iter = iter->next) { + EPluginUIHook *hook = iter->data; - return g_object_get_data (G_OBJECT (ui_manager), key); + if (!E_IS_PLUGIN_UI_HOOK (hook)) + continue; + + plugin_ui_disable_manager (hook, ui_manager, id, TRUE); + } + } } diff --git a/e-util/e-plugin-ui.h b/e-util/e-plugin-ui.h index cdefda5617..c9bddafb64 100644 --- a/e-util/e-plugin-ui.h +++ b/e-util/e-plugin-ui.h @@ -62,10 +62,13 @@ typedef gboolean (*EPluginUIInitFunc) (GtkUIManager *ui_manager, GType e_plugin_ui_hook_get_type (void); -void e_plugin_ui_register_manager (const gchar *id, - GtkUIManager *ui_manager, +void e_plugin_ui_register_manager (GtkUIManager *ui_manager, + const gchar *id, gpointer user_data); -const gchar * e_plugin_ui_get_manager_id (GtkUIManager *ui_manager); +void e_plugin_ui_enable_manager (GtkUIManager *ui_manager, + const gchar *id); +void e_plugin_ui_disable_manager (GtkUIManager *ui_manager, + const gchar *id); G_END_DECLS diff --git a/e-util/e-plugin.c b/e-util/e-plugin.c index 3b3d5d215d..5c5e55b147 100644 --- a/e-util/e-plugin.c +++ b/e-util/e-plugin.c @@ -72,12 +72,6 @@ static GHashTable *ep_types; static GSList *ep_path; /* global table of plugins by plugin.id */ static GHashTable *ep_plugins; -/* a table of GSLists of plugins by hook class for hooks not loadable yet */ -static GHashTable *ep_plugins_pending_hooks; -/* list of all cached xml docs:struct _plugin_doc's */ -static EDList ep_plugin_docs = E_DLIST_INITIALISER(ep_plugin_docs); -/* gconf client */ -static GConfClient *ep_gconf; /* the list of disabled plugins from gconf */ static GSList *ep_disabled; @@ -110,6 +104,8 @@ ep_check_enabled (const gchar *id) static void ep_set_enabled (const gchar *id, gint state) { + GConfClient *client; + /* Bail out if no change to state, when expressed as a boolean: */ if ((state == 0) == (ep_check_enabled(id) == 0)) return; @@ -126,9 +122,11 @@ ep_set_enabled (const gchar *id, gint state) } else ep_disabled = g_slist_prepend (ep_disabled, g_strdup (id)); - gconf_client_set_list( - ep_gconf, "/apps/evolution/eplugin/disabled", + client = gconf_client_get_default (); + gconf_client_set_list ( + client, "/apps/evolution/eplugin/disabled", GCONF_VALUE_STRING, ep_disabled, NULL); + g_object_unref (client); } static gint @@ -182,21 +180,6 @@ ep_construct (EPlugin *ep, xmlNodePtr root) } else { ep->hooks = g_slist_append(ep->hooks, hook); } - } else { - gpointer l, oldclass; - - if (ep_plugins_pending_hooks == NULL) - ep_plugins_pending_hooks = g_hash_table_new(g_str_hash, g_str_equal); - if (!g_hash_table_lookup_extended (ep_plugins_pending_hooks, class, &oldclass, &l)) { - oldclass = class; - l = NULL; - } - else { - g_free(class); - } - l = g_slist_prepend (l, ep); - g_hash_table_insert (ep_plugins_pending_hooks, oldclass, l); - ep->hooks_pending = g_slist_prepend (ep->hooks_pending, node); } } else if (strcmp((gchar *)node->name, "description") == 0) { ep->description = e_plugin_xml_content_domain(node, ep->domain); @@ -276,7 +259,6 @@ ep_finalize (GObject *object) g_free (ep->description); g_free (ep->name); g_free (ep->domain); - g_slist_free (ep->hooks_pending); g_slist_foreach (ep->hooks, (GFunc) g_object_unref, NULL); g_slist_free (ep->hooks); @@ -425,9 +407,7 @@ ep_load(const gchar *filename, gint load_level) { xmlDocPtr doc; xmlNodePtr root; - gint res = -1; EPlugin *ep = NULL; - gint cache = FALSE; struct _plugin_doc *pdoc; doc = e_xml_parse_file (filename); @@ -478,80 +458,12 @@ ep_load(const gchar *filename, gint load_level) g_free (is_system_plugin); pdoc->plugin_hooks = g_slist_prepend(pdoc->plugin_hooks, ep); - cache |= (ep->hooks_pending != NULL); ep = NULL; } - cache |= pdoc->plugins != NULL; - } - } - - res = 0; - - if (cache) { - pd(printf("Caching plugin description '%s' for unknown future hooks\n", filename)); - e_dlist_addtail(&ep_plugin_docs, (EDListNode *)pdoc); - } else { - pd(printf("freeing plugin description '%s', nothing uses it\n", filename)); - xmlFreeDoc(pdoc->doc); - g_free(pdoc->filename); - g_free(pdoc); - } - - return res; -} - -/* This loads a hook that was pending on a given plugin but the type wasn't registered yet */ -/* This works in conjunction with ep_construct and e_plugin_hook_register_type to make sure - everything works nicely together. Apparently. */ -static gint -ep_load_pending(EPlugin *ep, EPluginHookClass *type) -{ - gint res = 0; - GSList *l, *p; - - phd(printf("New hook type registered '%s', loading pending hooks on plugin '%s'\n", type->id, ep->id)); - - l = ep->hooks_pending; - p = NULL; - while (l) { - GSList *n = l->next; - xmlNodePtr node = l->data; - gchar *class = (gchar *)xmlGetProp(node, (const guchar *)"class"); - EPluginHook *hook; - - phd(printf(" checking pending hook '%s'\n", class?class:"<unknown>")); - - if (class) { - if (strcmp(class, type->id) == 0) { - hook = g_object_new(G_OBJECT_CLASS_TYPE(type), NULL); - - /* Don't bother loading hooks for plugins that are not anyway enabled */ - if (ep->enabled) { - res = type->construct(hook, ep, node); - if (res == -1) { - g_warning("Plugin '%s' failed to load hook '%s'", ep->name, type->id); - g_object_unref(hook); - } else { - ep->hooks = g_slist_append(ep->hooks, hook); - } - } - - if (p) - p->next = n; - else - ep->hooks_pending = n; - g_slist_free_1(l); - l = p; - } - - xmlFree(class); } - - p = l; - l = n; } - return res; + return 0; } /** @@ -574,6 +486,69 @@ e_plugin_add_load_path(const gchar *path) ep_path = g_slist_append(ep_path, g_strdup(path)); } +static void +plugin_load_subclasses (void) +{ + GType *children; + guint n_children, ii; + + ep_types = g_hash_table_new (g_str_hash, g_str_equal); + eph_types = g_hash_table_new (g_str_hash, g_str_equal); + ep_plugins = g_hash_table_new (g_str_hash, g_str_equal); + + /* Load EPlugin subclasses. */ + + children = g_type_children (E_TYPE_PLUGIN, &n_children); + + for (ii = 0; ii < n_children; ii++) { + EPluginClass *class; + + class = g_type_class_ref (children[ii]); + g_hash_table_insert (ep_types, (gpointer) class->type, class); + } + + g_free (children); + + /* Load EPluginHook subclasses. */ + + children = g_type_children (E_TYPE_PLUGIN_HOOK, &n_children); + + for (ii = 0; ii < n_children; ii++) { + EPluginHookClass *hook_class; + EPluginHookClass *dupe_class; + + hook_class = g_type_class_ref (children[ii]); + + /* Sanity check the hook class. */ + if (hook_class->id == NULL || *hook_class->id == '\0') { + g_warning ( + "%s has no hook ID, so skipping", + G_OBJECT_CLASS_NAME (hook_class)); + g_type_class_unref (hook_class); + continue; + } + + /* Check for class ID collisions. */ + dupe_class = g_hash_table_lookup (eph_types, hook_class->id); + if (dupe_class != NULL) { + g_warning ( + "%s and %s have the same hook " + "ID ('%s'), so skipping %s", + G_OBJECT_CLASS_NAME (dupe_class), + G_OBJECT_CLASS_NAME (hook_class), + hook_class->id, + G_OBJECT_CLASS_NAME (hook_class)); + g_type_class_unref (hook_class); + continue; + } + + g_hash_table_insert ( + eph_types, (gpointer) hook_class->id, hook_class); + } + + g_free (children); +} + /** * e_plugin_load_plugins: * @@ -585,13 +560,23 @@ e_plugin_add_load_path(const gchar *path) gint e_plugin_load_plugins(void) { + GConfClient *client; GSList *l; gint i; - if (ep_types == NULL) { - g_warning("no plugin types defined"); + if (eph_types != NULL) return 0; - } + + /* We require that all GTypes for EPlugin and EPluginHook + * subclasses be registered prior to loading any plugins. + * It greatly simplifies the loading process. */ + plugin_load_subclasses (); + + client = gconf_client_get_default (); + ep_disabled = gconf_client_get_list ( + client, "/apps/evolution/eplugin/disabled", + GCONF_VALUE_STRING, NULL); + g_object_unref (client); for (i=0; i < 3; i++) { for (l = ep_path;l;l = g_slist_next(l)) { @@ -623,70 +608,6 @@ e_plugin_load_plugins(void) return 0; } -/** - * e_plugin_register_type: - * @type: The GObject type of the plugin loader. - * - * Register a new plugin type with the plugin system. Each type must - * subclass EPlugin and must override the type member of the - * EPluginClass with a unique name. - **/ -void -e_plugin_register_type(GType type) -{ - EPluginClass *class; - struct _plugin_doc *pdoc, *ndoc; - - if (ep_types == NULL) { - ep_types = g_hash_table_new(g_str_hash, g_str_equal); - ep_plugins = g_hash_table_new(g_str_hash, g_str_equal); - /* TODO: notify listening */ - ep_gconf = gconf_client_get_default(); - ep_disabled = gconf_client_get_list(ep_gconf, "/apps/evolution/eplugin/disabled", GCONF_VALUE_STRING, NULL); - } - - class = g_type_class_ref(type); - - pd(printf("register plugin type '%s'\n", class->type)); - - g_hash_table_insert(ep_types, (gpointer)class->type, class); - - /* check for pending plugins */ - pdoc = (struct _plugin_doc *)ep_plugin_docs.head; - ndoc = pdoc->next; - while (ndoc) { - if (pdoc->plugins) { - GSList *l, *add = NULL; - - for (l=pdoc->plugins;l;l=g_slist_next(l)) { - xmlNodePtr root = l->data; - gchar *prop_type; - - prop_type = (gchar *)xmlGetProp(root, (const guchar *)"type"); - if (!strcmp(prop_type, class->type)) - add = g_slist_append(add, l->data); - xmlFree(prop_type); - } - - for (l=add;l;l=g_slist_next(l)) { - xmlNodePtr root = l->data; - EPlugin *ep; - - pdoc->plugins = g_slist_remove(pdoc->plugins, root); - ep = ep_load_plugin(root, pdoc); - if (ep) - pdoc->plugin_hooks = g_slist_prepend(pdoc->plugin_hooks, ep); - /* TODO: garbage collect plugin doc? */ - } - - g_slist_free(add); - } - - pdoc = ndoc; - ndoc = ndoc->next; - } -} - static void ep_list_plugin(gpointer key, gpointer val, gpointer dat) { @@ -973,265 +894,6 @@ e_plugin_xml_content_domain(xmlNodePtr node, const gchar *domain) /* ********************************************************************** */ -static gpointer epl_parent_class; - -/* TODO: - We need some way to manage lifecycle. - We need some way to manage state. - - Maybe just the g module init method will do, or we could add - another which returns context. - - There is also the question of per-instance context, e.g. for config - pages. -*/ - -static GList *missing_symbols = NULL; - -static gint -epl_loadmodule(EPlugin *ep, gboolean fatal) -{ - EPluginLib *epl = E_PLUGIN_LIB (ep); - EPluginLibEnableFunc enable; - - if (epl->module != NULL) - return 0; - - if ((epl->module = g_module_open(epl->location, 0)) == NULL) { - if (fatal) - g_warning("can't load plugin '%s': %s", epl->location, g_module_error()); - else - missing_symbols = g_list_prepend (missing_symbols, g_object_ref (ep)); - return -1; - } - - if (g_module_symbol(epl->module, "e_plugin_lib_enable", (gpointer)&enable)) { - if (enable(epl, TRUE) != 0) { - ep->enabled = FALSE; - g_module_close(epl->module); - epl->module = NULL; - return -1; - } - } - - return 0; -} - -void -e_plugin_load_plugins_with_missing_symbols (void) -{ - GList *list = missing_symbols; - - while (list) { - EPlugin *ep = list->data; - epl_loadmodule (ep, TRUE); - g_object_unref (ep); - list = g_list_next (list); - } - - g_list_free (missing_symbols); - missing_symbols = NULL; -} - -static gpointer -epl_invoke(EPlugin *ep, const gchar *name, gpointer data) -{ - EPluginLib *epl = E_PLUGIN_LIB (ep); - EPluginLibFunc cb; - - if (!ep->enabled) { - g_warning("trying to invoke '%s' on disabled plugin '%s'", name, ep->id); - return NULL; - } - - if (epl_loadmodule(ep, FALSE) != 0) - return NULL; - - if (!g_module_symbol(epl->module, name, (gpointer)&cb)) { - g_warning("Cannot resolve symbol '%s' in plugin '%s' (not exported?)", name, epl->location); - return NULL; - } - - return cb(epl, data); -} - -static gpointer -epl_get_symbol(EPlugin *ep, const gchar *name) -{ - EPluginLib *epl = E_PLUGIN_LIB (ep); - gpointer symbol; - - if (epl_loadmodule (ep, FALSE) != 0) - return NULL; - - if (!g_module_symbol (epl->module, name, &symbol)) - return NULL; - - return symbol; -} - -static gint -epl_construct(EPlugin *ep, xmlNodePtr root) -{ - EPluginLib *epl = E_PLUGIN_LIB (ep); - - if (E_PLUGIN_CLASS (epl_parent_class)->construct (ep, root) == -1) - return -1; - - epl->location = e_plugin_xml_prop(root, "location"); - - if (epl->location == NULL) { - g_warning("Library plugin '%s' has no location", ep->id); - return -1; - } -#ifdef G_OS_WIN32 - { - gchar *mapped_location = - e_util_replace_prefix (EVOLUTION_PREFIX, - e_util_get_prefix (), - epl->location); - g_free (epl->location); - epl->location = mapped_location; - } -#endif - /* If we're enabled, check for the load-on-startup property */ - if (ep->enabled) { - xmlChar *tmp; - - tmp = xmlGetProp(root, (const guchar *)"load-on-startup"); - if (tmp) { - if (strcmp ((const gchar *)tmp, "after-ui") == 0) { - missing_symbols = g_list_prepend (missing_symbols, g_object_ref (ep)); - } else { - if (epl_loadmodule(ep, FALSE) != 0) { - xmlFree(tmp); - return -1; - } - } - xmlFree(tmp); - } - } - - return 0; -} - -static GtkWidget * -epl_get_configure_widget (EPlugin *ep) -{ - EPluginLib *epl = E_PLUGIN_LIB (ep); - EPluginLibGetConfigureWidgetFunc get_configure_widget; - - pd (printf ("\n epl_get_configure_widget \n")); - - if (epl_loadmodule (ep, FALSE) != 0) { - pd (printf ("\n epl_loadmodule \n")); - return NULL; - } - - if (g_module_symbol (epl->module, "e_plugin_lib_get_configure_widget", (gpointer)&get_configure_widget)) { - pd (printf ("\n g_module_symbol is loaded\n")); - return (GtkWidget*) get_configure_widget (epl); - } - return NULL; -} - -static void -epl_enable(EPlugin *ep, gint state) -{ - EPluginLib *epl = E_PLUGIN_LIB (ep); - EPluginLibEnableFunc enable; - - E_PLUGIN_CLASS (epl_parent_class)->enable (ep, state); - - /* if we're disabling and it isn't loaded, nothing to do */ - if (!state && epl->module == NULL) - return; - - /* this will noop if we're disabling since we tested it above */ - if (epl_loadmodule(ep, FALSE) != 0) - return; - - if (g_module_symbol(epl->module, "e_plugin_lib_enable", (gpointer)&enable)) { - if (enable(epl, state) != 0) - return; - } -#if 0 - if (!state) { - g_module_close(epl->module); - epl->module = NULL; - } -#endif -} - -static void -epl_finalize (GObject *object) -{ - EPluginLib *epl = E_PLUGIN_LIB (object); - - g_free (epl->location); - - if (epl->module) - g_module_close (epl->module); - - /* Chain up to parent's finalize() method. */ - G_OBJECT_CLASS (epl_parent_class)->finalize (object); -} - -static void -epl_class_init (EPluginClass *class) -{ - GObjectClass *object_class; - - epl_parent_class = g_type_class_peek_parent (class); - - object_class = G_OBJECT_CLASS (class); - object_class->finalize = epl_finalize; - - class->construct = epl_construct; - class->invoke = epl_invoke; - class->get_symbol = epl_get_symbol; - class->enable = epl_enable; - class->get_configure_widget = epl_get_configure_widget; - class->type = "shlib"; -} - -/** - * e_plugin_lib_get_type: - * - * Standard GObject function to retrieve the EPluginLib type. Use to - * register the type with the plugin system if you want to use shared - * library plugins. - * - * Return value: The EPluginLib type. - **/ -GType -e_plugin_lib_get_type (void) -{ - static GType type = 0; - - if (G_UNLIKELY (type == 0)) { - static const GTypeInfo type_info = { - sizeof (EPluginLibClass), - (GBaseInitFunc) NULL, - (GBaseFinalizeFunc) NULL, - (GClassInitFunc) epl_class_init, - (GClassFinalizeFunc) NULL, - NULL, /* class_data */ - sizeof (EPluginLib), - 0, /* n_preallocs */ - (GInstanceInitFunc) NULL, - NULL /* value_table */ - }; - - type = g_type_register_static ( - e_plugin_get_type (), "EPluginLib", &type_info, 0); - } - - return type; -} - -/* ********************************************************************** */ - static gpointer eph_parent_class; static gint @@ -1315,83 +977,6 @@ e_plugin_hook_enable (EPluginHook *eph, gint state) } /** - * e_plugin_hook_register_type: - * @type: - * - * Register a new plugin hook type with the plugin system. Each type - * must subclass EPluginHook and must override the id member of the - * EPluginHookClass with a unique identification string. - **/ -void -e_plugin_hook_register_type(GType type) -{ - EPluginHookClass *klass, *oldklass; - GSList *l; - - gpointer plugins; /* GSList */ - gpointer class; - - if (eph_types == NULL) - eph_types = g_hash_table_new(g_str_hash, g_str_equal); - - klass = g_type_class_ref(type); - - oldklass = g_hash_table_lookup(eph_types, (gpointer)klass->id); - if (oldklass == klass) { - g_type_class_unref(klass); - return; - } else if (oldklass != NULL) { - g_warning("Trying to re-register hook type '%s'", klass->id); - return; - } - - phd(printf("register plugin hook type '%s'\n", klass->id)); - g_hash_table_insert(eph_types, (gpointer)klass->id, klass); - - /* if we've already loaded a plugin that needed this hook but it didn't exist, re-load it now */ - - if (ep_plugins_pending_hooks - && g_hash_table_lookup_extended (ep_plugins_pending_hooks, klass->id, &class, &plugins)) { - struct _plugin_doc *pdoc, *ndoc; - - g_hash_table_remove (ep_plugins_pending_hooks, class); - g_free (class); - for (l = plugins; l; l = g_slist_next(l)) { - EPlugin *ep = l->data; - - ep_load_pending (ep, klass); - } - g_slist_free (plugins); - - /* See if we can now garbage collect the xml definition since its been fully loaded */ - - /* This is all because libxml doesn't refcount! */ - - pdoc = (struct _plugin_doc *)ep_plugin_docs.head; - ndoc = pdoc->next; - while (ndoc) { - if (pdoc->doc) { - gint cache = pdoc->plugins != NULL; - - for (l=pdoc->plugin_hooks;!cache && l;l=g_slist_next(l)) - cache |= (((EPlugin *)l->data)->hooks_pending != NULL); - - if (!cache) { - pd(printf("Gargabe collecting plugin description '%s'\n", pdoc->filename)); - e_dlist_remove((EDListNode *)pdoc); - xmlFreeDoc(pdoc->doc); - g_free(pdoc->filename); - g_free(pdoc); - } - } - - pdoc = ndoc; - ndoc = ndoc->next; - } - } -} - -/** * e_plugin_hook_mask: * @root: An XML node. * @map: A zero-fill terminated array of EPluginHookTargeKeys used to @@ -1478,118 +1063,3 @@ e_plugin_hook_id(xmlNodePtr root, const struct _EPluginHookTargetKey *map, const return ~0; } - -/* ********************************************************************** */ -/* Plugin plugin */ - -static gpointer epth_parent_class; - -static gint -epth_load_plugin(gpointer d) -{ - EPluginHook *eph = d; - EPluginTypeHook *epth = d; - GType type; - - epth->idle = 0; - - type = GPOINTER_TO_UINT(e_plugin_invoke(eph->plugin, epth->get_type, eph->plugin)); - if (type != 0) - e_plugin_register_type(type); - - return FALSE; -} - -static gint -epth_construct(EPluginHook *eph, EPlugin *ep, xmlNodePtr root) -{ - EPluginTypeHook *epth = E_PLUGIN_TYPE_HOOK (eph); - xmlNodePtr node; - - phd(printf("loading plugin hook\n")); - - if (((EPluginHookClass *)epth_parent_class)->construct(eph, ep, root) == -1) - return -1; - - node = root->children; - while (node) { - if (strcmp((gchar *)node->name, "plugin-type") == 0) { - epth->get_type = e_plugin_xml_prop(node, "get-type"); - /* We need to run this in an idle handler, - * since at this point the parent EPlugin wont - * be fully initialised ... darn */ - if (epth->get_type) - epth->idle = g_idle_add(epth_load_plugin, epth); - else - g_warning("Plugin type plugin missing get-type callback"); - } - node = node->next; - } - - eph->plugin = ep; - - return 0; -} - -static void -epth_finalize (GObject *object) -{ - EPluginTypeHook *epth = E_PLUGIN_TYPE_HOOK (object); - - if (epth->idle != 0) - g_source_remove (epth->idle); - - g_free (epth->get_type); - - /* Chain up to parent's finalize() method. */ - G_OBJECT_CLASS (epth_parent_class)->finalize (object); -} - -static void -epth_class_init (EPluginTypeHookClass *class) -{ - GObjectClass *object_class; - EPluginHookClass *hook_class; - - epth_parent_class = g_type_class_peek_parent (class); - - object_class = G_OBJECT_CLASS (class); - object_class->finalize = epth_finalize; - - hook_class = E_PLUGIN_HOOK_CLASS (class); - hook_class->construct = epth_construct; - hook_class->id = "org.gnome.evolution.plugin.type:1.0"; -} - -/** - * e_plugin_type_hook_get_type: - * - * Get the type for the plugin plugin hook. - * - * Return value: The type of the plugin type hook. - **/ -GType -e_plugin_type_hook_get_type(void) -{ - static GType type = 0; - - if (G_UNLIKELY (type == 0)) { - static const GTypeInfo type_info = { - sizeof (EPluginTypeHookClass), - (GBaseInitFunc) NULL, - (GBaseFinalizeFunc) NULL, - (GClassInitFunc) epth_class_init, - (GClassFinalizeFunc) NULL, - NULL, /* class_data */ - sizeof (EPluginTypeHook), - 0, /* n_preallocs */ - (GInstanceInitFunc) NULL, - NULL /* value_table */ - }; - - type = g_type_register_static ( - E_TYPE_PLUGIN_HOOK, "EPluginTypeHook", &type_info, 0); - } - - return type; -} diff --git a/e-util/e-plugin.h b/e-util/e-plugin.h index 18949bf893..8e24436605 100644 --- a/e-util/e-plugin.h +++ b/e-util/e-plugin.h @@ -64,8 +64,6 @@ struct _EPluginAuthor { * @object: Superclass. * @id: Unique identifier for plugin instance. * @path: Filename where the xml definition resides. - * @hooks_pending: A list hooks which can't yet be loaded. This is - * the xmlNodePtr to the root node of the hook definition. * @description: A description of the plugin's purpose. * @name: The name of the plugin. * @domain: The translation domain for this plugin. @@ -82,7 +80,6 @@ struct _EPlugin { gchar *id; gchar *path; - GSList *hooks_pending; gchar *description; gchar *name; @@ -134,11 +131,8 @@ GType e_plugin_get_type(void); gint e_plugin_construct(EPlugin *ep, xmlNodePtr root); void e_plugin_add_load_path(const gchar *); gint e_plugin_load_plugins(void); -void e_plugin_load_plugins_with_missing_symbols(void); GSList * e_plugin_list_plugins(void); -void e_plugin_register_type(GType type); - gpointer e_plugin_get_symbol(EPlugin *ep, const gchar *name); gpointer e_plugin_invoke(EPlugin *ep, const gchar *name, gpointer data); void e_plugin_enable(EPlugin *eph, gint state); @@ -154,73 +148,6 @@ gchar *e_plugin_xml_content(xmlNodePtr node); gchar *e_plugin_xml_content_domain(xmlNodePtr node, const gchar *domain); /* ********************************************************************** */ -#include <gmodule.h> - -/* Standard GObject macros */ -#define E_TYPE_PLUGIN_LIB \ - (e_plugin_lib_get_type ()) -#define E_PLUGIN_LIB(obj) \ - (G_TYPE_CHECK_INSTANCE_CAST \ - ((obj), E_TYPE_PLUGIN_LIB, EPluginLib)) -#define E_PLUGIN_LIB_CLASS(cls) \ - (G_TYPE_CHECK_CLASS_CAST \ - ((cls), E_TYPE_PLUGIN_LIB, EPluginLibClass)) -#define E_IS_PLUGIN_LIB(obj) \ - (G_TYPE_CHECK_INSTANCE_TYPE \ - ((obj), E_TYPE_PLUGIN_LIB)) -#define E_IS_PLUGIN_LIB_CLASS(cls) \ - (G_TYPE_CHECK_CLASS_TYPE \ - ((cls), E_TYPE_PLUGIN_LIB)) -#define E_PLUGIN_LIB_GET_CLASS(obj) \ - (G_TYPE_INSTANCE_GET_CLASS \ - ((obj), E_TYPE_PLUGIN_LIB, EPluginLibClass)) - -typedef struct _EPluginLib EPluginLib; -typedef struct _EPluginLibClass EPluginLibClass; - -/* The callback signature used for epluginlib methods */ -typedef gpointer (*EPluginLibFunc)(EPluginLib *ep, gpointer data); -/* The setup method, this will be called when the plugin is - * initialised. In the future it may also be called when the plugin - * is disabled. */ -typedef gint (*EPluginLibEnableFunc)(EPluginLib *ep, gint enable); -typedef gpointer (*EPluginLibGetConfigureWidgetFunc)(EPluginLib *ep); - -/** - * struct _EPluginLib - - * - * @plugin: Superclass. - * @location: The filename of the shared object. - * @module: The GModule once it is loaded. - * - * This is a concrete EPlugin class. It loads and invokes dynamically - * loaded libraries using GModule. The shared object isn't loaded - * until the first callback is invoked. - * - * When the plugin is loaded, and if it exists, "e_plugin_lib_enable" - * will be invoked to initialise the - **/ -struct _EPluginLib { - EPlugin plugin; - - gchar *location; - GModule *module; -}; - -/** - * struct _EPluginLibClass - - * - * @plugin_class: Superclass. - * - * The plugin library needs no additional class data. - **/ -struct _EPluginLibClass { - EPluginClass plugin_class; -}; - -GType e_plugin_lib_get_type(void); - -/* ********************************************************************** */ /* Standard GObject macros */ #define E_TYPE_PLUGIN_HOOK \ @@ -323,8 +250,6 @@ struct _EPluginHookClass { GType e_plugin_hook_get_type(void); -void e_plugin_hook_register_type(GType type); - EPluginHook * e_plugin_hook_new(EPlugin *ep, xmlNodePtr root); void e_plugin_hook_enable(EPluginHook *eph, gint state); @@ -332,49 +257,6 @@ void e_plugin_hook_enable(EPluginHook *eph, gint state); guint32 e_plugin_hook_mask(xmlNodePtr root, const struct _EPluginHookTargetKey *map, const gchar *prop); guint32 e_plugin_hook_id(xmlNodePtr root, const struct _EPluginHookTargetKey *map, const gchar *prop); -/* ********************************************************************** */ - -/* EPluginTypeHook lets a plugin register a new plugin type. - <hook class="org.gnome.evolution.plugin.type:1.0"> - <plugin-type get-type="e_plugin_mono_get_type/> - </hook> -*/ - -/* Standard GObject macros */ -#define E_TYPE_PLUGIN_TYPE_HOOK \ - (e_plugin_type_hook_get_type ()) -#define E_PLUGIN_TYPE_HOOK(obj) \ - (G_TYPE_CHECK_INSTANCE_CAST \ - ((obj), E_TYPE_PLUGIN_TYPE_HOOK, EPluginTypeHook)) -#define E_PLUGIN_TYPE_HOOK_CLASS(cls) \ - (G_TYPE_CHECK_CLASS_CAST \ - ((cls), E_TYPE_PLUGIN_TYPE_HOOK, EPluginTypeHookClass)) -#define E_IS_PLUGIN_TYPE_HOOK(obj) \ - (G_TYPE_CHECK_INSTANCE_TYPE \ - ((obj), E_TYPE_PLUGIN_TYPE_HOOK)) -#define E_IS_PLUGIN_TYPE_HOOK_CLASS(cls) \ - (G_TYPE_CHECK_CLASS_TYPE \ - ((cls), E_TYPE_PLUGIN_TYPE_HOOK)) -#define E_PLUGIN_TYPE_HOOK_GET_CLASS(obj) \ - (G_TYPE_INSTANCE_GET_CLASS \ - ((obj), E_TYPE_PLUGIN_TYPE_HOOK, EPluginTypeHookClass)) - -typedef struct _EPluginTypeHook EPluginTypeHook; -typedef struct _EPluginTypeHookClass EPluginTypeHookClass; - -struct _EPluginTypeHook { - EPluginHook hook; - - gchar *get_type; - guint idle; -}; - -struct _EPluginTypeHookClass { - EPluginHookClass hook_class; -}; - -GType e_plugin_type_hook_get_type(void); - /* README: Currently there is only one flag. But we may need more in the future and hence makes sense to keep as an enum */ 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); -} diff --git a/e-util/e-popup.h b/e-util/e-popup.h deleted file mode 100644 index 257234dc81..0000000000 --- a/e-util/e-popup.h +++ /dev/null @@ -1,305 +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: - * Michel Zucchi <notzed@ximian.com> - * - * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com) - * - */ - -#ifndef __E_POPUP_H__ -#define __E_POPUP_H__ - -#include <gtk/gtk.h> -#include <libedataserver/e-msgport.h> - -G_BEGIN_DECLS - -/* This is an abstract popup menu management/merging class. - - To implement your own popup menu system, just create your own - target types and implement the target free method. */ - -typedef struct _EPopup EPopup; -typedef struct _EPopupClass EPopupClass; - -typedef struct _EPopupItem EPopupItem; -typedef struct _EPopupFactory EPopupFactory; /* anonymous type */ -typedef struct _EPopupTarget EPopupTarget; - -typedef void (*EPopupActivateFunc)(EPopup *ep, EPopupItem *item, gpointer data); -typedef void (*EPopupFactoryFunc)(EPopup *emp, gpointer data); -typedef void (*EPopupItemsFunc)(EPopup *ep, GSList *items, gpointer data); - -/** - * enum _e_popup_t - Popup item type enumeration. - * @E_POPUP_ITEM: A simple menu item. - * @E_POPUP_TOGGLE: A toggle menu item. If struct _EPopupItem::image is - * not NULL, then it points to GtkImage directly and there is a toggle - * with an image and caption shown in the popup menu. - * @E_POPUP_RADIO: A radio menu item. Note that the radio group is - * global for the entire (sub) menu. i.e. submenu's must be used to - * separate radio button menu items. - * @E_POPUP_IMAGE: A &GtkImage menu item. In this case the @image - * field of &struct _EPopupItem points to the &GtkImage directly. - * @E_POPUP_SUBMENU: A sub-menu header. It is up to the application - * to define the @path properly so that the submenu comes before the - * submenu items. - * @E_POPUP_BAR: A menu separator bar. - * @E_POPUP_TYPE_MASK: Mask used to separate item type from option bits. - * @E_POPUP_ACTIVE: An option bit to signify that the radio button or - * toggle button is active. - * @E_POPUP_INCONSISTENT: An option to toggle only, if set, the toggle - * is shown in inconsistent state. This is used before E_POPUP_ACTIVE. - */ -enum _e_popup_t { - E_POPUP_ITEM = 0, - E_POPUP_TOGGLE, - E_POPUP_RADIO, - E_POPUP_IMAGE, - E_POPUP_SUBMENU, - E_POPUP_BAR, - E_POPUP_TYPE_MASK = 0xffff, - E_POPUP_ACTIVE = 0x10000, - E_POPUP_INCONSISTENT = 0x20000 -}; - -/* FIXME: activate passes back no context data apart from that provided. - FIXME: It should pass the target at the least. The menu widget is - useless */ - -/** - * struct _EPopupItem - A popup menu item definition. - * @type: The type of the popup. See the &enum _epopup_t definition - * for possible values. - * @path: An absolute path, which when sorted using a simple ASCII - * sort, will put the menu item in the right place in the menu - * heirarchy. '/' is used to separate menus from submenu items. - * @label: The text of the menyu item. - * @activate: A function conforming to &EPopupActivateFunc which will - * be called when the menu item is activated. - * @user_data: Extra per-item user-data available to the - * application. This is not passed to the @data field of @activate. - * @image: For most types, the name of the icon in the icon theme to - * display next to the menu item, if required. For the %E_POPUP_IMAGE - * type, it is a pointer to the &GtkWidget instead. - * @visible: Visibility mask. Used together with the &EPopupTarget mask - * to determine if the item should be part of the menu or not. - * @enable: Sensitivity mask. Similar to the visibility mask, but - * currently unimplemented. - * @popup: Used by e-popup to reference the parent object from - * callbacks. - * - * The EPopupItem defines a single popup menu item, or submenu item, - * or menu separator based on the @type. Any number of these are - * merged at popup display type to form the popup menu. - * - * The application may extend this structure using simple C structure - * containers to add any additional fields it may require. - */ -struct _EPopupItem { - enum _e_popup_t type; - gchar *path; /* absolute path! must sort ascii-lexographically into the right spot */ - gchar *label; - EPopupActivateFunc activate; - gpointer user_data; /* user data, not passed directly to @activate */ - gpointer image; /* gchar * for item type, GtkWidget * for image type */ - guint32 visible; /* visibility mask */ - guint32 enable; /* sensitivity mask */ -}; - -/** - * struct EPopupTarget - A popup menu target definition. - * - * @popup: The parent popup object, used for virtual methods on the target. - * @widget: The parent widget, where available. In some cases the - * type of this object is part of the published api for the target. - * @type: The target type. This will be defined by the - * implementation. - * @mask: Target mask. This is used to sensitise and show items - * based on their definition in EPopupItem. - * - * An EPopupTarget defines the context for a specific popup menu - * instance. The root target object is abstract, and it is up to - * sub-classes of &EPopup to define the additional fields required to - * make it usable. - */ -struct _EPopupTarget { - struct _EPopup *popup; /* used for virtual methods */ - - GtkWidget *widget; /* used if you need a parent toplevel, if available */ - guint32 type; /* targe type, for implementors */ - - guint32 mask; /* depends on type, visibility mask */ - - /* implementation fields follow */ -}; - -/** - * struct _EPopup - A Popup menu manager. - * - * @object: Superclass, GObject. - * @priv: Private data. - * @menuid: The id of this menu instance. - * @target: The current target during the display of the popup menu. - * - * The EPopup manager object. Each popup menu is built using this - * one-off object which is created each time the popup is invoked. - */ -struct _EPopup { - GObject object; - - struct _EPopupPrivate *priv; - - gchar *menuid; - - EPopupTarget *target; -}; - -/** - * struct _EPopupClass - - * - * @object_class: Superclass type. - * @factories: A list of factories for this particular class of popup - * menu. - * @target_free: Virtual method to free the popup target. The base - * class frees the allocation and unrefs the popup pointer - * structure. - * - * The EPopup class definition. This should be sub-classed for each - * component that wants to provide hookable popup menus. The - * sub-class only needs to know how to allocate and free the various target - * types it supports. - */ -struct _EPopupClass { - GObjectClass object_class; - - EDList factories; - - void (*target_free)(EPopup *ep, EPopupTarget *t); -}; - -GType e_popup_get_type(void); - -EPopup *e_popup_new(const gchar *menuid); - -/* Static class methods */ -EPopupFactory *e_popup_class_add_factory(EPopupClass *klass, const gchar *menuid, EPopupFactoryFunc func, gpointer data); -void e_popup_class_remove_factory(EPopupClass *klass, EPopupFactory *f); - -EPopup *e_popup_construct(EPopup *, const gchar *menuid); - -void e_popup_add_items(EPopup *, GSList *items, const gchar *domain, EPopupItemsFunc freefunc, gpointer data); - -void e_popup_add_static_items(EPopup *emp, EPopupTarget *target); -/* do not call e_popup_create_menu, it can leak structures if not used right */ -GtkMenu *e_popup_create_menu(EPopup *, EPopupTarget *, guint32 mask); -GtkMenu *e_popup_create_menu_once(EPopup *emp, EPopupTarget *, guint32 mask); - -gpointer e_popup_target_new(EPopup *, gint type, gsize size); -void e_popup_target_free(EPopup *, gpointer ); - -/* ********************************************************************** */ - -/* popup plugin target, they are closely integrated */ - -/* To implement a basic popup menu plugin, you just need to subclass - this and initialise the class target type tables */ - -#include "e-util/e-plugin.h" - -typedef struct _EPopupHookMenu EPopupHookMenu; -typedef struct _EPopupHook EPopupHook; -typedef struct _EPopupHookClass EPopupHookClass; - -typedef struct _EPluginHookTargetMap EPopupHookTargetMap; -typedef struct _EPluginHookTargetKey EPopupHookTargetMask; - -typedef void (*EPopupHookFunc)(struct _EPlugin *plugin, EPopupTarget *target); - -/** - * struct _EPopupHookMenu - - * - * @hook: Parent pointer. - * @id: The identifier of the menu to which these items belong. - * @target_type: The target number of the type of target these menu - * items expect. It will generally also be defined by the menu id. - * @items: A list of EPopupItems. - * @factory: If supplied, a function to call - * - * The structure used to keep track of all of the items that a plugin - * wishes to add to a given menu. This is used internally by a factory - * method set on EPlugin to add the right menu items to a given menu. - */ -struct _EPopupHookMenu { - struct _EPopupHook *hook; /* parent pointer */ - gchar *id; /* target menu id for these menu items */ - gint target_type; /* target type of this menu */ - GSList *items; /* items to add to menu */ - gchar *factory; /* optional factory to call for adding menu items */ -}; - -/** - * struct _EPopupHook - A popup menu hook. - * - * @hook: Superclass. - * @menus: A list of EPopupHookMenus, for all menus registered on - * this hook type. - * - * The EPopupHook class loads and manages the meta-data required to - * map plugin definitions to physical menus. - */ -struct _EPopupHook { - EPluginHook hook; - - GSList *menus; -}; - -/** - * struct _EPopupHookClass - - * - * @hook_class: Superclass. - * @target_map: Table of EPluginHookTargetMaps which enumerate the - * target types and enable bits of the implementing class. - * @popup_class: The EPopupClass of the corresponding popup manager - * for the implementing class. - * - * The EPopupHookClass is a concrete class, however it is empty on its - * own. It needs to be sub-classed and initialised appropriately. - * - * The EPluginHookClass.id must be set to the name and version of the - * hook handler itself. The @target_map must be initialised with the - * data required to enumerate the target types and enable flags - * supported by the implementing class. - */ -struct _EPopupHookClass { - EPluginHookClass hook_class; - - /* EPopupHookTargetMap by .type */ - GHashTable *target_map; - /* the popup class these popups belong to */ - EPopupClass *popup_class; -}; - -GType e_popup_hook_get_type(void); - -/* for implementors */ -void e_popup_hook_class_add_target_map(EPopupHookClass *klass, const EPopupHookTargetMap *); - -G_END_DECLS - -#endif /* __E_POPUP_H__ */ diff --git a/e-util/e-request.c b/e-util/e-request.c index 3cd23968b2..58784ee1ae 100644 --- a/e-util/e-request.c +++ b/e-util/e-request.c @@ -64,7 +64,7 @@ e_request_string (GtkWindow *parent, gtk_window_set_default_size (GTK_WINDOW (dialog), 275, -1); gtk_container_set_border_width (GTK_CONTAINER (dialog), 6); - vbox = GTK_DIALOG (dialog)->vbox; + vbox = gtk_dialog_get_content_area (GTK_DIALOG (dialog)); prompt_label = gtk_label_new (prompt); gtk_box_pack_start (GTK_BOX (vbox), prompt_label, TRUE, TRUE, 6); diff --git a/e-util/e-signature-utils.c b/e-util/e-signature-utils.c new file mode 100644 index 0000000000..4ae5ac2c8f --- /dev/null +++ b/e-util/e-signature-utils.c @@ -0,0 +1,351 @@ +/* + * e-signature-utils.c + * + * 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/> + * + * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com) + */ + +#include "e-signature-utils.h" + +#include <errno.h> +#include <glib/gstdio.h> +#include <gconf/gconf-client.h> +#include <camel/camel-stream.h> +#include <camel/camel-stream-fs.h> +#include <camel/camel-stream-mem.h> +#include <camel/camel-stream-filter.h> +#include <camel/camel-mime-filter-charset.h> +#include <camel/camel-mime-filter-tohtml.h> + +#ifndef G_OS_WIN32 +#include <sys/wait.h> +#endif + +#include "e-util/e-util.h" + +static ESignatureList *global_signature_list; + +ESignatureList * +e_get_signature_list (void) +{ + if (G_UNLIKELY (global_signature_list == NULL)) { + GConfClient *client; + + client = gconf_client_get_default (); + global_signature_list = e_signature_list_new (client); + g_object_unref (client); + } + + g_return_val_if_fail (global_signature_list != NULL, NULL); + + return global_signature_list; +} + +ESignature * +e_get_signature_by_name (const gchar *name) +{ + ESignatureList *signature_list; + const ESignature *signature; + e_signature_find_t find; + + g_return_val_if_fail (name != NULL, NULL); + + find = E_SIGNATURE_FIND_NAME; + signature_list = e_get_signature_list (); + signature = e_signature_list_find (signature_list, find, name); + + /* XXX ESignatureList misuses const. */ + return (ESignature *) signature; +} + +ESignature * +e_get_signature_by_uid (const gchar *uid) +{ + ESignatureList *signature_list; + const ESignature *signature; + e_signature_find_t find; + + g_return_val_if_fail (uid != NULL, NULL); + + find = E_SIGNATURE_FIND_UID; + signature_list = e_get_signature_list (); + signature = e_signature_list_find (signature_list, find, uid); + + /* XXX ESignatureList misuses const. */ + return (ESignature *) signature; +} + +gchar * +e_create_signature_file (GError **error) +{ + const gchar *data_dir; + gchar basename[32]; + gchar *filename; + gchar *pathname; + gint32 ii; + + data_dir = e_get_user_data_dir (); + pathname = g_build_filename (data_dir, "signatures", NULL); + filename = NULL; + + if (g_mkdir_with_parents (pathname, 0700) < 0) { + g_set_error ( + error, G_FILE_ERROR, + g_file_error_from_errno (errno), + "%s: %s", pathname, g_strerror (errno)); + g_free (pathname); + return NULL; + } + + for (ii = 0; ii < G_MAXINT32; ii++) { + + g_snprintf ( + basename, sizeof (basename), + "signature-%" G_GINT32_FORMAT, ii); + + g_free (filename); + filename = g_build_filename (pathname, basename, NULL); + + if (!g_file_test (filename, G_FILE_TEST_EXISTS)) { + gint fd; + + fd = g_creat (filename, 0600); + if (fd >= 0) { + close (fd); + break; + } + + /* If we failed once we're probably going + * to continue failing, so just give up. */ + g_set_error ( + error, G_FILE_ERROR, + g_file_error_from_errno (errno), + "%s: %s", filename, g_strerror (errno)); + g_free (filename); + filename = NULL; + break; + } + } + + /* If there are actually G_MAXINT32 signature files, the + * most recent signature file we be overwritten. Sorry. */ + + return filename; +} + +gchar * +e_read_signature_file (ESignature *signature, + gboolean convert_to_html, + GError **error) +{ + CamelStream *input_stream; + CamelStream *output_stream; + GByteArray *buffer; + const gchar *filename; + gboolean is_html; + gchar *content; + gsize length; + gint fd; + + g_return_val_if_fail (E_IS_SIGNATURE (signature), NULL); + + filename = e_signature_get_filename (signature); + is_html = e_signature_get_is_html (signature); + + fd = g_open (filename, O_RDONLY, 0); + if (fd < 0) { + g_set_error ( + error, G_FILE_ERROR, + g_file_error_from_errno (errno), + "%s: %s", filename, g_strerror (errno)); + return NULL; + } + + input_stream = camel_stream_fs_new_with_fd (fd); + + if (!is_html && convert_to_html) { + CamelStreamFilter *filtered_stream; + CamelMimeFilter *filter; + gint32 flags; + + filtered_stream = + camel_stream_filter_new_with_stream (input_stream); + camel_object_unref (input_stream); + + flags = + CAMEL_MIME_FILTER_TOHTML_PRESERVE_8BIT | + CAMEL_MIME_FILTER_TOHTML_CONVERT_URLS | + CAMEL_MIME_FILTER_TOHTML_CONVERT_ADDRESSES | + CAMEL_MIME_FILTER_TOHTML_CONVERT_SPACES; + filter = camel_mime_filter_tohtml_new (flags, 0); + camel_stream_filter_add (filtered_stream, filter); + camel_object_unref (filter); + + input_stream = (CamelStream *) filtered_stream; + } + + buffer = g_byte_array_new (); + output_stream = camel_stream_mem_new (); + camel_stream_mem_set_byte_array ( + CAMEL_STREAM_MEM (output_stream), buffer); + camel_stream_write_to_stream (input_stream, output_stream); + camel_object_unref (output_stream); + camel_object_unref (input_stream); + + /* Make sure the buffer is nul-terminated. */ + length = (gsize) buffer->len; + g_byte_array_append (buffer, (guint8 *) "", 1); + content = (gchar *) g_byte_array_free (buffer, FALSE); + + /* Signatures are saved as UTF-8, but we still need to check that + * the signature is valid UTF-8 because the user may be opening + * a signature file that is in his/her locale character set. If + * it's not in UTF-8 then try converting from the current locale. */ + if (!g_utf8_validate (content, length, NULL)) { + gchar *utf8; + + utf8 = g_locale_to_utf8 (content, length, NULL, NULL, error); + g_free (content); + content = utf8; + } + + return content; +} + +gchar * +e_run_signature_script (const gchar *filename) +{ + /* FIXME Make this cross-platform, prefer GLib functions over + * POSIX, and report errors via GError instead of dumping + * messages to the terminal where users won't see them. */ + +#ifndef G_OS_WIN32 + gint in_fds[2]; + pid_t pid; + + g_return_val_if_fail (filename != NULL, NULL); + + if (pipe (in_fds) == -1) { + g_warning ( + "Failed to create pipe to '%s': %s", + filename, g_strerror (errno)); + return NULL; + } + + pid = fork (); + + /* Child Process */ + if (pid == 0) { + gint maxfd, ii; + + close (in_fds[0]); + if (dup2 (in_fds[1], STDOUT_FILENO) < 0) + _exit (255); + close (in_fds[1]); + + setsid (); + + maxfd = sysconf (_SC_OPEN_MAX); + for (ii = 3; ii < maxfd; ii++) { + if (ii == STDIN_FILENO) + continue; + if (ii == STDOUT_FILENO) + continue; + if (ii == STDERR_FILENO) + continue; + fcntl (ii, F_SETFD, FD_CLOEXEC); + } + + execlp ("/bin/sh", "/bin/sh", "-c", filename, NULL); + + g_warning ( + "Could not execute '%s': %s", + filename, g_strerror (errno)); + + _exit (255); + + /* Parent Process */ + } else if (pid > 0) { + CamelStream *output_stream; + CamelStream *input_stream; + GByteArray *buffer; + gchar *content; + gsize length; + gint result; + gint status; + + close (in_fds[1]); + + buffer = g_byte_array_new (); + output_stream = camel_stream_mem_new (); + camel_stream_mem_set_byte_array ( + CAMEL_STREAM_MEM (output_stream), buffer); + + input_stream = camel_stream_fs_new_with_fd (in_fds[0]); + camel_stream_write_to_stream (input_stream, output_stream); + camel_object_unref (input_stream); + + camel_object_unref (output_stream); + + /* Make sure the buffer is nul-terminated. */ + length = (gsize) buffer->len; + g_byte_array_append (buffer, (guchar *) "", 1); + content = (gchar *) g_byte_array_free (buffer, FALSE); + + /* Signature scripts are supposed to generate UTF-8 content, + * but because users are known to never read the manual, we + * try to do our best if the content isn't valid UTF-8 by + * assuming that the content is in the user's locale + * character set. */ + if (!g_utf8_validate (content, length, NULL)) { + gchar *utf8; + + /* XXX Should pass a GError here. */ + utf8 = g_locale_to_utf8 ( + content, length, NULL, NULL, NULL); + g_free (content); + content = utf8; + } + + /* Wait for the script process to terminate. */ + result = waitpid (pid, &status, 0); + + if (result == -1 && errno == EINTR) { + /* Child process is hanging... */ + kill (pid, SIGTERM); + sleep (1); + result = waitpid (pid, &status, WNOHANG); + if (result == 0) { + /* ...still hanging, set phasers to KILL. */ + kill (pid, SIGKILL); + sleep (1); + result = waitpid (pid, &status, WNOHANG); + } + } + + return content; + + /* Forking Failed */ + } else { + g_warning ( + "Failed to create child process '%s': %s", + filename, g_strerror (errno)); + close (in_fds[0]); + close (in_fds[1]); + } +#endif + + return NULL; +} diff --git a/e-util/e-signature-utils.h b/e-util/e-signature-utils.h new file mode 100644 index 0000000000..56f8564131 --- /dev/null +++ b/e-util/e-signature-utils.h @@ -0,0 +1,40 @@ +/* + * e-signature-utils.h + * + * 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/> + * + * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com) + */ + +#ifndef E_SIGNATURE_UTILS_H +#define E_SIGNATURE_UTILS_H + +#include <gtk/gtk.h> +#include <e-util/e-signature.h> +#include <e-util/e-signature-list.h> + +G_BEGIN_DECLS + +ESignatureList *e_get_signature_list (void); +ESignature * e_get_signature_by_name (const gchar *name); +ESignature * e_get_signature_by_uid (const gchar *uid); +gchar * e_create_signature_file (GError **error); +gchar * e_read_signature_file (ESignature *signature, + gboolean convert_to_html, + GError **error); +gchar * e_run_signature_script (const gchar *filename); + +G_END_DECLS + +#endif /* E_SIGNATURE_UTILS_H */ diff --git a/e-util/e-unicode.c b/e-util/e-unicode.c new file mode 100644 index 0000000000..fb815ff94f --- /dev/null +++ b/e-util/e-unicode.c @@ -0,0 +1,2052 @@ +/* + * e-unicode.c - utf-8 support functions for gal + * + * 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: + * Lauris Kaplinski <lauris@ximian.com> + * + * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com) + * + */ + +/* + * TODO: Break simple ligatures in e_utf8_strstrcasedecomp + */ + +#include <config.h> + +#include <stdlib.h> +#include <string.h> +#include <stdio.h> +#include <ctype.h> +#include <iconv.h> +#ifdef HAVE_ALLOCA_H +#include <alloca.h> +#endif + +#include <gdk/gdkkeysyms.h> +#include <gtk/gtk.h> +#include <libxml/xmlmemory.h> + +#include <camel/camel-iconv.h> + +#include <glib/gi18n.h> +#include "e-unicode.h" + +#define d(x) + +#define FONT_TESTING +#define MAX_DECOMP 8 + +static gint e_canonical_decomposition (gunichar ch, gunichar * buf); +static gunichar e_stripped_char (gunichar ch); + +/* FIXME: this has not been ported fully yet - non ASCII people beware. */ + +/* + * This my favourite + * + * strstr doing case insensitive, decomposing search + * + * Lauris + */ + +const gchar * +e_utf8_strstrcasedecomp (const gchar *haystack, const gchar *needle) +{ + gunichar *nuni; + gunichar unival; + gint nlen; + const gchar *o, *p; + + if (haystack == NULL) return NULL; + if (needle == NULL) return NULL; + if (strlen (needle) == 0) return haystack; + if (strlen (haystack) == 0) return NULL; + + nuni = alloca (sizeof (gunichar) * strlen (needle)); + + nlen = 0; + for (p = e_unicode_get_utf8 (needle, &unival); p && unival; p = e_unicode_get_utf8 (p, &unival)) { + gint sc; + sc = e_stripped_char (unival); + if (sc) { + nuni[nlen++] = sc; + } + } + /* NULL means there was illegal utf-8 sequence */ + if (!p) return NULL; + /* If everything is correct, we have decomposed, lowercase, stripped needle */ + if (nlen < 1) return haystack; + + o = haystack; + for (p = e_unicode_get_utf8 (o, &unival); p && unival; p = e_unicode_get_utf8 (p, &unival)) { + gint sc; + sc = e_stripped_char (unival); + if (sc) { + /* We have valid stripped gchar */ + if (sc == nuni[0]) { + const gchar *q = p; + gint npos = 1; + while (npos < nlen) { + q = e_unicode_get_utf8 (q, &unival); + if (!q || !unival) return NULL; + sc = e_stripped_char (unival); + if ((!sc) || (sc != nuni[npos])) break; + npos++; + } + if (npos == nlen) { + return o; + } + } + } + o = p; + } + + return NULL; +} + +const gchar * +e_utf8_strstrcase (const gchar *haystack, const gchar *needle) +{ + gunichar *nuni; + gunichar unival; + gint nlen; + const gchar *o, *p; + + if (haystack == NULL) return NULL; + if (needle == NULL) return NULL; + if (strlen (needle) == 0) return haystack; + if (strlen (haystack) == 0) return NULL; + + nuni = alloca (sizeof (gunichar) * strlen (needle)); + + nlen = 0; + for (p = e_unicode_get_utf8 (needle, &unival); p && unival; p = e_unicode_get_utf8 (p, &unival)) { + nuni[nlen++] = g_unichar_tolower (unival); + } + /* NULL means there was illegal utf-8 sequence */ + if (!p) return NULL; + + o = haystack; + for (p = e_unicode_get_utf8 (o, &unival); p && unival; p = e_unicode_get_utf8 (p, &unival)) { + gint sc; + sc = g_unichar_tolower (unival); + /* We have valid stripped gchar */ + if (sc == nuni[0]) { + const gchar *q = p; + gint npos = 1; + while (npos < nlen) { + q = e_unicode_get_utf8 (q, &unival); + if (!q || !unival) return NULL; + sc = g_unichar_tolower (unival); + if (sc != nuni[npos]) break; + npos++; + } + if (npos == nlen) { + return o; + } + } + o = p; + } + + return NULL; +} + +#if 0 +const gchar * +e_utf8_strstrcase (const gchar *haystack, const gchar *needle) +{ + gchar *p; + gunichar *huni, *nuni; + gunichar unival; + gint hlen, nlen, hp, np; + + if (haystack == NULL) return NULL; + if (needle == NULL) return NULL; + if (strlen (needle) == 0) return haystack; + + huni = alloca (sizeof (gunichar) * strlen (haystack)); + + for (hlen = 0, p = e_unicode_get_utf8 (haystack, &unival); p && unival; hlen++, p = e_unicode_get_utf8 (p, &unival)) { + huni[hlen] = g_unichar_tolower (unival); + } + + if (!p) return NULL; + if (hlen == 0) return NULL; + + nuni = alloca (sizeof (gunichar) * strlen (needle)); + + for (nlen = 0, p = e_unicode_get_utf8 (needle, &unival); p && unival; nlen++, p = e_unicode_get_utf8 (p, &unival)) { + nuni[nlen] = g_unichar_tolower (unival); + } + + if (!p) return NULL; + if (nlen == 0) return NULL; + + if (hlen < nlen) return NULL; + + for (hp = 0; hp <= hlen - nlen; hp++) { + for (np = 0; np < nlen; np++) { + if (huni[hp + np] != nuni[np]) break; + } + if (np == nlen) return haystack + unicode_offset_to_index (haystack, hp); + } + + return NULL; +} +#endif + +gchar * +e_utf8_from_gtk_event_key (GtkWidget *widget, guint keyval, const gchar *string) +{ + gint unival; + gchar *utf; + gint unilen; + + if (keyval == GDK_VoidSymbol) { + utf = e_utf8_from_locale_string (string); + } else { + unival = gdk_keyval_to_unicode (keyval); + + if (unival < ' ') return NULL; + + utf = g_new (gchar, 7); + + unilen = e_unichar_to_utf8 (unival, utf); + + utf[unilen] = '\0'; + } + + return utf; +} + +gchar * +e_utf8_from_iconv_string_sized (iconv_t ic, const gchar *string, gint bytes) +{ + gchar *new, *ob; + const gchar *ib; + gsize ibl, obl; + + if (!string) return NULL; + + if (ic == (iconv_t) -1) { + gint i; + /* iso-8859-1 */ + ib = (gchar *) string; + new = ob = (gchar *)g_new (unsigned char, bytes * 2 + 1); + for (i = 0; i < (bytes); i ++) { + ob += e_unichar_to_utf8 (ib[i], ob); + } + *ob = '\0'; + return new; + } + + ib = string; + ibl = bytes; + new = ob = g_new (gchar, ibl * 6 + 1); + obl = ibl * 6; + + while (ibl > 0) { + camel_iconv (ic, &ib, &ibl, &ob, &obl); + if (ibl > 0) { + gint len; + if ((*ib & 0x80) == 0x00) len = 1; + else if ((*ib &0xe0) == 0xc0) len = 2; + else if ((*ib &0xf0) == 0xe0) len = 3; + else if ((*ib &0xf8) == 0xf0) len = 4; + else { + g_warning ("Invalid UTF-8 sequence"); + break; + } + ib += len; + ibl = bytes - (ib - string); + if (ibl > bytes) ibl = 0; + *ob++ = '_'; + obl--; + } + } + + *ob = '\0'; + + return new; +} + +gchar * +e_utf8_from_iconv_string (iconv_t ic, const gchar *string) +{ + if (!string) return NULL; + return e_utf8_from_iconv_string_sized (ic, string, strlen (string)); +} + +gchar * +e_utf8_to_iconv_string_sized (iconv_t ic, const gchar *string, gint bytes) +{ + gchar *new, *ob; + const gchar *ib; + gsize ibl, obl; + + if (!string) return NULL; + + if (ic == (iconv_t) -1) { + gint len; + const gchar *u; + gunichar uc; + + new = (gchar *)g_new (unsigned char, bytes * 4 + 1); + u = string; + len = 0; + + while ((u) && (u - string < bytes)) { + u = e_unicode_get_utf8 (u, &uc); + new[len++] = uc & 0xff; + } + new[len] = '\0'; + return new; + } + + ib = string; + ibl = bytes; + new = ob = g_new (char, ibl * 4 + 4); + obl = ibl * 4; + + while (ibl > 0) { + camel_iconv (ic, &ib, &ibl, &ob, &obl); + if (ibl > 0) { + gint len; + if ((*ib & 0x80) == 0x00) len = 1; + else if ((*ib &0xe0) == 0xc0) len = 2; + else if ((*ib &0xf0) == 0xe0) len = 3; + else if ((*ib &0xf8) == 0xf0) len = 4; + else { + g_warning ("Invalid UTF-8 sequence"); + break; + } + ib += len; + ibl = bytes - (ib - string); + if (ibl > bytes) ibl = 0; + + /* FIXME: this is wrong... what if the destination charset is 16 or 32 bit? */ + *ob++ = '_'; + obl--; + } + } + + /* Make sure to terminate with plenty of padding */ + memset (ob, 0, 4); + + return new; +} + +gchar * +e_utf8_to_iconv_string (iconv_t ic, const gchar *string) +{ + if (!string) return NULL; + return e_utf8_to_iconv_string_sized (ic, string, strlen (string)); +} + +gchar * +e_utf8_from_charset_string_sized (const gchar *charset, const gchar *string, gint bytes) +{ + iconv_t ic; + gchar *ret; + + if (!string) return NULL; + + ic = camel_iconv_open("utf-8", charset); + ret = e_utf8_from_iconv_string_sized (ic, string, bytes); + camel_iconv_close(ic); + + return ret; +} + +gchar * +e_utf8_from_charset_string (const gchar *charset, const gchar *string) +{ + if (!string) return NULL; + return e_utf8_from_charset_string_sized (charset, string, strlen (string)); +} + +gchar * +e_utf8_to_charset_string_sized (const gchar *charset, const gchar *string, gint bytes) +{ + iconv_t ic; + gchar *ret; + + if (!string) return NULL; + + ic = camel_iconv_open(charset, "utf-8"); + ret = e_utf8_to_iconv_string_sized (ic, string, bytes); + camel_iconv_close(ic); + + return ret; +} + +gchar * +e_utf8_to_charset_string (const gchar *charset, const gchar *string) +{ + if (!string) return NULL; + return e_utf8_to_charset_string_sized (charset, string, strlen (string)); +} + +gchar * +e_utf8_from_locale_string_sized (const gchar *string, gint bytes) +{ + iconv_t ic; + gchar *ret; + + if (!string) return NULL; + + ic = camel_iconv_open("utf-8", camel_iconv_locale_charset()); + ret = e_utf8_from_iconv_string_sized (ic, string, bytes); + camel_iconv_close(ic); + + return ret; +} + +gchar * +e_utf8_from_locale_string (const gchar *string) +{ + if (!string) return NULL; + return e_utf8_from_locale_string_sized (string, strlen (string)); +} + +gchar * +e_utf8_to_locale_string_sized (const gchar *string, gint bytes) +{ + iconv_t ic; + gchar *ret; + + if (!string) return NULL; + + ic = camel_iconv_open(camel_iconv_locale_charset(), "utf-8"); + ret = e_utf8_to_iconv_string_sized (ic, string, bytes); + camel_iconv_close(ic); + + return ret; +} + +gchar * +e_utf8_to_locale_string (const gchar *string) +{ + if (!string) return NULL; + return e_utf8_to_locale_string_sized (string, strlen (string)); +} + +gboolean +e_utf8_is_ascii (const gchar *string) +{ + gchar c; + + g_return_val_if_fail (string != NULL, FALSE); + + for (; (c = *string); string++) { + if (c & 0x80) + return FALSE; + } + + return TRUE; +} + +gchar * +e_utf8_gtk_entry_get_text (GtkEntry *entry) +{ + return g_strdup (gtk_entry_get_text (entry)); +} + +gchar * +e_utf8_gtk_editable_get_text (GtkEditable *editable) +{ + return gtk_editable_get_chars (editable, 0, -1); +} + +gchar * +e_utf8_gtk_editable_get_chars (GtkEditable *editable, gint start, gint end) +{ + return gtk_editable_get_chars (editable, start, end); +} + +void +e_utf8_gtk_editable_insert_text (GtkEditable *editable, const gchar *text, gint length, gint *position) +{ + gtk_editable_insert_text (editable, text, length, position); +} + +void +e_utf8_gtk_editable_set_text (GtkEditable *editable, const gchar *text) +{ + gint position; + + gtk_editable_delete_text(editable, 0, -1); + gtk_editable_insert_text (editable, text, strlen (text), &position); +} + +void +e_utf8_gtk_entry_set_text (GtkEntry *entry, const gchar *text) +{ + if (!text) + gtk_entry_set_text(entry, ""); + else + gtk_entry_set_text (entry, text); +} + +/* + * Translate \U+XXXX\ sequences to utf8 chars + */ + +gchar * +e_utf8_xml1_decode (const gchar *text) +{ + const guchar *c; + gchar *u, *d; + gint len, s; + + g_return_val_if_fail (text != NULL, NULL); + + len = strlen (text)+1; + /* len * 2 is absolute maximum */ + u = d = g_malloc (len * 2); + + c = (guchar *)text; + s = 0; + while (s < len) { + if ((s <= (len - 8)) && + (c[s ] == '\\') && + (c[s + 1] == 'U' ) && + (c[s + 2] == '+' ) && + isxdigit (c[s + 3]) && + isxdigit (c[s + 4]) && + isxdigit (c[s + 5]) && + isxdigit (c[s + 6]) && + (c[s + 7] == '\\')) { + /* Valid \U+XXXX\ sequence */ + gint unival; + unival = strtol ((gchar *)(c + s + 3), NULL, 16); + d += e_unichar_to_utf8 (unival, d); + s += 8; + } else if (c[s] > 127) { + /* fixme: We assume iso-8859-1 currently */ + d += e_unichar_to_utf8 (c[s], d); + s += 1; + } else { + *d++ = c[s++]; + } + } + *d++ = '\0'; + u = g_realloc (u, (d - u)); + + return u; +} + +gchar * +e_utf8_xml1_encode (const gchar *text) +{ + gchar *u, *d, *c; + guint unival; + gint len; + + g_return_val_if_fail (text != NULL, NULL); + + len = 0; + for (u = e_unicode_get_utf8 (text, &unival); u && unival; u = e_unicode_get_utf8 (u, &unival)) { + if ((unival >= 0x80) || (unival == '\\')) { + len += 8; + } else { + len += 1; + } + } + d = c = (gchar *)g_new (guchar, len + 1); + + for (u = e_unicode_get_utf8 (text, &unival); u && unival; u = e_unicode_get_utf8 (u, &unival)) { + if ((unival >= 0x80) || (unival == '\\')) { + *c++ = '\\'; + *c++ = 'U'; + *c++ = '+'; + c += sprintf (c, "%04x", unival); + *c++ = '\\'; + } else { + *c++ = unival; + } + } + *c = '\0'; + + return d; +} + +/** + * e_unichar_to_utf8: + * @c: a ISO10646 character code + * @outbuf: output buffer, must have at least 6 bytes of space. + * If %NULL, the length will be computed and returned + * and nothing will be written to @out. + * + * Convert a single character to utf8 + * + * Return value: number of bytes written + **/ + +gint +e_unichar_to_utf8 (gint c, gchar *outbuf) +{ + gsize len = 0; + gint first; + gint i; + + if (c < 0x80) + { + first = 0; + len = 1; + } + else if (c < 0x800) + { + first = 0xc0; + len = 2; + } + else if (c < 0x10000) + { + first = 0xe0; + len = 3; + } + else if (c < 0x200000) + { + first = 0xf0; + len = 4; + } + else if (c < 0x4000000) + { + first = 0xf8; + len = 5; + } + else + { + first = 0xfc; + len = 6; + } + + if (outbuf) + { + for (i = len - 1; i > 0; --i) + { + outbuf[i] = (c & 0x3f) | 0x80; + c >>= 6; + } + outbuf[0] = c | first; + } + + return len; +} + +gchar * +e_unicode_get_utf8 (const gchar *text, gunichar *out) +{ + *out = g_utf8_get_char (text); + return (*out == (gunichar)-1) ? NULL : g_utf8_next_char (text); +} + +/* + * Canonical decomposition + * + * It is copied here from libunicode, because we do not want malloc + * + */ + +typedef struct +{ + gushort ch; + const gchar *expansion; +} e_decomposition; + +static e_decomposition e_decomp_table[] = +{ + { 0x00c0, "\x00\x41\x03\x00\0" }, + { 0x00c1, "\x00\x41\x03\x01\0" }, + { 0x00c2, "\x00\x41\x03\x02\0" }, + { 0x00c3, "\x00\x41\x03\x03\0" }, + { 0x00c4, "\x00\x41\x03\x08\0" }, + { 0x00c5, "\x00\x41\x03\x0a\0" }, + { 0x00c7, "\x00\x43\x03\x27\0" }, + { 0x00c8, "\x00\x45\x03\x00\0" }, + { 0x00c9, "\x00\x45\x03\x01\0" }, + { 0x00ca, "\x00\x45\x03\x02\0" }, + { 0x00cb, "\x00\x45\x03\x08\0" }, + { 0x00cc, "\x00\x49\x03\x00\0" }, + { 0x00cd, "\x00\x49\x03\x01\0" }, + { 0x00ce, "\x00\x49\x03\x02\0" }, + { 0x00cf, "\x00\x49\x03\x08\0" }, + { 0x00d1, "\x00\x4e\x03\x03\0" }, + { 0x00d2, "\x00\x4f\x03\x00\0" }, + { 0x00d3, "\x00\x4f\x03\x01\0" }, + { 0x00d4, "\x00\x4f\x03\x02\0" }, + { 0x00d5, "\x00\x4f\x03\x03\0" }, + { 0x00d6, "\x00\x4f\x03\x08\0" }, + { 0x00d9, "\x00\x55\x03\x00\0" }, + { 0x00da, "\x00\x55\x03\x01\0" }, + { 0x00db, "\x00\x55\x03\x02\0" }, + { 0x00dc, "\x00\x55\x03\x08\0" }, + { 0x00dd, "\x00\x59\x03\x01\0" }, + { 0x00e0, "\x00\x61\x03\x00\0" }, + { 0x00e1, "\x00\x61\x03\x01\0" }, + { 0x00e2, "\x00\x61\x03\x02\0" }, + { 0x00e3, "\x00\x61\x03\x03\0" }, + { 0x00e4, "\x00\x61\x03\x08\0" }, + { 0x00e5, "\x00\x61\x03\x0a\0" }, + { 0x00e7, "\x00\x63\x03\x27\0" }, + { 0x00e8, "\x00\x65\x03\x00\0" }, + { 0x00e9, "\x00\x65\x03\x01\0" }, + { 0x00ea, "\x00\x65\x03\x02\0" }, + { 0x00eb, "\x00\x65\x03\x08\0" }, + { 0x00ec, "\x00\x69\x03\x00\0" }, + { 0x00ed, "\x00\x69\x03\x01\0" }, + { 0x00ee, "\x00\x69\x03\x02\0" }, + { 0x00ef, "\x00\x69\x03\x08\0" }, + { 0x00f1, "\x00\x6e\x03\x03\0" }, + { 0x00f2, "\x00\x6f\x03\x00\0" }, + { 0x00f3, "\x00\x6f\x03\x01\0" }, + { 0x00f4, "\x00\x6f\x03\x02\0" }, + { 0x00f5, "\x00\x6f\x03\x03\0" }, + { 0x00f6, "\x00\x6f\x03\x08\0" }, + { 0x00f9, "\x00\x75\x03\x00\0" }, + { 0x00fa, "\x00\x75\x03\x01\0" }, + { 0x00fb, "\x00\x75\x03\x02\0" }, + { 0x00fc, "\x00\x75\x03\x08\0" }, + { 0x00fd, "\x00\x79\x03\x01\0" }, + { 0x00ff, "\x00\x79\x03\x08\0" }, + { 0x0100, "\x00\x41\x03\x04\0" }, + { 0x0101, "\x00\x61\x03\x04\0" }, + { 0x0102, "\x00\x41\x03\x06\0" }, + { 0x0103, "\x00\x61\x03\x06\0" }, + { 0x0104, "\x00\x41\x03\x28\0" }, + { 0x0105, "\x00\x61\x03\x28\0" }, + { 0x0106, "\x00\x43\x03\x01\0" }, + { 0x0107, "\x00\x63\x03\x01\0" }, + { 0x0108, "\x00\x43\x03\x02\0" }, + { 0x0109, "\x00\x63\x03\x02\0" }, + { 0x010a, "\x00\x43\x03\x07\0" }, + { 0x010b, "\x00\x63\x03\x07\0" }, + { 0x010c, "\x00\x43\x03\x0c\0" }, + { 0x010d, "\x00\x63\x03\x0c\0" }, + { 0x010e, "\x00\x44\x03\x0c\0" }, + { 0x010f, "\x00\x64\x03\x0c\0" }, + { 0x0112, "\x00\x45\x03\x04\0" }, + { 0x0113, "\x00\x65\x03\x04\0" }, + { 0x0114, "\x00\x45\x03\x06\0" }, + { 0x0115, "\x00\x65\x03\x06\0" }, + { 0x0116, "\x00\x45\x03\x07\0" }, + { 0x0117, "\x00\x65\x03\x07\0" }, + { 0x0118, "\x00\x45\x03\x28\0" }, + { 0x0119, "\x00\x65\x03\x28\0" }, + { 0x011a, "\x00\x45\x03\x0c\0" }, + { 0x011b, "\x00\x65\x03\x0c\0" }, + { 0x011c, "\x00\x47\x03\x02\0" }, + { 0x011d, "\x00\x67\x03\x02\0" }, + { 0x011e, "\x00\x47\x03\x06\0" }, + { 0x011f, "\x00\x67\x03\x06\0" }, + { 0x0120, "\x00\x47\x03\x07\0" }, + { 0x0121, "\x00\x67\x03\x07\0" }, + { 0x0122, "\x00\x47\x03\x27\0" }, + { 0x0123, "\x00\x67\x03\x27\0" }, + { 0x0124, "\x00\x48\x03\x02\0" }, + { 0x0125, "\x00\x68\x03\x02\0" }, + { 0x0128, "\x00\x49\x03\x03\0" }, + { 0x0129, "\x00\x69\x03\x03\0" }, + { 0x012a, "\x00\x49\x03\x04\0" }, + { 0x012b, "\x00\x69\x03\x04\0" }, + { 0x012c, "\x00\x49\x03\x06\0" }, + { 0x012d, "\x00\x69\x03\x06\0" }, + { 0x012e, "\x00\x49\x03\x28\0" }, + { 0x012f, "\x00\x69\x03\x28\0" }, + { 0x0130, "\x00\x49\x03\x07\0" }, + { 0x0134, "\x00\x4a\x03\x02\0" }, + { 0x0135, "\x00\x6a\x03\x02\0" }, + { 0x0136, "\x00\x4b\x03\x27\0" }, + { 0x0137, "\x00\x6b\x03\x27\0" }, + { 0x0139, "\x00\x4c\x03\x01\0" }, + { 0x013a, "\x00\x6c\x03\x01\0" }, + { 0x013b, "\x00\x4c\x03\x27\0" }, + { 0x013c, "\x00\x6c\x03\x27\0" }, + { 0x013d, "\x00\x4c\x03\x0c\0" }, + { 0x013e, "\x00\x6c\x03\x0c\0" }, + { 0x0143, "\x00\x4e\x03\x01\0" }, + { 0x0144, "\x00\x6e\x03\x01\0" }, + { 0x0145, "\x00\x4e\x03\x27\0" }, + { 0x0146, "\x00\x6e\x03\x27\0" }, + { 0x0147, "\x00\x4e\x03\x0c\0" }, + { 0x0148, "\x00\x6e\x03\x0c\0" }, + { 0x014c, "\x00\x4f\x03\x04\0" }, + { 0x014d, "\x00\x6f\x03\x04\0" }, + { 0x014e, "\x00\x4f\x03\x06\0" }, + { 0x014f, "\x00\x6f\x03\x06\0" }, + { 0x0150, "\x00\x4f\x03\x0b\0" }, + { 0x0151, "\x00\x6f\x03\x0b\0" }, + { 0x0154, "\x00\x52\x03\x01\0" }, + { 0x0155, "\x00\x72\x03\x01\0" }, + { 0x0156, "\x00\x52\x03\x27\0" }, + { 0x0157, "\x00\x72\x03\x27\0" }, + { 0x0158, "\x00\x52\x03\x0c\0" }, + { 0x0159, "\x00\x72\x03\x0c\0" }, + { 0x015a, "\x00\x53\x03\x01\0" }, + { 0x015b, "\x00\x73\x03\x01\0" }, + { 0x015c, "\x00\x53\x03\x02\0" }, + { 0x015d, "\x00\x73\x03\x02\0" }, + { 0x015e, "\x00\x53\x03\x27\0" }, + { 0x015f, "\x00\x73\x03\x27\0" }, + { 0x0160, "\x00\x53\x03\x0c\0" }, + { 0x0161, "\x00\x73\x03\x0c\0" }, + { 0x0162, "\x00\x54\x03\x27\0" }, + { 0x0163, "\x00\x74\x03\x27\0" }, + { 0x0164, "\x00\x54\x03\x0c\0" }, + { 0x0165, "\x00\x74\x03\x0c\0" }, + { 0x0168, "\x00\x55\x03\x03\0" }, + { 0x0169, "\x00\x75\x03\x03\0" }, + { 0x016a, "\x00\x55\x03\x04\0" }, + { 0x016b, "\x00\x75\x03\x04\0" }, + { 0x016c, "\x00\x55\x03\x06\0" }, + { 0x016d, "\x00\x75\x03\x06\0" }, + { 0x016e, "\x00\x55\x03\x0a\0" }, + { 0x016f, "\x00\x75\x03\x0a\0" }, + { 0x0170, "\x00\x55\x03\x0b\0" }, + { 0x0171, "\x00\x75\x03\x0b\0" }, + { 0x0172, "\x00\x55\x03\x28\0" }, + { 0x0173, "\x00\x75\x03\x28\0" }, + { 0x0174, "\x00\x57\x03\x02\0" }, + { 0x0175, "\x00\x77\x03\x02\0" }, + { 0x0176, "\x00\x59\x03\x02\0" }, + { 0x0177, "\x00\x79\x03\x02\0" }, + { 0x0178, "\x00\x59\x03\x08\0" }, + { 0x0179, "\x00\x5a\x03\x01\0" }, + { 0x017a, "\x00\x7a\x03\x01\0" }, + { 0x017b, "\x00\x5a\x03\x07\0" }, + { 0x017c, "\x00\x7a\x03\x07\0" }, + { 0x017d, "\x00\x5a\x03\x0c\0" }, + { 0x017e, "\x00\x7a\x03\x0c\0" }, + { 0x01a0, "\x00\x4f\x03\x1b\0" }, + { 0x01a1, "\x00\x6f\x03\x1b\0" }, + { 0x01af, "\x00\x55\x03\x1b\0" }, + { 0x01b0, "\x00\x75\x03\x1b\0" }, + { 0x01cd, "\x00\x41\x03\x0c\0" }, + { 0x01ce, "\x00\x61\x03\x0c\0" }, + { 0x01cf, "\x00\x49\x03\x0c\0" }, + { 0x01d0, "\x00\x69\x03\x0c\0" }, + { 0x01d1, "\x00\x4f\x03\x0c\0" }, + { 0x01d2, "\x00\x6f\x03\x0c\0" }, + { 0x01d3, "\x00\x55\x03\x0c\0" }, + { 0x01d4, "\x00\x75\x03\x0c\0" }, + { 0x01d5, "\x00\x55\x03\x08\x03\x04\0" }, + { 0x01d6, "\x00\x75\x03\x08\x03\x04\0" }, + { 0x01d7, "\x00\x55\x03\x08\x03\x01\0" }, + { 0x01d8, "\x00\x75\x03\x08\x03\x01\0" }, + { 0x01d9, "\x00\x55\x03\x08\x03\x0c\0" }, + { 0x01da, "\x00\x75\x03\x08\x03\x0c\0" }, + { 0x01db, "\x00\x55\x03\x08\x03\x00\0" }, + { 0x01dc, "\x00\x75\x03\x08\x03\x00\0" }, + { 0x01de, "\x00\x41\x03\x08\x03\x04\0" }, + { 0x01df, "\x00\x61\x03\x08\x03\x04\0" }, + { 0x01e0, "\x00\x41\x03\x07\x03\x04\0" }, + { 0x01e1, "\x00\x61\x03\x07\x03\x04\0" }, + { 0x01e2, "\x00\xc6\x03\x04\0" }, + { 0x01e3, "\x00\xe6\x03\x04\0" }, + { 0x01e6, "\x00\x47\x03\x0c\0" }, + { 0x01e7, "\x00\x67\x03\x0c\0" }, + { 0x01e8, "\x00\x4b\x03\x0c\0" }, + { 0x01e9, "\x00\x6b\x03\x0c\0" }, + { 0x01ea, "\x00\x4f\x03\x28\0" }, + { 0x01eb, "\x00\x6f\x03\x28\0" }, + { 0x01ec, "\x00\x4f\x03\x28\x03\x04\0" }, + { 0x01ed, "\x00\x6f\x03\x28\x03\x04\0" }, + { 0x01ee, "\x01\xb7\x03\x0c\0" }, + { 0x01ef, "\x02\x92\x03\x0c\0" }, + { 0x01f0, "\x00\x6a\x03\x0c\0" }, + { 0x01f4, "\x00\x47\x03\x01\0" }, + { 0x01f5, "\x00\x67\x03\x01\0" }, + { 0x01fa, "\x00\x41\x03\x0a\x03\x01\0" }, + { 0x01fb, "\x00\x61\x03\x0a\x03\x01\0" }, + { 0x01fc, "\x00\xc6\x03\x01\0" }, + { 0x01fd, "\x00\xe6\x03\x01\0" }, + { 0x01fe, "\x00\xd8\x03\x01\0" }, + { 0x01ff, "\x00\xf8\x03\x01\0" }, + { 0x0200, "\x00\x41\x03\x0f\0" }, + { 0x0201, "\x00\x61\x03\x0f\0" }, + { 0x0202, "\x00\x41\x03\x11\0" }, + { 0x0203, "\x00\x61\x03\x11\0" }, + { 0x0204, "\x00\x45\x03\x0f\0" }, + { 0x0205, "\x00\x65\x03\x0f\0" }, + { 0x0206, "\x00\x45\x03\x11\0" }, + { 0x0207, "\x00\x65\x03\x11\0" }, + { 0x0208, "\x00\x49\x03\x0f\0" }, + { 0x0209, "\x00\x69\x03\x0f\0" }, + { 0x020a, "\x00\x49\x03\x11\0" }, + { 0x020b, "\x00\x69\x03\x11\0" }, + { 0x020c, "\x00\x4f\x03\x0f\0" }, + { 0x020d, "\x00\x6f\x03\x0f\0" }, + { 0x020e, "\x00\x4f\x03\x11\0" }, + { 0x020f, "\x00\x6f\x03\x11\0" }, + { 0x0210, "\x00\x52\x03\x0f\0" }, + { 0x0211, "\x00\x72\x03\x0f\0" }, + { 0x0212, "\x00\x52\x03\x11\0" }, + { 0x0213, "\x00\x72\x03\x11\0" }, + { 0x0214, "\x00\x55\x03\x0f\0" }, + { 0x0215, "\x00\x75\x03\x0f\0" }, + { 0x0216, "\x00\x55\x03\x11\0" }, + { 0x0217, "\x00\x75\x03\x11\0" }, + { 0x0340, "\x03\x00\0" }, + { 0x0341, "\x03\x01\0" }, + { 0x0343, "\x03\x13\0" }, + { 0x0344, "\x03\x08\x03\x01\0" }, + { 0x0374, "\x02\xb9\0" }, + { 0x037e, "\x00\x3b\0" }, + { 0x0385, "\x00\xa8\x03\x01\0" }, + { 0x0386, "\x03\x91\x03\x01\0" }, + { 0x0387, "\x00\xb7\0" }, + { 0x0388, "\x03\x95\x03\x01\0" }, + { 0x0389, "\x03\x97\x03\x01\0" }, + { 0x038a, "\x03\x99\x03\x01\0" }, + { 0x038c, "\x03\x9f\x03\x01\0" }, + { 0x038e, "\x03\xa5\x03\x01\0" }, + { 0x038f, "\x03\xa9\x03\x01\0" }, + { 0x0390, "\x03\xb9\x03\x08\x03\x01\0" }, + { 0x03aa, "\x03\x99\x03\x08\0" }, + { 0x03ab, "\x03\xa5\x03\x08\0" }, + { 0x03ac, "\x03\xb1\x03\x01\0" }, + { 0x03ad, "\x03\xb5\x03\x01\0" }, + { 0x03ae, "\x03\xb7\x03\x01\0" }, + { 0x03af, "\x03\xb9\x03\x01\0" }, + { 0x03b0, "\x03\xc5\x03\x08\x03\x01\0" }, + { 0x03ca, "\x03\xb9\x03\x08\0" }, + { 0x03cb, "\x03\xc5\x03\x08\0" }, + { 0x03cc, "\x03\xbf\x03\x01\0" }, + { 0x03cd, "\x03\xc5\x03\x01\0" }, + { 0x03ce, "\x03\xc9\x03\x01\0" }, + { 0x03d3, "\x03\xd2\x03\x01\0" }, + { 0x03d4, "\x03\xd2\x03\x08\0" }, + { 0x0401, "\x04\x15\x03\x08\0" }, + { 0x0403, "\x04\x13\x03\x01\0" }, + { 0x0407, "\x04\x06\x03\x08\0" }, + { 0x040c, "\x04\x1a\x03\x01\0" }, + { 0x040e, "\x04\x23\x03\x06\0" }, + { 0x0419, "\x04\x18\x03\x06\0" }, + { 0x0439, "\x04\x38\x03\x06\0" }, + { 0x0451, "\x04\x35\x03\x08\0" }, + { 0x0453, "\x04\x33\x03\x01\0" }, + { 0x0457, "\x04\x56\x03\x08\0" }, + { 0x045c, "\x04\x3a\x03\x01\0" }, + { 0x045e, "\x04\x43\x03\x06\0" }, + { 0x0476, "\x04\x74\x03\x0f\0" }, + { 0x0477, "\x04\x75\x03\x0f\0" }, + { 0x04c1, "\x04\x16\x03\x06\0" }, + { 0x04c2, "\x04\x36\x03\x06\0" }, + { 0x04d0, "\x04\x10\x03\x06\0" }, + { 0x04d1, "\x04\x30\x03\x06\0" }, + { 0x04d2, "\x04\x10\x03\x08\0" }, + { 0x04d3, "\x04\x30\x03\x08\0" }, + { 0x04d6, "\x04\x15\x03\x06\0" }, + { 0x04d7, "\x04\x35\x03\x06\0" }, + { 0x04da, "\x04\xd8\x03\x08\0" }, + { 0x04db, "\x04\xd9\x03\x08\0" }, + { 0x04dc, "\x04\x16\x03\x08\0" }, + { 0x04dd, "\x04\x36\x03\x08\0" }, + { 0x04de, "\x04\x17\x03\x08\0" }, + { 0x04df, "\x04\x37\x03\x08\0" }, + { 0x04e2, "\x04\x18\x03\x04\0" }, + { 0x04e3, "\x04\x38\x03\x04\0" }, + { 0x04e4, "\x04\x18\x03\x08\0" }, + { 0x04e5, "\x04\x38\x03\x08\0" }, + { 0x04e6, "\x04\x1e\x03\x08\0" }, + { 0x04e7, "\x04\x3e\x03\x08\0" }, + { 0x04ea, "\x04\xe8\x03\x08\0" }, + { 0x04eb, "\x04\xe9\x03\x08\0" }, + { 0x04ee, "\x04\x23\x03\x04\0" }, + { 0x04ef, "\x04\x43\x03\x04\0" }, + { 0x04f0, "\x04\x23\x03\x08\0" }, + { 0x04f1, "\x04\x43\x03\x08\0" }, + { 0x04f2, "\x04\x23\x03\x0b\0" }, + { 0x04f3, "\x04\x43\x03\x0b\0" }, + { 0x04f4, "\x04\x27\x03\x08\0" }, + { 0x04f5, "\x04\x47\x03\x08\0" }, + { 0x04f8, "\x04\x2b\x03\x08\0" }, + { 0x04f9, "\x04\x4b\x03\x08\0" }, + { 0x0929, "\x09\x28\x09\x3c\0" }, + { 0x0931, "\x09\x30\x09\x3c\0" }, + { 0x0934, "\x09\x33\x09\x3c\0" }, + { 0x0958, "\x09\x15\x09\x3c\0" }, + { 0x0959, "\x09\x16\x09\x3c\0" }, + { 0x095a, "\x09\x17\x09\x3c\0" }, + { 0x095b, "\x09\x1c\x09\x3c\0" }, + { 0x095c, "\x09\x21\x09\x3c\0" }, + { 0x095d, "\x09\x22\x09\x3c\0" }, + { 0x095e, "\x09\x2b\x09\x3c\0" }, + { 0x095f, "\x09\x2f\x09\x3c\0" }, + { 0x09b0, "\x09\xac\x09\xbc\0" }, + { 0x09cb, "\x09\xc7\x09\xbe\0" }, + { 0x09cc, "\x09\xc7\x09\xd7\0" }, + { 0x09dc, "\x09\xa1\x09\xbc\0" }, + { 0x09dd, "\x09\xa2\x09\xbc\0" }, + { 0x09df, "\x09\xaf\x09\xbc\0" }, + { 0x0a59, "\x0a\x16\x0a\x3c\0" }, + { 0x0a5a, "\x0a\x17\x0a\x3c\0" }, + { 0x0a5b, "\x0a\x1c\x0a\x3c\0" }, + { 0x0a5c, "\x0a\x21\x0a\x3c\0" }, + { 0x0a5e, "\x0a\x2b\x0a\x3c\0" }, + { 0x0b48, "\x0b\x47\x0b\x56\0" }, + { 0x0b4b, "\x0b\x47\x0b\x3e\0" }, + { 0x0b4c, "\x0b\x47\x0b\x57\0" }, + { 0x0b5c, "\x0b\x21\x0b\x3c\0" }, + { 0x0b5d, "\x0b\x22\x0b\x3c\0" }, + { 0x0b5f, "\x0b\x2f\x0b\x3c\0" }, + { 0x0b94, "\x0b\x92\x0b\xd7\0" }, + { 0x0bca, "\x0b\xc6\x0b\xbe\0" }, + { 0x0bcb, "\x0b\xc7\x0b\xbe\0" }, + { 0x0bcc, "\x0b\xc6\x0b\xd7\0" }, + { 0x0c48, "\x0c\x46\x0c\x56\0" }, + { 0x0cc0, "\x0c\xbf\x0c\xd5\0" }, + { 0x0cc7, "\x0c\xc6\x0c\xd5\0" }, + { 0x0cc8, "\x0c\xc6\x0c\xd6\0" }, + { 0x0cca, "\x0c\xc6\x0c\xc2\0" }, + { 0x0ccb, "\x0c\xc6\x0c\xc2\x0c\xd5\0" }, + { 0x0d4a, "\x0d\x46\x0d\x3e\0" }, + { 0x0d4b, "\x0d\x47\x0d\x3e\0" }, + { 0x0d4c, "\x0d\x46\x0d\x57\0" }, + { 0x0e33, "\x0e\x4d\x0e\x32\0" }, + { 0x0eb3, "\x0e\xcd\x0e\xb2\0" }, + { 0x0f43, "\x0f\x42\x0f\xb7\0" }, + { 0x0f4d, "\x0f\x4c\x0f\xb7\0" }, + { 0x0f52, "\x0f\x51\x0f\xb7\0" }, + { 0x0f57, "\x0f\x56\x0f\xb7\0" }, + { 0x0f5c, "\x0f\x5b\x0f\xb7\0" }, + { 0x0f69, "\x0f\x40\x0f\xb5\0" }, + { 0x0f73, "\x0f\x71\x0f\x72\0" }, + { 0x0f75, "\x0f\x71\x0f\x74\0" }, + { 0x0f76, "\x0f\xb2\x0f\x80\0" }, + { 0x0f78, "\x0f\xb3\x0f\x80\0" }, + { 0x0f81, "\x0f\x71\x0f\x80\0" }, + { 0x0f93, "\x0f\x92\x0f\xb7\0" }, + { 0x0f9d, "\x0f\x9c\x0f\xb7\0" }, + { 0x0fa2, "\x0f\xa1\x0f\xb7\0" }, + { 0x0fa7, "\x0f\xa6\x0f\xb7\0" }, + { 0x0fac, "\x0f\xab\x0f\xb7\0" }, + { 0x0fb9, "\x0f\x90\x0f\xb5\0" }, + { 0x1e00, "\x00\x41\x03\x25\0" }, + { 0x1e01, "\x00\x61\x03\x25\0" }, + { 0x1e02, "\x00\x42\x03\x07\0" }, + { 0x1e03, "\x00\x62\x03\x07\0" }, + { 0x1e04, "\x00\x42\x03\x23\0" }, + { 0x1e05, "\x00\x62\x03\x23\0" }, + { 0x1e06, "\x00\x42\x03\x31\0" }, + { 0x1e07, "\x00\x62\x03\x31\0" }, + { 0x1e08, "\x00\x43\x03\x27\x03\x01\0" }, + { 0x1e09, "\x00\x63\x03\x27\x03\x01\0" }, + { 0x1e0a, "\x00\x44\x03\x07\0" }, + { 0x1e0b, "\x00\x64\x03\x07\0" }, + { 0x1e0c, "\x00\x44\x03\x23\0" }, + { 0x1e0d, "\x00\x64\x03\x23\0" }, + { 0x1e0e, "\x00\x44\x03\x31\0" }, + { 0x1e0f, "\x00\x64\x03\x31\0" }, + { 0x1e10, "\x00\x44\x03\x27\0" }, + { 0x1e11, "\x00\x64\x03\x27\0" }, + { 0x1e12, "\x00\x44\x03\x2d\0" }, + { 0x1e13, "\x00\x64\x03\x2d\0" }, + { 0x1e14, "\x00\x45\x03\x04\x03\x00\0" }, + { 0x1e15, "\x00\x65\x03\x04\x03\x00\0" }, + { 0x1e16, "\x00\x45\x03\x04\x03\x01\0" }, + { 0x1e17, "\x00\x65\x03\x04\x03\x01\0" }, + { 0x1e18, "\x00\x45\x03\x2d\0" }, + { 0x1e19, "\x00\x65\x03\x2d\0" }, + { 0x1e1a, "\x00\x45\x03\x30\0" }, + { 0x1e1b, "\x00\x65\x03\x30\0" }, + { 0x1e1c, "\x00\x45\x03\x27\x03\x06\0" }, + { 0x1e1d, "\x00\x65\x03\x27\x03\x06\0" }, + { 0x1e1e, "\x00\x46\x03\x07\0" }, + { 0x1e1f, "\x00\x66\x03\x07\0" }, + { 0x1e20, "\x00\x47\x03\x04\0" }, + { 0x1e21, "\x00\x67\x03\x04\0" }, + { 0x1e22, "\x00\x48\x03\x07\0" }, + { 0x1e23, "\x00\x68\x03\x07\0" }, + { 0x1e24, "\x00\x48\x03\x23\0" }, + { 0x1e25, "\x00\x68\x03\x23\0" }, + { 0x1e26, "\x00\x48\x03\x08\0" }, + { 0x1e27, "\x00\x68\x03\x08\0" }, + { 0x1e28, "\x00\x48\x03\x27\0" }, + { 0x1e29, "\x00\x68\x03\x27\0" }, + { 0x1e2a, "\x00\x48\x03\x2e\0" }, + { 0x1e2b, "\x00\x68\x03\x2e\0" }, + { 0x1e2c, "\x00\x49\x03\x30\0" }, + { 0x1e2d, "\x00\x69\x03\x30\0" }, + { 0x1e2e, "\x00\x49\x03\x08\x03\x01\0" }, + { 0x1e2f, "\x00\x69\x03\x08\x03\x01\0" }, + { 0x1e30, "\x00\x4b\x03\x01\0" }, + { 0x1e31, "\x00\x6b\x03\x01\0" }, + { 0x1e32, "\x00\x4b\x03\x23\0" }, + { 0x1e33, "\x00\x6b\x03\x23\0" }, + { 0x1e34, "\x00\x4b\x03\x31\0" }, + { 0x1e35, "\x00\x6b\x03\x31\0" }, + { 0x1e36, "\x00\x4c\x03\x23\0" }, + { 0x1e37, "\x00\x6c\x03\x23\0" }, + { 0x1e38, "\x00\x4c\x03\x23\x03\x04\0" }, + { 0x1e39, "\x00\x6c\x03\x23\x03\x04\0" }, + { 0x1e3a, "\x00\x4c\x03\x31\0" }, + { 0x1e3b, "\x00\x6c\x03\x31\0" }, + { 0x1e3c, "\x00\x4c\x03\x2d\0" }, + { 0x1e3d, "\x00\x6c\x03\x2d\0" }, + { 0x1e3e, "\x00\x4d\x03\x01\0" }, + { 0x1e3f, "\x00\x6d\x03\x01\0" }, + { 0x1e40, "\x00\x4d\x03\x07\0" }, + { 0x1e41, "\x00\x6d\x03\x07\0" }, + { 0x1e42, "\x00\x4d\x03\x23\0" }, + { 0x1e43, "\x00\x6d\x03\x23\0" }, + { 0x1e44, "\x00\x4e\x03\x07\0" }, + { 0x1e45, "\x00\x6e\x03\x07\0" }, + { 0x1e46, "\x00\x4e\x03\x23\0" }, + { 0x1e47, "\x00\x6e\x03\x23\0" }, + { 0x1e48, "\x00\x4e\x03\x31\0" }, + { 0x1e49, "\x00\x6e\x03\x31\0" }, + { 0x1e4a, "\x00\x4e\x03\x2d\0" }, + { 0x1e4b, "\x00\x6e\x03\x2d\0" }, + { 0x1e4c, "\x00\x4f\x03\x03\x03\x01\0" }, + { 0x1e4d, "\x00\x6f\x03\x03\x03\x01\0" }, + { 0x1e4e, "\x00\x4f\x03\x03\x03\x08\0" }, + { 0x1e4f, "\x00\x6f\x03\x03\x03\x08\0" }, + { 0x1e50, "\x00\x4f\x03\x04\x03\x00\0" }, + { 0x1e51, "\x00\x6f\x03\x04\x03\x00\0" }, + { 0x1e52, "\x00\x4f\x03\x04\x03\x01\0" }, + { 0x1e53, "\x00\x6f\x03\x04\x03\x01\0" }, + { 0x1e54, "\x00\x50\x03\x01\0" }, + { 0x1e55, "\x00\x70\x03\x01\0" }, + { 0x1e56, "\x00\x50\x03\x07\0" }, + { 0x1e57, "\x00\x70\x03\x07\0" }, + { 0x1e58, "\x00\x52\x03\x07\0" }, + { 0x1e59, "\x00\x72\x03\x07\0" }, + { 0x1e5a, "\x00\x52\x03\x23\0" }, + { 0x1e5b, "\x00\x72\x03\x23\0" }, + { 0x1e5c, "\x00\x52\x03\x23\x03\x04\0" }, + { 0x1e5d, "\x00\x72\x03\x23\x03\x04\0" }, + { 0x1e5e, "\x00\x52\x03\x31\0" }, + { 0x1e5f, "\x00\x72\x03\x31\0" }, + { 0x1e60, "\x00\x53\x03\x07\0" }, + { 0x1e61, "\x00\x73\x03\x07\0" }, + { 0x1e62, "\x00\x53\x03\x23\0" }, + { 0x1e63, "\x00\x73\x03\x23\0" }, + { 0x1e64, "\x00\x53\x03\x01\x03\x07\0" }, + { 0x1e65, "\x00\x73\x03\x01\x03\x07\0" }, + { 0x1e66, "\x00\x53\x03\x0c\x03\x07\0" }, + { 0x1e67, "\x00\x73\x03\x0c\x03\x07\0" }, + { 0x1e68, "\x00\x53\x03\x23\x03\x07\0" }, + { 0x1e69, "\x00\x73\x03\x23\x03\x07\0" }, + { 0x1e6a, "\x00\x54\x03\x07\0" }, + { 0x1e6b, "\x00\x74\x03\x07\0" }, + { 0x1e6c, "\x00\x54\x03\x23\0" }, + { 0x1e6d, "\x00\x74\x03\x23\0" }, + { 0x1e6e, "\x00\x54\x03\x31\0" }, + { 0x1e6f, "\x00\x74\x03\x31\0" }, + { 0x1e70, "\x00\x54\x03\x2d\0" }, + { 0x1e71, "\x00\x74\x03\x2d\0" }, + { 0x1e72, "\x00\x55\x03\x24\0" }, + { 0x1e73, "\x00\x75\x03\x24\0" }, + { 0x1e74, "\x00\x55\x03\x30\0" }, + { 0x1e75, "\x00\x75\x03\x30\0" }, + { 0x1e76, "\x00\x55\x03\x2d\0" }, + { 0x1e77, "\x00\x75\x03\x2d\0" }, + { 0x1e78, "\x00\x55\x03\x03\x03\x01\0" }, + { 0x1e79, "\x00\x75\x03\x03\x03\x01\0" }, + { 0x1e7a, "\x00\x55\x03\x04\x03\x08\0" }, + { 0x1e7b, "\x00\x75\x03\x04\x03\x08\0" }, + { 0x1e7c, "\x00\x56\x03\x03\0" }, + { 0x1e7d, "\x00\x76\x03\x03\0" }, + { 0x1e7e, "\x00\x56\x03\x23\0" }, + { 0x1e7f, "\x00\x76\x03\x23\0" }, + { 0x1e80, "\x00\x57\x03\x00\0" }, + { 0x1e81, "\x00\x77\x03\x00\0" }, + { 0x1e82, "\x00\x57\x03\x01\0" }, + { 0x1e83, "\x00\x77\x03\x01\0" }, + { 0x1e84, "\x00\x57\x03\x08\0" }, + { 0x1e85, "\x00\x77\x03\x08\0" }, + { 0x1e86, "\x00\x57\x03\x07\0" }, + { 0x1e87, "\x00\x77\x03\x07\0" }, + { 0x1e88, "\x00\x57\x03\x23\0" }, + { 0x1e89, "\x00\x77\x03\x23\0" }, + { 0x1e8a, "\x00\x58\x03\x07\0" }, + { 0x1e8b, "\x00\x78\x03\x07\0" }, + { 0x1e8c, "\x00\x58\x03\x08\0" }, + { 0x1e8d, "\x00\x78\x03\x08\0" }, + { 0x1e8e, "\x00\x59\x03\x07\0" }, + { 0x1e8f, "\x00\x79\x03\x07\0" }, + { 0x1e90, "\x00\x5a\x03\x02\0" }, + { 0x1e91, "\x00\x7a\x03\x02\0" }, + { 0x1e92, "\x00\x5a\x03\x23\0" }, + { 0x1e93, "\x00\x7a\x03\x23\0" }, + { 0x1e94, "\x00\x5a\x03\x31\0" }, + { 0x1e95, "\x00\x7a\x03\x31\0" }, + { 0x1e96, "\x00\x68\x03\x31\0" }, + { 0x1e97, "\x00\x74\x03\x08\0" }, + { 0x1e98, "\x00\x77\x03\x0a\0" }, + { 0x1e99, "\x00\x79\x03\x0a\0" }, + { 0x1e9b, "\x01\x7f\x03\x07\0" }, + { 0x1ea0, "\x00\x41\x03\x23\0" }, + { 0x1ea1, "\x00\x61\x03\x23\0" }, + { 0x1ea2, "\x00\x41\x03\x09\0" }, + { 0x1ea3, "\x00\x61\x03\x09\0" }, + { 0x1ea4, "\x00\x41\x03\x02\x03\x01\0" }, + { 0x1ea5, "\x00\x61\x03\x02\x03\x01\0" }, + { 0x1ea6, "\x00\x41\x03\x02\x03\x00\0" }, + { 0x1ea7, "\x00\x61\x03\x02\x03\x00\0" }, + { 0x1ea8, "\x00\x41\x03\x02\x03\x09\0" }, + { 0x1ea9, "\x00\x61\x03\x02\x03\x09\0" }, + { 0x1eaa, "\x00\x41\x03\x02\x03\x03\0" }, + { 0x1eab, "\x00\x61\x03\x02\x03\x03\0" }, + { 0x1eac, "\x00\x41\x03\x23\x03\x02\0" }, + { 0x1ead, "\x00\x61\x03\x23\x03\x02\0" }, + { 0x1eae, "\x00\x41\x03\x06\x03\x01\0" }, + { 0x1eaf, "\x00\x61\x03\x06\x03\x01\0" }, + { 0x1eb0, "\x00\x41\x03\x06\x03\x00\0" }, + { 0x1eb1, "\x00\x61\x03\x06\x03\x00\0" }, + { 0x1eb2, "\x00\x41\x03\x06\x03\x09\0" }, + { 0x1eb3, "\x00\x61\x03\x06\x03\x09\0" }, + { 0x1eb4, "\x00\x41\x03\x06\x03\x03\0" }, + { 0x1eb5, "\x00\x61\x03\x06\x03\x03\0" }, + { 0x1eb6, "\x00\x41\x03\x23\x03\x06\0" }, + { 0x1eb7, "\x00\x61\x03\x23\x03\x06\0" }, + { 0x1eb8, "\x00\x45\x03\x23\0" }, + { 0x1eb9, "\x00\x65\x03\x23\0" }, + { 0x1eba, "\x00\x45\x03\x09\0" }, + { 0x1ebb, "\x00\x65\x03\x09\0" }, + { 0x1ebc, "\x00\x45\x03\x03\0" }, + { 0x1ebd, "\x00\x65\x03\x03\0" }, + { 0x1ebe, "\x00\x45\x03\x02\x03\x01\0" }, + { 0x1ebf, "\x00\x65\x03\x02\x03\x01\0" }, + { 0x1ec0, "\x00\x45\x03\x02\x03\x00\0" }, + { 0x1ec1, "\x00\x65\x03\x02\x03\x00\0" }, + { 0x1ec2, "\x00\x45\x03\x02\x03\x09\0" }, + { 0x1ec3, "\x00\x65\x03\x02\x03\x09\0" }, + { 0x1ec4, "\x00\x45\x03\x02\x03\x03\0" }, + { 0x1ec5, "\x00\x65\x03\x02\x03\x03\0" }, + { 0x1ec6, "\x00\x45\x03\x23\x03\x02\0" }, + { 0x1ec7, "\x00\x65\x03\x23\x03\x02\0" }, + { 0x1ec8, "\x00\x49\x03\x09\0" }, + { 0x1ec9, "\x00\x69\x03\x09\0" }, + { 0x1eca, "\x00\x49\x03\x23\0" }, + { 0x1ecb, "\x00\x69\x03\x23\0" }, + { 0x1ecc, "\x00\x4f\x03\x23\0" }, + { 0x1ecd, "\x00\x6f\x03\x23\0" }, + { 0x1ece, "\x00\x4f\x03\x09\0" }, + { 0x1ecf, "\x00\x6f\x03\x09\0" }, + { 0x1ed0, "\x00\x4f\x03\x02\x03\x01\0" }, + { 0x1ed1, "\x00\x6f\x03\x02\x03\x01\0" }, + { 0x1ed2, "\x00\x4f\x03\x02\x03\x00\0" }, + { 0x1ed3, "\x00\x6f\x03\x02\x03\x00\0" }, + { 0x1ed4, "\x00\x4f\x03\x02\x03\x09\0" }, + { 0x1ed5, "\x00\x6f\x03\x02\x03\x09\0" }, + { 0x1ed6, "\x00\x4f\x03\x02\x03\x03\0" }, + { 0x1ed7, "\x00\x6f\x03\x02\x03\x03\0" }, + { 0x1ed8, "\x00\x4f\x03\x23\x03\x02\0" }, + { 0x1ed9, "\x00\x6f\x03\x23\x03\x02\0" }, + { 0x1eda, "\x00\x4f\x03\x1b\x03\x01\0" }, + { 0x1edb, "\x00\x6f\x03\x1b\x03\x01\0" }, + { 0x1edc, "\x00\x4f\x03\x1b\x03\x00\0" }, + { 0x1edd, "\x00\x6f\x03\x1b\x03\x00\0" }, + { 0x1ede, "\x00\x4f\x03\x1b\x03\x09\0" }, + { 0x1edf, "\x00\x6f\x03\x1b\x03\x09\0" }, + { 0x1ee0, "\x00\x4f\x03\x1b\x03\x03\0" }, + { 0x1ee1, "\x00\x6f\x03\x1b\x03\x03\0" }, + { 0x1ee2, "\x00\x4f\x03\x1b\x03\x23\0" }, + { 0x1ee3, "\x00\x6f\x03\x1b\x03\x23\0" }, + { 0x1ee4, "\x00\x55\x03\x23\0" }, + { 0x1ee5, "\x00\x75\x03\x23\0" }, + { 0x1ee6, "\x00\x55\x03\x09\0" }, + { 0x1ee7, "\x00\x75\x03\x09\0" }, + { 0x1ee8, "\x00\x55\x03\x1b\x03\x01\0" }, + { 0x1ee9, "\x00\x75\x03\x1b\x03\x01\0" }, + { 0x1eea, "\x00\x55\x03\x1b\x03\x00\0" }, + { 0x1eeb, "\x00\x75\x03\x1b\x03\x00\0" }, + { 0x1eec, "\x00\x55\x03\x1b\x03\x09\0" }, + { 0x1eed, "\x00\x75\x03\x1b\x03\x09\0" }, + { 0x1eee, "\x00\x55\x03\x1b\x03\x03\0" }, + { 0x1eef, "\x00\x75\x03\x1b\x03\x03\0" }, + { 0x1ef0, "\x00\x55\x03\x1b\x03\x23\0" }, + { 0x1ef1, "\x00\x75\x03\x1b\x03\x23\0" }, + { 0x1ef2, "\x00\x59\x03\x00\0" }, + { 0x1ef3, "\x00\x79\x03\x00\0" }, + { 0x1ef4, "\x00\x59\x03\x23\0" }, + { 0x1ef5, "\x00\x79\x03\x23\0" }, + { 0x1ef6, "\x00\x59\x03\x09\0" }, + { 0x1ef7, "\x00\x79\x03\x09\0" }, + { 0x1ef8, "\x00\x59\x03\x03\0" }, + { 0x1ef9, "\x00\x79\x03\x03\0" }, + { 0x1f00, "\x03\xb1\x03\x13\0" }, + { 0x1f01, "\x03\xb1\x03\x14\0" }, + { 0x1f02, "\x03\xb1\x03\x13\x03\x00\0" }, + { 0x1f03, "\x03\xb1\x03\x14\x03\x00\0" }, + { 0x1f04, "\x03\xb1\x03\x13\x03\x01\0" }, + { 0x1f05, "\x03\xb1\x03\x14\x03\x01\0" }, + { 0x1f06, "\x03\xb1\x03\x13\x03\x42\0" }, + { 0x1f07, "\x03\xb1\x03\x14\x03\x42\0" }, + { 0x1f08, "\x03\x91\x03\x13\0" }, + { 0x1f09, "\x03\x91\x03\x14\0" }, + { 0x1f0a, "\x03\x91\x03\x13\x03\x00\0" }, + { 0x1f0b, "\x03\x91\x03\x14\x03\x00\0" }, + { 0x1f0c, "\x03\x91\x03\x13\x03\x01\0" }, + { 0x1f0d, "\x03\x91\x03\x14\x03\x01\0" }, + { 0x1f0e, "\x03\x91\x03\x13\x03\x42\0" }, + { 0x1f0f, "\x03\x91\x03\x14\x03\x42\0" }, + { 0x1f10, "\x03\xb5\x03\x13\0" }, + { 0x1f11, "\x03\xb5\x03\x14\0" }, + { 0x1f12, "\x03\xb5\x03\x13\x03\x00\0" }, + { 0x1f13, "\x03\xb5\x03\x14\x03\x00\0" }, + { 0x1f14, "\x03\xb5\x03\x13\x03\x01\0" }, + { 0x1f15, "\x03\xb5\x03\x14\x03\x01\0" }, + { 0x1f18, "\x03\x95\x03\x13\0" }, + { 0x1f19, "\x03\x95\x03\x14\0" }, + { 0x1f1a, "\x03\x95\x03\x13\x03\x00\0" }, + { 0x1f1b, "\x03\x95\x03\x14\x03\x00\0" }, + { 0x1f1c, "\x03\x95\x03\x13\x03\x01\0" }, + { 0x1f1d, "\x03\x95\x03\x14\x03\x01\0" }, + { 0x1f20, "\x03\xb7\x03\x13\0" }, + { 0x1f21, "\x03\xb7\x03\x14\0" }, + { 0x1f22, "\x03\xb7\x03\x13\x03\x00\0" }, + { 0x1f23, "\x03\xb7\x03\x14\x03\x00\0" }, + { 0x1f24, "\x03\xb7\x03\x13\x03\x01\0" }, + { 0x1f25, "\x03\xb7\x03\x14\x03\x01\0" }, + { 0x1f26, "\x03\xb7\x03\x13\x03\x42\0" }, + { 0x1f27, "\x03\xb7\x03\x14\x03\x42\0" }, + { 0x1f28, "\x03\x97\x03\x13\0" }, + { 0x1f29, "\x03\x97\x03\x14\0" }, + { 0x1f2a, "\x03\x97\x03\x13\x03\x00\0" }, + { 0x1f2b, "\x03\x97\x03\x14\x03\x00\0" }, + { 0x1f2c, "\x03\x97\x03\x13\x03\x01\0" }, + { 0x1f2d, "\x03\x97\x03\x14\x03\x01\0" }, + { 0x1f2e, "\x03\x97\x03\x13\x03\x42\0" }, + { 0x1f2f, "\x03\x97\x03\x14\x03\x42\0" }, + { 0x1f30, "\x03\xb9\x03\x13\0" }, + { 0x1f31, "\x03\xb9\x03\x14\0" }, + { 0x1f32, "\x03\xb9\x03\x13\x03\x00\0" }, + { 0x1f33, "\x03\xb9\x03\x14\x03\x00\0" }, + { 0x1f34, "\x03\xb9\x03\x13\x03\x01\0" }, + { 0x1f35, "\x03\xb9\x03\x14\x03\x01\0" }, + { 0x1f36, "\x03\xb9\x03\x13\x03\x42\0" }, + { 0x1f37, "\x03\xb9\x03\x14\x03\x42\0" }, + { 0x1f38, "\x03\x99\x03\x13\0" }, + { 0x1f39, "\x03\x99\x03\x14\0" }, + { 0x1f3a, "\x03\x99\x03\x13\x03\x00\0" }, + { 0x1f3b, "\x03\x99\x03\x14\x03\x00\0" }, + { 0x1f3c, "\x03\x99\x03\x13\x03\x01\0" }, + { 0x1f3d, "\x03\x99\x03\x14\x03\x01\0" }, + { 0x1f3e, "\x03\x99\x03\x13\x03\x42\0" }, + { 0x1f3f, "\x03\x99\x03\x14\x03\x42\0" }, + { 0x1f40, "\x03\xbf\x03\x13\0" }, + { 0x1f41, "\x03\xbf\x03\x14\0" }, + { 0x1f42, "\x03\xbf\x03\x13\x03\x00\0" }, + { 0x1f43, "\x03\xbf\x03\x14\x03\x00\0" }, + { 0x1f44, "\x03\xbf\x03\x13\x03\x01\0" }, + { 0x1f45, "\x03\xbf\x03\x14\x03\x01\0" }, + { 0x1f48, "\x03\x9f\x03\x13\0" }, + { 0x1f49, "\x03\x9f\x03\x14\0" }, + { 0x1f4a, "\x03\x9f\x03\x13\x03\x00\0" }, + { 0x1f4b, "\x03\x9f\x03\x14\x03\x00\0" }, + { 0x1f4c, "\x03\x9f\x03\x13\x03\x01\0" }, + { 0x1f4d, "\x03\x9f\x03\x14\x03\x01\0" }, + { 0x1f50, "\x03\xc5\x03\x13\0" }, + { 0x1f51, "\x03\xc5\x03\x14\0" }, + { 0x1f52, "\x03\xc5\x03\x13\x03\x00\0" }, + { 0x1f53, "\x03\xc5\x03\x14\x03\x00\0" }, + { 0x1f54, "\x03\xc5\x03\x13\x03\x01\0" }, + { 0x1f55, "\x03\xc5\x03\x14\x03\x01\0" }, + { 0x1f56, "\x03\xc5\x03\x13\x03\x42\0" }, + { 0x1f57, "\x03\xc5\x03\x14\x03\x42\0" }, + { 0x1f59, "\x03\xa5\x03\x14\0" }, + { 0x1f5b, "\x03\xa5\x03\x14\x03\x00\0" }, + { 0x1f5d, "\x03\xa5\x03\x14\x03\x01\0" }, + { 0x1f5f, "\x03\xa5\x03\x14\x03\x42\0" }, + { 0x1f60, "\x03\xc9\x03\x13\0" }, + { 0x1f61, "\x03\xc9\x03\x14\0" }, + { 0x1f62, "\x03\xc9\x03\x13\x03\x00\0" }, + { 0x1f63, "\x03\xc9\x03\x14\x03\x00\0" }, + { 0x1f64, "\x03\xc9\x03\x13\x03\x01\0" }, + { 0x1f65, "\x03\xc9\x03\x14\x03\x01\0" }, + { 0x1f66, "\x03\xc9\x03\x13\x03\x42\0" }, + { 0x1f67, "\x03\xc9\x03\x14\x03\x42\0" }, + { 0x1f68, "\x03\xa9\x03\x13\0" }, + { 0x1f69, "\x03\xa9\x03\x14\0" }, + { 0x1f6a, "\x03\xa9\x03\x13\x03\x00\0" }, + { 0x1f6b, "\x03\xa9\x03\x14\x03\x00\0" }, + { 0x1f6c, "\x03\xa9\x03\x13\x03\x01\0" }, + { 0x1f6d, "\x03\xa9\x03\x14\x03\x01\0" }, + { 0x1f6e, "\x03\xa9\x03\x13\x03\x42\0" }, + { 0x1f6f, "\x03\xa9\x03\x14\x03\x42\0" }, + { 0x1f70, "\x03\xb1\x03\x00\0" }, + { 0x1f71, "\x03\xb1\x03\x01\0" }, + { 0x1f72, "\x03\xb5\x03\x00\0" }, + { 0x1f73, "\x03\xb5\x03\x01\0" }, + { 0x1f74, "\x03\xb7\x03\x00\0" }, + { 0x1f75, "\x03\xb7\x03\x01\0" }, + { 0x1f76, "\x03\xb9\x03\x00\0" }, + { 0x1f77, "\x03\xb9\x03\x01\0" }, + { 0x1f78, "\x03\xbf\x03\x00\0" }, + { 0x1f79, "\x03\xbf\x03\x01\0" }, + { 0x1f7a, "\x03\xc5\x03\x00\0" }, + { 0x1f7b, "\x03\xc5\x03\x01\0" }, + { 0x1f7c, "\x03\xc9\x03\x00\0" }, + { 0x1f7d, "\x03\xc9\x03\x01\0" }, + { 0x1f80, "\x03\xb1\x03\x13\x03\x45\0" }, + { 0x1f81, "\x03\xb1\x03\x14\x03\x45\0" }, + { 0x1f82, "\x03\xb1\x03\x13\x03\x00\x03\x45\0" }, + { 0x1f83, "\x03\xb1\x03\x14\x03\x00\x03\x45\0" }, + { 0x1f84, "\x03\xb1\x03\x13\x03\x01\x03\x45\0" }, + { 0x1f85, "\x03\xb1\x03\x14\x03\x01\x03\x45\0" }, + { 0x1f86, "\x03\xb1\x03\x13\x03\x42\x03\x45\0" }, + { 0x1f87, "\x03\xb1\x03\x14\x03\x42\x03\x45\0" }, + { 0x1f88, "\x03\x91\x03\x13\x03\x45\0" }, + { 0x1f89, "\x03\x91\x03\x14\x03\x45\0" }, + { 0x1f8a, "\x03\x91\x03\x13\x03\x00\x03\x45\0" }, + { 0x1f8b, "\x03\x91\x03\x14\x03\x00\x03\x45\0" }, + { 0x1f8c, "\x03\x91\x03\x13\x03\x01\x03\x45\0" }, + { 0x1f8d, "\x03\x91\x03\x14\x03\x01\x03\x45\0" }, + { 0x1f8e, "\x03\x91\x03\x13\x03\x42\x03\x45\0" }, + { 0x1f8f, "\x03\x91\x03\x14\x03\x42\x03\x45\0" }, + { 0x1f90, "\x03\xb7\x03\x13\x03\x45\0" }, + { 0x1f91, "\x03\xb7\x03\x14\x03\x45\0" }, + { 0x1f92, "\x03\xb7\x03\x13\x03\x00\x03\x45\0" }, + { 0x1f93, "\x03\xb7\x03\x14\x03\x00\x03\x45\0" }, + { 0x1f94, "\x03\xb7\x03\x13\x03\x01\x03\x45\0" }, + { 0x1f95, "\x03\xb7\x03\x14\x03\x01\x03\x45\0" }, + { 0x1f96, "\x03\xb7\x03\x13\x03\x42\x03\x45\0" }, + { 0x1f97, "\x03\xb7\x03\x14\x03\x42\x03\x45\0" }, + { 0x1f98, "\x03\x97\x03\x13\x03\x45\0" }, + { 0x1f99, "\x03\x97\x03\x14\x03\x45\0" }, + { 0x1f9a, "\x03\x97\x03\x13\x03\x00\x03\x45\0" }, + { 0x1f9b, "\x03\x97\x03\x14\x03\x00\x03\x45\0" }, + { 0x1f9c, "\x03\x97\x03\x13\x03\x01\x03\x45\0" }, + { 0x1f9d, "\x03\x97\x03\x14\x03\x01\x03\x45\0" }, + { 0x1f9e, "\x03\x97\x03\x13\x03\x42\x03\x45\0" }, + { 0x1f9f, "\x03\x97\x03\x14\x03\x42\x03\x45\0" }, + { 0x1fa0, "\x03\xc9\x03\x13\x03\x45\0" }, + { 0x1fa1, "\x03\xc9\x03\x14\x03\x45\0" }, + { 0x1fa2, "\x03\xc9\x03\x13\x03\x00\x03\x45\0" }, + { 0x1fa3, "\x03\xc9\x03\x14\x03\x00\x03\x45\0" }, + { 0x1fa4, "\x03\xc9\x03\x13\x03\x01\x03\x45\0" }, + { 0x1fa5, "\x03\xc9\x03\x14\x03\x01\x03\x45\0" }, + { 0x1fa6, "\x03\xc9\x03\x13\x03\x42\x03\x45\0" }, + { 0x1fa7, "\x03\xc9\x03\x14\x03\x42\x03\x45\0" }, + { 0x1fa8, "\x03\xa9\x03\x13\x03\x45\0" }, + { 0x1fa9, "\x03\xa9\x03\x14\x03\x45\0" }, + { 0x1faa, "\x03\xa9\x03\x13\x03\x00\x03\x45\0" }, + { 0x1fab, "\x03\xa9\x03\x14\x03\x00\x03\x45\0" }, + { 0x1fac, "\x03\xa9\x03\x13\x03\x01\x03\x45\0" }, + { 0x1fad, "\x03\xa9\x03\x14\x03\x01\x03\x45\0" }, + { 0x1fae, "\x03\xa9\x03\x13\x03\x42\x03\x45\0" }, + { 0x1faf, "\x03\xa9\x03\x14\x03\x42\x03\x45\0" }, + { 0x1fb0, "\x03\xb1\x03\x06\0" }, + { 0x1fb1, "\x03\xb1\x03\x04\0" }, + { 0x1fb2, "\x03\xb1\x03\x00\x03\x45\0" }, + { 0x1fb3, "\x03\xb1\x03\x45\0" }, + { 0x1fb4, "\x03\xb1\x03\x01\x03\x45\0" }, + { 0x1fb6, "\x03\xb1\x03\x42\0" }, + { 0x1fb7, "\x03\xb1\x03\x42\x03\x45\0" }, + { 0x1fb8, "\x03\x91\x03\x06\0" }, + { 0x1fb9, "\x03\x91\x03\x04\0" }, + { 0x1fba, "\x03\x91\x03\x00\0" }, + { 0x1fbb, "\x03\x91\x03\x01\0" }, + { 0x1fbc, "\x03\x91\x03\x45\0" }, + { 0x1fbe, "\x03\xb9\0" }, + { 0x1fc1, "\x00\xa8\x03\x42\0" }, + { 0x1fc2, "\x03\xb7\x03\x00\x03\x45\0" }, + { 0x1fc3, "\x03\xb7\x03\x45\0" }, + { 0x1fc4, "\x03\xb7\x03\x01\x03\x45\0" }, + { 0x1fc6, "\x03\xb7\x03\x42\0" }, + { 0x1fc7, "\x03\xb7\x03\x42\x03\x45\0" }, + { 0x1fc8, "\x03\x95\x03\x00\0" }, + { 0x1fc9, "\x03\x95\x03\x01\0" }, + { 0x1fca, "\x03\x97\x03\x00\0" }, + { 0x1fcb, "\x03\x97\x03\x01\0" }, + { 0x1fcc, "\x03\x97\x03\x45\0" }, + { 0x1fcd, "\x1f\xbf\x03\x00\0" }, + { 0x1fce, "\x1f\xbf\x03\x01\0" }, + { 0x1fcf, "\x1f\xbf\x03\x42\0" }, + { 0x1fd0, "\x03\xb9\x03\x06\0" }, + { 0x1fd1, "\x03\xb9\x03\x04\0" }, + { 0x1fd2, "\x03\xb9\x03\x08\x03\x00\0" }, + { 0x1fd3, "\x03\xb9\x03\x08\x03\x01\0" }, + { 0x1fd6, "\x03\xb9\x03\x42\0" }, + { 0x1fd7, "\x03\xb9\x03\x08\x03\x42\0" }, + { 0x1fd8, "\x03\x99\x03\x06\0" }, + { 0x1fd9, "\x03\x99\x03\x04\0" }, + { 0x1fda, "\x03\x99\x03\x00\0" }, + { 0x1fdb, "\x03\x99\x03\x01\0" }, + { 0x1fdd, "\x1f\xfe\x03\x00\0" }, + { 0x1fde, "\x1f\xfe\x03\x01\0" }, + { 0x1fdf, "\x1f\xfe\x03\x42\0" }, + { 0x1fe0, "\x03\xc5\x03\x06\0" }, + { 0x1fe1, "\x03\xc5\x03\x04\0" }, + { 0x1fe2, "\x03\xc5\x03\x08\x03\x00\0" }, + { 0x1fe3, "\x03\xc5\x03\x08\x03\x01\0" }, + { 0x1fe4, "\x03\xc1\x03\x13\0" }, + { 0x1fe5, "\x03\xc1\x03\x14\0" }, + { 0x1fe6, "\x03\xc5\x03\x42\0" }, + { 0x1fe7, "\x03\xc5\x03\x08\x03\x42\0" }, + { 0x1fe8, "\x03\xa5\x03\x06\0" }, + { 0x1fe9, "\x03\xa5\x03\x04\0" }, + { 0x1fea, "\x03\xa5\x03\x00\0" }, + { 0x1feb, "\x03\xa5\x03\x01\0" }, + { 0x1fec, "\x03\xa1\x03\x14\0" }, + { 0x1fed, "\x00\xa8\x03\x00\0" }, + { 0x1fee, "\x00\xa8\x03\x01\0" }, + { 0x1fef, "\x00\x60\0" }, + { 0x1ff2, "\x03\xc9\x03\x00\x03\x45\0" }, + { 0x1ff3, "\x03\xc9\x03\x45\0" }, + { 0x1ff4, "\x03\xc9\x03\x01\x03\x45\0" }, + { 0x1ff6, "\x03\xc9\x03\x42\0" }, + { 0x1ff7, "\x03\xc9\x03\x42\x03\x45\0" }, + { 0x1ff8, "\x03\x9f\x03\x00\0" }, + { 0x1ff9, "\x03\x9f\x03\x01\0" }, + { 0x1ffa, "\x03\xa9\x03\x00\0" }, + { 0x1ffb, "\x03\xa9\x03\x01\0" }, + { 0x1ffc, "\x03\xa9\x03\x45\0" }, + { 0x1ffd, "\x00\xb4\0" }, + { 0x2000, "\x20\x02\0" }, + { 0x2001, "\x20\x03\0" }, + { 0x2126, "\x03\xa9\0" }, + { 0x212a, "\x00\x4b\0" }, + { 0x212b, "\x00\x41\x03\x0a\0" }, + { 0x2204, "\x22\x03\x03\x38\0" }, + { 0x2209, "\x22\x08\x03\x38\0" }, + { 0x220c, "\x22\x0b\x03\x38\0" }, + { 0x2224, "\x22\x23\x03\x38\0" }, + { 0x2226, "\x22\x25\x03\x38\0" }, + { 0x2241, "\x00\x7e\x03\x38\0" }, + { 0x2244, "\x22\x43\x03\x38\0" }, + { 0x2247, "\x22\x45\x03\x38\0" }, + { 0x2249, "\x22\x48\x03\x38\0" }, + { 0x2260, "\x00\x3d\x03\x38\0" }, + { 0x2262, "\x22\x61\x03\x38\0" }, + { 0x226d, "\x22\x4d\x03\x38\0" }, + { 0x226e, "\x00\x3c\x03\x38\0" }, + { 0x226f, "\x00\x3e\x03\x38\0" }, + { 0x2270, "\x22\x64\x03\x38\0" }, + { 0x2271, "\x22\x65\x03\x38\0" }, + { 0x2274, "\x22\x72\x03\x38\0" }, + { 0x2275, "\x22\x73\x03\x38\0" }, + { 0x2278, "\x22\x76\x03\x38\0" }, + { 0x2279, "\x22\x77\x03\x38\0" }, + { 0x2280, "\x22\x7a\x03\x38\0" }, + { 0x2281, "\x22\x7b\x03\x38\0" }, + { 0x2284, "\x22\x82\x03\x38\0" }, + { 0x2285, "\x22\x83\x03\x38\0" }, + { 0x2288, "\x22\x86\x03\x38\0" }, + { 0x2289, "\x22\x87\x03\x38\0" }, + { 0x22ac, "\x22\xa2\x03\x38\0" }, + { 0x22ad, "\x22\xa8\x03\x38\0" }, + { 0x22ae, "\x22\xa9\x03\x38\0" }, + { 0x22af, "\x22\xab\x03\x38\0" }, + { 0x22e0, "\x22\x7c\x03\x38\0" }, + { 0x22e1, "\x22\x7d\x03\x38\0" }, + { 0x22e2, "\x22\x91\x03\x38\0" }, + { 0x22e3, "\x22\x92\x03\x38\0" }, + { 0x22ea, "\x22\xb2\x03\x38\0" }, + { 0x22eb, "\x22\xb3\x03\x38\0" }, + { 0x22ec, "\x22\xb4\x03\x38\0" }, + { 0x22ed, "\x22\xb5\x03\x38\0" }, + { 0x2329, "\x30\x08\0" }, + { 0x232a, "\x30\x09\0" }, + { 0x304c, "\x30\x4b\x30\x99\0" }, + { 0x304e, "\x30\x4d\x30\x99\0" }, + { 0x3050, "\x30\x4f\x30\x99\0" }, + { 0x3052, "\x30\x51\x30\x99\0" }, + { 0x3054, "\x30\x53\x30\x99\0" }, + { 0x3056, "\x30\x55\x30\x99\0" }, + { 0x3058, "\x30\x57\x30\x99\0" }, + { 0x305a, "\x30\x59\x30\x99\0" }, + { 0x305c, "\x30\x5b\x30\x99\0" }, + { 0x305e, "\x30\x5d\x30\x99\0" }, + { 0x3060, "\x30\x5f\x30\x99\0" }, + { 0x3062, "\x30\x61\x30\x99\0" }, + { 0x3065, "\x30\x64\x30\x99\0" }, + { 0x3067, "\x30\x66\x30\x99\0" }, + { 0x3069, "\x30\x68\x30\x99\0" }, + { 0x3070, "\x30\x6f\x30\x99\0" }, + { 0x3071, "\x30\x6f\x30\x9a\0" }, + { 0x3073, "\x30\x72\x30\x99\0" }, + { 0x3074, "\x30\x72\x30\x9a\0" }, + { 0x3076, "\x30\x75\x30\x99\0" }, + { 0x3077, "\x30\x75\x30\x9a\0" }, + { 0x3079, "\x30\x78\x30\x99\0" }, + { 0x307a, "\x30\x78\x30\x9a\0" }, + { 0x307c, "\x30\x7b\x30\x99\0" }, + { 0x307d, "\x30\x7b\x30\x9a\0" }, + { 0x3094, "\x30\x46\x30\x99\0" }, + { 0x309e, "\x30\x9d\x30\x99\0" }, + { 0x30ac, "\x30\xab\x30\x99\0" }, + { 0x30ae, "\x30\xad\x30\x99\0" }, + { 0x30b0, "\x30\xaf\x30\x99\0" }, + { 0x30b2, "\x30\xb1\x30\x99\0" }, + { 0x30b4, "\x30\xb3\x30\x99\0" }, + { 0x30b6, "\x30\xb5\x30\x99\0" }, + { 0x30b8, "\x30\xb7\x30\x99\0" }, + { 0x30ba, "\x30\xb9\x30\x99\0" }, + { 0x30bc, "\x30\xbb\x30\x99\0" }, + { 0x30be, "\x30\xbd\x30\x99\0" }, + { 0x30c0, "\x30\xbf\x30\x99\0" }, + { 0x30c2, "\x30\xc1\x30\x99\0" }, + { 0x30c5, "\x30\xc4\x30\x99\0" }, + { 0x30c7, "\x30\xc6\x30\x99\0" }, + { 0x30c9, "\x30\xc8\x30\x99\0" }, + { 0x30d0, "\x30\xcf\x30\x99\0" }, + { 0x30d1, "\x30\xcf\x30\x9a\0" }, + { 0x30d3, "\x30\xd2\x30\x99\0" }, + { 0x30d4, "\x30\xd2\x30\x9a\0" }, + { 0x30d6, "\x30\xd5\x30\x99\0" }, + { 0x30d7, "\x30\xd5\x30\x9a\0" }, + { 0x30d9, "\x30\xd8\x30\x99\0" }, + { 0x30da, "\x30\xd8\x30\x9a\0" }, + { 0x30dc, "\x30\xdb\x30\x99\0" }, + { 0x30dd, "\x30\xdb\x30\x9a\0" }, + { 0x30f4, "\x30\xa6\x30\x99\0" }, + { 0x30f7, "\x30\xef\x30\x99\0" }, + { 0x30f8, "\x30\xf0\x30\x99\0" }, + { 0x30f9, "\x30\xf1\x30\x99\0" }, + { 0x30fa, "\x30\xf2\x30\x99\0" }, + { 0x30fe, "\x30\xfd\x30\x99\0" }, + { 0xf900, "\x8c\x48\0" }, + { 0xf901, "\x66\xf4\0" }, + { 0xf902, "\x8e\xca\0" }, + { 0xf903, "\x8c\xc8\0" }, + { 0xf904, "\x6e\xd1\0" }, + { 0xf905, "\x4e\x32\0" }, + { 0xf906, "\x53\xe5\0" }, + { 0xf907, "\x9f\x9c\0" }, + { 0xf908, "\x9f\x9c\0" }, + { 0xf909, "\x59\x51\0" }, + { 0xf90a, "\x91\xd1\0" }, + { 0xf90b, "\x55\x87\0" }, + { 0xf90c, "\x59\x48\0" }, + { 0xf90d, "\x61\xf6\0" }, + { 0xf90e, "\x76\x69\0" }, + { 0xf90f, "\x7f\x85\0" }, + { 0xf910, "\x86\x3f\0" }, + { 0xf911, "\x87\xba\0" }, + { 0xf912, "\x88\xf8\0" }, + { 0xf913, "\x90\x8f\0" }, + { 0xf914, "\x6a\x02\0" }, + { 0xf915, "\x6d\x1b\0" }, + { 0xf916, "\x70\xd9\0" }, + { 0xf917, "\x73\xde\0" }, + { 0xf918, "\x84\x3d\0" }, + { 0xf919, "\x91\x6a\0" }, + { 0xf91a, "\x99\xf1\0" }, + { 0xf91b, "\x4e\x82\0" }, + { 0xf91c, "\x53\x75\0" }, + { 0xf91d, "\x6b\x04\0" }, + { 0xf91e, "\x72\x1b\0" }, + { 0xf91f, "\x86\x2d\0" }, + { 0xf920, "\x9e\x1e\0" }, + { 0xf921, "\x5d\x50\0" }, + { 0xf922, "\x6f\xeb\0" }, + { 0xf923, "\x85\xcd\0" }, + { 0xf924, "\x89\x64\0" }, + { 0xf925, "\x62\xc9\0" }, + { 0xf926, "\x81\xd8\0" }, + { 0xf927, "\x88\x1f\0" }, + { 0xf928, "\x5e\xca\0" }, + { 0xf929, "\x67\x17\0" }, + { 0xf92a, "\x6d\x6a\0" }, + { 0xf92b, "\x72\xfc\0" }, + { 0xf92c, "\x90\xce\0" }, + { 0xf92d, "\x4f\x86\0" }, + { 0xf92e, "\x51\xb7\0" }, + { 0xf92f, "\x52\xde\0" }, + { 0xf930, "\x64\xc4\0" }, + { 0xf931, "\x6a\xd3\0" }, + { 0xf932, "\x72\x10\0" }, + { 0xf933, "\x76\xe7\0" }, + { 0xf934, "\x80\x01\0" }, + { 0xf935, "\x86\x06\0" }, + { 0xf936, "\x86\x5c\0" }, + { 0xf937, "\x8d\xef\0" }, + { 0xf938, "\x97\x32\0" }, + { 0xf939, "\x9b\x6f\0" }, + { 0xf93a, "\x9d\xfa\0" }, + { 0xf93b, "\x78\x8c\0" }, + { 0xf93c, "\x79\x7f\0" }, + { 0xf93d, "\x7d\xa0\0" }, + { 0xf93e, "\x83\xc9\0" }, + { 0xf93f, "\x93\x04\0" }, + { 0xf940, "\x9e\x7f\0" }, + { 0xf941, "\x8a\xd6\0" }, + { 0xf942, "\x58\xdf\0" }, + { 0xf943, "\x5f\x04\0" }, + { 0xf944, "\x7c\x60\0" }, + { 0xf945, "\x80\x7e\0" }, + { 0xf946, "\x72\x62\0" }, + { 0xf947, "\x78\xca\0" }, + { 0xf948, "\x8c\xc2\0" }, + { 0xf949, "\x96\xf7\0" }, + { 0xf94a, "\x58\xd8\0" }, + { 0xf94b, "\x5c\x62\0" }, + { 0xf94c, "\x6a\x13\0" }, + { 0xf94d, "\x6d\xda\0" }, + { 0xf94e, "\x6f\x0f\0" }, + { 0xf94f, "\x7d\x2f\0" }, + { 0xf950, "\x7e\x37\0" }, + { 0xf951, "\x96\xfb\0" }, + { 0xf952, "\x52\xd2\0" }, + { 0xf953, "\x80\x8b\0" }, + { 0xf954, "\x51\xdc\0" }, + { 0xf955, "\x51\xcc\0" }, + { 0xf956, "\x7a\x1c\0" }, + { 0xf957, "\x7d\xbe\0" }, + { 0xf958, "\x83\xf1\0" }, + { 0xf959, "\x96\x75\0" }, + { 0xf95a, "\x8b\x80\0" }, + { 0xf95b, "\x62\xcf\0" }, + { 0xf95c, "\x6a\x02\0" }, + { 0xf95d, "\x8a\xfe\0" }, + { 0xf95e, "\x4e\x39\0" }, + { 0xf95f, "\x5b\xe7\0" }, + { 0xf960, "\x60\x12\0" }, + { 0xf961, "\x73\x87\0" }, + { 0xf962, "\x75\x70\0" }, + { 0xf963, "\x53\x17\0" }, + { 0xf964, "\x78\xfb\0" }, + { 0xf965, "\x4f\xbf\0" }, + { 0xf966, "\x5f\xa9\0" }, + { 0xf967, "\x4e\x0d\0" }, + { 0xf968, "\x6c\xcc\0" }, + { 0xf969, "\x65\x78\0" }, + { 0xf96a, "\x7d\x22\0" }, + { 0xf96b, "\x53\xc3\0" }, + { 0xf96c, "\x58\x5e\0" }, + { 0xf96d, "\x77\x01\0" }, + { 0xf96e, "\x84\x49\0" }, + { 0xf96f, "\x8a\xaa\0" }, + { 0xf970, "\x6b\xba\0" }, + { 0xf971, "\x8f\xb0\0" }, + { 0xf972, "\x6c\x88\0" }, + { 0xf973, "\x62\xfe\0" }, + { 0xf974, "\x82\xe5\0" }, + { 0xf975, "\x63\xa0\0" }, + { 0xf976, "\x75\x65\0" }, + { 0xf977, "\x4e\xae\0" }, + { 0xf978, "\x51\x69\0" }, + { 0xf979, "\x51\xc9\0" }, + { 0xf97a, "\x68\x81\0" }, + { 0xf97b, "\x7c\xe7\0" }, + { 0xf97c, "\x82\x6f\0" }, + { 0xf97d, "\x8a\xd2\0" }, + { 0xf97e, "\x91\xcf\0" }, + { 0xf97f, "\x52\xf5\0" }, + { 0xf980, "\x54\x42\0" }, + { 0xf981, "\x59\x73\0" }, + { 0xf982, "\x5e\xec\0" }, + { 0xf983, "\x65\xc5\0" }, + { 0xf984, "\x6f\xfe\0" }, + { 0xf985, "\x79\x2a\0" }, + { 0xf986, "\x95\xad\0" }, + { 0xf987, "\x9a\x6a\0" }, + { 0xf988, "\x9e\x97\0" }, + { 0xf989, "\x9e\xce\0" }, + { 0xf98a, "\x52\x9b\0" }, + { 0xf98b, "\x66\xc6\0" }, + { 0xf98c, "\x6b\x77\0" }, + { 0xf98d, "\x8f\x62\0" }, + { 0xf98e, "\x5e\x74\0" }, + { 0xf98f, "\x61\x90\0" }, + { 0xf990, "\x62\x00\0" }, + { 0xf991, "\x64\x9a\0" }, + { 0xf992, "\x6f\x23\0" }, + { 0xf993, "\x71\x49\0" }, + { 0xf994, "\x74\x89\0" }, + { 0xf995, "\x79\xca\0" }, + { 0xf996, "\x7d\xf4\0" }, + { 0xf997, "\x80\x6f\0" }, + { 0xf998, "\x8f\x26\0" }, + { 0xf999, "\x84\xee\0" }, + { 0xf99a, "\x90\x23\0" }, + { 0xf99b, "\x93\x4a\0" }, + { 0xf99c, "\x52\x17\0" }, + { 0xf99d, "\x52\xa3\0" }, + { 0xf99e, "\x54\xbd\0" }, + { 0xf99f, "\x70\xc8\0" }, + { 0xf9a0, "\x88\xc2\0" }, + { 0xf9a1, "\x8a\xaa\0" }, + { 0xf9a2, "\x5e\xc9\0" }, + { 0xf9a3, "\x5f\xf5\0" }, + { 0xf9a4, "\x63\x7b\0" }, + { 0xf9a5, "\x6b\xae\0" }, + { 0xf9a6, "\x7c\x3e\0" }, + { 0xf9a7, "\x73\x75\0" }, + { 0xf9a8, "\x4e\xe4\0" }, + { 0xf9a9, "\x56\xf9\0" }, + { 0xf9aa, "\x5b\xe7\0" }, + { 0xf9ab, "\x5d\xba\0" }, + { 0xf9ac, "\x60\x1c\0" }, + { 0xf9ad, "\x73\xb2\0" }, + { 0xf9ae, "\x74\x69\0" }, + { 0xf9af, "\x7f\x9a\0" }, + { 0xf9b0, "\x80\x46\0" }, + { 0xf9b1, "\x92\x34\0" }, + { 0xf9b2, "\x96\xf6\0" }, + { 0xf9b3, "\x97\x48\0" }, + { 0xf9b4, "\x98\x18\0" }, + { 0xf9b5, "\x4f\x8b\0" }, + { 0xf9b6, "\x79\xae\0" }, + { 0xf9b7, "\x91\xb4\0" }, + { 0xf9b8, "\x96\xb8\0" }, + { 0xf9b9, "\x60\xe1\0" }, + { 0xf9ba, "\x4e\x86\0" }, + { 0xf9bb, "\x50\xda\0" }, + { 0xf9bc, "\x5b\xee\0" }, + { 0xf9bd, "\x5c\x3f\0" }, + { 0xf9be, "\x65\x99\0" }, + { 0xf9bf, "\x6a\x02\0" }, + { 0xf9c0, "\x71\xce\0" }, + { 0xf9c1, "\x76\x42\0" }, + { 0xf9c2, "\x84\xfc\0" }, + { 0xf9c3, "\x90\x7c\0" }, + { 0xf9c4, "\x9f\x8d\0" }, + { 0xf9c5, "\x66\x88\0" }, + { 0xf9c6, "\x96\x2e\0" }, + { 0xf9c7, "\x52\x89\0" }, + { 0xf9c8, "\x67\x7b\0" }, + { 0xf9c9, "\x67\xf3\0" }, + { 0xf9ca, "\x6d\x41\0" }, + { 0xf9cb, "\x6e\x9c\0" }, + { 0xf9cc, "\x74\x09\0" }, + { 0xf9cd, "\x75\x59\0" }, + { 0xf9ce, "\x78\x6b\0" }, + { 0xf9cf, "\x7d\x10\0" }, + { 0xf9d0, "\x98\x5e\0" }, + { 0xf9d1, "\x51\x6d\0" }, + { 0xf9d2, "\x62\x2e\0" }, + { 0xf9d3, "\x96\x78\0" }, + { 0xf9d4, "\x50\x2b\0" }, + { 0xf9d5, "\x5d\x19\0" }, + { 0xf9d6, "\x6d\xea\0" }, + { 0xf9d7, "\x8f\x2a\0" }, + { 0xf9d8, "\x5f\x8b\0" }, + { 0xf9d9, "\x61\x44\0" }, + { 0xf9da, "\x68\x17\0" }, + { 0xf9db, "\x73\x87\0" }, + { 0xf9dc, "\x96\x86\0" }, + { 0xf9dd, "\x52\x29\0" }, + { 0xf9de, "\x54\x0f\0" }, + { 0xf9df, "\x5c\x65\0" }, + { 0xf9e0, "\x66\x13\0" }, + { 0xf9e1, "\x67\x4e\0" }, + { 0xf9e2, "\x68\xa8\0" }, + { 0xf9e3, "\x6c\xe5\0" }, + { 0xf9e4, "\x74\x06\0" }, + { 0xf9e5, "\x75\xe2\0" }, + { 0xf9e6, "\x7f\x79\0" }, + { 0xf9e7, "\x88\xcf\0" }, + { 0xf9e8, "\x88\xe1\0" }, + { 0xf9e9, "\x91\xcc\0" }, + { 0xf9ea, "\x96\xe2\0" }, + { 0xf9eb, "\x53\x3f\0" }, + { 0xf9ec, "\x6e\xba\0" }, + { 0xf9ed, "\x54\x1d\0" }, + { 0xf9ee, "\x71\xd0\0" }, + { 0xf9ef, "\x74\x98\0" }, + { 0xf9f0, "\x85\xfa\0" }, + { 0xf9f1, "\x96\xa3\0" }, + { 0xf9f2, "\x9c\x57\0" }, + { 0xf9f3, "\x9e\x9f\0" }, + { 0xf9f4, "\x67\x97\0" }, + { 0xf9f5, "\x6d\xcb\0" }, + { 0xf9f6, "\x81\xe8\0" }, + { 0xf9f7, "\x7a\xcb\0" }, + { 0xf9f8, "\x7b\x20\0" }, + { 0xf9f9, "\x7c\x92\0" }, + { 0xf9fa, "\x72\xc0\0" }, + { 0xf9fb, "\x70\x99\0" }, + { 0xf9fc, "\x8b\x58\0" }, + { 0xf9fd, "\x4e\xc0\0" }, + { 0xf9fe, "\x83\x36\0" }, + { 0xf9ff, "\x52\x3a\0" }, + { 0xfa00, "\x52\x07\0" }, + { 0xfa01, "\x5e\xa6\0" }, + { 0xfa02, "\x62\xd3\0" }, + { 0xfa03, "\x7c\xd6\0" }, + { 0xfa04, "\x5b\x85\0" }, + { 0xfa05, "\x6d\x1e\0" }, + { 0xfa06, "\x66\xb4\0" }, + { 0xfa07, "\x8f\x3b\0" }, + { 0xfa08, "\x88\x4c\0" }, + { 0xfa09, "\x96\x4d\0" }, + { 0xfa0a, "\x89\x8b\0" }, + { 0xfa0b, "\x5e\xd3\0" }, + { 0xfa0c, "\x51\x40\0" }, + { 0xfa0d, "\x55\xc0\0" }, + { 0xfa10, "\x58\x5a\0" }, + { 0xfa12, "\x66\x74\0" }, + { 0xfa15, "\x51\xde\0" }, + { 0xfa16, "\x73\x2a\0" }, + { 0xfa17, "\x76\xca\0" }, + { 0xfa18, "\x79\x3c\0" }, + { 0xfa19, "\x79\x5e\0" }, + { 0xfa1a, "\x79\x65\0" }, + { 0xfa1b, "\x79\x8f\0" }, + { 0xfa1c, "\x97\x56\0" }, + { 0xfa1d, "\x7c\xbe\0" }, + { 0xfa1e, "\x7f\xbd\0" }, + { 0xfa20, "\x86\x12\0" }, + { 0xfa22, "\x8a\xf8\0" }, + { 0xfa25, "\x90\x38\0" }, + { 0xfa26, "\x90\xfd\0" }, + { 0xfa2a, "\x98\xef\0" }, + { 0xfa2b, "\x98\xfc\0" }, + { 0xfa2c, "\x99\x28\0" }, + { 0xfa2d, "\x9d\xb4\0" }, + { 0xfb1f, "\x05\xf2\x05\xb7\0" }, + { 0xfb2a, "\x05\xe9\x05\xc1\0" }, + { 0xfb2b, "\x05\xe9\x05\xc2\0" }, + { 0xfb2c, "\x05\xe9\x05\xbc\x05\xc1\0" }, + { 0xfb2d, "\x05\xe9\x05\xbc\x05\xc2\0" }, + { 0xfb2e, "\x05\xd0\x05\xb7\0" }, + { 0xfb2f, "\x05\xd0\x05\xb8\0" }, + { 0xfb30, "\x05\xd0\x05\xbc\0" }, + { 0xfb31, "\x05\xd1\x05\xbc\0" }, + { 0xfb32, "\x05\xd2\x05\xbc\0" }, + { 0xfb33, "\x05\xd3\x05\xbc\0" }, + { 0xfb34, "\x05\xd4\x05\xbc\0" }, + { 0xfb35, "\x05\xd5\x05\xbc\0" }, + { 0xfb36, "\x05\xd6\x05\xbc\0" }, + { 0xfb38, "\x05\xd8\x05\xbc\0" }, + { 0xfb39, "\x05\xd9\x05\xbc\0" }, + { 0xfb3a, "\x05\xda\x05\xbc\0" }, + { 0xfb3b, "\x05\xdb\x05\xbc\0" }, + { 0xfb3c, "\x05\xdc\x05\xbc\0" }, + { 0xfb3e, "\x05\xde\x05\xbc\0" }, + { 0xfb40, "\x05\xe0\x05\xbc\0" }, + { 0xfb41, "\x05\xe1\x05\xbc\0" }, + { 0xfb43, "\x05\xe3\x05\xbc\0" }, + { 0xfb44, "\x05\xe4\x05\xbc\0" }, + { 0xfb46, "\x05\xe6\x05\xbc\0" }, + { 0xfb47, "\x05\xe7\x05\xbc\0" }, + { 0xfb48, "\x05\xe8\x05\xbc\0" }, + { 0xfb49, "\x05\xe9\x05\xbc\0" }, + { 0xfb4a, "\x05\xea\x05\xbc\0" }, + { 0xfb4b, "\x05\xd5\x05\xb9\0" }, + { 0xfb4c, "\x05\xd1\x05\xbf\0" }, + { 0xfb4d, "\x05\xdb\x05\xbf\0" }, + { 0xfb4e, "\x05\xe4\x05\xbf\0" } +}; + +/* + * WARNING! + * + * NO BUFFER CHECKING AHEAD! + * + */ + +static gint +e_canonical_decomposition (gunichar ch, gunichar * buf) +{ + gint len = 0; + + if (ch <= 0xffff) + { + gint start = 0; + gint end = sizeof (e_decomp_table) / sizeof (e_decomp_table[0]); + while (start != end) + { + gint half = (start + end) / 2; + if (ch == e_decomp_table[half].ch) { + /* Found it. */ + gint i; + /* We store as a double-nul terminated string. */ + for (len = 0; (e_decomp_table[half].expansion[len] || e_decomp_table[half].expansion[len + 1]); len += 2); + + /* We've counted twice as many bytes as there are + characters. */ + len /= 2; + + for (i = 0; i < len; i ++) { + buf[i] = (e_decomp_table[half].expansion[2 * i] << 8) | e_decomp_table[half].expansion[2 * i + 1]; + } + break; + } else if (ch > e_decomp_table[half].ch) { + if (start == half) break; + start = half; + } else { + if (end == half) break; + end = half; + } + } + } + + if (len == 0) + { + /* Not in our table. */ + *buf = ch; + len = 1; + } + + /* Supposedly following the Unicode 2.1.9 table means that the + decompositions come out in canonical order. I haven't tested + this, but we rely on it here. */ + return len; +} + +static gunichar +e_stripped_char (gunichar ch) +{ + gunichar decomp[MAX_DECOMP]; + GUnicodeType utype; + gint dlen; + + utype = g_unichar_type (ch); + + switch (utype) { + case G_UNICODE_CONTROL: + case G_UNICODE_FORMAT: + case G_UNICODE_UNASSIGNED: + case G_UNICODE_COMBINING_MARK: + /* Ignore those */ + return 0; + default: + /* Convert to lowercase, fall through */ + ch = g_unichar_tolower (ch); + case G_UNICODE_LOWERCASE_LETTER: + dlen = e_canonical_decomposition (ch, decomp); + if (dlen > 0) return *decomp; + break; + } + + return 0; +} + +gchar * +e_xml_get_translated_utf8_string_prop_by_name (const xmlNode *parent, const xmlChar *prop_name) +{ + xmlChar *prop; + gchar *ret_val = NULL; + gchar *combined_name; + + g_return_val_if_fail (parent != NULL, NULL); + g_return_val_if_fail (prop_name != NULL, NULL); + + prop = xmlGetProp ((xmlNode *) parent, prop_name); + if (prop != NULL) { + ret_val = g_strdup ((gchar *)prop); + xmlFree (prop); + return ret_val; + } + + combined_name = g_strdup_printf("_%s", prop_name); + prop = xmlGetProp ((xmlNode *) parent, (guchar *)combined_name); + if (prop != NULL) { + ret_val = g_strdup (gettext ((gchar *)prop)); + xmlFree (prop); + } + g_free(combined_name); + + return ret_val; +} diff --git a/e-util/e-unicode.h b/e-util/e-unicode.h new file mode 100644 index 0000000000..737c5088eb --- /dev/null +++ b/e-util/e-unicode.h @@ -0,0 +1,111 @@ +/* + * e-unicode.h - utf-8 support functions for gal + * + * 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: + * Lauris Kaplinski <lauris@ximian.com> + * + * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com) + * + */ + +#ifndef _E_UNICODE_H_ +#define _E_UNICODE_H_ + +#include <sys/types.h> +#include <glib.h> +#include <gtk/gtk.h> +#include <libxml/tree.h> +#include <iconv.h> + +G_BEGIN_DECLS + +#define G_UTF8_IN_GAL + +/* + * UTF-8 searching implementations + * + * e_utf8_strstrcase - case insensitive search + * e_utf8_strstrcasedecomp - case insensitive and decompositing search (i.e. accented + * letters are treated equal to their base letters, explicit accent marks (unicode + * not ascii/iso ones) are ignored). + */ + +const gchar *e_utf8_strstrcase (const gchar *haystack, + const gchar *needle); +const gchar *e_utf8_strstrcasedecomp (const gchar *haystack, + const gchar *needle); +gchar *e_utf8_from_gtk_event_key (GtkWidget *widget, + guint keyval, + const gchar *string); +gchar *e_utf8_from_iconv_string (iconv_t ic, + const gchar *string); +gchar *e_utf8_from_iconv_string_sized (iconv_t ic, + const gchar *string, + gint bytes); +gchar *e_utf8_to_iconv_string (iconv_t ic, + const gchar *string); +gchar *e_utf8_to_iconv_string_sized (iconv_t ic, + const gchar *string, + gint bytes); +gchar *e_utf8_from_charset_string (const gchar *charset, + const gchar *string); +gchar *e_utf8_from_charset_string_sized (const gchar *charset, + const gchar *string, + gint bytes); +gchar *e_utf8_to_charset_string (const gchar *charset, + const gchar *string); +gchar *e_utf8_to_charset_string_sized (const gchar *charset, + const gchar *string, + gint bytes); +gchar *e_utf8_from_locale_string (const gchar *string); +gchar *e_utf8_from_locale_string_sized (const gchar *string, + gint bytes); +gchar *e_utf8_to_locale_string (const gchar *string); +gchar *e_utf8_to_locale_string_sized (const gchar *string, + gint bytes); +gboolean e_utf8_is_ascii (const gchar *string); +/* + * These are simple wrappers that save us some typing + */ + +/* NB! This return newly allocated string, not const as gtk+ one */ +gchar *e_utf8_gtk_entry_get_text (GtkEntry *entry); +void e_utf8_gtk_entry_set_text (GtkEntry *entry, + const gchar *text); +gchar *e_utf8_gtk_editable_get_text (GtkEditable *editable); +void e_utf8_gtk_editable_set_text (GtkEditable *editable, + const gchar *text); +gchar *e_utf8_gtk_editable_get_chars (GtkEditable *editable, + gint start, + gint end); +void e_utf8_gtk_editable_insert_text (GtkEditable *editable, + const gchar *text, + gint length, + gint *position); +gchar *e_utf8_xml1_decode (const gchar *text); +gchar *e_utf8_xml1_encode (const gchar *text); +gint e_unichar_to_utf8 (gint c, + gchar *outbuf); +gchar *e_unicode_get_utf8 (const gchar *text, + gunichar *out); +gchar *e_xml_get_translated_utf8_string_prop_by_name (const xmlNode *parent, + const xmlChar *prop_name); + +G_END_DECLS + +#endif + diff --git a/e-util/e-util-labels.c b/e-util/e-util-labels.c deleted file mode 100644 index eeab09fe59..0000000000 --- a/e-util/e-util-labels.c +++ /dev/null @@ -1,591 +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: - * - * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com) - * - */ - -#include <gtk/gtk.h> -#include <glib/gi18n.h> - -#include <stdio.h> -#include <string.h> - -#include <gconf/gconf-client.h> - -#include <camel/camel-utf8.h> - -#include "e-util.h" -#include "e-util-labels.h" -#include "e-dialog-utils.h" -#include "filter/filter-option.h" - -typedef struct { - const gchar *tag; - const gchar *name; - const gchar *colour; -} DefaultLabel; - -/* Note, the first element of each DefaultLabel must NOT be translated */ -DefaultLabel label_defaults[] = { - { "$Labelimportant", N_("I_mportant"), "#EF2929" }, /* red */ - { "$Labelwork", N_("_Work"), "#F57900" }, /* orange */ - { "$Labelpersonal", N_("_Personal"), "#4E9A06" }, /* green */ - { "$Labeltodo", N_("_To Do"), "#3465A4" }, /* blue */ - { "$Labellater", N_("_Later"), "#75507B" } /* purple */ -}; - -/** - * e_util_labels_parse - * Reads the setup from client and parses it to list of EUtilLabel objects. - * - * @param client The config client to be used for reading setup. - * Can be NULL, in that case it will use the default client. - * @return Newly allocated list of labels, should be freed with @ref e_util_labels_free. - **/ -GSList * -e_util_labels_parse (GConfClient *client) -{ - GSList *labels, *list, *head; - EUtilLabel *label; - gchar *buf; - gint num = 0; - gboolean unref_client = client == NULL; - - labels = NULL; - - if (!client) - client = gconf_client_get_default (); - - head = gconf_client_get_list (client, E_UTIL_LABELS_GCONF_KEY, GCONF_VALUE_STRING, NULL); - - for (list = head; list; list = list->next) { - gchar *color, *name, *tag; - name = buf = list->data; - color = strrchr (buf, ':'); - if (color == NULL) { - g_free (buf); - continue; - } - - *color++ = '\0'; - tag = strchr (color, '|'); - if (tag) - *tag++ = '\0'; - - label = g_new (EUtilLabel, 1); - - /* Needed for Backward Compatibility */ - if (num < G_N_ELEMENTS (label_defaults)) { - label->name = g_strdup ((buf && *buf) ? buf : _(label_defaults[num].name)); - label->tag = g_strdup (label_defaults[num].tag); - num++; - } else if (!tag) { - g_free (buf); - g_free (label); - continue; - } else { - label->name = g_strdup (name); - label->tag = g_strdup (tag); - } - - label->colour = g_strdup (color); - labels = g_slist_prepend (labels, label); - - g_free (buf); - } - - if (head) - g_slist_free (head); - - while (num < G_N_ELEMENTS (label_defaults)) { - /* complete the list with defaults */ - label = g_new (EUtilLabel, 1); - label->tag = g_strdup (label_defaults[num].tag); - label->name = g_strdup (_(label_defaults[num].name)); - label->colour = g_strdup (label_defaults[num].colour); - - labels = g_slist_prepend (labels, label); - - num++; - } - - if (unref_client) - g_object_unref (client); - - return g_slist_reverse (labels); -} - -static void -free_label_struct (EUtilLabel *label) -{ - if (!label) - return; - - g_free (label->tag); - g_free (label->name); - g_free (label->colour); - g_free (label); -} - -/** - * e_util_labels_free - * Frees memory previously allocated by @ref e_util_labels_parse - * - * @param labels Labels list, previously allocated by @ref e_util_labels_parse - * It is safe to call with NULL. - **/ -void -e_util_labels_free (GSList *labels) -{ - if (!labels) - return; - - g_slist_foreach (labels, (GFunc)free_label_struct, NULL); - g_slist_free (labels); -} - -/* stores the actual cache to gconf */ -static gboolean -flush_labels_cache (GSList *labels, gboolean free_labels) -{ - GSList *l, *text_labels; - GConfClient *client; - - if (!labels) - return FALSE; - - text_labels = NULL; - - for (l = labels; l; l = l->next) { - EUtilLabel *label = l->data; - - if (label && label->tag && label->name && label->colour) - text_labels = g_slist_prepend (text_labels, g_strdup_printf ("%s:%s|%s", label->name, label->colour, label->tag)); - } - - if (!text_labels) { - if (free_labels) - e_util_labels_free (labels); - - return FALSE; - } - - text_labels = g_slist_reverse (text_labels); - - client = gconf_client_get_default (); - gconf_client_set_list (client, E_UTIL_LABELS_GCONF_KEY, GCONF_VALUE_STRING, text_labels, NULL); - g_object_unref (client); - - g_slist_foreach (text_labels, (GFunc)g_free, NULL); - g_slist_free (text_labels); - - if (free_labels) - e_util_labels_free (labels); - - /* not true if gconf failed to write; who cares */ - return TRUE; -} - -/** - * find_label - * - * Looks for label in labels cache by tag and returns actual pointer to cache. - * @param labels The cache of labels; comes from @ref e_util_labels_parse - * @param tag Tag of label you are looking for. - * @return Pointer to cache data if label with such tag exists or NULL. Do not free it! - **/ -static EUtilLabel * -find_label (GSList *labels, const gchar *tag) -{ - GSList *l; - - g_return_val_if_fail (tag != NULL, NULL); - - for (l = labels; l; l = l->next) { - EUtilLabel *label = l->data; - - if (label && label->tag && !strcmp (tag, label->tag)) - return label; - } - - return NULL; -} - -static gchar * -tag_from_name (const gchar *name) -{ - /* this does thunderbird, just do not ask */ - gchar *s1, *s2, *p; - const gchar *bads = " ()/{%*<>\\\""; - - if (!name || !*name) - return NULL; - - s1 = g_strdup (name); - for (p = s1; p && *p; p++) { - if (strchr (bads, *p)) - *p = '_'; - } - - s2 = camel_utf8_utf7 (s1); - g_free (s1); - - s1 = g_ascii_strdown (s2, -1); - g_free (s2); - - return s1; -} - -/** - * e_util_labels_add - * Creates new label at the end of actual list of labels. - * - * @param name User readable name of this label. Should not be NULL. - * @param color Color assigned to this label. Should not be NULL. - * @return If succeeded then new label tag, NULL otherwise. - * Returned pointer should be freed with g_free. - * It will return NULL when the tag will be same as already existed. - * Tag name is generated in similar way as in Thunderbird. - **/ -gchar * -e_util_labels_add (const gchar *name, const GdkColor *color) -{ - EUtilLabel *label; - GSList *labels; - gchar *tag; - - g_return_val_if_fail (name != NULL, NULL); - g_return_val_if_fail (color != NULL, NULL); - - labels = e_util_labels_parse (NULL); - tag = tag_from_name (name); - - if (!tag || find_label (labels, tag) != NULL) { - g_free (tag); - e_util_labels_free (labels); - return NULL; - } - - label = g_new0 (EUtilLabel, 1); - label->tag = g_strdup (tag); - label->name = g_strdup (name); - label->colour = gdk_color_to_string (color); - - labels = g_slist_append (labels, label); - - flush_labels_cache (labels, TRUE); - - return tag; -} - -/** - * e_util_labels_add_with_dlg - * This will open a dialog to add or edit label. - * - * @param parent Parent widget for the dialog. - * @param tag A tag for existing label to edit or NULL to add new label. - * @return Tag for newly added label or NULL, if something failed. - * Returned value should be freed with g_free. - **/ -gchar * -e_util_labels_add_with_dlg (GtkWindow *parent, const gchar *tag) -{ - GtkWidget *table, *dialog, *l, *e, *c; - const gchar *name; - GdkColor color; - gboolean is_edit = FALSE; - gchar *new_tag = NULL; - GSList *labels; - - table = gtk_table_new (2, 2, FALSE); - - labels = e_util_labels_parse (NULL); - name = tag ? e_util_labels_get_name (labels, tag) : NULL; - - l = gtk_label_new_with_mnemonic (_("Label _Name:")); - e = gtk_entry_new (); - c = gtk_color_button_new (); - - if (!tag || !e_util_labels_get_color (labels, tag, &color)) - memset (&color, 0xCD, sizeof (GdkColor)); - else - is_edit = TRUE; - - if (name) - gtk_entry_set_text (GTK_ENTRY (e), name); - - gtk_entry_set_activates_default (GTK_ENTRY (e), TRUE); - gtk_label_set_mnemonic_widget (GTK_LABEL (l), e); - gtk_misc_set_alignment (GTK_MISC (l), 0.0, 0.0); - gtk_color_button_set_color (GTK_COLOR_BUTTON (c), &color); - - gtk_table_attach (GTK_TABLE (table), l, 0, 1, 0, 1, GTK_EXPAND | GTK_FILL, 0, 0, 0); - gtk_table_attach (GTK_TABLE (table), e, 0, 1, 1, 2, 0, 0, 0, 0); - gtk_table_attach (GTK_TABLE (table), c, 1, 2, 1, 2, 0, 0, 0, 0); - gtk_container_set_border_width (GTK_CONTAINER (table), 10); - gtk_widget_show_all (table); - - dialog = gtk_dialog_new_with_buttons (is_edit ? _("Edit Label") : _("Add Label"), - parent, - GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT, - GTK_STOCK_CANCEL, GTK_RESPONSE_REJECT, - GTK_STOCK_OK, GTK_RESPONSE_ACCEPT, - NULL); - - gtk_dialog_set_has_separator (GTK_DIALOG (dialog), FALSE); - gtk_dialog_set_default_response (GTK_DIALOG (dialog), GTK_RESPONSE_ACCEPT); - gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dialog)->vbox), table, TRUE, TRUE, 0); - - while (!new_tag) { - const gchar *error = NULL; - - if (gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_ACCEPT) { - name = gtk_entry_get_text (GTK_ENTRY (e)); - gtk_color_button_get_color (GTK_COLOR_BUTTON (c), &color); - - if (!name || !*name) - error = _("Label name cannot be empty."); - else if (is_edit) { - e_util_labels_set_data (tag, name, &color); - break; - } else if (!(new_tag = e_util_labels_add (name, &color))) - error = _("A label having the same tag already exists on the server. Please rename your label."); - else - break; - } else - break; - - if (error) - e_notice (parent, GTK_MESSAGE_ERROR, error); - } - - gtk_widget_destroy (dialog); - e_util_labels_free (labels); - - return new_tag; -} - -/** - * e_util_labels_remove - * - * @param tag Tag of the label to remove. - * @return Whether was removed. - **/ -gboolean -e_util_labels_remove (const gchar *tag) -{ - EUtilLabel *label; - GSList *labels; - - g_return_val_if_fail (tag != NULL, FALSE); - - labels = e_util_labels_parse (NULL); - label = find_label (labels, tag); - - if (!label) { - e_util_labels_free (labels); - return FALSE; - } - - labels = g_slist_remove (labels, label); - - free_label_struct (label); - - return flush_labels_cache (labels, TRUE); -} - -/** - * e_util_labels_set_data - * - * @param tag Tag of the label of our interest. - * @param name New name for the label. - * @param color New color for the label. - * @return Whether successfully saved. - **/ -gboolean -e_util_labels_set_data (const gchar *tag, const gchar *name, const GdkColor *color) -{ - EUtilLabel *label; - GSList *labels; - - g_return_val_if_fail (tag != NULL, FALSE); - g_return_val_if_fail (name != NULL, FALSE); - g_return_val_if_fail (color != NULL, FALSE); - - labels = e_util_labels_parse (NULL); - label = find_label (labels, tag); - - if (!label) { - e_util_labels_free (labels); - return FALSE; - } - - g_free (label->name); - label->name = g_strdup (name); - - g_free (label->colour); - label->colour = gdk_color_to_string (color); - - return flush_labels_cache (labels, TRUE); -} - -/** - * e_util_labels_is_system - * - * @return Whether the tag is one of default/system labels or not. - **/ -gboolean -e_util_labels_is_system (const gchar *tag) -{ - gint i; - - if (!tag) - return FALSE; - - for (i = 0; i < G_N_ELEMENTS (label_defaults); i++) { - if (strcmp (tag, label_defaults[i].tag) == 0) - return TRUE; - } - - return FALSE; -} - -/** - * e_util_labels_get_new_tag - * - * @param old_tag Tag of the label from old version of Evolution. - * @return New tag name equivalent with the old tag, or NULL if no such name existed before. - **/ -const gchar * -e_util_labels_get_new_tag (const gchar *old_tag) -{ - gint i; - - if (!old_tag) - return NULL; - - for (i = 0; i < G_N_ELEMENTS (label_defaults); i++) { - /* default labels have same name as those old, only with prefix "$Label" */ - if (!strcmp (old_tag, label_defaults[i].tag + 6)) - return label_defaults[i].tag; - } - - return NULL; -} - -/** - * e_util_labels_get_name - * - * @param labels Cache of labels from call of @ref e_util_labels_parse. - * The returned pointer will be taken from this list, so it's alive as long as the list. - * @param tag Tag of the label of our interest. - * @return Name of the label with that tag or NULL, if no such label exists. - **/ -const gchar * -e_util_labels_get_name (GSList *labels, const gchar *tag) -{ - EUtilLabel *label; - - g_return_val_if_fail (tag != NULL, NULL); - - label = find_label (labels, tag); - if (!label) - return NULL; - - return label->name; -} - -/** - * e_util_labels_get_color - * - * @param labels Cache of labels from call of @ref e_util_labels_parse. - * @param tag Tag of the label of our interest. - * @param color [out] Actual color of the label with that tag, or unchanged if failed. - * @return Whether found such label and color has been set. - **/ -gboolean -e_util_labels_get_color (GSList *labels, const gchar *tag, GdkColor *color) -{ - EUtilLabel *label; - - g_return_val_if_fail (tag != NULL, FALSE); - g_return_val_if_fail (color != NULL, FALSE); - - label = find_label (labels, tag); - if (!label) - return FALSE; - - return gdk_color_parse (label->colour, color); -} - -/** - * e_util_labels_get_color_str - * - * @param labels Cache of labels from call of @ref e_util_labels_parse. - * The returned pointer will be taken from this list, so it's alive as long as the list. - * @param tag Tag of the label of our interest. - * @return String representation of that label, or NULL, if no such label exists. - **/ -const gchar * -e_util_labels_get_color_str (GSList *labels, const gchar *tag) -{ - EUtilLabel *label; - - g_return_val_if_fail (tag != NULL, NULL); - - label = find_label (labels, tag); - if (!label) - return NULL; - - return label->colour; -} - -/** - * e_util_labels_get_filter_options: - * Returns list of newly allocated struct _filter_option-s, to be used in filters. - **/ -GSList * -e_util_labels_get_filter_options (void) -{ - GSList *known = e_util_labels_parse (NULL), *l; - GSList *res = NULL; - - for (l = known; l; l = l->next) { - EUtilLabel *label = l->data; - const gchar *tag; - struct _filter_option *fo; - - if (!label) - continue; - - tag = label->tag; - - if (tag && strncmp (tag, "$Label", 6) == 0) - tag += 6; - - fo = g_new0 (struct _filter_option, 1); - fo->title = e_str_without_underscores (label->name); - fo->value = g_strdup (tag); - - res = g_slist_prepend (res, fo); - } - - e_util_labels_free (known); - - return g_slist_reverse (res); -} diff --git a/e-util/e-util-labels.h b/e-util/e-util-labels.h deleted file mode 100644 index f0f3ae3bfe..0000000000 --- a/e-util/e-util-labels.h +++ /dev/null @@ -1,52 +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/> - * - * - * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com) - * - */ - -#ifndef _E_UTIL_LABELS_H -#define _E_UTIL_LABELS_H - -#include <gtk/gtk.h> -#include <gconf/gconf-client.h> - -typedef struct { - gchar *tag; - gchar *name; - gchar *colour; -} EUtilLabel; - -#define E_UTIL_LABELS_GCONF_KEY "/apps/evolution/mail/labels" - -GSList * e_util_labels_parse (struct _GConfClient *client); -void e_util_labels_free (GSList *labels); - -gchar * e_util_labels_add (const gchar *name, const GdkColor *color); -gchar * e_util_labels_add_with_dlg (GtkWindow *parent, const gchar *tag); -gboolean e_util_labels_remove (const gchar *tag); -gboolean e_util_labels_set_data (const gchar *tag, const gchar *name, const GdkColor *color); - -gboolean e_util_labels_is_system (const gchar *tag); -const gchar *e_util_labels_get_new_tag (const gchar *old_tag); - -const gchar *e_util_labels_get_name (GSList *labels, const gchar *tag); -gboolean e_util_labels_get_color (GSList *labels, const gchar *tag, GdkColor *color); -const gchar *e_util_labels_get_color_str (GSList *labels, const gchar *tag); - -GSList * e_util_labels_get_filter_options (void); - -#endif /* _E_UTIL_LABELS_H */ diff --git a/e-util/e-util.c b/e-util/e-util.c index ebd4251b00..57ec251c55 100644 --- a/e-util/e-util.c +++ b/e-util/e-util.c @@ -372,6 +372,41 @@ e_action_group_remove_all_actions (GtkActionGroup *action_group) } /** + * e_radio_action_get_current_action: + * @radio_action: a #GtkRadioAction + * + * Returns the currently active member of the group to which @radio_action + * belongs. + * + * Returns: the currently active group member + **/ +GtkRadioAction * +e_radio_action_get_current_action (GtkRadioAction *radio_action) +{ + GSList *group; + gint current_value; + + g_return_val_if_fail (GTK_IS_RADIO_ACTION (radio_action), NULL); + + group = gtk_radio_action_get_group (radio_action); + current_value = gtk_radio_action_get_current_value (radio_action); + + while (group != NULL) { + gint value; + + radio_action = GTK_RADIO_ACTION (group->data); + g_object_get (radio_action, "value", &value, NULL); + + if (value == current_value) + return radio_action; + + group = g_slist_next (group); + } + + return NULL; +} + +/** * e_str_without_underscores: * @s: the string to strip underscores from. * @@ -521,6 +556,30 @@ e_write_file_uri (const gchar *filename, const gchar *data) return res; } +/** + * e_color_to_value: + * color: a #GdkColor + * + * Converts a #GdkColor to a 24-bit RGB color value. + * + * Returns: a 24-bit color value + **/ +guint32 +e_color_to_value (GdkColor *color) +{ + guint16 red; + guint16 green; + guint16 blue; + + g_return_val_if_fail (color != NULL, 0); + + red = color->red >> 8; + green = color->green >> 8; + blue = color->blue >> 8; + + return (guint32) (((red << 16) | (green << 8) | blue) & 0xffffff); +} + static gint epow10 (gint number) { diff --git a/e-util/e-util.h b/e-util/e-util.h index ecb389b8b3..33bc940df7 100644 --- a/e-util/e-util.h +++ b/e-util/e-util.h @@ -57,6 +57,8 @@ gint e_action_compare_by_label (GtkAction *action1, GtkAction *action2); void e_action_group_remove_all_actions (GtkActionGroup *action_group); +GtkRadioAction *e_radio_action_get_current_action + (GtkRadioAction *radio_action); gchar * e_str_without_underscores (const gchar *s); gint e_str_compare (gconstpointer x, @@ -69,6 +71,7 @@ gint e_int_compare (gconstpointer x, gconstpointer y); gboolean e_write_file_uri (const gchar *filename, const gchar *data); +guint32 e_color_to_value (GdkColor *color); /* This only makes a filename safe for usage as a filename. * It still may have shell meta-characters in it. */ @@ -129,7 +132,8 @@ gboolean e_file_lock_create (void); void e_file_lock_destroy (void); gboolean e_file_lock_exists (void); -gchar * e_util_guess_mime_type (const gchar *filename, gboolean localfile); +gchar * e_util_guess_mime_type (const gchar *filename, + gboolean localfile); gchar * e_util_filename_to_uri (const gchar *filename); gchar * e_util_uri_to_filename (const gchar *uri); @@ -138,8 +142,8 @@ gboolean e_util_read_file (const gchar *filename, gchar **buffer, gsize *read, GError **error); - -GSList *e_util_get_category_filter_options (void); +GSList * e_util_get_category_filter_options + (void); /* Camel uses its own object system, so we have to box * CamelObjects to safely use them as GObject properties. */ diff --git a/e-util/gconf-bridge.c b/e-util/gconf-bridge.c index 259ad14adc..be2a0cabd7 100644 --- a/e-util/gconf-bridge.c +++ b/e-util/gconf-bridge.c @@ -1083,17 +1083,17 @@ gconf_bridge_bind_string_list_store (GConfBridge *bridge, (list_store_binding_store_changed_cb), binding); binding->row_changed_id = - g_signal_connect_swapped (list_store, "row-inserted", + g_signal_connect_swapped (list_store, "row-changed", G_CALLBACK (list_store_binding_store_changed_cb), binding); binding->row_deleted_id = - g_signal_connect_swapped (list_store, "row-inserted", + g_signal_connect_swapped (list_store, "row-deleted", G_CALLBACK (list_store_binding_store_changed_cb), binding); binding->rows_reordered_id = - g_signal_connect_swapped (list_store, "row-inserted", + g_signal_connect_swapped (list_store, "rows-reordered", G_CALLBACK (list_store_binding_store_changed_cb), binding); |