diff options
Diffstat (limited to 'e-util')
-rw-r--r-- | e-util/Makefile.am | 20 | ||||
-rw-r--r-- | e-util/e-account-utils.c | 96 | ||||
-rw-r--r-- | e-util/e-account-utils.h (renamed from e-util/e-corba-utils.c) | 36 | ||||
-rw-r--r-- | e-util/e-corba-utils.h | 31 | ||||
-rw-r--r-- | e-util/e-dialog-utils.c | 26 | ||||
-rw-r--r-- | e-util/e-dialog-utils.h | 2 | ||||
-rw-r--r-- | e-util/e-gui-utils.c | 66 | ||||
-rw-r--r-- | e-util/e-logger.c | 74 | ||||
-rw-r--r-- | e-util/e-logger.h | 26 | ||||
-rw-r--r-- | e-util/e-marshal.list | 1 | ||||
-rw-r--r-- | e-util/e-non-intrusive-error-dialog.c | 1 | ||||
-rw-r--r-- | e-util/e-non-intrusive-error-dialog.h | 2 | ||||
-rw-r--r-- | e-util/e-plugin-ui.c | 435 | ||||
-rw-r--r-- | e-util/e-plugin-ui.h | 9 | ||||
-rw-r--r-- | e-util/e-signature-utils.c | 347 | ||||
-rw-r--r-- | e-util/e-signature-utils.h (renamed from e-util/e-gui-utils.h) | 27 | ||||
-rw-r--r-- | e-util/e-util-labels.c | 586 | ||||
-rw-r--r-- | e-util/e-util-labels.h | 57 | ||||
-rw-r--r-- | e-util/e-util.c | 238 | ||||
-rw-r--r-- | e-util/e-util.h | 20 | ||||
-rw-r--r-- | e-util/gconf-bridge.c | 6 |
21 files changed, 1098 insertions, 1008 deletions
diff --git a/e-util/Makefile.am b/e-util/Makefile.am index ee54891c1d..e8df3bcb13 100644 --- a/e-util/Makefile.am +++ b/e-util/Makefile.am @@ -34,18 +34,18 @@ INCLUDES = \ -DSEARCH_RULE_DIR=\"$(ruledir)\" \ -DG_LOG_DOMAIN=\"e-utils\" \ $(GNOME_PILOT_CFLAGS) \ - $(ICONV_CFLAGS) \ + $(ICONV_CFLAGS) \ $(E_UTIL_CFLAGS) privsolib_LTLIBRARIES = libeutil.la libeconduit.la eutilinclude_HEADERS = \ + e-account-utils.h \ e-bconf-map.h \ e-binding.h \ e-categories-config.h \ e-config.h \ e-config-listener.h \ - e-corba-utils.h \ e-cursor.h \ e-dialog-utils.h \ e-dialog-widgets.h \ @@ -53,15 +53,14 @@ eutilinclude_HEADERS = \ e-event.h \ e-folder-map.h \ e-fsutils.h \ - e-gui-utils.h \ e-html-utils.h \ 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-non-intrusive-error-dialog.h \ e-print.h \ e-plugin.h \ e-plugin-ui.h \ @@ -70,6 +69,7 @@ eutilinclude_HEADERS = \ 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 \ @@ -77,17 +77,16 @@ eutilinclude_HEADERS = \ e-text-event-processor-types.h \ e-text-event-processor.h \ e-util.h \ - e-util-labels.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-config.c \ e-config-listener.c \ - e-corba-utils.c \ + e-config.c \ e-cursor.c \ e-dialog-utils.c \ e-dialog-widgets.c \ @@ -95,30 +94,29 @@ libeutil_la_SOURCES = \ e-event.c \ e-folder-map.c \ e-fsutils.c \ - e-gui-utils.c \ e-html-utils.c \ 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-non-intrusive-error-dialog.c \ e-plugin-ui.c \ + e-plugin.c \ e-popup.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-util-private.h \ e-xml-utils.c \ gconf-bridge.c \ diff --git a/e-util/e-account-utils.c b/e-util/e-account-utils.c new file mode 100644 index 0000000000..d98a378b48 --- /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 0288602a7e..24262349d2 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 char *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 char *s) -{ - return CORBA_string_dup (e_safe_corba_string (s)); -} +#endif /* E_ACCOUNT_UTILS_H */ diff --git a/e-util/e-corba-utils.h b/e-util/e-corba-utils.h deleted file mode 100644 index 979237929d..0000000000 --- a/e-util/e-corba-utils.h +++ /dev/null @@ -1,31 +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: - * Ettore Perazzoli <ettore@ximian.com> - * - * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com) - * - */ - -#ifndef E_CORBA_UTILS_H -#define E_CORBA_UTILS_H - -#include <orbit/orbit.h> - -const CORBA_char *e_safe_corba_string (const char *s); -CORBA_char *e_safe_corba_string_dup (const char *s); - -#endif diff --git a/e-util/e-dialog-utils.c b/e-util/e-dialog-utils.c index 0546430512..7d1d4836b6 100644 --- a/e-util/e-dialog-utils.c +++ b/e-util/e-dialog-utils.c @@ -344,29 +344,29 @@ e_file_dialog_save_folder (const char *title) * no signals connected and is not shown. **/ GtkWidget * -e_file_get_save_filesel (GtkWidget *parent, const char *title, const char *name, GtkFileChooserAction action) +e_file_get_save_filesel (GtkWindow *parent, const char *title, const char *name, GtkFileChooserAction action) { GtkWidget *filesel; char *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 9d594122e2..9e6e7992c1 100644 --- a/e-util/e-dialog-utils.h +++ b/e-util/e-dialog-utils.h @@ -43,7 +43,7 @@ char *e_file_dialog_save (const char *title, const char *fname) char *e_file_dialog_save_folder (const char *title); -GtkWidget * e_file_get_save_filesel (GtkWidget *parent, const char *title, const char *name, GtkFileChooserAction action); +GtkWidget * e_file_get_save_filesel (GtkWindow *parent, const char *title, const char *name, GtkFileChooserAction action); gboolean e_file_can_save(GtkWindow *parent, const char *uri); gboolean e_file_check_local(const char *name); diff --git a/e-util/e-gui-utils.c b/e-util/e-gui-utils.c deleted file mode 100644 index 37d3fc9c48..0000000000 --- a/e-util/e-gui-utils.c +++ /dev/null @@ -1,66 +0,0 @@ -/* - * GUI utility functions - * - * 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: - * Miguel de Icaza (miguel@ximian.com) - * Chris Toshok (toshok@ximian.com) - * - * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com) - * - */ - -#ifdef HAVE_CONFIG_H -#include <config.h> -#endif - -#include <string.h> - -#include "e-gui-utils.h" - -#include <libgnome/gnome-program.h> -#include <libgnomeui/gnome-icon-lookup.h> - -/** - * e_icon_for_mime_type: - * @mime_type: a MIME type - * @size_hint: the size the caller plans to display the icon at - * - * Tries to find an icon representing @mime_type that will display - * nicely at @size_hint by @size_hint pixels. The returned icon - * may or may not actually be that size. - * - * Return value: a pixbuf, which the caller must unref when it is done - **/ -GdkPixbuf * -e_icon_for_mime_type (const char *mime_type, int size_hint) -{ - gchar *icon_name; - GdkPixbuf *pixbuf = NULL; - - icon_name = gnome_icon_lookup ( - gtk_icon_theme_get_default (), - NULL, NULL, NULL, NULL, mime_type, 0, NULL); - - if (icon_name != NULL) { - pixbuf = gtk_icon_theme_load_icon ( - gtk_icon_theme_get_default (), - icon_name, size_hint, 0, NULL); - g_free (icon_name); - } - - return pixbuf; -} diff --git a/e-util/e-logger.c b/e-util/e-logger.c index 9db0ca0e37..c304e362e6 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; } @@ -133,7 +143,7 @@ logger_finalize (GObject *object) 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 (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 ( - 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 f7dfd8017e..ce595d691c 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 (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..b667ca4a84 100644 --- a/e-util/e-marshal.list +++ b/e-util/e-marshal.list @@ -66,3 +66,4 @@ NONE:STRING,STRING,STRING NONE:STRING,STRING,UINT OBJECT:OBJECT,DOUBLE,DOUBLE,BOOLEAN POINTER:NONE +STRING:NONE diff --git a/e-util/e-non-intrusive-error-dialog.c b/e-util/e-non-intrusive-error-dialog.c index 070c1e9bef..5fd98cacd2 100644 --- a/e-util/e-non-intrusive-error-dialog.c +++ b/e-util/e-non-intrusive-error-dialog.c @@ -305,4 +305,3 @@ eni_show_logger(ELogger *logger, GtkWidget *top,const char *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 e801d47a52..159242c0fa 100644 --- a/e-util/e-non-intrusive-error-dialog.h +++ b/e-util/e-non-intrusive-error-dialog.h @@ -38,7 +38,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 c192ece939..2528efd0fa 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,195 +50,309 @@ 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 *manager) +plugin_ui_hook_unregister_manager (EPluginUIHook *hook, + GtkUIManager *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, manager); - if (g_hash_table_size (hash_table) == 0) - g_hash_table_remove (registry, hook); + registry = hook->priv->registry; + g_hash_table_remove (registry, manager); } static void -plugin_ui_registry_insert (EPluginUIHook *hook, - GtkUIManager *manager, - guint merge_id) +plugin_ui_hook_register_manager (EPluginUIHook *hook, + GtkUIManager *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 (manager, user_data)) + return; g_object_weak_ref ( G_OBJECT (manager), (GWeakNotify) - plugin_ui_registry_remove, hook); + plugin_ui_hook_unregister_manager, hook); - g_hash_table_insert (hash_table, manager, GUINT_TO_POINTER (merge_id)); + registry = hook->priv->registry; + hash_table = g_hash_table_lookup (registry, 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, manager, hash_table); + } } -/* Helper for plugin_ui_hook_merge_ui() */ -static void -plugin_ui_hook_merge_foreach (GtkUIManager *manager, - const gchar *ui_definition, - GHashTable *hash_table) +static guint +plugin_ui_hook_merge_ui (EPluginUIHook *hook, + GtkUIManager *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 ( manager, ui_definition, -1, &error); - gtk_ui_manager_ensure_update (manager); + if (error != NULL) { g_warning ("%s", error->message); g_error_free (error); } - /* Merge ID will be 0 on error, which is what we want. */ - g_hash_table_insert (hash_table, manager, GUINT_TO_POINTER (merge_id)); + return merge_id; } static void -plugin_ui_hook_merge_ui (EPluginUIHook *hook) +plugin_ui_enable_manager (EPluginUIHook *hook, + GtkUIManager *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, 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 *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 (manager)); + ui_definitions = hook->priv->ui_definitions; - g_hash_table_insert (intermediate, 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, 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 *manager, - gpointer value, - GHashTable *hash_table) +plugin_ui_disable_manager (EPluginUIHook *hook, + GtkUIManager *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, 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 (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, 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 (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 *manager = key; + plugin_ui_enable_manager (hook, manager, NULL); + } } static void -plugin_ui_hook_register_manager (EPluginUIHook *hook, - GtkUIManager *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 (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 ( - manager, ui_definition, -1, &error); - gtk_ui_manager_ensure_update (manager); - if (error != NULL) { - g_warning ("%s", error->message); - g_error_free (error); - } + while (g_hash_table_iter_next (&iter, &key, NULL)) { + GtkUIManager *manager = key; + plugin_ui_disable_manager (hook, manager, NULL, FALSE); } - - /* Save merge ID's for later use. */ - plugin_ui_registry_insert (hook, manager, merge_id); } static void plugin_ui_hook_finalize (GObject *object) { EPluginUIHookPrivate *priv; + GHashTableIter iter; + gpointer 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, &manager, NULL)) + g_object_weak_unref ( + G_OBJECT (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); @@ -298,9 +413,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 @@ -319,25 +434,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 @@ -367,17 +481,14 @@ e_plugin_ui_hook_get_type (void) } void -e_plugin_ui_register_manager (const gchar *id, - GtkUIManager *manager, +e_plugin_ui_register_manager (GtkUIManager *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 (manager)); - - g_object_set_data (G_OBJECT (manager), key, (gpointer) id); + g_return_if_fail (id != NULL); /* Loop over all installed plugins. */ plugin_list = e_plugin_list_plugins (); @@ -385,36 +496,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, manager, ui_definition, user_data); + hook, manager, user_data); } + } +} + +void +e_plugin_ui_enable_manager (GtkUIManager *manager, + const gchar *id) +{ + GSList *plugin_list; + + g_return_if_fail (GTK_IS_UI_MANAGER (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, manager, id); + } } } -const gchar * -e_plugin_ui_get_manager_id (GtkUIManager *manager) +void +e_plugin_ui_disable_manager (GtkUIManager *manager, + const gchar *id) { - const gchar *key = E_PLUGIN_UI_MANAGER_ID_KEY; + GSList *plugin_list; + + g_return_if_fail (GTK_IS_UI_MANAGER (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 (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 (manager), key); + if (!E_IS_PLUGIN_UI_HOOK (hook)) + continue; + + plugin_ui_disable_manager (hook, manager, id, TRUE); + } + } } diff --git a/e-util/e-plugin-ui.h b/e-util/e-plugin-ui.h index 00e6ed5fcf..d1a380d91e 100644 --- a/e-util/e-plugin-ui.h +++ b/e-util/e-plugin-ui.h @@ -62,10 +62,13 @@ typedef gboolean (*EPluginUIInitFunc) (GtkUIManager *manager, GType e_plugin_ui_hook_get_type (void); -void e_plugin_ui_register_manager (const gchar *id, - GtkUIManager *manager, +void e_plugin_ui_register_manager (GtkUIManager *manager, + const gchar *id, gpointer user_data); -const gchar * e_plugin_ui_get_manager_id (GtkUIManager *manager); +void e_plugin_ui_enable_manager (GtkUIManager *manager, + const gchar *id); +void e_plugin_ui_disable_manager (GtkUIManager *manager, + const gchar *id); G_END_DECLS diff --git a/e-util/e-signature-utils.c b/e-util/e-signature-utils.c new file mode 100644 index 0000000000..0114ce6e06 --- /dev/null +++ b/e-util/e-signature-utils.c @@ -0,0 +1,347 @@ +/* + * 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; + gchar *content; + gsize length; + gint fd; + + g_return_val_if_fail (E_IS_SIGNATURE (signature), NULL); + + fd = g_open (signature->filename, O_RDONLY, 0); + if (fd < 0) { + g_set_error ( + error, G_FILE_ERROR, + g_file_error_from_errno (errno), + "%s: %s", signature->filename, + g_strerror (errno)); + return NULL; + } + + input_stream = camel_stream_fs_new_with_fd (fd); + + if (!signature->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-gui-utils.h b/e-util/e-signature-utils.h index d7552d5379..41472f45d0 100644 --- a/e-util/e-gui-utils.h +++ b/e-util/e-signature-utils.h @@ -1,4 +1,6 @@ /* + * 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 @@ -12,18 +14,27 @@ * 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) - * */ -#ifndef E_GUI_UTILS_H -#define E_GUI_UTILS_H +#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); -GdkPixbuf *e_icon_for_mime_type (const char *mime_type, int size); +G_END_DECLS -#endif /* E_GUI_UTILS_H */ +#endif /* E_SIGNATURE_UTILS_H */ diff --git a/e-util/e-util-labels.c b/e-util/e-util-labels.c deleted file mode 100644 index 85984da59c..0000000000 --- a/e-util/e-util-labels.c +++ /dev/null @@ -1,586 +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" - -/* Note, the first element of each EUtilLabel must NOT be translated */ -EUtilLabel label_defaults[LABEL_DEFAULTS_NUM] = { - { "$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; - char *buf; - int 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) { - char *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 < LABEL_DEFAULTS_NUM) { - 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 < LABEL_DEFAULTS_NUM) { - /* 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 char *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 char * -tag_from_name (const char *name) -{ - /* this does thunderbird, just do not ask */ - char *s1, *s2, *p; - const char *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. - **/ -char * -e_util_labels_add (const char *name, const GdkColor *color) -{ - EUtilLabel *label; - GSList *labels; - char *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. - **/ -char * -e_util_labels_add_with_dlg (GtkWindow *parent, const char *tag) -{ - GtkWidget *table, *dialog, *l, *e, *c; - const char *name; - GdkColor color; - gboolean is_edit = FALSE; - char *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 char *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 char *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 char *tag, const char *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 char *tag) -{ - int i; - - if (!tag) - return FALSE; - - for (i = 0; i < LABEL_DEFAULTS_NUM; 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 char * -e_util_labels_get_new_tag (const char *old_tag) -{ - int i; - - if (!old_tag) - return NULL; - - for (i = 0; i < LABEL_DEFAULTS_NUM; 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 char * -e_util_labels_get_name (GSList *labels, const char *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 char *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, is no such label exists. - **/ -const char * -e_util_labels_get_color_str (GSList *labels, const char *tag) -{ - EUtilLabel *label; - - g_return_val_if_fail (tag != NULL, FALSE); - - label = find_label (labels, tag); - if (!label) - return FALSE; - - 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 char *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 26520ff226..0000000000 --- a/e-util/e-util-labels.h +++ /dev/null @@ -1,57 +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> - -struct _GtkWindow; -struct _GConfClient; - -typedef struct { - char *tag; - char *name; - char *colour; -} EUtilLabel; - -#define E_UTIL_LABELS_GCONF_KEY "/apps/evolution/mail/labels" - -#define LABEL_DEFAULTS_NUM 5 -extern EUtilLabel label_defaults[LABEL_DEFAULTS_NUM]; - -GSList * e_util_labels_parse (struct _GConfClient *client); -void e_util_labels_free (GSList *labels); - -char * e_util_labels_add (const char *name, const GdkColor *color); -char * e_util_labels_add_with_dlg (struct _GtkWindow *parent, const char *tag); -gboolean e_util_labels_remove (const char *tag); -gboolean e_util_labels_set_data (const char *tag, const char *name, const GdkColor *color); - -gboolean e_util_labels_is_system (const char *tag); -const char *e_util_labels_get_new_tag (const char *old_tag); - -const char *e_util_labels_get_name (GSList *labels, const char *tag); -gboolean e_util_labels_get_color (GSList *labels, const char *tag, GdkColor *color); -const char *e_util_labels_get_color_str (GSList *labels, const char *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 0b28404c82..071f5e58b8 100644 --- a/e-util/e-util.c +++ b/e-util/e-util.c @@ -186,6 +186,183 @@ exit: } /** + * e_lookup_action: + * @ui_manager: a #GtkUIManager + * @action_name: the name of an action + * + * Returns the first #GtkAction named @action_name by traversing the + * list of action groups in @ui_manager. If no such action exists, the + * function emits a critical warning before returning %NULL, since this + * probably indicates a programming error and most code is not prepared + * to deal with lookup failures. + * + * Returns: the first #GtkAction named @action_name + **/ +GtkAction * +e_lookup_action (GtkUIManager *ui_manager, + const gchar *action_name) +{ + GtkAction *action = NULL; + GList *iter; + + g_return_val_if_fail (GTK_IS_UI_MANAGER (ui_manager), NULL); + g_return_val_if_fail (action_name != NULL, NULL); + + iter = gtk_ui_manager_get_action_groups (ui_manager); + + while (iter != NULL) { + GtkActionGroup *action_group = iter->data; + + action = gtk_action_group_get_action ( + action_group, action_name); + if (action != NULL) + return action; + + iter = g_list_next (iter); + } + + g_critical ("%s: action `%s' not found", G_STRFUNC, action_name); + + return NULL; +} + +/** + * e_lookup_action_group: + * @ui_manager: a #GtkUIManager + * @group_name: the name of an action group + * + * Returns the #GtkActionGroup in @ui_manager named @group_name. If no + * such action group exists, the function emits a critical warnings before + * returning %NULL, since this probably indicates a programming error and + * most code is not prepared to deal with lookup failures. + * + * Returns: the #GtkActionGroup named @group_name + **/ +GtkActionGroup * +e_lookup_action_group (GtkUIManager *ui_manager, + const gchar *group_name) +{ + GList *iter; + + g_return_val_if_fail (GTK_IS_UI_MANAGER (ui_manager), NULL); + g_return_val_if_fail (group_name != NULL, NULL); + + iter = gtk_ui_manager_get_action_groups (ui_manager); + + while (iter != NULL) { + GtkActionGroup *action_group = iter->data; + const gchar *name; + + name = gtk_action_group_get_name (action_group); + if (strcmp (name, group_name) == 0) + return action_group; + + iter = g_list_next (iter); + } + + g_critical ("%s: action group `%s' not found", G_STRFUNC, group_name); + + return NULL; +} + +/** + * e_load_ui_definition: + * @ui_manager: a #GtkUIManager + * @basename: basename of the UI definition file + * + * Loads a UI definition into @ui_manager from Evolution's UI directory. + * Failure here is fatal, since the application can't function without + * its UI definitions. + * + * Returns: The merge ID for the merged UI. The merge ID can be used to + * unmerge the UI with gtk_ui_manager_remove_ui(). + **/ +guint +e_load_ui_definition (GtkUIManager *ui_manager, + const gchar *basename) +{ + gchar *filename; + guint merge_id; + GError *error = NULL; + + g_return_val_if_fail (GTK_IS_UI_MANAGER (ui_manager), 0); + g_return_val_if_fail (basename != NULL, 0); + + filename = g_build_filename (EVOLUTION_UIDIR, basename, NULL); + merge_id = gtk_ui_manager_add_ui_from_file ( + ui_manager, filename, &error); + g_free (filename); + + if (error != NULL) { + g_error ("%s: %s", basename, error->message); + g_assert_not_reached (); + } + + return merge_id; +} + +/** + * e_action_compare_by_label: + * @action1: a #GtkAction + * @action2: a #GtkAction + * + * Compares the labels for @action1 and @action2 using g_utf8_collate(). + * + * Returns: < 0 if @action1 compares before @action2, 0 if they + * compare equal, > 0 if @action1 compares after @action2 + **/ +gint +e_action_compare_by_label (GtkAction *action1, + GtkAction *action2) +{ + gchar *label1; + gchar *label2; + gint result; + + /* XXX This is horribly inefficient but will generally only be + * used on short lists of actions during UI construction. */ + + if (action1 == action2) + return 0; + + g_object_get (action1, "label", &label1, NULL); + g_object_get (action2, "label", &label2, NULL); + + result = g_utf8_collate (label1, label2); + + g_free (label1); + g_free (label2); + + return result; +} + +/** + * e_action_group_remove_all_actions: + * @action_group: a #GtkActionGroup + * + * Removes all actions from the action group. + **/ +void +e_action_group_remove_all_actions (GtkActionGroup *action_group) +{ + GList *list, *iter; + + /* XXX I've proposed this function for inclusion in GTK+. + * GtkActionGroup stores actions in an internal hash + * table and can do this more efficiently by calling + * g_hash_table_remove_all(). + * + * http://bugzilla.gnome.org/show_bug.cgi?id=550485 */ + + g_return_if_fail (GTK_IS_ACTION_GROUP (action_group)); + + list = gtk_action_group_list_actions (action_group); + for (iter = list; iter != NULL; iter = iter->next) + gtk_action_group_remove_action (action_group, iter->data); + g_list_free (list); +} + +/** * e_str_without_underscores: * @s: the string to strip underscores from. * @@ -335,6 +512,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) { @@ -1301,23 +1502,32 @@ e_util_read_file (const char *filename, gboolean filename_is_uri, char **buffer, return res; } -GSList * -e_util_get_category_filter_options (void) +static gpointer +e_camel_object_copy (gpointer camel_object) { - GSList *res = NULL; - GList *clist, *l; + if (CAMEL_IS_OBJECT (camel_object)) + camel_object_ref (camel_object); + + return camel_object; +} - clist = e_categories_get_list (); - for (l = clist; l; l = l->next) { - const char *cname = l->data; - struct _filter_option *fo = g_new0 (struct _filter_option, 1); +static void +e_camel_object_free (gpointer camel_object) +{ + if (CAMEL_IS_OBJECT (camel_object)) + camel_object_unref (camel_object); +} - fo->title = g_strdup (cname); - fo->value = g_strdup (cname); - res = g_slist_prepend (res, fo); - } +GType +e_camel_object_get_type (void) +{ + static GType type = 0; - g_list_free (clist); + if (G_UNLIKELY (type == 0)) + type = g_boxed_type_register_static ( + "ECamelObject", + (GBoxedCopyFunc) e_camel_object_copy, + (GBoxedFreeFunc) e_camel_object_free); - return g_slist_reverse (res); + return type; } diff --git a/e-util/e-util.h b/e-util/e-util.h index 021e3286c7..84ec411516 100644 --- a/e-util/e-util.h +++ b/e-util/e-util.h @@ -27,6 +27,7 @@ #include <gtk/gtk.h> #include <limits.h> #include <gconf/gconf-client.h> +#include <camel/camel-object.h> #include <cairo.h> #include <e-util/e-marshal.h> @@ -46,6 +47,16 @@ void e_show_uri (GtkWindow *parent, const gchar *uri); void e_display_help (GtkWindow *parent, const gchar *link_id); +GtkAction * e_lookup_action (GtkUIManager *ui_manager, + const gchar *action_name); +GtkActionGroup *e_lookup_action_group (GtkUIManager *ui_manager, + const gchar *group_name); +guint e_load_ui_definition (GtkUIManager *ui_manager, + const gchar *basename); +gint e_action_compare_by_label (GtkAction *action1, + GtkAction *action2); +void e_action_group_remove_all_actions + (GtkActionGroup *action_group); char * e_str_without_underscores (const char *s); gint e_str_compare (gconstpointer x, @@ -58,6 +69,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. */ @@ -118,7 +130,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); @@ -128,7 +141,10 @@ gboolean e_util_read_file (const gchar *filename, gsize *read, GError **error); -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. */ +#define E_TYPE_CAMEL_OBJECT (e_camel_object_get_type ()) +GType e_camel_object_get_type (void); G_END_DECLS diff --git a/e-util/gconf-bridge.c b/e-util/gconf-bridge.c index 66dcbc7ea2..4ab0f59646 100644 --- a/e-util/gconf-bridge.c +++ b/e-util/gconf-bridge.c @@ -1082,17 +1082,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); |