From 03d8740213e324efaf7b774b0c7497ced2fa626b Mon Sep 17 00:00:00 2001 From: Matthew Barnes Date: Mon, 16 Feb 2009 00:44:40 +0000 Subject: Move signature script execution to e-util/e-signature-utils.s so the composer can invoke it. Composer no longer needs mail-config.h. Split signature preview into a new widget: ESignaturePreview. svn path=/branches/kill-bonobo/; revision=37272 --- composer/e-msg-composer.c | 3 +- e-util/e-signature-utils.c | 130 +++++++++++++ e-util/e-signature-utils.h | 1 + mail/em-composer-prefs.c | 126 ++----------- mail/mail-config.c | 126 ------------- mail/mail-config.h | 4 - widgets/misc/Makefile.am | 2 + widgets/misc/e-signature-preview.c | 344 +++++++++++++++++++++++++++++++++++ widgets/misc/e-signature-preview.h | 81 +++++++++ widgets/misc/e-signature-tree-view.c | 46 ++++- 10 files changed, 615 insertions(+), 248 deletions(-) create mode 100644 widgets/misc/e-signature-preview.c create mode 100644 widgets/misc/e-signature-preview.h diff --git a/composer/e-msg-composer.c b/composer/e-msg-composer.c index 65a372d0d0..b495474882 100644 --- a/composer/e-msg-composer.c +++ b/composer/e-msg-composer.c @@ -76,7 +76,6 @@ #include "mail/em-popup.h" #include "mail/em-utils.h" -#include "mail/mail-config.h" #include "mail/mail-crypto.h" #include "mail/mail-tools.h" @@ -1180,7 +1179,7 @@ get_signature_html (EMsgComposer *composer) format_html = signature->html; if (signature->script) - text = mail_config_signature_run_script ( + text = e_run_signature_script ( signature->filename); else text = e_read_signature_file ( diff --git a/e-util/e-signature-utils.c b/e-util/e-signature-utils.c index 5565ef9faf..0114ce6e06 100644 --- a/e-util/e-signature-utils.c +++ b/e-util/e-signature-utils.c @@ -29,6 +29,10 @@ #include #include +#ifndef G_OS_WIN32 +#include +#endif + #include "e-util/e-util.h" static ESignatureList *global_signature_list; @@ -215,3 +219,129 @@ e_read_signature_file (ESignature *signature, 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 index d4fdfd97f4..41472f45d0 100644 --- a/e-util/e-signature-utils.h +++ b/e-util/e-signature-utils.h @@ -33,6 +33,7 @@ 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 diff --git a/mail/em-composer-prefs.c b/mail/em-composer-prefs.c index ef73c23355..9b81935e90 100644 --- a/mail/em-composer-prefs.c +++ b/mail/em-composer-prefs.c @@ -49,6 +49,7 @@ #include "misc/e-charset-picker.h" #include "misc/e-signature-manager.h" +#include "misc/e-signature-preview.h" #include "e-util/e-error.h" #include "e-util/e-util-private.h" @@ -213,49 +214,6 @@ em_composer_prefs_get_type (void) return type; } -static void -sig_load_preview (EMComposerPrefs *prefs, - ESignature *signature) -{ - GtkHTML *html; - gchar *str; - - html = prefs->sig_preview; - - if (signature == NULL) { - gtk_html_load_from_string (html, " ", 1); - return; - } - - if (signature->script) - str = mail_config_signature_run_script (signature->filename); - else - /* FIXME Show an error in the preview area. */ - str = e_read_signature_file (signature, FALSE, NULL); - if (!str || !*str) { - /* make html stream happy and write at least one character */ - g_free (str); - str = g_strdup (" "); - } - - if (signature->html) { - gtk_html_load_from_string (html, str, strlen (str)); - } else { - GtkHTMLStream *stream; - int len; - - len = strlen (str); - stream = gtk_html_begin_content (html, "text/html; charset=utf-8"); - gtk_html_write (html, stream, "
", 5);
-		if (len)
-			gtk_html_write (html, stream, str, len);
-		gtk_html_write (html, stream, "
", 6); - gtk_html_end (html, stream, GTK_HTML_STREAM_OK); - } - - g_free (str); -} - void em_composer_prefs_new_signature (GtkWindow *parent, gboolean html_mode) @@ -268,59 +226,6 @@ em_composer_prefs_new_signature (GtkWindow *parent, gtk_widget_show (editor); } -static void -sig_selection_changed (GtkTreeSelection *selection, - EMComposerPrefs *prefs) -{ - ESignature *signature; - GtkTreeView *tree_view; - - tree_view = gtk_tree_selection_get_tree_view (selection); - - signature = e_signature_tree_view_get_selected ( - E_SIGNATURE_TREE_VIEW (tree_view)); - - sig_load_preview (prefs, signature); - - if (signature != NULL) - g_object_unref (signature); -} - -static void -url_requested (GtkHTML *html, - const gchar *url, - GtkHTMLStream *handle) -{ - GtkHTMLStreamStatus status; - gchar buf[128]; - gssize size; - gint fd; - gchar *filename; - - if (strncmp (url, "file:", 5) == 0) - filename = g_filename_from_uri (url, NULL, NULL); - else - filename = g_strdup (url); - fd = g_open (filename, O_RDONLY | O_BINARY, 0); - g_free (filename); - - status = GTK_HTML_STREAM_OK; - if (fd != -1) { - while ((size = read (fd, buf, sizeof (buf)))) { - if (size == -1) { - status = GTK_HTML_STREAM_ERROR; - break; - } else - gtk_html_write (html, handle, buf, size); - } - } else - status = GTK_HTML_STREAM_ERROR; - - gtk_html_end (html, handle, status); - if (fd > 0) - close (fd); -} - static void spell_language_toggled_cb (GtkCellRendererToggle *renderer, const gchar *path_string, @@ -383,10 +288,8 @@ spell_setup (EMComposerPrefs *prefs) { const GList *available_languages; GList *active_languages; - GConfClient *client; GtkListStore *store; - client = mail_config_get_gconf_client (); store = GTK_LIST_STORE (prefs->language_model); available_languages = gtkhtml_spell_language_get_available (); @@ -681,22 +584,19 @@ em_composer_prefs_construct (EMComposerPrefs *prefs, signature_tree_view = e_signature_manager_get_tree_view ( E_SIGNATURE_MANAGER (widget)); - selection = gtk_tree_view_get_selection ( - GTK_TREE_VIEW (signature_tree_view)); - g_signal_connect ( - selection, "changed", - G_CALLBACK (sig_selection_changed), prefs); - /* preview GtkHTML widget */ - widget = glade_xml_get_widget (gui, "scrolled-sig"); - prefs->sig_preview = (GtkHTML *) gtk_html_new (); - g_signal_connect ( - prefs->sig_preview, "url_requested", - G_CALLBACK (url_requested), NULL); - gtk_widget_show (GTK_WIDGET (prefs->sig_preview)); - gtk_container_add ( - GTK_CONTAINER (widget), - GTK_WIDGET (prefs->sig_preview)); + container = glade_xml_get_widget (gui, "scrolled-sig"); + widget = e_signature_preview_new (); + gtk_container_add (GTK_CONTAINER (container), widget); + gtk_widget_show (widget); + + e_binding_new_with_negation ( + G_OBJECT (shell_settings), "disable-command-line", + G_OBJECT (widget), "allow-scripts"); + + e_binding_new ( + G_OBJECT (signature_tree_view), "selected", + G_OBJECT (widget), "signature"); /* get our toplevel widget */ target = em_config_target_new_prefs (ec, client); diff --git a/mail/mail-config.c b/mail/mail-config.c index a7e8bb908c..3c39791dfa 100644 --- a/mail/mail-config.c +++ b/mail/mail-config.c @@ -39,10 +39,6 @@ #include #include -#ifndef G_OS_WIN32 -#include -#endif - #include #include @@ -983,125 +979,3 @@ mail_config_get_lookup_book_local_only (void) return config->book_lookup_local_only; } - -char * -mail_config_signature_run_script (const char *script) -{ -#ifndef G_OS_WIN32 - int result, status; - int in_fds[2]; - pid_t pid; - - if (config == NULL) - mail_config_init (); - - if (config->scripts_disabled) - return NULL; - - if (pipe (in_fds) == -1) { - g_warning ("Failed to create pipe to '%s': %s", script, g_strerror (errno)); - return NULL; - } - - if (!(pid = fork ())) { - /* child process */ - int maxfd, i; - - 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 (i = 3; i < maxfd; i++) { - if (i != STDIN_FILENO && i != STDOUT_FILENO && i != STDERR_FILENO) - fcntl (i, F_SETFD, FD_CLOEXEC); - } - - execlp("/bin/sh", "/bin/sh", "-c", script, NULL); - g_warning ("Could not execute %s: %s\n", script, g_strerror (errno)); - _exit (255); - } else if (pid < 0) { - g_warning ("Failed to create create child process '%s': %s", script, g_strerror (errno)); - close (in_fds [0]); - close (in_fds [1]); - return NULL; - } else { - CamelStreamFilter *filtered_stream; - CamelStreamMem *memstream; - CamelMimeFilter *charenc; - CamelStream *stream; - GByteArray *buffer; - char *charset; - char *content; - - /* parent process */ - close (in_fds[1]); - - stream = camel_stream_fs_new_with_fd (in_fds[0]); - - memstream = (CamelStreamMem *) camel_stream_mem_new (); - buffer = g_byte_array_new (); - camel_stream_mem_set_byte_array (memstream, buffer); - - camel_stream_write_to_stream (stream, (CamelStream *) memstream); - camel_object_unref (stream); - - /* signature scripts are supposed to generate UTF-8 content, but because users - are known to not ever 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 - preferred charset. */ - if (!g_utf8_validate ((char *)buffer->data, buffer->len, NULL)) { - stream = (CamelStream *) memstream; - memstream = (CamelStreamMem *) camel_stream_mem_new (); - camel_stream_mem_set_byte_array (memstream, g_byte_array_new ()); - - filtered_stream = camel_stream_filter_new_with_stream (stream); - camel_object_unref (stream); - - charset = gconf_client_get_string (config->gconf, "/apps/evolution/mail/composer/charset", NULL); - if (charset && *charset) { - if ((charenc = (CamelMimeFilter *) camel_mime_filter_charset_new_convert (charset, "utf-8"))) { - camel_stream_filter_add (filtered_stream, charenc); - camel_object_unref (charenc); - } - } - g_free (charset); - - camel_stream_write_to_stream ((CamelStream *) filtered_stream, (CamelStream *) memstream); - camel_object_unref (filtered_stream); - g_byte_array_free (buffer, TRUE); - - buffer = memstream->buffer; - } - - camel_object_unref (memstream); - - g_byte_array_append (buffer, (const unsigned char *)"", 1); - content = (char *)buffer->data; - g_byte_array_free (buffer, FALSE); - - /* 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; - } -#else - return NULL; -#endif -} diff --git a/mail/mail-config.h b/mail/mail-config.h index ecbdb198ea..6c4683113f 100644 --- a/mail/mail-config.h +++ b/mail/mail-config.h @@ -110,10 +110,6 @@ gboolean mail_config_get_enable_magic_spacebar (void); struct _EAccountService *mail_config_get_default_transport (void); -/* signatures */ -char *mail_config_signature_run_script (const char *script); - - /* uri's got changed by the store, etc */ void mail_config_uri_renamed (GCompareFunc uri_cmp, const char *old, const char *new); void mail_config_uri_deleted (GCompareFunc uri_cmp, const char *uri); diff --git a/widgets/misc/Makefile.am b/widgets/misc/Makefile.am index a1d555085b..589bd1083e 100644 --- a/widgets/misc/Makefile.am +++ b/widgets/misc/Makefile.am @@ -80,6 +80,7 @@ widgetsinclude_HEADERS = \ e-signature-combo-box.h \ e-signature-editor.h \ e-signature-manager.h \ + e-signature-preview.h \ e-signature-script-dialog.h \ e-signature-tree-view.h \ e-unicode.h \ @@ -131,6 +132,7 @@ libemiscwidgets_la_SOURCES = \ e-signature-combo-box.c \ e-signature-editor.c \ e-signature-manager.c \ + e-signature-preview.c \ e-signature-script-dialog.c \ e-signature-tree-view.c \ e-unicode.c \ diff --git a/widgets/misc/e-signature-preview.c b/widgets/misc/e-signature-preview.c new file mode 100644 index 0000000000..d618e05daa --- /dev/null +++ b/widgets/misc/e-signature-preview.c @@ -0,0 +1,344 @@ +/* + * e-signature-preview.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 + * + * + * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com) + * + */ + +#include "e-signature-preview.h" + +#include +#include +#include +#include +#include "e-util/e-signature-utils.h" + +#define E_SIGNATURE_PREVIEW_GET_PRIVATE(obj) \ + (G_TYPE_INSTANCE_GET_PRIVATE \ + ((obj), E_TYPE_SIGNATURE_PREVIEW, ESignaturePreviewPrivate)) + +enum { + PROP_0, + PROP_ALLOW_SCRIPTS, + PROP_SIGNATURE +}; + +enum { + REFRESH, + LAST_SIGNAL +}; + +struct _ESignaturePreviewPrivate { + ESignature *signature; + guint allow_scripts : 1; +}; + +static gpointer parent_class; +static guint signals[LAST_SIGNAL]; + +static void +signature_preview_set_property (GObject *object, + guint property_id, + const GValue *value, + GParamSpec *pspec) +{ + switch (property_id) { + case PROP_ALLOW_SCRIPTS: + e_signature_preview_set_allow_scripts ( + E_SIGNATURE_PREVIEW (object), + g_value_get_boolean (value)); + return; + + case PROP_SIGNATURE: + e_signature_preview_set_signature ( + E_SIGNATURE_PREVIEW (object), + g_value_get_object (value)); + return; + } + + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); +} + +static void +signature_preview_get_property (GObject *object, + guint property_id, + GValue *value, + GParamSpec *pspec) +{ + switch (property_id) { + case PROP_ALLOW_SCRIPTS: + g_value_set_boolean ( + value, e_signature_preview_get_allow_scripts ( + E_SIGNATURE_PREVIEW (object))); + return; + + case PROP_SIGNATURE: + g_value_set_object ( + value, e_signature_preview_get_signature ( + E_SIGNATURE_PREVIEW (object))); + return; + } + + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); +} + +static void +signature_preview_dispose (GObject *object) +{ + ESignaturePreviewPrivate *priv; + + priv = E_SIGNATURE_PREVIEW_GET_PRIVATE (object); + + if (priv->signature != NULL) { + g_object_unref (priv->signature); + priv->signature = NULL; + } + + /* Chain up to parent's dispose() method. */ + G_OBJECT_CLASS (parent_class)->dispose (object); +} + +static void +signature_preview_url_requested (GtkHTML *html, + const gchar *url, + GtkHTMLStream *handle) +{ + GtkHTMLStreamStatus status; + gchar buffer[128]; + gchar *filename; + gssize size; + gint fd; + + /* FIXME Use GInputStream for this. */ + + if (g_str_has_prefix (url, "file:")) + filename = g_filename_from_uri (url, NULL, NULL); + else + filename = g_strdup (url); + fd = g_open (filename, O_RDONLY, 0); + g_free (filename); + + status = GTK_HTML_STREAM_OK; + if (fd != -1) { + while ((size = read (fd, buffer, sizeof (buffer)))) { + if (size == -1) { + status = GTK_HTML_STREAM_ERROR; + break; + } else + gtk_html_write (html, handle, buffer, size); + } + } else + status = GTK_HTML_STREAM_ERROR; + + gtk_html_end (html, handle, status); + + if (fd > 0) + close (fd); +} + +static void +signature_preview_refresh (ESignaturePreview *preview) +{ + GtkHTML *html; + ESignature *signature; + gchar *content = NULL; + gsize length; + + /* XXX We should show error messages in the preview. */ + + html = GTK_HTML (preview); + signature = e_signature_preview_get_signature (preview); + + if (signature == NULL) + goto clear; + + if (signature->script && !preview->priv->allow_scripts) + goto clear; + + if (signature->script) + content = e_run_signature_script (signature->filename); + else + content = e_read_signature_file (signature, FALSE, NULL); + + if (content == NULL || *content == '\0') + goto clear; + + length = strlen (content); + + if (signature->html) + gtk_html_load_from_string (html, content, length); + else { + GtkHTMLStream *stream; + + stream = gtk_html_begin_content ( + html, "text/html; charset=utf-8"); + gtk_html_write (html, stream, "
", 5);
+		if (length > 0)
+			gtk_html_write (html, stream, content, length);
+		gtk_html_write (html, stream, "
", 6); + gtk_html_end (html, stream, GTK_HTML_STREAM_OK); + } + + g_free (content); + return; + +clear: + gtk_html_load_from_string (html, " ", 1); + g_free (content); +} + +static void +signature_preview_class_init (ESignaturePreviewClass *class) +{ + GObjectClass *object_class; + GtkHTMLClass *html_class; + + parent_class = g_type_class_peek_parent (class); + g_type_class_add_private (class, sizeof (ESignaturePreviewPrivate)); + + object_class = G_OBJECT_CLASS (class); + object_class->set_property = signature_preview_set_property; + object_class->get_property = signature_preview_get_property; + object_class->dispose = signature_preview_dispose; + + html_class = GTK_HTML_CLASS (class); + html_class->url_requested = signature_preview_url_requested; + + class->refresh = signature_preview_refresh; + + g_object_class_install_property ( + object_class, + PROP_ALLOW_SCRIPTS, + g_param_spec_boolean ( + "allow-scripts", + "Allow Scripts", + NULL, + TRUE, + G_PARAM_READWRITE | + G_PARAM_CONSTRUCT)); + + g_object_class_install_property ( + object_class, + PROP_SIGNATURE, + g_param_spec_object ( + "signature", + "Signature", + NULL, + E_TYPE_SIGNATURE, + G_PARAM_READWRITE)); + + signals[REFRESH] = g_signal_new ( + "refresh", + G_TYPE_FROM_CLASS (class), + G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION, + G_STRUCT_OFFSET (ESignaturePreviewClass, refresh), + NULL, NULL, + g_cclosure_marshal_VOID__VOID, + G_TYPE_NONE, 0); +} + +static void +signature_preview_init (ESignaturePreview *preview) +{ + preview->priv = E_SIGNATURE_PREVIEW_GET_PRIVATE (preview); +} + +GType +e_signature_preview_get_type (void) +{ + static GType type = 0; + + if (G_UNLIKELY (type == 0)) { + static const GTypeInfo type_info = { + sizeof (ESignaturePreviewClass), + (GBaseInitFunc) NULL, + (GBaseFinalizeFunc) NULL, + (GClassInitFunc) signature_preview_class_init, + (GClassFinalizeFunc) NULL, + NULL, /* class_data */ + sizeof (ESignaturePreview), + 0, /* n_preallocs */ + (GInstanceInitFunc) signature_preview_init, + NULL /* value_table */ + }; + + type = g_type_register_static ( + GTK_TYPE_HTML, "ESignaturePreview", &type_info, 0); + } + + return type; +} + +GtkWidget * +e_signature_preview_new (void) +{ + return g_object_new (E_TYPE_SIGNATURE_PREVIEW, NULL); +} + +void +e_signature_preview_refresh (ESignaturePreview *preview) +{ + g_return_if_fail (E_IS_SIGNATURE_PREVIEW (preview)); + + g_signal_emit (preview, signals[REFRESH], 0); +} + +gboolean +e_signature_preview_get_allow_scripts (ESignaturePreview *preview) +{ + g_return_val_if_fail (E_IS_SIGNATURE_PREVIEW (preview), FALSE); + + return preview->priv->allow_scripts; +} + +void +e_signature_preview_set_allow_scripts (ESignaturePreview *preview, + gboolean allow_scripts) +{ + g_return_if_fail (E_IS_SIGNATURE_PREVIEW (preview)); + + preview->priv->allow_scripts = allow_scripts; + g_object_notify (G_OBJECT (preview), "allow-scripts"); +} + +ESignature * +e_signature_preview_get_signature (ESignaturePreview *preview) +{ + g_return_val_if_fail (E_IS_SIGNATURE_PREVIEW (preview), NULL); + + return preview->priv->signature; +} + +void +e_signature_preview_set_signature (ESignaturePreview *preview, + ESignature *signature) +{ + g_return_if_fail (E_IS_SIGNATURE_PREVIEW (preview)); + + if (signature != NULL) { + g_return_if_fail (E_IS_SIGNATURE (signature)); + g_object_ref (signature); + } + + if (preview->priv->signature != NULL) + g_object_unref (preview->priv->signature); + + preview->priv->signature = signature; + g_object_notify (G_OBJECT (preview), "signature"); + + e_signature_preview_refresh (preview); +} diff --git a/widgets/misc/e-signature-preview.h b/widgets/misc/e-signature-preview.h new file mode 100644 index 0000000000..2cedcc1d2f --- /dev/null +++ b/widgets/misc/e-signature-preview.h @@ -0,0 +1,81 @@ +/* + * e-signature-preview.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 + * + * + * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com) + * + */ + +#ifndef E_SIGNATURE_PREVIEW_H +#define E_SIGNATURE_PREVIEW_H + +#include +#include + +/* Standard GObject macros */ +#define E_TYPE_SIGNATURE_PREVIEW \ + (e_signature_preview_get_type ()) +#define E_SIGNATURE_PREVIEW(obj) \ + (G_TYPE_CHECK_INSTANCE_CAST \ + ((obj), E_TYPE_SIGNATURE_PREVIEW, ESignaturePreview)) +#define E_SIGNATURE_PREVIEW_CLASS(cls) \ + (G_TYPE_CHECK_CLASS_CAST \ + ((cls), E_TYPE_SIGNATURE_PREVIEW, ESignaturePreviewClass)) +#define E_IS_SIGNATURE_PREVIEW(obj) \ + (G_TYPE_CHECK_INSTANCE_TYPE \ + ((obj), E_TYPE_SIGNATURE_PREVIEW)) +#define E_IS_SIGNATURE_PREVIEW_CLASS(cls) \ + (G_TYPE_CHECK_CLASS_TYPE \ + ((cls), E_TYPE_SIGNATURE_PREVIEW)) +#define E_SIGNATURE_PREVIEW_GET_CLASS(obj) \ + (G_TYPE_INSTANCE_GET_CLASS \ + ((obj), E_TYPE_SIGNATURE_PREVIEW, ESignaturePreview)) + +G_BEGIN_DECLS + +typedef struct _ESignaturePreview ESignaturePreview; +typedef struct _ESignaturePreviewClass ESignaturePreviewClass; +typedef struct _ESignaturePreviewPrivate ESignaturePreviewPrivate; + +struct _ESignaturePreview { + GtkHTML parent; + ESignaturePreviewPrivate *priv; +}; + +struct _ESignaturePreviewClass { + GtkHTMLClass parent_class; + + /* Signals */ + void (*refresh) (ESignaturePreview *preview); +}; + +GType e_signature_preview_get_type (void); +GtkWidget * e_signature_preview_new (void); +void e_signature_preview_refresh (ESignaturePreview *preview); +gboolean e_signature_preview_get_allow_scripts + (ESignaturePreview *preview); +void e_signature_preview_set_allow_scripts + (ESignaturePreview *preview, + gboolean allow_scripts); +ESignature * e_signature_preview_get_signature + (ESignaturePreview *preview); +void e_signature_preview_set_signature + (ESignaturePreview *preview, + ESignature *signature); + +G_END_DECLS + +#endif /* E_SIGNATURE_PREVIEW_H */ diff --git a/widgets/misc/e-signature-tree-view.c b/widgets/misc/e-signature-tree-view.c index ef1cc36b14..1f6d75b5b5 100644 --- a/widgets/misc/e-signature-tree-view.c +++ b/widgets/misc/e-signature-tree-view.c @@ -32,6 +32,7 @@ enum { enum { PROP_0, + PROP_SELECTED, PROP_SIGNATURE_LIST }; @@ -46,7 +47,7 @@ struct _ESignatureTreeViewPrivate { }; static gpointer parent_class; -static guint signal_ids[LAST_SIGNAL]; +static guint signals[LAST_SIGNAL]; static void signature_tree_view_refresh_cb (ESignatureList *signature_list, @@ -117,7 +118,13 @@ skip: if (signature != NULL) g_object_unref (signature); - g_signal_emit (tree_view, signal_ids[REFRESHED], 0); + g_signal_emit (tree_view, signals[REFRESHED], 0); +} + +static void +signature_tree_view_selection_changed_cb (ESignatureTreeView *tree_view) +{ + g_object_notify (G_OBJECT (tree_view), "selected"); } static GObject * @@ -154,6 +161,12 @@ signature_tree_view_set_property (GObject *object, GParamSpec *pspec) { switch (property_id) { + case PROP_SELECTED: + e_signature_tree_view_set_selected ( + E_SIGNATURE_TREE_VIEW (object), + g_value_get_object (value)); + return; + case PROP_SIGNATURE_LIST: e_signature_tree_view_set_signature_list ( E_SIGNATURE_TREE_VIEW (object), @@ -171,6 +184,13 @@ signature_tree_view_get_property (GObject *object, GParamSpec *pspec) { switch (property_id) { + case PROP_SELECTED: + g_value_set_object ( + value, + e_signature_tree_view_get_selected ( + E_SIGNATURE_TREE_VIEW (object))); + return; + case PROP_SIGNATURE_LIST: g_value_set_object ( value, @@ -231,6 +251,16 @@ signature_tree_view_class_init (ESignatureTreeViewClass *class) object_class->dispose = signature_tree_view_dispose; object_class->finalize = signature_tree_view_finalize; + g_object_class_install_property ( + object_class, + PROP_SELECTED, + g_param_spec_object ( + "selected", + "Selected Signature", + NULL, + E_TYPE_SIGNATURE, + G_PARAM_READWRITE)); + g_object_class_install_property ( object_class, PROP_SIGNATURE_LIST, @@ -242,7 +272,7 @@ signature_tree_view_class_init (ESignatureTreeViewClass *class) G_PARAM_READWRITE | G_PARAM_CONSTRUCT)); - signal_ids[REFRESHED] = g_signal_new ( + signals[REFRESHED] = g_signal_new ( "refreshed", G_TYPE_FROM_CLASS (class), G_SIGNAL_RUN_LAST, @@ -255,6 +285,7 @@ static void signature_tree_view_init (ESignatureTreeView *tree_view) { GHashTable *index; + GtkTreeSelection *selection; /* Reverse-lookup index */ index = g_hash_table_new_full ( @@ -264,6 +295,13 @@ signature_tree_view_init (ESignatureTreeView *tree_view) tree_view->priv = E_SIGNATURE_TREE_VIEW_GET_PRIVATE (tree_view); tree_view->priv->index = index; + + selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (tree_view)); + + g_signal_connect_swapped ( + selection, "changed", + G_CALLBACK (signature_tree_view_selection_changed_cb), + tree_view); } GType @@ -401,5 +439,7 @@ e_signature_tree_view_set_selected (ESignatureTreeView *tree_view, gtk_tree_selection_select_path (selection, path); gtk_tree_path_free (path); + g_object_notify (G_OBJECT (tree_view), "selected"); + return TRUE; } -- cgit