aboutsummaryrefslogtreecommitdiffstats
path: root/e-util
diff options
context:
space:
mode:
Diffstat (limited to 'e-util')
-rw-r--r--e-util/Makefile.am26
-rw-r--r--e-util/e-account-utils.c96
-rw-r--r--e-util/e-account-utils.h (renamed from e-util/e-corba-utils.c)36
-rw-r--r--e-util/e-charset.c255
-rw-r--r--e-util/e-charset.h (renamed from e-util/e-corba-utils.h)23
-rw-r--r--e-util/e-config.c458
-rw-r--r--e-util/e-config.h25
-rw-r--r--e-util/e-dialog-utils.c26
-rw-r--r--e-util/e-dialog-utils.h2
-rw-r--r--e-util/e-dialog-widgets.c14
-rw-r--r--e-util/e-error.c19
-rw-r--r--e-util/e-import.c4
-rw-r--r--e-util/e-import.h2
-rw-r--r--e-util/e-logger.c76
-rw-r--r--e-util/e-logger.h26
-rw-r--r--e-util/e-marshal.list2
-rw-r--r--e-util/e-menu.c925
-rw-r--r--e-util/e-menu.h319
-rw-r--r--e-util/e-module.c318
-rw-r--r--e-util/e-module.h81
-rw-r--r--e-util/e-non-intrusive-error-dialog.c1
-rw-r--r--e-util/e-non-intrusive-error-dialog.h2
-rw-r--r--e-util/e-plugin-ui.c438
-rw-r--r--e-util/e-plugin-ui.h9
-rw-r--r--e-util/e-plugin.c696
-rw-r--r--e-util/e-plugin.h118
-rw-r--r--e-util/e-popup.c953
-rw-r--r--e-util/e-popup.h305
-rw-r--r--e-util/e-request.c2
-rw-r--r--e-util/e-signature-utils.c351
-rw-r--r--e-util/e-signature-utils.h40
-rw-r--r--e-util/e-unicode.c2052
-rw-r--r--e-util/e-unicode.h111
-rw-r--r--e-util/e-util-labels.c591
-rw-r--r--e-util/e-util-labels.h52
-rw-r--r--e-util/e-util.c59
-rw-r--r--e-util/e-util.h10
-rw-r--r--e-util/gconf-bridge.c6
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);