diff options
49 files changed, 1708 insertions, 1458 deletions
diff --git a/Makefile.am b/Makefile.am index f79d67fbd8..53b463b10c 100644 --- a/Makefile.am +++ b/Makefile.am @@ -53,8 +53,8 @@ SUBDIRS = \ shell \ $(SMIME_SUBDIR) \ em-format \ - composer \ addressbook \ + composer \ mail \ calendar \ art \ diff --git a/addressbook/gui/merging/Makefile.am b/addressbook/gui/merging/Makefile.am index fd13c9779e..e399c19747 100644 --- a/addressbook/gui/merging/Makefile.am +++ b/addressbook/gui/merging/Makefile.am @@ -2,6 +2,7 @@ AM_CPPFLAGS = \ -DG_LOG_DOMAIN=\"eab-contact-merging\" \ -DEVOLUTION_GLADEDIR=\""$(gladedir)"\" \ -I$(top_srcdir) \ + -I$(top_srcdir)/widgets \ -I$(top_srcdir)/addressbook \ $(EVOLUTION_ADDRESSBOOK_CFLAGS) diff --git a/addressbook/gui/widgets/Makefile.am b/addressbook/gui/widgets/Makefile.am index 58d1e1b1d1..b642fde5c2 100644 --- a/addressbook/gui/widgets/Makefile.am +++ b/addressbook/gui/widgets/Makefile.am @@ -1,7 +1,7 @@ ruledir = $(privdatadir) rule_DATA = addresstypes.xml -AM_CPPFLAGS = \ +AM_CPPFLAGS = \ -DG_LOG_DOMAIN=\"eab-widgets\" \ -DEVOLUTION_ETSPECDIR=\""$(etspecdir)"\" \ -DEVOLUTION_GALVIEWSDIR=\""$(viewsdir)"\" \ diff --git a/addressbook/gui/widgets/eab-contact-display.c b/addressbook/gui/widgets/eab-contact-display.c index d47b3e1866..0ade284323 100644 --- a/addressbook/gui/widgets/eab-contact-display.c +++ b/addressbook/gui/widgets/eab-contact-display.c @@ -240,71 +240,6 @@ contact_display_selection_clear_event (EABContactDisplay *display, } static void -contact_display_on_url_requested (GtkHTML *html, - const gchar *url, - GtkHTMLStream *handle, - EABContactDisplay *display) -{ - if (!strcmp (url, "internal-contact-photo:")) { - EContactPhoto *photo; - - photo = e_contact_get (display->priv->contact, E_CONTACT_PHOTO); - if (!photo) - photo = e_contact_get (display->priv->contact, E_CONTACT_LOGO); - - gtk_html_stream_write (handle, (gchar *)photo->data.inlined.data, photo->data.inlined.length); - - gtk_html_end (html, handle, GTK_HTML_STREAM_OK); - - e_contact_photo_free (photo); - } - else if (!strncmp (url, "evo-icon:", strlen ("evo-icon:"))) { - gchar *data; - gsize data_length; - gchar *filename; - - filename = e_icon_factory_get_icon_filename (url + strlen ("evo-icon:"), GTK_ICON_SIZE_MENU); - if (g_file_get_contents (filename, &data, &data_length, NULL)) { - gtk_html_stream_write (handle, data, data_length); - g_free (data); - } - - gtk_html_stream_close (handle, GTK_HTML_STREAM_OK); - - g_free (filename); - } -} - -static void -contact_display_on_link_clicked (GtkHTML *html, - const gchar *uri, - EABContactDisplay *display) -{ -#ifdef HANDLE_MAILTO_INTERNALLY - if (!strncmp (uri, "internal-mailto:", strlen ("internal-mailto:"))) { - EDestination *destination; - EContact *contact; - gint email_num; - - email_num = atoi (uri + strlen ("internal-mailto:")); - if (email_num == -1) - return; - - destination = e_destination_new (); - contact = eab_contact_display_get_contact (display); - e_destination_set_contact (destination, contact, email_num); - g_signal_emit (display, signals[SEND_MESSAGE], 0, destination); - g_object_unref (destination); - - return; - } -#endif - - /* FIXME Pass a parent window. */ - e_show_uri (NULL, uri); -} - -static void render_name_value (GtkHTMLStream *html_stream, const gchar *label, const gchar *str, const gchar *icon, guint html_flags) { gchar *value = e_text_to_html (str, html_flags); @@ -1033,9 +968,89 @@ contact_display_finalize (GObject *object) } static void +contact_display_url_requested (GtkHTML *html, + const gchar *url, + GtkHTMLStream *handle) +{ + EABContactDisplayPrivate *priv; + + priv = EAB_CONTACT_DISPLAY_GET_PRIVATE (html); + + if (strcmp (url, "internal-contact-photo:") == 0) { + EContactPhoto *photo; + + photo = e_contact_get (priv->contact, E_CONTACT_PHOTO); + if (!photo) + photo = e_contact_get (priv->contact, E_CONTACT_LOGO); + + gtk_html_stream_write (handle, (gchar *)photo->data.inlined.data, photo->data.inlined.length); + + gtk_html_end (html, handle, GTK_HTML_STREAM_OK); + + e_contact_photo_free (photo); + + return; + } + + if (strncmp (url, "evo-icon:", strlen ("evo-icon:")) == 0) { + gchar *data; + gsize data_length; + gchar *filename; + + filename = e_icon_factory_get_icon_filename (url + strlen ("evo-icon:"), GTK_ICON_SIZE_MENU); + if (g_file_get_contents (filename, &data, &data_length, NULL)) { + gtk_html_stream_write (handle, data, data_length); + g_free (data); + } + + gtk_html_stream_close (handle, GTK_HTML_STREAM_OK); + + g_free (filename); + + return; + } + + /* Chain up to parent's url_requested() method. */ + GTK_HTML_CLASS (parent_class)->url_requested (html, url, handle); +} + +static void +contact_display_link_clicked (GtkHTML *html, + const gchar *uri) +{ + EABContactDisplay *display; + + display = EAB_CONTACT_DISPLAY (html); + +#ifdef HANDLE_MAILTO_INTERNALLY + if (!strncmp (uri, "internal-mailto:", strlen ("internal-mailto:"))) { + EDestination *destination; + EContact *contact; + gint email_num; + + email_num = atoi (uri + strlen ("internal-mailto:")); + if (email_num == -1) + return; + + destination = e_destination_new (); + contact = eab_contact_display_get_contact (display); + e_destination_set_contact (destination, contact, email_num); + g_signal_emit (display, signals[SEND_MESSAGE], 0, destination); + g_object_unref (destination); + + return; + } +#endif + + /* Chain up to parent's link_clicked() method. */ + GTK_HTML_CLASS (parent_class)->link_clicked (html, uri); +} + +static void eab_contact_display_class_init (EABContactDisplayClass *class) { GObjectClass *object_class; + GtkHTMLClass *html_class; parent_class = g_type_class_peek_parent (class); g_type_class_add_private (class, sizeof (EABContactDisplayPrivate)); @@ -1046,6 +1061,10 @@ eab_contact_display_class_init (EABContactDisplayClass *class) object_class->dispose = contact_display_dispose; object_class->finalize = contact_display_finalize; + html_class = GTK_HTML_CLASS (class); + html_class->url_requested = contact_display_url_requested; + html_class->link_clicked = contact_display_link_clicked; + g_object_class_install_property ( object_class, PROP_CONTACT, @@ -1123,12 +1142,6 @@ eab_contact_display_init (EABContactDisplay *display) gtk_html_set_default_content_type (html, "text/html; charset=utf-8"); g_signal_connect ( - display, "url-requested", - G_CALLBACK (contact_display_on_url_requested), display); - g_signal_connect ( - display, "link-clicked", - G_CALLBACK (contact_display_on_link_clicked), display); - g_signal_connect ( display, "button-press-event", G_CALLBACK (contact_display_button_press_event), display); @@ -1170,7 +1183,7 @@ eab_contact_display_get_type (void) }; type = g_type_register_static ( - GTK_TYPE_HTML, "EABContactDisplay", &type_info, 0); + E_TYPE_WEB_VIEW, "EABContactDisplay", &type_info, 0); } return type; diff --git a/addressbook/gui/widgets/eab-contact-display.h b/addressbook/gui/widgets/eab-contact-display.h index 5a6902fc20..7b9707e0af 100644 --- a/addressbook/gui/widgets/eab-contact-display.h +++ b/addressbook/gui/widgets/eab-contact-display.h @@ -23,9 +23,9 @@ #ifndef EAB_CONTACT_DISPLAY_H #define EAB_CONTACT_DISPLAY_H -#include <gtkhtml/gtkhtml.h> #include <libebook/e-contact.h> #include <libebook/e-destination.h> +#include <misc/e-web-view.h> /* Standard GObject macros */ #define EAB_TYPE_CONTACT_DISPLAY \ @@ -58,12 +58,12 @@ typedef enum { } EABContactDisplayMode; struct _EABContactDisplay { - GtkHTML parent; + EWebView parent; EABContactDisplayPrivate *priv; }; struct _EABContactDisplayClass { - GtkHTMLClass parent_class; + EWebViewClass parent_class; /* Signals */ void (*send_message) (EABContactDisplay *display, diff --git a/calendar/Makefile.am b/calendar/Makefile.am index 87057a4d3a..ecdd2d2cc6 100644 --- a/calendar/Makefile.am +++ b/calendar/Makefile.am @@ -4,7 +4,7 @@ else CONDUIT_DIR = endif -SUBDIRS = idl common importers gui $(CONDUIT_DIR) +SUBDIRS = common importers gui $(CONDUIT_DIR) error_DATA = calendar.error errordir = $(privdatadir)/errors diff --git a/calendar/gui/Makefile.am b/calendar/gui/Makefile.am index ede213e1ff..f05a038624 100644 --- a/calendar/gui/Makefile.am +++ b/calendar/gui/Makefile.am @@ -2,7 +2,9 @@ if OS_WIN32 WIN32_BOOTSTRAP_LIBS = $(top_builddir)/win32/libevolution-mail.la endif -SUBDIRS = alarm-notify dialogs +# KILL-BONOBO: Temporarily disabled alarm-notify +#SUBDIRS = alarm-notify dialogs +SUBDIRS = dialogs privsolib_LTLIBRARIES = libevolution-calendar.la diff --git a/calendar/gui/alarm-notify/Makefile.am b/calendar/gui/alarm-notify/Makefile.am index ea1c36e0d9..d8a68387fe 100644 --- a/calendar/gui/alarm-notify/Makefile.am +++ b/calendar/gui/alarm-notify/Makefile.am @@ -1,19 +1,3 @@ -CORBA_GENERATED_H = \ - evolution-calendar.h -CORBA_GENERATED_C = \ - evolution-calendar-common.c \ - evolution-calendar-skels.c \ - evolution-calendar-stubs.c -CORBA_GENERATED = $(CORBA_GENERATED_C) $(CORBA_GENERATED_H) - -idls = $(top_srcdir)/calendar/idl/evolution-calendar.idl -idl_flags = $(IDL_INCLUDES) - -$(CORBA_GENERATED_H): $(idls) - $(ORBIT_IDL) $(idl_flags) $(top_srcdir)/calendar/idl/evolution-calendar.idl -$(CORBA_GENERATED_C): $(CORBA_GENERATED_H) - - privlibexec_PROGRAMS = evolution-alarm-notify @@ -59,19 +43,6 @@ if OS_WIN32 evolution_alarm_notify_LDFLAGS = -mwindows endif -server_in_files = GNOME_Evolution_Calendar_AlarmNotify.server.in.in -server_DATA = $(server_in_files:.server.in.in=.server) -@EVO_SERVER_RULE@ -@INTLTOOL_SERVER_RULE@ - -EXTRA_DIST = \ - $(server_in_files) \ - $(glade_DATA) - -BUILT_SOURCES = $(CORBA_GENERATED) $(server_DATA) -CLEANFILES = $(BUILT_SOURCES) - -dist-hook: - cd $(distdir); rm -f $(BUILT_SOURCES) +EXTRA_DIST = $(glade_DATA) -include $(top_srcdir)/git.mk diff --git a/calendar/gui/e-cal-component-preview.c b/calendar/gui/e-cal-component-preview.c index 633eb5678e..b0ba329286 100644 --- a/calendar/gui/e-cal-component-preview.c +++ b/calendar/gui/e-cal-component-preview.c @@ -271,83 +271,10 @@ cal_component_preview_write_html (GtkHTMLStream *stream, } static void -cal_component_preview_url_requested (GtkHTML *html, - const gchar *url, - GtkHTMLStream *html_stream) -{ - GFile *file; - GFileInputStream *input_stream; - gchar buffer[4096]; - gssize bytes_read; - GError *error = NULL; - - file = g_file_new_for_uri (url); - - /* XXX We only handle native files, which I guess minimizes - * the damage from doing blocking reads here. Annoying - * that GtkHTML does not handle this itself. */ - if (!g_file_is_native (file)) - goto exit; - - input_stream = g_file_read (file, NULL, &error); - - if (error != NULL) - goto fail; - - do { - bytes_read = g_input_stream_read ( - G_INPUT_STREAM (input_stream), - buffer, sizeof (buffer), NULL, &error); - - if (bytes_read > 0) - gtk_html_stream_write ( - html_stream, buffer, bytes_read); - - } while (bytes_read > 0); - - if (error != NULL) - goto fail; - - gtk_html_stream_close (html_stream, GTK_HTML_STREAM_OK); - - goto exit; - -fail: - g_warning ("%s", error->message); - g_error_free (error); - - gtk_html_stream_close (html_stream, GTK_HTML_STREAM_ERROR); - -exit: - if (input_stream != NULL) - g_object_unref (input_stream); - - g_object_unref (file); -} - -static void -cal_component_preview_link_clicked (GtkHTML *html, - const gchar *uri) -{ - gpointer parent; - - parent = gtk_widget_get_toplevel (GTK_WIDGET (html)); - parent = GTK_WIDGET_TOPLEVEL (parent) ? parent : NULL; - - e_show_uri (parent, uri); -} - -static void cal_component_preview_class_init (ECalComponentPreviewClass *class) { - GtkHTMLClass *gtkhtml_class; - parent_class = g_type_class_peek_parent (class); g_type_class_add_private (class, sizeof (ECalComponentPreviewPrivate)); - - gtkhtml_class = GTK_HTML_CLASS (class); - gtkhtml_class->url_requested = cal_component_preview_url_requested; - gtkhtml_class->link_clicked = cal_component_preview_link_clicked; } static void @@ -384,7 +311,8 @@ e_cal_component_preview_get_type (void) }; type = g_type_register_static ( - GTK_TYPE_HTML, "ECalComponentPreview", &type_info, 0); + E_TYPE_WEB_VIEW, "ECalComponentPreview", + &type_info, 0); } return type; @@ -429,11 +357,3 @@ e_cal_component_preview_display (ECalComponentPreview *preview, stream, ecal, comp, preview->priv->zone); gtk_html_stream_close (stream, GTK_HTML_STREAM_OK); } - -void -e_cal_component_preview_clear (ECalComponentPreview *preview) -{ - g_return_if_fail (E_IS_CAL_COMPONENT_PREVIEW (preview)); - - gtk_html_load_empty (GTK_HTML (preview)); -} diff --git a/calendar/gui/e-cal-component-preview.h b/calendar/gui/e-cal-component-preview.h index 8b2b0acd18..78567f06ec 100644 --- a/calendar/gui/e-cal-component-preview.h +++ b/calendar/gui/e-cal-component-preview.h @@ -26,7 +26,7 @@ #include <gtk/gtk.h> #include <libecal/e-cal.h> -#include <gtkhtml/gtkhtml.h> +#include <misc/e-web-view.h> /* Standard GObject macros */ #define E_TYPE_CAL_COMPONENT_PREVIEW \ @@ -54,12 +54,12 @@ typedef struct _ECalComponentPreviewClass ECalComponentPreviewClass; typedef struct _ECalComponentPreviewPrivate ECalComponentPreviewPrivate; struct _ECalComponentPreview { - GtkHTML parent; + EWebView parent; ECalComponentPreviewPrivate *priv; }; struct _ECalComponentPreviewClass { - GtkHTMLClass parent_class; + EWebViewClass parent_class; /* Notification signals */ void (* selection_changed) (ECalComponentPreview *preview, gint n_selected); @@ -75,7 +75,6 @@ void e_cal_component_preview_set_default_timezone void e_cal_component_preview_display (ECalComponentPreview *preview, ECal *ecal, ECalComponent *comp); -void e_cal_component_preview_clear (ECalComponentPreview *preview); G_END_DECLS diff --git a/calendar/idl/Makefile.am b/calendar/idl/Makefile.am deleted file mode 100644 index 1d393a8f9d..0000000000 --- a/calendar/idl/Makefile.am +++ /dev/null @@ -1,7 +0,0 @@ -idl_DATA = \ - evolution-calendar.idl - -EXTRA_DIST = \ - $(idl_DATA) - --include $(top_srcdir)/git.mk diff --git a/calendar/idl/evolution-calendar.idl b/calendar/idl/evolution-calendar.idl deleted file mode 100644 index 48f7281ab3..0000000000 --- a/calendar/idl/evolution-calendar.idl +++ /dev/null @@ -1,52 +0,0 @@ -/* Evolution calendar interface - * - * Copyright (C) 2000 Eskil Heyn Olsen - * Copyright (C) 2000 Ximian, Inc. - * Copyright (C) 2000 Ximian, Inc. - * - * Authors: Eskil Heyn Olsen <deity@eskil.dk> - * Federico Mena-Quintero <federico@ximian.com> - */ - -#ifndef _EVOLUTION_CALENDAR_IDL_ -#define _EVOLUTION_CALENDAR_IDL_ - -#include <Bonobo.idl> -#include <Evolution-DataServer-Calendar.idl> - -module GNOME { -module Evolution { - -module Calendar { - /* Factory to centralize calendar component editor dialogs */ - interface CompEditorFactory : Bonobo::Unknown { - exception InvalidURI {}; - exception BackendContactError {}; - exception UnsupportedType {}; - - typedef long CompEditorMode; - const CompEditorMode EDITOR_MODE_EVENT = 1 << 0; - const CompEditorMode EDITOR_MODE_ALLDAY_EVENT = 1 << 1; - const CompEditorMode EDITOR_MODE_MEETING = 1 << 2; - const CompEditorMode EDITOR_MODE_TODO = 1 << 3; - - /* Loads a calendar and opens an editor for the specified object */ - /* FIXME Its nasty to use CompEditorMode to pass event/todo source type - but it saves adding yet another corba type - only MODE_EVENT or - MODE_TODO should be passed here */ - void editExisting (in string uri, in CalObjUID uid, in CompEditorMode mode) - raises (InvalidURI, BackendContactError); - - /* Loads a calendar and creates a new component of the specified type */ - void editNew (in string uri, in CompEditorMode mode) - raises (InvalidURI, BackendContactError, UnsupportedType); - }; - - interface AlarmNotify : Bonobo::Unknown { - }; -}; - -}; -}; - -#endif diff --git a/configure.ac b/configure.ac index 1f709dc44e..1ac2923ce6 100644 --- a/configure.ac +++ b/configure.ac @@ -52,7 +52,6 @@ m4_define([gtk_minimum_version], [2.16.0]) m4_define([eds_minimum_version], [evo_version]) m4_define([gnome_icon_theme_minimum_version], [2.19.91]) m4_define([gnome_desktop_minimum_version], [2.26.0]) -m4_define([libbonobo_minimum_version], [2.20.3]) m4_define([libgtkhtml_minimum_version], [3.27.90]) m4_define([gconf_minimum_version], [2.0.0]) dnl XXX Just a Guess m4_define([libglade_minimum_version], [2.0.0]) dnl XXX Just a Guess @@ -238,7 +237,6 @@ PKG_CHECK_MODULES([GNOME_PLATFORM], [glib-2.0 >= glib_minimum_version gtk+-2.0 >= gtk_minimum_version gconf-2.0 >= gconf_minimum_version - libbonobo-2.0 >= libbonobo_minimum_version libglade-2.0 >= libglade_minimum_version libgnomecanvas-2.0 >= libgnomecanvas_minimum_version libgnomeui-2.0 >= libgnomeui_minimum_version @@ -1383,11 +1381,6 @@ dnl Orbit / Bonobo dnl ************************* AM_PATH_ORBIT2(2.9.8) -AC_MSG_CHECKING([for CORBA include paths]) -IDL_INCLUDES="-I "`${PKG_CONFIG} --variable=idldir libbonobo-2.0`" -I "`${PKG_CONFIG} --variable=idldir bonobo-activation-2.0`" -I "`${PKG_CONFIG} --variable=idldir evolution-data-server-1.2` -AC_MSG_RESULT([$IDL_INCLUDES]) -AC_SUBST(IDL_INCLUDES) - dnl ***************************************************************** dnl Utility macro to set compiler flags for a specific lib. dnl EVO_SET_COMPILE_FLAGS(VAR-PREFIX, DEPS, EXTRA-CFLAGS, EXTRA-LIBS) @@ -1611,7 +1604,7 @@ fi dnl ********** dnl Mail Flags dnl ********** -EVO_SET_COMPILE_FLAGS(EVOLUTION_MAIL, camel-provider-$EDS_PACKAGE libgnomeui-2.0 libglade-2.0 gio-2.0 gconf-2.0 gobject-2.0 libgtkhtml-$GTKHTML_PACKAGE gtkhtml-editor bonobo-activation-2.0 $mozilla_nss libebook-$EDS_PACKAGE libedataserverui-$EDS_PACKAGE unique-1.0) +EVO_SET_COMPILE_FLAGS(EVOLUTION_MAIL, camel-provider-$EDS_PACKAGE libgnomeui-2.0 libglade-2.0 gio-2.0 gconf-2.0 gobject-2.0 libgtkhtml-$GTKHTML_PACKAGE gtkhtml-editor $mozilla_nss libebook-$EDS_PACKAGE libedataserverui-$EDS_PACKAGE unique-1.0) AC_SUBST(EVOLUTION_MAIL_CFLAGS) AC_SUBST(EVOLUTION_MAIL_LIBS) @@ -1672,12 +1665,6 @@ AC_SUBST(componentdir) moduledir="$privlibdir/modules" AC_SUBST(moduledir) -idldir='${datadir}'/idl/evolution-$BASE_VERSION -AC_SUBST(idldir) - -serverdir="$libdir/bonobo/servers" -AC_SUBST(serverdir) - evolutionuidir="$privdatadir/ui" AC_SUBST(evolutionuidir) @@ -1999,7 +1986,6 @@ widgets/table/Makefile calendar/Makefile calendar/importers/Makefile calendar/common/Makefile -calendar/idl/Makefile calendar/conduits/Makefile calendar/conduits/common/Makefile calendar/conduits/todo/Makefile diff --git a/e-util/e-marshal.list b/e-util/e-marshal.list index d6a3f0cb55..c4426d46d7 100644 --- a/e-util/e-marshal.list +++ b/e-util/e-marshal.list @@ -1,4 +1,4 @@ -BOOLEAN:BOXED,POINTER,POINTER +BOOLEAN:BOXED,STRING BOOLEAN:INT,INT,OBJECT,INT,INT,UINT BOOLEAN:INT,POINTER,INT,OBJECT,INT,INT,UINT BOOLEAN:NONE diff --git a/e-util/e-plugin.c b/e-util/e-plugin.c index 5d77decfd9..49a15da651 100644 --- a/e-util/e-plugin.c +++ b/e-util/e-plugin.c @@ -31,6 +31,7 @@ #include "e-plugin.h" #include "e-util-private.h" +#include "e-util.h" /* plugin debug */ #define pd(x) @@ -487,79 +488,50 @@ e_plugin_add_load_path(const gchar *path) } static void -plugin_load_subclasses (void) +plugin_load_subclass (GType type, + GHashTable *hash_table) { - GType *children; - guint n_children, ii; - - ep_types = g_hash_table_new (g_str_hash, g_str_equal); - eph_types = g_hash_table_new (g_str_hash, g_str_equal); - ep_plugins = g_hash_table_new (g_str_hash, g_str_equal); - - /* Load EPlugin subclasses. */ - - children = g_type_children (E_TYPE_PLUGIN, &n_children); - - for (ii = 0; ii < n_children; ii++) { - EPluginClass *class; - - class = g_type_class_ref (children[ii]); - g_hash_table_insert (ep_types, (gpointer) class->type, class); - } + EPluginClass *class; - g_free (children); + class = g_type_class_ref (type); + g_hash_table_insert (hash_table, (gpointer) class->type, class); } static void -plugin_load_hook_subclasses (GType parent_type) +plugin_hook_load_subclass (GType type, + GHashTable *hash_table) { - GType *children; - guint n_children, ii; - - children = g_type_children (parent_type, &n_children); - - for (ii = 0; ii < n_children; ii++) { - EPluginHookClass *hook_class; - EPluginHookClass *dupe_class; - gpointer key; - - /* First load the child's children. */ - plugin_load_hook_subclasses (children[ii]); - - /* Skip abstract types. */ - if (G_TYPE_IS_ABSTRACT (children[ii])) - continue; - - hook_class = g_type_class_ref (children[ii]); - - /* Sanity check the hook class. */ - if (hook_class->id == NULL || *hook_class->id == '\0') { - g_warning ( - "%s has no hook ID, so skipping", - G_OBJECT_CLASS_NAME (hook_class)); - g_type_class_unref (hook_class); - continue; - } - - /* Check for class ID collisions. */ - dupe_class = g_hash_table_lookup (eph_types, hook_class->id); - if (dupe_class != NULL) { - g_warning ( - "%s and %s have the same hook " - "ID ('%s'), so skipping %s", - G_OBJECT_CLASS_NAME (dupe_class), - G_OBJECT_CLASS_NAME (hook_class), - hook_class->id, - G_OBJECT_CLASS_NAME (hook_class)); - g_type_class_unref (hook_class); - continue; - } + EPluginHookClass *hook_class; + EPluginHookClass *dupe_class; + gpointer key; + + hook_class = g_type_class_ref (type); + + /* Sanity check the hook class. */ + if (hook_class->id == NULL || *hook_class->id == '\0') { + g_warning ( + "%s has no hook ID, so skipping", + G_OBJECT_CLASS_NAME (hook_class)); + g_type_class_unref (hook_class); + return; + } - key = (gpointer) hook_class->id; - g_hash_table_insert (eph_types, key, hook_class); + /* Check for class ID collisions. */ + dupe_class = g_hash_table_lookup (hash_table, hook_class->id); + if (dupe_class != NULL) { + g_warning ( + "%s and %s have the same hook " + "ID ('%s'), so skipping %s", + G_OBJECT_CLASS_NAME (dupe_class), + G_OBJECT_CLASS_NAME (hook_class), + hook_class->id, + G_OBJECT_CLASS_NAME (hook_class)); + g_type_class_unref (hook_class); + return; } - g_free (children); + key = (gpointer) hook_class->id; + g_hash_table_insert (hash_table, key, hook_class); } /** @@ -580,11 +552,19 @@ e_plugin_load_plugins(void) if (eph_types != NULL) return 0; + ep_types = g_hash_table_new (g_str_hash, g_str_equal); + eph_types = g_hash_table_new (g_str_hash, g_str_equal); + ep_plugins = g_hash_table_new (g_str_hash, g_str_equal); + /* We require that all GTypes for EPlugin and EPluginHook * subclasses be registered prior to loading any plugins. * It greatly simplifies the loading process. */ - plugin_load_subclasses (); - plugin_load_hook_subclasses (E_TYPE_PLUGIN_HOOK); + e_type_traverse ( + E_TYPE_PLUGIN, (ETypeFunc) + plugin_load_subclass, ep_types); + e_type_traverse ( + E_TYPE_PLUGIN_HOOK, (ETypeFunc) + plugin_hook_load_subclass, eph_types); client = gconf_client_get_default (); ep_disabled = gconf_client_get_list ( diff --git a/e-util/e-util.c b/e-util/e-util.c index 57ec251c55..3c004e57cb 100644 --- a/e-util/e-util.c +++ b/e-util/e-util.c @@ -407,6 +407,47 @@ e_radio_action_get_current_action (GtkRadioAction *radio_action) } /** + * e_type_traverse: + * @parent_type: the root #GType to traverse from + * @func: the function to call for each visited #GType + * @user_data: user data to pass to the function + * + * Calls @func for all instantiable subtypes of @parent_type. + * + * This is often useful for extending functionality by way of #EModule. + * A module may register a subtype of @parent_type in its e_module_load() + * function. Then later on the application will call e_type_traverse() + * to instantiate all registered subtypes of @parent_type. + **/ +void +e_type_traverse (GType parent_type, + ETypeFunc func, + gpointer user_data) +{ + GType *children; + guint n_children, ii; + + g_return_if_fail (func != NULL); + + children = g_type_children (parent_type, &n_children); + + for (ii = 0; ii < n_children; ii++) { + GType type = children[ii]; + + /* Recurse over the child's children. */ + e_type_traverse (type, func, user_data); + + /* Skip abstract types. */ + if (G_TYPE_IS_ABSTRACT (type)) + continue; + + func (type, user_data); + } + + g_free (children); +} + +/** * e_str_without_underscores: * @s: the string to strip underscores from. * diff --git a/e-util/e-util.h b/e-util/e-util.h index 33bc940df7..1e2320914e 100644 --- a/e-util/e-util.h +++ b/e-util/e-util.h @@ -41,6 +41,8 @@ typedef enum { E_FOCUS_END } EFocus; +typedef void (*ETypeFunc) (GType type, gpointer user_data); + const gchar * e_get_user_data_dir (void); const gchar * e_get_accels_filename (void); void e_show_uri (GtkWindow *parent, @@ -59,6 +61,9 @@ void e_action_group_remove_all_actions (GtkActionGroup *action_group); GtkRadioAction *e_radio_action_get_current_action (GtkRadioAction *radio_action); +void e_type_traverse (GType parent_type, + ETypeFunc func, + gpointer user_data); gchar * e_str_without_underscores (const gchar *s); gint e_str_compare (gconstpointer x, diff --git a/evolution-shell.pc.in b/evolution-shell.pc.in index b94dd8512f..c9e4ade8c3 100644 --- a/evolution-shell.pc.in +++ b/evolution-shell.pc.in @@ -17,8 +17,6 @@ imagesdir=@imagesdir@ execversion=@BASE_VERSION@ -IDL_INCLUDES=-I ${idldir} @IDL_INCLUDES@ - Name: evolution-shell Description: libraries needed for Evolution shell components Version: @VERSION@ diff --git a/mail/e-mail-browser.c b/mail/e-mail-browser.c index ea860c016f..69199bfa1a 100644 --- a/mail/e-mail-browser.c +++ b/mail/e-mail-browser.c @@ -123,22 +123,20 @@ static GtkActionEntry mail_browser_entries[] = { static void mail_browser_menu_item_select_cb (EMailBrowser *browser, - GtkWidget *menu_item) + GtkWidget *widget) { GtkAction *action; GtkStatusbar *statusbar; - gchar *tooltip = NULL; + const gchar *tooltip; guint context_id; gpointer data; - action = g_object_get_data (G_OBJECT (menu_item), "action"); - g_return_if_fail (GTK_IS_ACTION (action)); + action = gtk_widget_get_action (widget); + tooltip = gtk_action_get_tooltip (action); - data = g_object_get_data (G_OBJECT (menu_item), "context-id"); + data = g_object_get_data (G_OBJECT (widget), "context-id"); context_id = GPOINTER_TO_UINT (data); - g_object_get (action, "tooltip", &tooltip, NULL); - if (tooltip == NULL) return; @@ -175,11 +173,6 @@ mail_browser_connect_proxy_cb (EMailBrowser *browser, statusbar = GTK_STATUSBAR (browser->priv->statusbar); context_id = gtk_statusbar_get_context_id (statusbar, G_STRFUNC); - g_object_set_data_full ( - G_OBJECT (proxy), - "action", g_object_ref (action), - (GDestroyNotify) g_object_unref); - g_object_set_data ( G_OBJECT (proxy), "context-id", GUINT_TO_POINTER (context_id)); @@ -440,7 +433,7 @@ mail_browser_constructed (GObject *object) priv->statusbar = g_object_ref (widget); gtk_widget_show (widget); - widget = e_mail_search_bar_new (EM_FORMAT_HTML (html_display)->html); + widget = e_mail_search_bar_new (E_WEB_VIEW (html)); gtk_box_pack_end (GTK_BOX (container), widget, FALSE, FALSE, 0); priv->search_bar = g_object_ref (widget); gtk_widget_hide (widget); diff --git a/mail/e-mail-display.c b/mail/e-mail-display.c index c29328b36b..df65c256f7 100644 --- a/mail/e-mail-display.c +++ b/mail/e-mail-display.c @@ -22,7 +22,6 @@ #include "e-mail-display.h" #include <config.h> -#include <string.h> #include <glib/gi18n.h> #include "e-util/e-util.h" @@ -36,162 +35,30 @@ struct _EMailDisplayPrivate { EMFormatHTML *formatter; - GtkUIManager *ui_manager; - gchar *selected_uri; }; enum { PROP_0, - PROP_ANIMATE, - PROP_CARET_MODE, - PROP_FORMATTER, - PROP_SELECTED_URI -}; - -enum { - POPUP_EVENT, - STATUS_MESSAGE, - LAST_SIGNAL + PROP_FORMATTER }; static gpointer parent_class; -static guint signals[LAST_SIGNAL]; static const gchar *ui = "<ui>" " <popup name='context'>" -" <menuitem action='http-open'/>" -" <menuitem action='send-message'/>" -" <menuitem action='uri-copy'/>" -" <menuitem action='add-to-address-book'/>" -" <menuitem action='mailto-copy'/>" -" <menu action='search-folder-menu'>" -" <menuitem action='search-folder-sender'/>" -" <menuitem action='search-folder-recipient'/>" -" </menu>" +" <placeholder name='custom-actions-1'>" +" <menuitem action='add-to-address-book'/>" +" </placeholder>" +" <placeholder name='custom-actions-3'>" +" <menu action='search-folder-menu'>" +" <menuitem action='search-folder-recipient'/>" +" <menuitem action='search-folder-sender'/>" +" </menu>" +" </placeholder>" " </popup>" "</ui>"; -static void -action_add_to_address_book_cb (GtkAction *action, - EMailDisplay *display) -{ - CamelURL *curl; - const gchar *uri; - gpointer parent; - - parent = gtk_widget_get_toplevel (GTK_WIDGET (display)); - parent = GTK_WIDGET_TOPLEVEL (parent) ? parent : NULL; - - uri = e_mail_display_get_selected_uri (display); - g_return_if_fail (uri != NULL); - - /* This should work because we checked it in update_actions(). */ - curl = camel_url_new (uri, NULL); - g_return_if_fail (curl != NULL); - - if (curl->path != NULL && *curl->path != '\0') - em_utils_add_address (parent, curl->path); - - camel_url_free (curl); -} - -static void -action_http_open_cb (GtkAction *action, - EMailDisplay *display) -{ - const gchar *uri; - gpointer parent; - - parent = gtk_widget_get_toplevel (GTK_WIDGET (display)); - parent = GTK_WIDGET_TOPLEVEL (parent) ? parent : NULL; - - uri = e_mail_display_get_selected_uri (display); - g_return_if_fail (uri != NULL); - - e_show_uri (parent, uri); -} - -static void -action_mailto_copy_cb (GtkAction *action, - EMailDisplay *display) -{ - CamelURL *curl; - CamelInternetAddress *inet_addr; - GtkClipboard *clipboard; - const gchar *uri; - gchar *text; - - clipboard = gtk_clipboard_get (GDK_SELECTION_CLIPBOARD); - uri = e_mail_display_get_selected_uri (display); - g_return_if_fail (uri != NULL); - - /* This should work because we checked it in update_actions(). */ - curl = camel_url_new (uri, NULL); - g_return_if_fail (curl != NULL); - - inet_addr = camel_internet_address_new (); - camel_address_decode (CAMEL_ADDRESS (inet_addr), curl->path); - text = camel_address_encode (CAMEL_ADDRESS (inet_addr)); - if (text == NULL || *text == '\0') - text = g_strdup (uri + strlen ("mailto:")); - - camel_object_unref (inet_addr); - camel_url_free (curl); - - gtk_clipboard_set_text (clipboard, text, -1); - gtk_clipboard_store (clipboard); - - g_free (text); -} - -static void -action_send_message_cb (GtkAction *action, - EMailDisplay *display) -{ - const gchar *uri; - - uri = e_mail_display_get_selected_uri (display); - g_return_if_fail (uri != NULL); - - em_utils_compose_new_message_with_mailto (uri, NULL); -} - -static void -action_uri_copy_cb (GtkAction *action, - EMailDisplay *display) -{ - GtkClipboard *clipboard; - const gchar *uri; - - clipboard = gtk_clipboard_get (GDK_SELECTION_CLIPBOARD); - uri = e_mail_display_get_selected_uri (display); - g_return_if_fail (uri != NULL); - - gtk_clipboard_set_text (clipboard, uri, -1); - gtk_clipboard_store (clipboard); -} - -static GtkActionEntry uri_entries[] = { - - { "uri-copy", - GTK_STOCK_COPY, - N_("_Copy Link Location"), - NULL, - NULL, /* XXX Add a tooltip! */ - G_CALLBACK (action_uri_copy_cb) }, -}; - -static GtkActionEntry http_entries[] = { - - { "http-open", - "emblem-web", - N_("_Open Link in Browser"), - NULL, - NULL, /* XXX Add a tooltip! */ - G_CALLBACK (action_http_open_cb) }, -}; - static GtkActionEntry mailto_entries[] = { { "add-to-address-book", @@ -199,14 +66,7 @@ static GtkActionEntry mailto_entries[] = { N_("_Add to Address Book..."), NULL, NULL, /* XXX Add a tooltip! */ - G_CALLBACK (action_add_to_address_book_cb) }, - - { "mailto-copy", - GTK_STOCK_COPY, - N_("_Copy Email Address"), - NULL, - NULL, /* XXX Add a tooltip! */ - G_CALLBACK (action_mailto_copy_cb) }, + NULL /* Handled by EMailReader */ }, { "search-folder-recipient", NULL, @@ -222,13 +82,6 @@ static GtkActionEntry mailto_entries[] = { NULL, /* XXX Add a tooltip! */ NULL /* Handled by EMailReader */ }, - { "send-message", - "mail-message-new", - N_("_Send New Message To..."), - NULL, - NULL, /* XXX Add a tooltip! */ - G_CALLBACK (action_send_message_cb) }, - /*** Menus ***/ { "search-folder-menu", @@ -239,123 +92,6 @@ static GtkActionEntry mailto_entries[] = { NULL } }; -static gboolean -mail_display_emit_popup_event (EMailDisplay *display, - GdkEventButton *event, - const gchar *uri, - EMFormatPURI *puri) -{ - CamelMimePart *mime_part; - gboolean stop_handlers = FALSE; - - mime_part = (puri != NULL) ? puri->part : NULL; - - g_signal_emit ( - display, signals[POPUP_EVENT], 0, - event, uri, mime_part, &stop_handlers); - - return stop_handlers; -} - -static void -mail_display_emit_status_message (EMailDisplay *display, - const gchar *status_message) -{ - g_signal_emit (display, signals[STATUS_MESSAGE], 0, status_message); -} - -static void -mail_display_get_uri_puri (EMailDisplay *display, - GdkEventButton *event, - GtkHTML *html, - gchar **uri, - EMFormatPURI **puri) -{ - EMFormat *formatter; - gchar *text_uri; - gchar *image_uri; - gboolean is_cid; - - formatter = EM_FORMAT (display->priv->formatter); - - if (event != NULL) { - text_uri = gtk_html_get_url_at (html, event->x, event->y); - image_uri = gtk_html_get_image_src_at (html, event->x, event->y); - } else { - text_uri = gtk_html_get_cursor_url (html); - image_uri = gtk_html_get_cursor_image_src (html); - } - - is_cid = (image_uri != NULL) && - (g_ascii_strncasecmp (image_uri, "cid:", 4) == 0); - - if (image_uri != NULL) { - if (strstr (image_uri, "://") == NULL && !is_cid) { - gchar *temp; - - temp = g_strconcat ("file://", image_uri, NULL); - g_free (image_uri); - image_uri = temp; - } - } - - if (puri != NULL) { - if (text_uri != NULL) - *puri = em_format_find_puri (formatter, text_uri); - - if (*puri == NULL && image_uri != NULL) - *puri = em_format_find_puri (formatter, image_uri); - } - - if (uri != NULL) { - *uri = NULL; - if (is_cid) { - if (text_uri != NULL) - *uri = g_strdup_printf ( - "%s\n%s", text_uri, image_uri); - else { - *uri = image_uri; - image_uri = NULL; - } - } else { - *uri = text_uri; - text_uri = NULL; - } - } - - g_free (text_uri); - g_free (image_uri); -} - -static gboolean -mail_display_button_press_event_cb (EMailDisplay *display, - GdkEventButton *event, - GtkHTML *html) -{ - EMFormatPURI *puri = NULL; - gboolean finished = TRUE; - gchar *uri = NULL; - - /* The GtkHTML object may be the EMailDisplay itself - * or an inner iframe. */ - - if (event->button != 3) - return FALSE; - - mail_display_get_uri_puri (display, event, html, &uri, &puri); - - if (uri == NULL || g_str_has_prefix (uri, "##")) { - g_free (uri); - return FALSE; - } - - finished = mail_display_emit_popup_event (display, event, uri, puri); - - g_free (uri); - - return finished; -} - static void mail_display_update_formatter_colors (EMailDisplay *display) { @@ -404,29 +140,11 @@ mail_display_set_property (GObject *object, GParamSpec *pspec) { switch (property_id) { - case PROP_ANIMATE: - e_mail_display_set_animate ( - E_MAIL_DISPLAY (object), - g_value_get_boolean (value)); - return; - - case PROP_CARET_MODE: - e_mail_display_set_caret_mode ( - E_MAIL_DISPLAY (object), - g_value_get_boolean (value)); - return; - case PROP_FORMATTER: e_mail_display_set_formatter ( E_MAIL_DISPLAY (object), g_value_get_object (value)); return; - - case PROP_SELECTED_URI: - e_mail_display_set_selected_uri ( - E_MAIL_DISPLAY (object), - g_value_get_string (value)); - return; } G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); @@ -439,29 +157,11 @@ mail_display_get_property (GObject *object, GParamSpec *pspec) { switch (property_id) { - case PROP_ANIMATE: - g_value_set_boolean ( - value, e_mail_display_get_animate ( - E_MAIL_DISPLAY (object))); - return; - - case PROP_CARET_MODE: - g_value_set_boolean ( - value, e_mail_display_get_caret_mode ( - E_MAIL_DISPLAY (object))); - return; - case PROP_FORMATTER: g_value_set_object ( value, e_mail_display_get_formatter ( E_MAIL_DISPLAY (object))); return; - - case PROP_SELECTED_URI: - g_value_set_string ( - value, e_mail_display_get_selected_uri ( - E_MAIL_DISPLAY (object))); - return; } G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); @@ -479,11 +179,6 @@ mail_display_dispose (GObject *object) priv->formatter = NULL; } - if (priv->ui_manager) { - g_object_unref (priv->ui_manager); - priv->ui_manager = NULL; - } - /* Chain up to parent's dispose() method. */ G_OBJECT_CLASS (parent_class)->dispose (object); } @@ -512,39 +207,13 @@ mail_display_style_set (GtkWidget *widget, em_format_redraw (EM_FORMAT (priv->formatter)); } -static gboolean -mail_display_button_press_event (GtkWidget *widget, - GdkEventButton *event) -{ - EMailDisplay *display = E_MAIL_DISPLAY (widget); - GtkHTML *html = GTK_HTML (widget); - - if (mail_display_button_press_event_cb (display, event, html)) - return TRUE; - - /* Chain up to parent's button_press_event() method. */ - return GTK_WIDGET_CLASS (parent_class)-> - button_press_event (widget, event); -} - -static gboolean -mail_display_scroll_event (GtkWidget *widget, - GdkEventScroll *event) +static void +mail_display_url_requested (GtkHTML *html, + const gchar *uri, + GtkHTMLStream *stream) { - if (event->state & GDK_CONTROL_MASK) { - switch (event->direction) { - case GDK_SCROLL_UP: - gtk_html_zoom_in (GTK_HTML (widget)); - return TRUE; - case GDK_SCROLL_DOWN: - gtk_html_zoom_out (GTK_HTML (widget)); - return TRUE; - default: - break; - } - } - - return FALSE; + /* XXX Sadly, we must block the default method + * until EMFormatHTML is made asynchronous. */ } static void @@ -591,89 +260,12 @@ mail_display_link_clicked (GtkHTML *html, /* ignore */ ; else { - gpointer parent; - - parent = gtk_widget_get_toplevel (GTK_WIDGET (html)); - parent = GTK_WIDGET_TOPLEVEL (parent) ? parent : NULL; - - e_show_uri (parent, uri); + /* Chain up to parent's link_clicked() method. */ + GTK_HTML_CLASS (parent_class)->link_clicked (html, uri); } } static void -mail_display_on_url (GtkHTML *html, - const gchar *uri) -{ - EMailDisplay *display; - CamelInternetAddress *address; - CamelURL *curl; - const gchar *format = NULL; - gchar *message = NULL; - gchar *who; - - display = E_MAIL_DISPLAY (html); - - if (uri == NULL || *uri == '\0') - goto exit; - - if (g_str_has_prefix (uri, "mailto:")) - format = _("Click to mail %s"); - else if (g_str_has_prefix (uri, "callto:")) - format = _("Click to call %s"); - else if (g_str_has_prefix (uri, "h323:")) - format = _("Click to call %s"); - else if (g_str_has_prefix (uri, "sip:")) - format = _("Click to call %s"); - else if (g_str_has_prefix (uri, "##")) - message = g_strdup (_("Click to hide/unhide addresses")); - else - message = g_strdup_printf (_("Click to open %s"), uri); - - if (format == NULL) - goto exit; - - curl = camel_url_new (uri, NULL); - address = camel_internet_address_new (); - camel_address_decode (CAMEL_ADDRESS (address), curl->path); - who = camel_address_format (CAMEL_ADDRESS (address)); - camel_object_unref (address); - camel_url_free (curl); - - if (who == NULL) - who = g_strdup (strchr (uri, ':') + 1); - - message = g_strdup_printf (format, who); - - g_free (who); - -exit: - mail_display_emit_status_message (display, message); - - g_free (message); -} - -static void -mail_display_iframe_created (GtkHTML *html, - GtkHTML *iframe) -{ - g_signal_connect_swapped ( - iframe, "button-press-event", - G_CALLBACK (mail_display_button_press_event_cb), html); -} - -static gboolean -mail_display_popup_event (EMailDisplay *display, - GdkEventButton *event, - const gchar *uri, - EMFormatPURI *puri) -{ - e_mail_display_set_selected_uri (display, uri); - e_mail_display_show_popup_menu (display, event, NULL, NULL); - - return TRUE; -} - -static void mail_display_class_init (EMailDisplayClass *class) { GObjectClass *object_class; @@ -691,35 +283,10 @@ mail_display_class_init (EMailDisplayClass *class) widget_class = GTK_WIDGET_CLASS (class); widget_class->realize = mail_display_realize; widget_class->style_set = mail_display_style_set; - widget_class->button_press_event = mail_display_button_press_event; - widget_class->scroll_event = mail_display_scroll_event; html_class = GTK_HTML_CLASS (class); + html_class->url_requested = mail_display_url_requested; html_class->link_clicked = mail_display_link_clicked; - html_class->on_url = mail_display_on_url; - html_class->iframe_created = mail_display_iframe_created; - - class->popup_event = mail_display_popup_event; - - g_object_class_install_property ( - object_class, - PROP_ANIMATE, - g_param_spec_boolean ( - "animate", - "Animate Images", - NULL, - FALSE, - G_PARAM_READWRITE)); - - g_object_class_install_property ( - object_class, - PROP_CARET_MODE, - g_param_spec_boolean ( - "caret-mode", - "Caret Mode", - NULL, - FALSE, - G_PARAM_READWRITE)); g_object_class_install_property ( object_class, @@ -730,67 +297,27 @@ mail_display_class_init (EMailDisplayClass *class) NULL, EM_TYPE_FORMAT_HTML, G_PARAM_READWRITE)); - - g_object_class_install_property ( - object_class, - PROP_SELECTED_URI, - g_param_spec_string ( - "selected-uri", - "Selected URI", - NULL, - NULL, - G_PARAM_READWRITE)); - - signals[POPUP_EVENT] = g_signal_new ( - "popup-event", - G_TYPE_FROM_CLASS (class), - G_SIGNAL_RUN_LAST, - G_STRUCT_OFFSET (EMailDisplayClass, popup_event), - g_signal_accumulator_true_handled, NULL, - e_marshal_BOOLEAN__BOXED_POINTER_POINTER, - G_TYPE_BOOLEAN, 3, - GDK_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE, - G_TYPE_POINTER, - G_TYPE_POINTER); - - signals[STATUS_MESSAGE] = g_signal_new ( - "status-message", - G_TYPE_FROM_CLASS (class), - G_SIGNAL_RUN_FIRST, - G_STRUCT_OFFSET (EMailDisplayClass, status_message), - NULL, NULL, - g_cclosure_marshal_VOID__STRING, - G_TYPE_NONE, 1, - G_TYPE_STRING); } static void mail_display_init (EMailDisplay *display) { + EWebView *web_view; GtkUIManager *ui_manager; GtkActionGroup *action_group; - const gchar *id; GError *error = NULL; - display->priv = E_MAIL_DISPLAY_GET_PRIVATE (display); - - ui_manager = gtk_ui_manager_new (); - display->priv->ui_manager = ui_manager; - - action_group = e_mail_display_add_action_group (display, "uri"); + web_view = E_WEB_VIEW (display); - gtk_action_group_add_actions ( - action_group, uri_entries, - G_N_ELEMENTS (uri_entries), display); - - action_group = e_mail_display_add_action_group (display, "http"); - - gtk_action_group_add_actions ( - action_group, http_entries, - G_N_ELEMENTS (http_entries), display); + display->priv = E_MAIL_DISPLAY_GET_PRIVATE (display); - action_group = e_mail_display_add_action_group (display, "mailto"); + /* EWebView's action groups are added during its instance + * initialization function (like what we're in now), so it + * is safe to fetch them this early in construction. */ + action_group = e_web_view_get_action_group (web_view, "mailto"); + /* We don't actually handle the actions we're adding. + * EMailReader handles them. How devious is that? */ gtk_action_group_add_actions ( action_group, mailto_entries, G_N_ELEMENTS (mailto_entries), display); @@ -798,13 +325,10 @@ mail_display_init (EMailDisplay *display) /* Because we are loading from a hard-coded string, there is * no chance of I/O errors. Failure here implies a malformed * UI definition. Full stop. */ + ui_manager = e_web_view_get_ui_manager (web_view); gtk_ui_manager_add_ui_from_string (ui_manager, ui, -1, &error); if (error != NULL) g_error ("%s", error->message); - - id = "org.gnome.evolution.mail.display"; - e_plugin_ui_register_manager (ui_manager, id, display); - e_plugin_ui_enable_manager (ui_manager, id); } GType @@ -827,64 +351,12 @@ e_mail_display_get_type (void) }; type = g_type_register_static ( - GTK_TYPE_HTML, "EMailDisplay", &type_info, 0); + E_TYPE_WEB_VIEW, "EMailDisplay", &type_info, 0); } return type; } -gboolean -e_mail_display_get_animate (EMailDisplay *display) -{ - /* XXX This is just here to maintain symmetry - * with e_mail_display_set_animate(). */ - - g_return_val_if_fail (E_IS_MAIL_DISPLAY (display), FALSE); - - return gtk_html_get_animate (GTK_HTML (display)); -} - -void -e_mail_display_set_animate (EMailDisplay *display, - gboolean animate) -{ - /* XXX GtkHTML does not utilize GObject properties as well - * as it could. This just wraps gtk_html_set_animate() - * so we can get a "notify::animate" signal. */ - - g_return_if_fail (E_IS_MAIL_DISPLAY (display)); - - gtk_html_set_animate (GTK_HTML (display), animate); - - g_object_notify (G_OBJECT (display), "animate"); -} - -gboolean -e_mail_display_get_caret_mode (EMailDisplay *display) -{ - /* XXX This is just here to maintain symmetry - * with e_mail_display_set_caret_mode(). */ - - g_return_val_if_fail (E_IS_MAIL_DISPLAY (display), FALSE); - - return gtk_html_get_caret_mode (GTK_HTML (display)); -} - -void -e_mail_display_set_caret_mode (EMailDisplay *display, - gboolean caret_mode) -{ - /* XXX GtkHTML does not utilize GObject properties as well - * as it could. This just wraps gtk_html_set_caret_mode() - * so we can get a "notify::caret-mode" signal. */ - - g_return_if_fail (E_IS_MAIL_DISPLAY (display)); - - gtk_html_set_caret_mode (GTK_HTML (display), caret_mode); - - g_object_notify (G_OBJECT (display), "caret-mode"); -} - EMFormatHTML * e_mail_display_get_formatter (EMailDisplay *display) { @@ -907,166 +379,3 @@ e_mail_display_set_formatter (EMailDisplay *display, g_object_notify (G_OBJECT (display), "formatter"); } - -const gchar * -e_mail_display_get_selected_uri (EMailDisplay *display) -{ - g_return_val_if_fail (E_IS_MAIL_DISPLAY (display), NULL); - - return display->priv->selected_uri; -} - -void -e_mail_display_set_selected_uri (EMailDisplay *display, - const gchar *selected_uri) -{ - g_return_if_fail (E_IS_MAIL_DISPLAY (display)); - - g_free (display->priv->selected_uri); - display->priv->selected_uri = g_strdup (selected_uri); - - g_object_notify (G_OBJECT (display), "selected-uri"); -} - -GtkAction * -e_mail_display_get_action (EMailDisplay *display, - const gchar *action_name) -{ - GtkUIManager *ui_manager; - - g_return_val_if_fail (E_IS_MAIL_DISPLAY (display), NULL); - g_return_val_if_fail (action_name != NULL, NULL); - - ui_manager = e_mail_display_get_ui_manager (display); - - return e_lookup_action (ui_manager, action_name); -} - -GtkActionGroup * -e_mail_display_add_action_group (EMailDisplay *display, - const gchar *group_name) -{ - GtkActionGroup *action_group; - GtkUIManager *ui_manager; - const gchar *domain; - - g_return_val_if_fail (E_IS_MAIL_DISPLAY (display), NULL); - g_return_val_if_fail (group_name != NULL, NULL); - - ui_manager = e_mail_display_get_ui_manager (display); - domain = GETTEXT_PACKAGE; - - action_group = gtk_action_group_new (group_name); - gtk_action_group_set_translation_domain (action_group, domain); - gtk_ui_manager_insert_action_group (ui_manager, action_group, 0); - g_object_unref (action_group); - - return action_group; -} - -GtkActionGroup * -e_mail_display_get_action_group (EMailDisplay *display, - const gchar *group_name) -{ - GtkUIManager *ui_manager; - - g_return_val_if_fail (E_IS_MAIL_DISPLAY (display), NULL); - g_return_val_if_fail (group_name != NULL, NULL); - - ui_manager = e_mail_display_get_ui_manager (display); - - return e_lookup_action_group (ui_manager, group_name); -} - -GtkWidget * -e_mail_display_get_popup_menu (EMailDisplay *display) -{ - GtkUIManager *ui_manager; - GtkWidget *menu; - - g_return_val_if_fail (E_IS_MAIL_DISPLAY (display), NULL); - - ui_manager = e_mail_display_get_ui_manager (display); - menu = gtk_ui_manager_get_widget (ui_manager, "/context"); - g_return_val_if_fail (GTK_IS_MENU (menu), NULL); - - return menu; -} - -GtkUIManager * -e_mail_display_get_ui_manager (EMailDisplay *display) -{ - EMailDisplayPrivate *priv; - - g_return_val_if_fail (E_IS_MAIL_DISPLAY (display), NULL); - - priv = E_MAIL_DISPLAY_GET_PRIVATE (display); - - return priv->ui_manager; -} - -void -e_mail_display_show_popup_menu (EMailDisplay *display, - GdkEventButton *event, - GtkMenuPositionFunc func, - gpointer user_data) -{ - GtkWidget *menu; - - g_return_if_fail (E_IS_MAIL_DISPLAY (display)); - - e_mail_display_update_actions (display); - - menu = e_mail_display_get_popup_menu (display); - - if (event != NULL) - gtk_menu_popup ( - GTK_MENU (menu), NULL, NULL, func, - user_data, event->button, event->time); - else - gtk_menu_popup ( - GTK_MENU (menu), NULL, NULL, func, - user_data, 0, gtk_get_current_event_time ()); -} - -void -e_mail_display_update_actions (EMailDisplay *display) -{ - CamelURL *curl; - GtkActionGroup *action_group; - gboolean scheme_is_http; - gboolean scheme_is_mailto; - gboolean uri_is_valid; - gboolean visible; - const gchar *uri; - - g_return_if_fail (E_IS_MAIL_DISPLAY (display)); - - uri = e_mail_display_get_selected_uri (display); - g_return_if_fail (uri != NULL); - - /* Parse the URI early so we know if the actions will work. */ - curl = camel_url_new (uri, NULL); - uri_is_valid = (curl != NULL); - camel_url_free (curl); - - scheme_is_http = - (g_ascii_strncasecmp (uri, "http:", 5) == 0) || - (g_ascii_strncasecmp (uri, "https:", 6) == 0); - - scheme_is_mailto = - (g_ascii_strncasecmp (uri, "mailto:", 7) == 0); - - /* Allow copying the URI even if it's malformed. */ - visible = !scheme_is_mailto; - action_group = e_mail_display_get_action_group (display, "uri"); - gtk_action_group_set_visible (action_group, visible); - - visible = uri_is_valid && scheme_is_http; - action_group = e_mail_display_get_action_group (display, "http"); - gtk_action_group_set_visible (action_group, visible); - - visible = uri_is_valid && scheme_is_mailto; - action_group = e_mail_display_get_action_group (display, "mailto"); - gtk_action_group_set_visible (action_group, visible); -} diff --git a/mail/e-mail-display.h b/mail/e-mail-display.h index 9f273fb26f..1b71a9db7f 100644 --- a/mail/e-mail-display.h +++ b/mail/e-mail-display.h @@ -22,8 +22,8 @@ #ifndef E_MAIL_DISPLAY_H #define E_MAIL_DISPLAY_H -#include <gtkhtml/gtkhtml.h> #include <mail/em-format-html.h> +#include <misc/e-web-view.h> /* Standard GObject macros */ #define E_TYPE_MAIL_DISPLAY \ @@ -51,48 +51,18 @@ typedef struct _EMailDisplayClass EMailDisplayClass; typedef struct _EMailDisplayPrivate EMailDisplayPrivate; struct _EMailDisplay { - GtkHTML parent; + EWebView parent; EMailDisplayPrivate *priv; }; struct _EMailDisplayClass { - GtkHTMLClass parent_class; - - /* Signals */ - gboolean (*popup_event) (EMailDisplay *display, - GdkEventButton *event, - const gchar *uri, - EMFormatPURI *puri); - void (*status_message) (EMailDisplay *display, - const gchar *status_message); + EWebViewClass parent_class; }; GType e_mail_display_get_type (void); -gboolean e_mail_display_get_animate (EMailDisplay *display); -void e_mail_display_set_animate (EMailDisplay *display, - gboolean animate); -gboolean e_mail_display_get_caret_mode (EMailDisplay *display); -void e_mail_display_set_caret_mode (EMailDisplay *display, - gboolean caret_mode); EMFormatHTML * e_mail_display_get_formatter (EMailDisplay *display); void e_mail_display_set_formatter (EMailDisplay *display, EMFormatHTML *formatter); -const gchar * e_mail_display_get_selected_uri (EMailDisplay *display); -void e_mail_display_set_selected_uri (EMailDisplay *display, - const gchar *uri); -GtkAction * e_mail_display_get_action (EMailDisplay *display, - const gchar *action_name); -GtkActionGroup *e_mail_display_add_action_group (EMailDisplay *display, - const gchar *group_name); -GtkActionGroup *e_mail_display_get_action_group (EMailDisplay *display, - const gchar *group_name); -GtkWidget * e_mail_display_get_popup_menu (EMailDisplay *display); -GtkUIManager * e_mail_display_get_ui_manager (EMailDisplay *display); -void e_mail_display_show_popup_menu (EMailDisplay *display, - GdkEventButton *event, - GtkMenuPositionFunc func, - gpointer user_data); -void e_mail_display_update_actions (EMailDisplay *display); G_END_DECLS diff --git a/mail/e-mail-reader.c b/mail/e-mail-reader.c index 72f79181f8..d3a845c125 100644 --- a/mail/e-mail-reader.c +++ b/mail/e-mail-reader.c @@ -67,15 +67,16 @@ static void action_mail_add_sender_cb (GtkAction *action, EMailReader *reader) { + EShell *shell; + EShellBackend *shell_backend; MessageList *message_list; CamelMessageInfo *info; CamelFolder *folder; - GtkWindow *window; GPtrArray *uids; const gchar *address; message_list = e_mail_reader_get_message_list (reader); - window = e_mail_reader_get_window (reader); + shell_backend = e_mail_reader_get_shell_backend (reader); folder = message_list->folder; uids = message_list_get_selected (message_list); @@ -91,13 +92,52 @@ action_mail_add_sender_cb (GtkAction *action, if (address == NULL || *address == '\0') goto exit; - em_utils_add_address (window, address); + /* XXX EBookShellBackend should be listening for this + * event. Kind of kludgey, but works for now. */ + shell = e_shell_backend_get_shell (shell_backend); + e_shell_event (shell, "contact-quick-add-email", (gpointer) address); exit: em_utils_uids_free (uids); } static void +action_add_to_address_book_cb (GtkAction *action, + EMailReader *reader) +{ + EShell *shell; + EShellBackend *shell_backend; + EMFormatHTMLDisplay *html_display; + EWebView *web_view; + CamelURL *curl; + const gchar *uri; + + /* This action is defined in EMailDisplay. */ + + html_display = e_mail_reader_get_html_display (reader); + shell_backend = e_mail_reader_get_shell_backend (reader); + + web_view = E_WEB_VIEW (EM_FORMAT_HTML (html_display)->html); + + uri = e_web_view_get_selected_uri (web_view); + g_return_if_fail (uri != NULL); + + curl = camel_url_new (uri, NULL); + g_return_if_fail (curl != NULL); + + if (curl->path == NULL || *curl->path == '\0') + goto exit; + + /* XXX EBookShellBackend should be listening for this + * event. Kind of kludgey, but works for now. */ + shell = e_shell_backend_get_shell (shell_backend); + e_shell_event (shell, "contact-quick-add-email", curl->path); + +exit: + camel_url_free (curl); +} + +static void action_mail_charset_cb (GtkRadioAction *action, GtkRadioAction *current, EMailReader *reader) @@ -955,7 +995,7 @@ action_search_folder_recipient_cb (GtkAction *action, { EMFormatHTMLDisplay *html_display; MessageList *message_list; - EMailDisplay *display; + EWebView *web_view; CamelURL *curl; const gchar *uri; @@ -964,9 +1004,9 @@ action_search_folder_recipient_cb (GtkAction *action, html_display = e_mail_reader_get_html_display (reader); message_list = e_mail_reader_get_message_list (reader); - display = E_MAIL_DISPLAY (EM_FORMAT_HTML (html_display)->html); + web_view = E_WEB_VIEW (EM_FORMAT_HTML (html_display)->html); - uri = e_mail_display_get_selected_uri (display); + uri = e_web_view_get_selected_uri (web_view); g_return_if_fail (uri != NULL); curl = camel_url_new (uri, NULL); @@ -996,7 +1036,7 @@ action_search_folder_sender_cb (GtkAction *action, { EMFormatHTMLDisplay *html_display; MessageList *message_list; - EMailDisplay *display; + EWebView *web_view; CamelURL *curl; const gchar *uri; @@ -1005,9 +1045,9 @@ action_search_folder_sender_cb (GtkAction *action, html_display = e_mail_reader_get_html_display (reader); message_list = e_mail_reader_get_message_list (reader); - display = E_MAIL_DISPLAY (EM_FORMAT_HTML (html_display)->html); + web_view = E_WEB_VIEW (EM_FORMAT_HTML (html_display)->html); - uri = e_mail_display_get_selected_uri (display); + uri = e_web_view_get_selected_uri (web_view); g_return_if_fail (uri != NULL); curl = camel_url_new (uri, NULL); @@ -2252,7 +2292,7 @@ e_mail_reader_init (EMailReader *reader) EShellBackend *shell_backend; EShellSettings *shell_settings; EMFormatHTMLDisplay *html_display; - EMailDisplay *display; + EWebView *web_view; GtkActionGroup *action_group; MessageList *message_list; GConfBridge *bridge; @@ -2270,7 +2310,7 @@ e_mail_reader_init (EMailReader *reader) shell = e_shell_backend_get_shell (shell_backend); shell_settings = e_shell_get_shell_settings (shell); - display = E_MAIL_DISPLAY (EM_FORMAT_HTML (html_display)->html); + web_view = E_WEB_VIEW (EM_FORMAT_HTML (html_display)->html); gtk_action_group_add_actions ( action_group, mail_reader_entries, @@ -2320,14 +2360,20 @@ e_mail_reader_init (EMailReader *reader) action = e_mail_reader_get_action (reader, action_name); g_object_set (action, "short-label", _("Reply"), NULL); + action_name = "add-to-address-book"; + action = e_web_view_get_action (web_view, action_name); + g_signal_connect ( + action, "activate", + G_CALLBACK (action_add_to_address_book_cb), reader); + action_name = "search-folder-recipient"; - action = e_mail_display_get_action (display, action_name); + action = e_web_view_get_action (web_view, action_name); g_signal_connect ( action, "activate", G_CALLBACK (action_search_folder_recipient_cb), reader); action_name = "search-folder-sender"; - action = e_mail_display_get_action (display, action_name); + action = e_web_view_get_action (web_view, action_name); g_signal_connect ( action, "activate", G_CALLBACK (action_search_folder_sender_cb), reader); @@ -2350,7 +2396,7 @@ e_mail_reader_init (EMailReader *reader) e_binding_new ( shell_settings, "mail-show-animated-images", - display, "animate"); + web_view, "animate"); e_binding_new ( shell_settings, "mail-show-sender-photo", @@ -2361,16 +2407,16 @@ e_mail_reader_init (EMailReader *reader) e_mutual_binding_new ( action, "active", - display, "caret-mode"); + web_view, "caret-mode"); /* Connect signals. */ g_signal_connect_swapped ( - display, "button-release-event", + web_view, "button-release-event", G_CALLBACK (mail_reader_button_release_event_cb), reader); g_signal_connect_swapped ( - display, "key-press-event", + web_view, "key-press-event", G_CALLBACK (mail_reader_key_press_event_cb), reader); g_signal_connect_swapped ( diff --git a/mail/e-mail-search-bar.c b/mail/e-mail-search-bar.c index d068eb1123..bfd4270cb9 100644 --- a/mail/e-mail-search-bar.c +++ b/mail/e-mail-search-bar.c @@ -32,7 +32,7 @@ ((obj), E_TYPE_MAIL_SEARCH_BAR, EMailSearchBarPrivate)) struct _EMailSearchBarPrivate { - GtkHTML *html; + EWebView *web_view; GtkWidget *entry; GtkWidget *case_sensitive_button; GtkWidget *wrapped_next_box; @@ -48,8 +48,8 @@ struct _EMailSearchBarPrivate { enum { PROP_0, PROP_CASE_SENSITIVE, - PROP_HTML, - PROP_TEXT + PROP_TEXT, + PROP_WEB_VIEW }; enum { @@ -108,14 +108,14 @@ static void mail_search_bar_find (EMailSearchBar *search_bar, gboolean search_forward) { - GtkHTML *html; + EWebView *web_view; GtkWidget *widget; gboolean case_sensitive; gboolean new_search; gboolean wrapped = FALSE; gchar *text; - html = e_mail_search_bar_get_html (search_bar); + web_view = e_mail_search_bar_get_web_view (search_bar); case_sensitive = e_mail_search_bar_get_case_sensitive (search_bar); text = e_mail_search_bar_get_text (search_bar); @@ -146,20 +146,23 @@ mail_search_bar_find (EMailSearchBar *search_bar, mail_search_bar_update_tokenizer (search_bar); } else if (search_bar->priv->rerun_search) { gtk_html_engine_search ( - html, search_bar->priv->active_search, + GTK_HTML (web_view), + search_bar->priv->active_search, case_sensitive, search_forward, FALSE); search_bar->priv->rerun_search = FALSE; g_free (text); } else { - gtk_html_engine_search_set_forward (html, search_forward); - if (!gtk_html_engine_search_next (html)) + gtk_html_engine_search_set_forward ( + GTK_HTML (web_view), search_forward); + if (!gtk_html_engine_search_next (GTK_HTML (web_view))) wrapped = TRUE; g_free (text); } if (new_search || wrapped) gtk_html_engine_search ( - html, search_bar->priv->active_search, + GTK_HTML (web_view), + search_bar->priv->active_search, case_sensitive, search_forward, FALSE); /* Update wrapped label visibility. */ @@ -218,15 +221,17 @@ mail_search_bar_toggled_cb (EMailSearchBar *search_bar) } static void -mail_search_bar_set_html (EMailSearchBar *search_bar, - GtkHTML *html) +mail_search_bar_set_web_view (EMailSearchBar *search_bar, + EWebView *web_view) { + GtkHTML *html; ESearchingTokenizer *tokenizer; - g_return_if_fail (search_bar->priv->html == NULL); + g_return_if_fail (search_bar->priv->web_view == NULL); - search_bar->priv->html = g_object_ref (html); + search_bar->priv->web_view = g_object_ref (web_view); + html = GTK_HTML (web_view); tokenizer = e_mail_search_bar_get_tokenizer (search_bar); gtk_html_set_tokenizer (html, HTML_TOKENIZER (tokenizer)); } @@ -244,17 +249,17 @@ mail_search_bar_set_property (GObject *object, g_value_get_boolean (value)); return; - case PROP_HTML: - mail_search_bar_set_html ( - E_MAIL_SEARCH_BAR (object), - g_value_get_object (value)); - return; - case PROP_TEXT: e_mail_search_bar_set_text ( E_MAIL_SEARCH_BAR (object), g_value_get_string (value)); return; + + case PROP_WEB_VIEW: + mail_search_bar_set_web_view ( + E_MAIL_SEARCH_BAR (object), + g_value_get_object (value)); + return; } G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); @@ -273,17 +278,17 @@ mail_search_bar_get_property (GObject *object, E_MAIL_SEARCH_BAR (object))); return; - case PROP_HTML: - g_value_set_object ( - value, e_mail_search_bar_get_html ( - E_MAIL_SEARCH_BAR (object))); - return; - case PROP_TEXT: g_value_take_string ( value, e_mail_search_bar_get_text ( E_MAIL_SEARCH_BAR (object))); return; + + case PROP_WEB_VIEW: + g_value_set_object ( + value, e_mail_search_bar_get_web_view ( + E_MAIL_SEARCH_BAR (object))); + return; } G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); @@ -296,9 +301,9 @@ mail_search_bar_dispose (GObject *object) priv = E_MAIL_SEARCH_BAR_GET_PRIVATE (object); - if (priv->html != NULL) { - g_object_unref (priv->html); - priv->html = NULL; + if (priv->web_view != NULL) { + g_object_unref (priv->web_view); + priv->web_view = NULL; } if (priv->entry != NULL) { @@ -450,17 +455,6 @@ mail_search_bar_class_init (EMailSearchBarClass *class) g_object_class_install_property ( object_class, - PROP_HTML, - g_param_spec_object ( - "html", - "HTML Display", - NULL, - GTK_TYPE_HTML, - G_PARAM_READWRITE | - G_PARAM_CONSTRUCT_ONLY)); - - g_object_class_install_property ( - object_class, PROP_TEXT, g_param_spec_string ( "text", @@ -469,6 +463,17 @@ mail_search_bar_class_init (EMailSearchBarClass *class) NULL, G_PARAM_READWRITE)); + g_object_class_install_property ( + object_class, + PROP_WEB_VIEW, + g_param_spec_object ( + "web-view", + "Web View", + NULL, + E_TYPE_WEB_VIEW, + G_PARAM_READWRITE | + G_PARAM_CONSTRUCT_ONLY)); + signals[CHANGED] = g_signal_new ( "changed", G_TYPE_FROM_CLASS (class), @@ -676,11 +681,12 @@ e_mail_search_bar_get_type (void) } GtkWidget * -e_mail_search_bar_new (GtkHTML *html) +e_mail_search_bar_new (EWebView *web_view) { - g_return_val_if_fail (GTK_IS_HTML (html), NULL); + g_return_val_if_fail (E_IS_WEB_VIEW (web_view), NULL); - return g_object_new (E_TYPE_MAIL_SEARCH_BAR, "html", html, NULL); + return g_object_new ( + E_TYPE_MAIL_SEARCH_BAR, "web-view", web_view, NULL); } void @@ -699,12 +705,12 @@ e_mail_search_bar_changed (EMailSearchBar *search_bar) g_signal_emit (search_bar, signals[CHANGED], 0); } -GtkHTML * -e_mail_search_bar_get_html (EMailSearchBar *search_bar) +EWebView * +e_mail_search_bar_get_web_view (EMailSearchBar *search_bar) { g_return_val_if_fail (E_IS_MAIL_SEARCH_BAR (search_bar), NULL); - return search_bar->priv->html; + return search_bar->priv->web_view; } ESearchingTokenizer * diff --git a/mail/e-mail-search-bar.h b/mail/e-mail-search-bar.h index f4748c77ad..1ad343777b 100644 --- a/mail/e-mail-search-bar.h +++ b/mail/e-mail-search-bar.h @@ -23,8 +23,8 @@ #define E_MAIL_SEARCH_BAR_H #include <gtk/gtk.h> -#include <gtkhtml/gtkhtml.h> #include <mail/e-searching-tokenizer.h> +#include <misc/e-web-view.h> /* Standard GObject macros */ #define E_TYPE_MAIL_SEARCH_BAR \ @@ -65,10 +65,10 @@ struct _EMailSearchBarClass { }; GType e_mail_search_bar_get_type (void); -GtkWidget * e_mail_search_bar_new (GtkHTML *html); +GtkWidget * e_mail_search_bar_new (EWebView *web_view); void e_mail_search_bar_clear (EMailSearchBar *search_bar); void e_mail_search_bar_changed (EMailSearchBar *search_bar); -GtkHTML * e_mail_search_bar_get_html (EMailSearchBar *search_bar); +EWebView * e_mail_search_bar_get_web_view (EMailSearchBar *search_bar); ESearchingTokenizer * e_mail_search_bar_get_tokenizer (EMailSearchBar *search_bar); gboolean e_mail_search_bar_get_case_sensitive diff --git a/mail/em-utils.c b/mail/em-utils.c index 0a55ea842d..4ee9110ae5 100644 --- a/mail/em-utils.c +++ b/mail/em-utils.c @@ -48,10 +48,6 @@ #include "em-filter-editor.h" -#include <bonobo/bonobo-listener.h> -#include <bonobo/bonobo-widget.h> -#include <bonobo/bonobo-event-source.h> - #include <glib/gi18n.h> #include <gio/gio.h> @@ -661,94 +657,6 @@ em_utils_save_messages (GtkWindow *parent, CamelFolder *folder, GPtrArray *uids) } /* ********************************************************************** */ - -static void -emu_add_address_cb(BonoboListener *listener, const gchar *name, const CORBA_any *any, CORBA_Environment *ev, gpointer data) -{ - gchar *type = bonobo_event_subtype(name); - - if (!strcmp(type, "Destroy")) - gtk_widget_destroy((GtkWidget *)data); - - g_free(type); -} - -/* one of email or vcard should be always NULL, never both of them */ -static void -emu_add_address_or_vcard (GtkWindow *parent, const gchar *email, const gchar *vcard) -{ - GtkWidget *win; - GtkWidget *control; - /*GtkWidget *socket;*/ - gchar *email_buf = NULL; - - if (email) { - CamelInternetAddress *cia; - - cia = camel_internet_address_new (); - if (camel_address_decode ((CamelAddress *) cia, email) == -1) { - camel_object_unref (cia); - return; - } - - email_buf = camel_address_format ((CamelAddress *) cia); - camel_object_unref (cia); - } - - win = gtk_window_new(GTK_WINDOW_TOPLEVEL); - gtk_window_set_title((GtkWindow *)win, _("Add address")); - - gtk_window_set_transient_for ((GtkWindow *)win, parent); - - gtk_window_set_position((GtkWindow *)win, GTK_WIN_POS_CENTER_ON_PARENT); - gtk_window_set_type_hint((GtkWindow *)win, GDK_WINDOW_TYPE_HINT_DIALOG); - - control = bonobo_widget_new_control("OAFIID:GNOME_Evolution_Addressbook_AddressPopup:" BASE_VERSION, CORBA_OBJECT_NIL); - - if (email_buf) - bonobo_widget_set_property ((BonoboWidget *) control, "email", TC_CORBA_string, email_buf, NULL); - else - bonobo_widget_set_property ((BonoboWidget *) control, "vcard", TC_CORBA_string, vcard, NULL); - - g_free (email_buf); - - bonobo_event_source_client_add_listener(bonobo_widget_get_objref((BonoboWidget *)control), emu_add_address_cb, NULL, NULL, win); - - /*socket = find_socket (GTK_CONTAINER (control)); - g_object_weak_ref ((GObject *) socket, (GWeakNotify) gtk_widget_destroy, win);*/ - - gtk_container_add((GtkContainer *)win, control); - gtk_widget_show_all(win); -} - -/** - * em_utils_add_address: - * @parent: - * @email: - * - * Add address @email to the addressbook. - **/ -void -em_utils_add_address (GtkWindow *parent, const gchar *email) -{ - g_return_if_fail (GTK_IS_WINDOW (parent)); - - emu_add_address_or_vcard (parent, email, NULL); -} - -/** - * em_utils_add_vcard: - * Adds whole vCard to the addressbook. - **/ -void -em_utils_add_vcard (GtkWindow *parent, const gchar *vcard) -{ - g_return_if_fail (GTK_IS_WINDOW (parent)); - - emu_add_address_or_vcard (parent, NULL, vcard); -} - -/* ********************************************************************** */ /* Flag-for-Followup... */ /** diff --git a/mail/em-utils.h b/mail/em-utils.h index 14dc8cef23..e1064c520a 100644 --- a/mail/em-utils.h +++ b/mail/em-utils.h @@ -56,9 +56,6 @@ void em_utils_save_part(GtkWindow *parent, const gchar *prompt, CamelMimePart *p gboolean em_utils_save_part_to_file(GtkWindow *parent, const gchar *filename, CamelMimePart *part); void em_utils_save_messages (GtkWindow *parent, CamelFolder *folder, GPtrArray *uids); -void em_utils_add_address(GtkWindow *parent, const gchar *email); -void em_utils_add_vcard(GtkWindow *parent, const gchar *vcard); - void em_utils_flag_for_followup (EMailReader *reader, CamelFolder *folder, GPtrArray *uids); void em_utils_flag_for_followup_clear (GtkWindow *parent, CamelFolder *folder, GPtrArray *uids); void em_utils_flag_for_followup_completed (GtkWindow *parent, CamelFolder *folder, GPtrArray *uids); diff --git a/modules/addressbook/e-book-shell-backend.c b/modules/addressbook/e-book-shell-backend.c index 243ce3a848..a14b3bad16 100644 --- a/modules/addressbook/e-book-shell-backend.c +++ b/modules/addressbook/e-book-shell-backend.c @@ -37,6 +37,7 @@ #include "addressbook/gui/widgets/eab-gui-util.h" #include "addressbook/gui/contact-editor/e-contact-editor.h" +#include "addressbook/gui/contact-editor/e-contact-quick-add.h" #include "addressbook/gui/contact-list-editor/e-contact-list-editor.h" #include "addressbook/importers/evolution-addressbook-importers.h" @@ -379,6 +380,26 @@ book_shell_backend_init_preferences (EShell *shell) return FALSE; } +static void +book_shell_backend_quick_add_email_cb (EShell *shell, + const gchar *email) +{ + /* XXX This is an ugly hack but it's the only way I could think + * of to integrate this feature with other shell modules. */ + + e_contact_quick_add_free_form (email, NULL, NULL); +} + +static void +book_shell_backend_quick_add_vcard_cb (EShell *shell, + const gchar *vcard) +{ + /* XXX This is an ugly hack but it's the only way I could think + * of to integrate this feature with other shell modules. */ + + e_contact_quick_add_vcard (vcard, NULL, NULL); +} + static gboolean book_shell_backend_handle_uri_cb (EShellBackend *shell_backend, const gchar *uri) @@ -518,6 +539,14 @@ book_shell_backend_constructed (GObject *object) book_shell_backend_init_importers (); book_shell_backend_ensure_sources (shell_backend); + g_signal_connect ( + shell, "event::contact-quick-add-email", + G_CALLBACK (book_shell_backend_quick_add_email_cb), NULL); + + g_signal_connect_swapped ( + shell, "event::contact-quick-add-vcard", + G_CALLBACK (book_shell_backend_quick_add_vcard_cb), NULL); + g_signal_connect_swapped ( shell, "handle-uri", G_CALLBACK (book_shell_backend_handle_uri_cb), diff --git a/modules/calendar/e-memo-shell-content.c b/modules/calendar/e-memo-shell-content.c index 027beec1cd..0e8d73bbe5 100644 --- a/modules/calendar/e-memo-shell-content.c +++ b/modules/calendar/e-memo-shell-content.c @@ -200,7 +200,7 @@ memo_shell_content_cursor_change_cb (EMemoShellContent *memo_shell_content, memo_preview = e_memo_shell_content_get_memo_preview (memo_shell_content); if (e_table_selected_count (table) != 1) { - e_cal_component_preview_clear (memo_preview); + e_web_view_clear (E_WEB_VIEW (memo_preview)); return; } @@ -231,7 +231,7 @@ memo_shell_content_selection_change_cb (EMemoShellContent *memo_shell_content, /* XXX Old code emits a "selection-changed" signal here. */ if (e_table_selected_count (table) != 1) - e_cal_component_preview_clear (memo_preview); + e_web_view_clear (E_WEB_VIEW (memo_preview)); } static void @@ -391,6 +391,7 @@ memo_shell_content_constructed (GObject *object) EShellSettings *shell_settings; EShellBackend *shell_backend; EShellContent *shell_content; + EShellTaskbar *shell_taskbar; GalViewInstance *view_instance; icaltimezone *timezone; ETable *table; @@ -407,6 +408,7 @@ memo_shell_content_constructed (GObject *object) shell_content = E_SHELL_CONTENT (object); shell_view = e_shell_content_get_shell_view (shell_content); shell_backend = e_shell_view_get_shell_backend (shell_view); + shell_taskbar = e_shell_view_get_shell_taskbar (shell_view); shell = e_shell_backend_get_shell (shell_backend); shell_settings = e_shell_get_shell_settings (shell); @@ -458,6 +460,11 @@ memo_shell_content_constructed (GObject *object) priv->memo_preview = g_object_ref (widget); gtk_widget_show (widget); + g_signal_connect_swapped ( + widget, "status-message", + G_CALLBACK (e_shell_taskbar_set_message), + shell_taskbar); + /* Configure the memo table. */ widget = E_MEMO_TABLE (priv->memo_table)->etable; diff --git a/modules/calendar/e-memo-shell-view-actions.c b/modules/calendar/e-memo-shell-view-actions.c index 99761b2c74..463e01f71b 100644 --- a/modules/calendar/e-memo-shell-view-actions.c +++ b/modules/calendar/e-memo-shell-view-actions.c @@ -97,7 +97,7 @@ action_memo_delete_cb (GtkAction *action, e_memo_table_delete_selected (memo_table); e_memo_shell_view_set_status_message (memo_shell_view, NULL, -1.0); - e_cal_component_preview_clear (memo_preview); + e_web_view_clear (E_WEB_VIEW (memo_preview)); } static void diff --git a/modules/calendar/e-memo-shell-view-private.c b/modules/calendar/e-memo-shell-view-private.c index 0a96d29664..f1d331fab3 100644 --- a/modules/calendar/e-memo-shell-view-private.c +++ b/modules/calendar/e-memo-shell-view-private.c @@ -24,24 +24,6 @@ #include "widgets/menus/gal-view-factory-etable.h" static void -memo_shell_view_preview_on_url_cb (EShellView *shell_view, - const gchar *url) -{ - EShellTaskbar *shell_taskbar; - gchar *message; - - shell_taskbar = e_shell_view_get_shell_taskbar (shell_view); - - if (url == NULL || *url == '\0') - e_shell_taskbar_set_message (shell_taskbar, NULL); - else { - message = g_strdup_printf (_("Click to open %s"), url); - e_shell_taskbar_set_message (shell_taskbar, message); - g_free (message); - } -} - -static void memo_shell_view_table_popup_event_cb (EShellView *shell_view, GdkEventButton *event) { @@ -189,7 +171,6 @@ e_memo_shell_view_private_constructed (EMemoShellView *memo_shell_view) EShellContent *shell_content; EShellSidebar *shell_sidebar; EShellWindow *shell_window; - ECalComponentPreview *memo_preview; EMemoTable *memo_table; ECalModel *model; ETable *table; @@ -210,7 +191,6 @@ e_memo_shell_view_private_constructed (EMemoShellView *memo_shell_view) priv->memo_shell_sidebar = g_object_ref (shell_sidebar); memo_shell_content = E_MEMO_SHELL_CONTENT (shell_content); - memo_preview = e_memo_shell_content_get_memo_preview (memo_shell_content); memo_table = e_memo_shell_content_get_memo_table (memo_shell_content); model = e_memo_table_get_model (memo_table); table = e_memo_table_get_table (memo_table); @@ -224,11 +204,6 @@ e_memo_shell_view_private_constructed (EMemoShellView *memo_shell_view) memo_shell_view); g_signal_connect_swapped ( - memo_preview, "on-url", - G_CALLBACK (memo_shell_view_preview_on_url_cb), - memo_shell_view); - - g_signal_connect_swapped ( memo_table, "open-component", G_CALLBACK (e_memo_shell_view_open_memo), memo_shell_view); diff --git a/modules/calendar/e-memo-shell-view.c b/modules/calendar/e-memo-shell-view.c index 54dea9c444..ea869b55c4 100644 --- a/modules/calendar/e-memo-shell-view.c +++ b/modules/calendar/e-memo-shell-view.c @@ -151,7 +151,7 @@ memo_shell_view_execute_search (EShellView *shell_view) memo_preview = e_memo_shell_content_get_memo_preview (memo_shell_content); - e_cal_component_preview_clear (memo_preview); + e_web_view_clear (E_WEB_VIEW (memo_preview)); } static void diff --git a/modules/calendar/e-task-shell-content.c b/modules/calendar/e-task-shell-content.c index f78f142d60..8dea4b840b 100644 --- a/modules/calendar/e-task-shell-content.c +++ b/modules/calendar/e-task-shell-content.c @@ -201,7 +201,7 @@ task_shell_content_cursor_change_cb (ETaskShellContent *task_shell_content, task_preview = e_task_shell_content_get_task_preview (task_shell_content); if (e_table_selected_count (table) != 1) { - e_cal_component_preview_clear (task_preview); + e_web_view_clear (E_WEB_VIEW (task_preview)); return; } @@ -230,7 +230,7 @@ task_shell_content_selection_change_cb (ETaskShellContent *task_shell_content, task_preview = e_task_shell_content_get_task_preview (task_shell_content); if (e_table_selected_count (table) != 1) - e_cal_component_preview_clear (task_preview); + e_web_view_clear (E_WEB_VIEW (task_preview)); } static void @@ -388,6 +388,7 @@ task_shell_content_constructed (GObject *object) EShell *shell; EShellSettings *shell_settings; EShellContent *shell_content; + EShellTaskbar *shell_taskbar; EShellWindow *shell_window; EShellView *shell_view; GalViewInstance *view_instance; @@ -405,6 +406,7 @@ task_shell_content_constructed (GObject *object) shell_content = E_SHELL_CONTENT (object); shell_view = e_shell_content_get_shell_view (shell_content); + shell_taskbar = e_shell_view_get_shell_taskbar (shell_view); shell_window = e_shell_view_get_shell_window (shell_view); shell = e_shell_window_get_shell (shell_window); shell_settings = e_shell_get_shell_settings (shell); @@ -456,6 +458,11 @@ task_shell_content_constructed (GObject *object) priv->task_preview = g_object_ref (widget); gtk_widget_show (widget); + g_signal_connect_swapped ( + widget, "status-message", + G_CALLBACK (e_shell_taskbar_set_message), + shell_taskbar); + /* Configure the task table. */ widget = E_CALENDAR_TABLE (priv->task_table)->etable; diff --git a/modules/calendar/e-task-shell-view-actions.c b/modules/calendar/e-task-shell-view-actions.c index 7833873832..2592df2481 100644 --- a/modules/calendar/e-task-shell-view-actions.c +++ b/modules/calendar/e-task-shell-view-actions.c @@ -128,7 +128,7 @@ action_task_delete_cb (GtkAction *action, e_calendar_table_delete_selected (task_table); e_task_shell_view_set_status_message (task_shell_view, NULL, -1.0); - e_cal_component_preview_clear (task_preview); + e_web_view_clear (E_WEB_VIEW (task_preview)); } static void diff --git a/modules/calendar/e-task-shell-view-private.c b/modules/calendar/e-task-shell-view-private.c index 380d54ef3d..581ad88b47 100644 --- a/modules/calendar/e-task-shell-view-private.c +++ b/modules/calendar/e-task-shell-view-private.c @@ -47,24 +47,6 @@ task_shell_view_process_completed_tasks (ETaskShellView *task_shell_view) } static void -task_shell_view_preview_on_url_cb (EShellView *shell_view, - const gchar *url) -{ - EShellTaskbar *shell_taskbar; - gchar *message; - - shell_taskbar = e_shell_view_get_shell_taskbar (shell_view); - - if (url == NULL || *url == '\0') - e_shell_taskbar_set_message (shell_taskbar, NULL); - else { - message = g_strdup_printf (_("Click to open %s"), url); - e_shell_taskbar_set_message (shell_taskbar, message); - g_free (message); - } -} - -static void task_shell_view_table_popup_event_cb (EShellView *shell_view, GdkEventButton *event) { @@ -235,10 +217,10 @@ e_task_shell_view_private_constructed (ETaskShellView *task_shell_view) EShellView *shell_view; EShellBackend *shell_backend; EShellContent *shell_content; - EShellSettings *shell_settings; EShellSidebar *shell_sidebar; + EShellTaskbar *shell_taskbar; + EShellSettings *shell_settings; EShellWindow *shell_window; - ECalComponentPreview *task_preview; ECalendarTable *task_table; ECalModel *model; ETable *table; @@ -248,6 +230,7 @@ e_task_shell_view_private_constructed (ETaskShellView *task_shell_view) shell_backend = e_shell_view_get_shell_backend (shell_view); shell_content = e_shell_view_get_shell_content (shell_view); shell_sidebar = e_shell_view_get_shell_sidebar (shell_view); + shell_taskbar = e_shell_view_get_shell_taskbar (shell_view); shell_window = e_shell_view_get_shell_window (shell_view); shell = e_shell_window_get_shell (shell_window); @@ -262,7 +245,6 @@ e_task_shell_view_private_constructed (ETaskShellView *task_shell_view) priv->task_shell_sidebar = g_object_ref (shell_sidebar); task_shell_content = E_TASK_SHELL_CONTENT (shell_content); - task_preview = e_task_shell_content_get_task_preview (task_shell_content); task_table = e_task_shell_content_get_task_table (task_shell_content); model = e_calendar_table_get_model (task_table); table = e_calendar_table_get_table (task_table); @@ -276,11 +258,6 @@ e_task_shell_view_private_constructed (ETaskShellView *task_shell_view) task_shell_view); g_signal_connect_swapped ( - task_preview, "on-url", - G_CALLBACK (task_shell_view_preview_on_url_cb), - task_shell_view); - - g_signal_connect_swapped ( task_table, "open-component", G_CALLBACK (e_task_shell_view_open_task), task_shell_view); diff --git a/modules/calendar/e-task-shell-view.c b/modules/calendar/e-task-shell-view.c index 7237b1cddd..650037b730 100644 --- a/modules/calendar/e-task-shell-view.c +++ b/modules/calendar/e-task-shell-view.c @@ -263,7 +263,7 @@ task_shell_view_execute_search (EShellView *shell_view) task_preview = e_task_shell_content_get_task_preview (task_shell_content); - e_cal_component_preview_clear (task_preview); + e_web_view_clear (E_WEB_VIEW (task_preview)); } static void diff --git a/modules/mail/e-mail-shell-content.c b/modules/mail/e-mail-shell-content.c index ac740fb6c5..60ddde7727 100644 --- a/modules/mail/e-mail-shell-content.c +++ b/modules/mail/e-mail-shell-content.c @@ -438,7 +438,7 @@ mail_shell_content_constructed (GObject *object) GConfBridge *bridge; GtkWidget *container; GtkWidget *widget; - GtkHTML *html; + EWebView *web_view; GalViewCollection *view_collection; const gchar *key; @@ -454,7 +454,7 @@ mail_shell_content_constructed (GObject *object) shell_backend = e_shell_view_get_shell_backend (shell_view); view_collection = shell_view_class->view_collection; - html = EM_FORMAT_HTML (priv->html_display)->html; + web_view = E_WEB_VIEW (EM_FORMAT_HTML (priv->html_display)->html); /* Build content widgets. */ @@ -492,12 +492,12 @@ mail_shell_content_constructed (GObject *object) GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC); gtk_scrolled_window_set_shadow_type ( GTK_SCROLLED_WINDOW (widget), GTK_SHADOW_IN); - gtk_container_add (GTK_CONTAINER (widget), GTK_WIDGET (html)); + gtk_container_add (GTK_CONTAINER (widget), GTK_WIDGET (web_view)); gtk_box_pack_start (GTK_BOX (container), widget, TRUE, TRUE, 0); - gtk_widget_show (GTK_WIDGET (html)); + gtk_widget_show (GTK_WIDGET (web_view)); gtk_widget_show (widget); - widget = e_mail_search_bar_new (html); + widget = e_mail_search_bar_new (web_view); gtk_box_pack_start (GTK_BOX (container), widget, FALSE, FALSE, 0); priv->search_bar = g_object_ref (widget); gtk_widget_hide (widget); diff --git a/modules/mail/e-mail-shell-view-actions.c b/modules/mail/e-mail-shell-view-actions.c index adb288d8fb..9c79164a35 100644 --- a/modules/mail/e-mail-shell-view-actions.c +++ b/modules/mail/e-mail-shell-view-actions.c @@ -681,7 +681,7 @@ action_mail_smart_backward_cb (GtkAction *action, html = EM_FORMAT_HTML (html_display)->html; - if (gtk_html_command (html, "scroll-backward")) + if (e_web_view_scroll_backward (E_WEB_VIEW (html))) return; if (caret_mode || !magic_spacebar) @@ -744,7 +744,7 @@ action_mail_smart_forward_cb (GtkAction *action, html = EM_FORMAT_HTML (html_display)->html; - if (gtk_html_command (html, "scroll-forward")) + if (e_web_view_scroll_forward (E_WEB_VIEW (html))) return; if (caret_mode || !magic_spacebar) diff --git a/modules/mail/e-mail-shell-view-private.h b/modules/mail/e-mail-shell-view-private.h index 30724b26b5..5c52e1251c 100644 --- a/modules/mail/e-mail-shell-view-private.h +++ b/modules/mail/e-mail-shell-view-private.h @@ -36,6 +36,7 @@ #include "e-util/gconf-bridge.h" #include "e-util/e-account-utils.h" #include "filter/filter-part.h" +#include "widgets/misc/e-web-view.h" #include "widgets/misc/e-popup-action.h" #include "widgets/menus/gal-view-instance.h" diff --git a/plugins/vcard-inline/Makefile.am b/plugins/vcard-inline/Makefile.am index dd8f92fd1a..a1267507ae 100644 --- a/plugins/vcard-inline/Makefile.am +++ b/plugins/vcard-inline/Makefile.am @@ -6,8 +6,9 @@ NO_UNDEFINED_REQUIRED_LIBS = \ endif AM_CPPFLAGS = \ - -I$(top_srcdir) \ - $(EVOLUTION_ADDRESSBOOK_CFLAGS) \ + -I$(top_srcdir) \ + -I$(top_srcdir)/widgets \ + $(EVOLUTION_ADDRESSBOOK_CFLAGS) \ $(EVOLUTION_MAIL_CFLAGS) @EVO_PLUGIN_RULE@ diff --git a/po/POTFILES.in b/po/POTFILES.in index 5d6310101e..ec74fd86e5 100644 --- a/po/POTFILES.in +++ b/po/POTFILES.in @@ -387,9 +387,9 @@ plugins/mail-notification/mail-notification.c plugins/mail-notification/org-gnome-mail-notification.eplug.xml plugins/mail-to-task/mail-to-task.c plugins/mail-to-task/org-gnome-mail-to-task.eplug.xml +plugins/mailing-list-actions/mailing-list-actions.c plugins/mailing-list-actions/org-gnome-mailing-list-actions.eplug.xml plugins/mailing-list-actions/org-gnome-mailing-list-actions.error.xml -plugins/mailing-list-actions/org-gnome-mailing-list-actions.xml plugins/mark-all-read/mark-all-read.c plugins/mark-all-read/org-gnome-mark-all-read.eplug.xml plugins/plugin-manager/org-gnome-plugin-manager.eplug.xml @@ -505,6 +505,7 @@ widgets/misc/e-signature-editor.c widgets/misc/e-signature-manager.c widgets/misc/e-signature-script-dialog.c widgets/misc/e-url-entry.c +widgets/misc/e-web-view.c widgets/misc/ea-calendar-item.c widgets/table/e-cell-combo.c widgets/table/e-cell-date-edit.c diff --git a/shell/e-shell-view.c b/shell/e-shell-view.c index f580b1aa4e..0bfa17c0cc 100644 --- a/shell/e-shell-view.c +++ b/shell/e-shell-view.c @@ -401,6 +401,12 @@ shell_view_constructed (GObject *object) /* Invoke factory methods. */ + /* Create the taskbar widget first so the content and + * sidebar widgets can access it during construction. */ + widget = shell_view_class->new_shell_taskbar (shell_view); + shell_view->priv->shell_taskbar = g_object_ref_sink (widget); + gtk_widget_show (widget); + widget = shell_view_class->new_shell_content (shell_view); shell_view->priv->shell_content = g_object_ref_sink (widget); gtk_widget_show (widget); @@ -409,10 +415,6 @@ shell_view_constructed (GObject *object) shell_view->priv->shell_sidebar = g_object_ref_sink (widget); gtk_widget_show (widget); - widget = shell_view_class->new_shell_taskbar (shell_view); - shell_view->priv->shell_taskbar = g_object_ref_sink (widget); - gtk_widget_show (widget); - /* Size group should be safe to unreference now. */ g_object_unref (shell_view->priv->size_group); shell_view->priv->size_group = NULL; diff --git a/shell/e-shell-window-private.c b/shell/e-shell-window-private.c index 2cf24ba061..2934a82730 100644 --- a/shell/e-shell-window-private.c +++ b/shell/e-shell-window-private.c @@ -107,23 +107,20 @@ shell_window_init_switcher_style (EShellWindow *shell_window) static void shell_window_menu_item_select_cb (EShellWindow *shell_window, - GtkWidget *menu_item) + GtkWidget *widget) { GtkAction *action; GtkLabel *label; - gchar *tooltip = NULL; + const gchar *tooltip; - action = g_object_get_data (G_OBJECT (menu_item), "action"); - g_return_if_fail (GTK_IS_ACTION (action)); - - g_object_get (action, "tooltip", &tooltip, NULL); + action = gtk_widget_get_action (widget); + tooltip = gtk_action_get_tooltip (action); if (tooltip == NULL) return; label = GTK_LABEL (shell_window->priv->tooltip_label); gtk_label_set_text (label, tooltip); - g_free (tooltip); gtk_widget_show (shell_window->priv->tooltip_label); gtk_widget_hide (shell_window->priv->status_notebook); @@ -144,11 +141,6 @@ shell_window_connect_proxy_cb (EShellWindow *shell_window, if (!GTK_IS_MENU_ITEM (proxy)) return; - g_object_set_data_full ( - G_OBJECT (proxy), - "action", g_object_ref (action), - (GDestroyNotify) g_object_unref); - g_signal_connect_swapped ( proxy, "select", G_CALLBACK (shell_window_menu_item_select_cb), diff --git a/shell/e-shell.c b/shell/e-shell.c index d2a82675ae..bf664649fc 100644 --- a/shell/e-shell.c +++ b/shell/e-shell.c @@ -371,7 +371,7 @@ shell_load_modules (EShell *shell) } } -/* Helper for shell_process_backend() */ +/* Helper for shell_add_backend() */ static void shell_split_and_insert_items (GHashTable *hash_table, const gchar *items, @@ -392,14 +392,17 @@ shell_split_and_insert_items (GHashTable *hash_table, } static void -shell_process_backend (EShell *shell, - EShellBackend *shell_backend) +shell_add_backend (GType type, + EShell *shell) { EShellBackendClass *class; + EShellBackend *shell_backend; GHashTable *backends_by_name; GHashTable *backends_by_scheme; const gchar *string; + shell_backend = g_object_new (type, "shell", shell, NULL); + shell->priv->loaded_backends = g_list_insert_sorted ( shell->priv->loaded_backends, shell_backend, (GCompareFunc) e_shell_backend_compare); @@ -425,26 +428,6 @@ shell_process_backend (EShell *shell, } static void -shell_create_backends (EShell *shell) -{ - GType *children; - guint ii, n_children; - - /* Create an instance of each EShellBackend subclass. */ - children = g_type_children (E_TYPE_SHELL_BACKEND, &n_children); - - for (ii = 0; ii < n_children; ii++) { - EShellBackend *shell_backend; - GType type = children[ii]; - - shell_backend = g_object_new (type, "shell", shell, NULL); - shell_process_backend (shell, shell_backend); - } - - g_free (children); -} - -static void shell_sm_quit_requested_cb (EShell *shell, EggSMClient *sm_client) { @@ -596,7 +579,10 @@ shell_constructed (GObject *object) e_file_lock_create (); shell_load_modules (E_SHELL (object)); - shell_create_backends (E_SHELL (object)); + + e_type_traverse ( + E_TYPE_SHELL_BACKEND, (ETypeFunc) + shell_add_backend, object); } static gboolean diff --git a/widgets/misc/Makefile.am b/widgets/misc/Makefile.am index 29607758e5..91906b0448 100644 --- a/widgets/misc/Makefile.am +++ b/widgets/misc/Makefile.am @@ -86,6 +86,7 @@ widgetsinclude_HEADERS = \ e-spinner.h \ e-timeout-activity.h \ e-url-entry.h \ + e-web-view.h \ ea-calendar-cell.h \ ea-calendar-item.h \ ea-cell-table.h \ @@ -148,6 +149,7 @@ libemiscwidgets_la_SOURCES = \ e-signature-tree-view.c \ e-timeout-activity.c \ e-url-entry.c \ + e-web-view.c \ ea-calendar-cell.c \ ea-calendar-item.c \ ea-cell-table.c \ diff --git a/widgets/misc/e-attachment-view.c b/widgets/misc/e-attachment-view.c index 17a2b6c9b4..cd5301a987 100644 --- a/widgets/misc/e-attachment-view.c +++ b/widgets/misc/e-attachment-view.c @@ -682,12 +682,30 @@ attachment_view_update_actions (EAttachmentView *view) } static void +attachment_view_add_handler (GType type, + EAttachmentView *view) +{ + EAttachmentViewPrivate *priv; + EAttachmentHandler *handler; + const GtkTargetEntry *targets; + guint n_targets; + + priv = e_attachment_view_get_private (view); + + handler = g_object_new (type, "view", view, NULL); + + targets = e_attachment_handler_get_target_table (handler, &n_targets); + gtk_target_list_add_table (priv->target_list, targets, n_targets); + priv->drag_actions = e_attachment_handler_get_drag_actions (handler); + + g_ptr_array_add (priv->handlers, handler); +} + +static void attachment_view_init_handlers (EAttachmentView *view) { EAttachmentViewPrivate *priv; GtkTargetList *target_list; - GType *children; - guint ii; priv = e_attachment_view_get_private (view); @@ -700,25 +718,9 @@ attachment_view_init_handlers (EAttachmentView *view) priv->target_list = target_list; priv->drag_actions = GDK_ACTION_COPY; - children = g_type_children (E_TYPE_ATTACHMENT_HANDLER, NULL); - - for (ii = 0; children[ii] != G_TYPE_INVALID; ii++) { - EAttachmentHandler *handler; - const GtkTargetEntry *targets; - guint n_targets; - - handler = g_object_new (children[ii], "view", view, NULL); - - targets = e_attachment_handler_get_target_table ( - handler, &n_targets); - gtk_target_list_add_table (target_list, targets, n_targets); - priv->drag_actions |= - e_attachment_handler_get_drag_actions (handler); - - g_ptr_array_add (priv->handlers, handler); - } - - g_free (children); + e_type_traverse ( + E_TYPE_ATTACHMENT_HANDLER, (ETypeFunc) + attachment_view_add_handler, view); } static void diff --git a/widgets/misc/e-signature-preview.c b/widgets/misc/e-signature-preview.c index bbef65f39c..a9316e44ec 100644 --- a/widgets/misc/e-signature-preview.c +++ b/widgets/misc/e-signature-preview.c @@ -113,56 +113,17 @@ signature_preview_dispose (GObject *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; + EWebView *web_view; ESignature *signature; const gchar *filename; gboolean is_script; gchar *content = NULL; - gsize length; /* XXX We should show error messages in the preview. */ - html = GTK_HTML (preview); + web_view = E_WEB_VIEW (preview); signature = e_signature_preview_get_signature (preview); if (signature == NULL) @@ -182,27 +143,23 @@ signature_preview_refresh (ESignaturePreview *preview) if (content == NULL || *content == '\0') goto clear; - length = strlen (content); - if (e_signature_get_is_html (signature)) - gtk_html_load_from_string (html, content, length); + e_web_view_load_string (web_view, content); else { - GtkHTMLStream *stream; - - stream = gtk_html_begin_content ( - html, "text/html; charset=utf-8"); - gtk_html_write (html, stream, "<PRE>", 5); - if (length > 0) - gtk_html_write (html, stream, content, length); - gtk_html_write (html, stream, "</PRE>", 6); - gtk_html_end (html, stream, GTK_HTML_STREAM_OK); + gchar *string; + + string = g_strdup_printf ("<PRE>%s</PRE>", content); + e_web_view_load_string (web_view, string); + g_free (string); } g_free (content); + return; clear: - gtk_html_load_from_string (html, " ", 1); + e_web_view_clear (web_view); + g_free (content); } @@ -210,7 +167,6 @@ 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)); @@ -220,9 +176,6 @@ signature_preview_class_init (ESignaturePreviewClass *class) 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 ( @@ -282,7 +235,7 @@ e_signature_preview_get_type (void) }; type = g_type_register_static ( - GTK_TYPE_HTML, "ESignaturePreview", &type_info, 0); + E_TYPE_WEB_VIEW, "ESignaturePreview", &type_info, 0); } return type; diff --git a/widgets/misc/e-signature-preview.h b/widgets/misc/e-signature-preview.h index a4221832c2..d0d5c22eff 100644 --- a/widgets/misc/e-signature-preview.h +++ b/widgets/misc/e-signature-preview.h @@ -22,8 +22,8 @@ #ifndef E_SIGNATURE_PREVIEW_H #define E_SIGNATURE_PREVIEW_H -#include <gtkhtml/gtkhtml.h> #include <e-util/e-signature.h> +#include <misc/e-web-view.h> /* Standard GObject macros */ #define E_TYPE_SIGNATURE_PREVIEW \ @@ -51,12 +51,12 @@ typedef struct _ESignaturePreviewClass ESignaturePreviewClass; typedef struct _ESignaturePreviewPrivate ESignaturePreviewPrivate; struct _ESignaturePreview { - GtkHTML parent; + EWebView parent; ESignaturePreviewPrivate *priv; }; struct _ESignaturePreviewClass { - GtkHTMLClass parent_class; + EWebViewClass parent_class; /* Signals */ void (*refresh) (ESignaturePreview *preview); diff --git a/widgets/misc/e-web-view.c b/widgets/misc/e-web-view.c new file mode 100644 index 0000000000..a49fd22527 --- /dev/null +++ b/widgets/misc/e-web-view.c @@ -0,0 +1,1110 @@ +/* + * e-web-view.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-web-view.h" + +#include <config.h> +#include <string.h> +#include <glib/gi18n-lib.h> + +#include <camel/camel-internet-address.h> +#include <camel/camel-url.h> + +#include "e-util/e-util.h" +#include "e-util/e-plugin-ui.h" + +#define E_WEB_VIEW_GET_PRIVATE(obj) \ + (G_TYPE_INSTANCE_GET_PRIVATE \ + ((obj), E_TYPE_WEB_VIEW, EWebViewPrivate)) + +typedef struct _EWebViewRequest EWebViewRequest; + +struct _EWebViewPrivate { + GList *requests; + GtkUIManager *ui_manager; + gchar *selected_uri; +}; + +struct _EWebViewRequest { + GFile *file; + EWebView *web_view; + GCancellable *cancellable; + GInputStream *input_stream; + GtkHTMLStream *output_stream; + gchar buffer[4096]; +}; + +enum { + PROP_0, + PROP_ANIMATE, + PROP_CARET_MODE, + PROP_SELECTED_URI +}; + +enum { + POPUP_EVENT, + STATUS_MESSAGE, + STOP_LOADING, + UPDATE_ACTIONS, + LAST_SIGNAL +}; + +static gpointer parent_class; +static guint signals[LAST_SIGNAL]; + +static const gchar *ui = +"<ui>" +" <popup name='context'>" +" <placeholder name='custom-actions-1'>" +" <menuitem action='http-open'/>" +" <menuitem action='send-message'/>" +" </placeholder>" +" <placeholder name='custom-actions-2'>" +" <menuitem action='uri-copy'/>" +" <menuitem action='mailto-copy'/>" +" </placeholder>" +" <placeholder name='custom-actions-3'/>" +" </popup>" +"</ui>"; + +static EWebViewRequest * +web_view_request_new (EWebView *web_view, + const gchar *uri, + GtkHTMLStream *stream) +{ + EWebViewRequest *request; + GList *list; + + request = g_slice_new (EWebViewRequest); + + /* Try to detect file paths posing as URIs. */ + if (*uri == '/') + request->file = g_file_new_for_path (uri); + else + request->file = g_file_new_for_uri (uri); + + request->web_view = g_object_ref (web_view); + request->cancellable = g_cancellable_new (); + request->input_stream = NULL; + request->output_stream = stream; + + list = request->web_view->priv->requests; + list = g_list_prepend (list, request); + request->web_view->priv->requests = list; + + return request; +} + +static void +web_view_request_free (EWebViewRequest *request) +{ + GList *list; + + list = request->web_view->priv->requests; + list = g_list_remove (list, request); + request->web_view->priv->requests = list; + + g_object_unref (request->file); + g_object_unref (request->web_view); + g_object_unref (request->cancellable); + + if (request->input_stream != NULL) + g_object_unref (request->input_stream); + + g_slice_free (EWebViewRequest, request); +} + +static void +web_view_request_cancel (EWebViewRequest *request) +{ + g_cancellable_cancel (request->cancellable); +} + +static gboolean +web_view_request_check_for_error (EWebViewRequest *request, + GError *error) +{ + GtkHTML *html; + GtkHTMLStream *stream; + + if (error == NULL) + return FALSE; + + /* XXX Should we log errors that are not cancellations? */ + + html = GTK_HTML (request->web_view); + stream = request->output_stream; + + gtk_html_end (html, stream, GTK_HTML_STREAM_ERROR); + web_view_request_free (request); + g_error_free (error); + + return TRUE; +} + +static void +web_view_request_stream_read_cb (GInputStream *input_stream, + GAsyncResult *result, + EWebViewRequest *request) +{ + GtkHTML *html; + gssize bytes_read; + GError *error = NULL; + + html = GTK_HTML (request->web_view); + bytes_read = g_input_stream_read_finish (input_stream, result, &error); + + if (web_view_request_check_for_error (request, error)) + return; + + if (bytes_read == 0) { + gtk_html_end ( + GTK_HTML (request->web_view), + request->output_stream, GTK_HTML_STREAM_OK); + web_view_request_free (request); + return; + } + + gtk_html_write ( + GTK_HTML (request->web_view), + request->output_stream, request->buffer, bytes_read); + + g_input_stream_read_async ( + request->input_stream, request->buffer, + sizeof (request->buffer), G_PRIORITY_DEFAULT, + request->cancellable, (GAsyncReadyCallback) + web_view_request_stream_read_cb, request); +} + +static void +web_view_request_read_cb (GFile *file, + GAsyncResult *result, + EWebViewRequest *request) +{ + GFileInputStream *input_stream; + GError *error = NULL; + + /* Input stream might be NULL, so don't use cast macro. */ + input_stream = g_file_read_finish (file, result, &error); + request->input_stream = (GInputStream *) input_stream; + + if (web_view_request_check_for_error (request, error)) + return; + + g_input_stream_read_async ( + request->input_stream, request->buffer, + sizeof (request->buffer), G_PRIORITY_DEFAULT, + request->cancellable, (GAsyncReadyCallback) + web_view_request_stream_read_cb, request); +} + +static void +action_http_open_cb (GtkAction *action, + EWebView *web_view) +{ + const gchar *uri; + gpointer parent; + + parent = gtk_widget_get_toplevel (GTK_WIDGET (web_view)); + parent = GTK_WIDGET_TOPLEVEL (parent) ? parent : NULL; + + uri = e_web_view_get_selected_uri (web_view); + g_return_if_fail (uri != NULL); + + e_show_uri (parent, uri); +} + +static void +action_mailto_copy_cb (GtkAction *action, + EWebView *web_view) +{ + CamelURL *curl; + CamelInternetAddress *inet_addr; + GtkClipboard *clipboard; + const gchar *uri; + gchar *text; + + clipboard = gtk_clipboard_get (GDK_SELECTION_CLIPBOARD); + uri = e_web_view_get_selected_uri (web_view); + g_return_if_fail (uri != NULL); + + /* This should work because we checked it in update_actions(). */ + curl = camel_url_new (uri, NULL); + g_return_if_fail (curl != NULL); + + inet_addr = camel_internet_address_new (); + camel_address_decode (CAMEL_ADDRESS (inet_addr), curl->path); + text = camel_address_encode (CAMEL_ADDRESS (inet_addr)); + if (text == NULL || *text == '\0') + text = g_strdup (uri + strlen ("mailto:")); + + camel_object_unref (inet_addr); + camel_url_free (curl); + + gtk_clipboard_set_text (clipboard, text, -1); + gtk_clipboard_store (clipboard); + + g_free (text); +} + +static void +action_send_message_cb (GtkAction *action, + EWebView *web_view) +{ + const gchar *uri; + gpointer parent; + + parent = gtk_widget_get_toplevel (GTK_WIDGET (web_view)); + parent = GTK_WIDGET_TOPLEVEL (parent) ? parent : NULL; + + uri = e_web_view_get_selected_uri (web_view); + g_return_if_fail (uri != NULL); + + e_show_uri (parent, uri); +} + +static void +action_uri_copy_cb (GtkAction *action, + EWebView *web_view) +{ + GtkClipboard *clipboard; + const gchar *uri; + + clipboard = gtk_clipboard_get (GDK_SELECTION_CLIPBOARD); + uri = e_web_view_get_selected_uri (web_view); + g_return_if_fail (uri != NULL); + + gtk_clipboard_set_text (clipboard, uri, -1); + gtk_clipboard_store (clipboard); +} + +static GtkActionEntry uri_entries[] = { + + { "uri-copy", + GTK_STOCK_COPY, + N_("_Copy Link Location"), + NULL, + N_("Copy the link to the clipboard"), + G_CALLBACK (action_uri_copy_cb) } +}; + +static GtkActionEntry http_entries[] = { + + { "http-open", + "emblem-web", + N_("_Open Link in Browser"), + NULL, + N_("Open the link in a web browser"), + G_CALLBACK (action_http_open_cb) } +}; + +static GtkActionEntry mailto_entries[] = { + + { "mailto-copy", + GTK_STOCK_COPY, + N_("_Copy Email Address"), + NULL, + N_("Copy the email address to the clipboard"), + G_CALLBACK (action_mailto_copy_cb) }, + + { "send-message", + "mail-message-new", + N_("_Send New Message To..."), + NULL, + N_("Send a mail message to this address"), + G_CALLBACK (action_send_message_cb) } +}; + +static gboolean +web_view_button_press_event_cb (EWebView *web_view, + GdkEventButton *event, + GtkHTML *frame) +{ + gboolean event_handled = FALSE; + gchar *uri; + + if (event != NULL && event->button != 3) + return FALSE; + + uri = e_web_view_extract_uri (web_view, event, frame); + + if (uri == NULL || g_str_has_prefix (uri, "##")) { + g_free (uri); + return FALSE; + } + + g_signal_emit ( + web_view, signals[POPUP_EVENT], 0, + event, uri, &event_handled); + + g_free (uri); + + return event_handled; +} + +static void +web_view_menu_item_select_cb (EWebView *web_view, + GtkWidget *widget) +{ + GtkAction *action; + const gchar *tooltip; + + action = gtk_widget_get_action (widget); + tooltip = gtk_action_get_tooltip (action); + + if (tooltip == NULL) + return; + + e_web_view_status_message (web_view, tooltip); +} + +static void +web_view_menu_item_deselect_cb (EWebView *web_view) +{ + e_web_view_status_message (web_view, NULL); +} + +static void +web_view_connect_proxy_cb (EWebView *web_view, + GtkAction *action, + GtkWidget *proxy) +{ + if (!GTK_IS_MENU_ITEM (proxy)) + return; + + g_signal_connect_swapped ( + proxy, "select", + G_CALLBACK (web_view_menu_item_select_cb), web_view); + + g_signal_connect_swapped ( + proxy, "deselect", + G_CALLBACK (web_view_menu_item_deselect_cb), web_view); +} + +static void +web_view_set_property (GObject *object, + guint property_id, + const GValue *value, + GParamSpec *pspec) +{ + switch (property_id) { + case PROP_ANIMATE: + e_web_view_set_animate ( + E_WEB_VIEW (object), + g_value_get_boolean (value)); + return; + + case PROP_CARET_MODE: + e_web_view_set_caret_mode ( + E_WEB_VIEW (object), + g_value_get_boolean (value)); + return; + + case PROP_SELECTED_URI: + e_web_view_set_selected_uri ( + E_WEB_VIEW (object), + g_value_get_string (value)); + return; + } + + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); +} + +static void +web_view_get_property (GObject *object, + guint property_id, + GValue *value, + GParamSpec *pspec) +{ + switch (property_id) { + case PROP_ANIMATE: + g_value_set_boolean ( + value, e_web_view_get_animate ( + E_WEB_VIEW (object))); + return; + + case PROP_CARET_MODE: + g_value_set_boolean ( + value, e_web_view_get_caret_mode ( + E_WEB_VIEW (object))); + return; + + case PROP_SELECTED_URI: + g_value_set_string ( + value, e_web_view_get_selected_uri ( + E_WEB_VIEW (object))); + return; + } + + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); +} + +static void +web_view_dispose (GObject *object) +{ + EWebViewPrivate *priv; + + priv = E_WEB_VIEW_GET_PRIVATE (object); + + if (priv->ui_manager != NULL) { + g_object_unref (priv->ui_manager); + priv->ui_manager = NULL; + } + + /* Chain up to parent's dispose() method. */ + G_OBJECT_CLASS (parent_class)->dispose (object); +} + +static void +web_view_finalize (GObject *object) +{ + EWebViewPrivate *priv; + + priv = E_WEB_VIEW_GET_PRIVATE (object); + + /* All URI requests should be complete or cancelled by now. */ + if (priv->requests != NULL) + g_warning ("Finalizing EWebView with active URI requests"); + + g_free (priv->selected_uri); + + /* Chain up to parent's finalize() method. */ + G_OBJECT_CLASS (parent_class)->finalize (object); +} + +static gboolean +web_view_button_press_event (GtkWidget *widget, + GdkEventButton *event) +{ + GtkWidgetClass *widget_class; + EWebView *web_view; + + web_view = E_WEB_VIEW (widget); + + if (web_view_button_press_event_cb (web_view, event, NULL)) + return TRUE; + + /* Chain up to parent's button_press_event() method. */ + widget_class = GTK_WIDGET_CLASS (parent_class); + return widget_class->button_press_event (widget, event); +} + +static gboolean +web_view_scroll_event (GtkWidget *widget, + GdkEventScroll *event) +{ + if (event->state & GDK_CONTROL_MASK) { + switch (event->direction) { + case GDK_SCROLL_UP: + gtk_html_zoom_in (GTK_HTML (widget)); + return TRUE; + case GDK_SCROLL_DOWN: + gtk_html_zoom_out (GTK_HTML (widget)); + return TRUE; + default: + break; + } + } + + return FALSE; +} + +static void +web_view_url_requested (GtkHTML *html, + const gchar *uri, + GtkHTMLStream *stream) +{ + EWebViewRequest *request; + + request = web_view_request_new (E_WEB_VIEW (html), uri, stream); + + g_file_read_async ( + request->file, G_PRIORITY_DEFAULT, + request->cancellable, (GAsyncReadyCallback) + web_view_request_read_cb, request); +} + +static void +web_view_link_clicked (GtkHTML *html, + const gchar *uri) +{ + gpointer parent; + + parent = gtk_widget_get_toplevel (GTK_WIDGET (html)); + parent = GTK_WIDGET_TOPLEVEL (parent) ? parent : NULL; + + e_show_uri (parent, uri); +} + +static void +web_view_on_url (GtkHTML *html, + const gchar *uri) +{ + EWebView *web_view; + CamelInternetAddress *address; + CamelURL *curl; + const gchar *format = NULL; + gchar *message = NULL; + gchar *who; + + web_view = E_WEB_VIEW (html); + + if (uri == NULL || *uri == '\0') + goto exit; + + if (g_str_has_prefix (uri, "mailto:")) + format = _("Click to mail %s"); + else if (g_str_has_prefix (uri, "callto:")) + format = _("Click to call %s"); + else if (g_str_has_prefix (uri, "h323:")) + format = _("Click to call %s"); + else if (g_str_has_prefix (uri, "sip:")) + format = _("Click to call %s"); + else if (g_str_has_prefix (uri, "##")) + message = g_strdup (_("Click to hide/unhide addresses")); + else + message = g_strdup_printf (_("Click to open %s"), uri); + + if (format == NULL) + goto exit; + + /* XXX Use something other than Camel here. Surely + * there's other APIs around that can do this. */ + curl = camel_url_new (uri, NULL); + address = camel_internet_address_new (); + camel_address_decode (CAMEL_ADDRESS (address), curl->path); + who = camel_address_format (CAMEL_ADDRESS (address)); + camel_object_unref (address); + camel_url_free (curl); + + if (who == NULL) + who = g_strdup (strchr (uri, ':') + 1); + + message = g_strdup_printf (format, who); + + g_free (who); + +exit: + e_web_view_status_message (web_view, message); + + g_free (message); +} + +static void +web_view_iframe_created (GtkHTML *html, + GtkHTML *iframe) +{ + g_signal_connect_swapped ( + iframe, "button-press-event", + G_CALLBACK (web_view_button_press_event_cb), html); +} + +static gchar * +web_view_extract_uri (EWebView *web_view, + GdkEventButton *event, + GtkHTML *html) +{ + gchar *uri; + + if (event != NULL) + uri = gtk_html_get_url_at (html, event->x, event->y); + else + uri = gtk_html_get_cursor_url (html); + + return uri; +} + +static gboolean +web_view_popup_event (EWebView *web_view, + GdkEventButton *event, + const gchar *uri) +{ + e_web_view_set_selected_uri (web_view, uri); + e_web_view_show_popup_menu (web_view, event, NULL, NULL); + + return TRUE; +} + +static void +web_view_stop_loading (EWebView *web_view) +{ + g_list_foreach ( + web_view->priv->requests, (GFunc) + web_view_request_cancel, NULL); + + gtk_html_stop (GTK_HTML (web_view)); +} + +static void +web_view_update_actions (EWebView *web_view) +{ + CamelURL *curl; + GtkActionGroup *action_group; + gboolean scheme_is_http; + gboolean scheme_is_mailto; + gboolean uri_is_valid; + gboolean visible; + const gchar *uri; + + uri = e_web_view_get_selected_uri (web_view); + g_return_if_fail (uri != NULL); + + /* Parse the URI early so we know if the actions will work. */ + curl = camel_url_new (uri, NULL); + uri_is_valid = (curl != NULL); + camel_url_free (curl); + + scheme_is_http = + (g_ascii_strncasecmp (uri, "http:", 5) == 0) || + (g_ascii_strncasecmp (uri, "https:", 6) == 0); + + scheme_is_mailto = + (g_ascii_strncasecmp (uri, "mailto:", 7) == 0); + + /* Allow copying the URI even if it's malformed. */ + visible = !scheme_is_mailto; + action_group = e_web_view_get_action_group (web_view, "uri"); + gtk_action_group_set_visible (action_group, visible); + + visible = uri_is_valid && scheme_is_http; + action_group = e_web_view_get_action_group (web_view, "http"); + gtk_action_group_set_visible (action_group, visible); + + visible = uri_is_valid && scheme_is_mailto; + action_group = e_web_view_get_action_group (web_view, "mailto"); + gtk_action_group_set_visible (action_group, visible); +} + +static void +web_view_class_init (EWebViewClass *class) +{ + GObjectClass *object_class; + GtkWidgetClass *widget_class; + GtkHTMLClass *html_class; + + parent_class = g_type_class_peek_parent (class); + g_type_class_add_private (class, sizeof (EWebViewPrivate)); + + object_class = G_OBJECT_CLASS (class); + object_class->set_property = web_view_set_property; + object_class->get_property = web_view_get_property; + object_class->dispose = web_view_dispose; + object_class->finalize = web_view_finalize; + + widget_class = GTK_WIDGET_CLASS (class); + widget_class->button_press_event = web_view_button_press_event; + widget_class->scroll_event = web_view_scroll_event; + + html_class = GTK_HTML_CLASS (class); + html_class->url_requested = web_view_url_requested; + html_class->link_clicked = web_view_link_clicked; + html_class->on_url = web_view_on_url; + html_class->iframe_created = web_view_iframe_created; + + class->extract_uri = web_view_extract_uri; + class->popup_event = web_view_popup_event; + class->stop_loading = web_view_stop_loading; + class->update_actions = web_view_update_actions; + + g_object_class_install_property ( + object_class, + PROP_ANIMATE, + g_param_spec_boolean ( + "animate", + "Animate Images", + NULL, + FALSE, + G_PARAM_READWRITE)); + + g_object_class_install_property ( + object_class, + PROP_CARET_MODE, + g_param_spec_boolean ( + "caret-mode", + "Caret Mode", + NULL, + FALSE, + G_PARAM_READWRITE)); + + g_object_class_install_property ( + object_class, + PROP_SELECTED_URI, + g_param_spec_string ( + "selected-uri", + "Selected URI", + NULL, + NULL, + G_PARAM_READWRITE)); + + signals[POPUP_EVENT] = g_signal_new ( + "popup-event", + G_TYPE_FROM_CLASS (class), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (EWebViewClass, popup_event), + g_signal_accumulator_true_handled, NULL, + e_marshal_BOOLEAN__BOXED_STRING, + G_TYPE_BOOLEAN, 2, + GDK_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE, + G_TYPE_STRING); + + signals[STATUS_MESSAGE] = g_signal_new ( + "status-message", + G_TYPE_FROM_CLASS (class), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (EWebViewClass, status_message), + NULL, NULL, + g_cclosure_marshal_VOID__STRING, + G_TYPE_NONE, 1, + G_TYPE_STRING); + + signals[STOP_LOADING] = g_signal_new ( + "stop-loading", + G_TYPE_FROM_CLASS (class), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (EWebViewClass, stop_loading), + NULL, NULL, + g_cclosure_marshal_VOID__VOID, + G_TYPE_NONE, 0); + + signals[UPDATE_ACTIONS] = g_signal_new ( + "update-actions", + G_TYPE_FROM_CLASS (class), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (EWebViewClass, update_actions), + NULL, NULL, + g_cclosure_marshal_VOID__VOID, + G_TYPE_NONE, 0); +} + +static void +web_view_init (EWebView *web_view) +{ + GtkUIManager *ui_manager; + GtkActionGroup *action_group; + const gchar *domain = GETTEXT_PACKAGE; + const gchar *id; + GError *error = NULL; + + web_view->priv = E_WEB_VIEW_GET_PRIVATE (web_view); + + ui_manager = gtk_ui_manager_new (); + web_view->priv->ui_manager = ui_manager; + + g_signal_connect_swapped ( + ui_manager, "connect-proxy", + G_CALLBACK (web_view_connect_proxy_cb), web_view); + + action_group = gtk_action_group_new ("uri"); + gtk_action_group_set_translation_domain (action_group, domain); + gtk_ui_manager_insert_action_group (ui_manager, action_group, 0); + g_object_unref (action_group); + + gtk_action_group_add_actions ( + action_group, uri_entries, + G_N_ELEMENTS (uri_entries), web_view); + + action_group = gtk_action_group_new ("http"); + gtk_action_group_set_translation_domain (action_group, domain); + gtk_ui_manager_insert_action_group (ui_manager, action_group, 0); + g_object_unref (action_group); + + gtk_action_group_add_actions ( + action_group, http_entries, + G_N_ELEMENTS (http_entries), web_view); + + action_group = gtk_action_group_new ("mailto"); + gtk_action_group_set_translation_domain (action_group, domain); + gtk_ui_manager_insert_action_group (ui_manager, action_group, 0); + g_object_unref (action_group); + + gtk_action_group_add_actions ( + action_group, mailto_entries, + G_N_ELEMENTS (mailto_entries), web_view); + + /* Because we are loading from a hard-coded string, there is + * no chance of I/O errors. Failure here implies a malformed + * UI definition. Full stop. */ + gtk_ui_manager_add_ui_from_string (ui_manager, ui, -1, &error); + if (error != NULL) + g_error ("%s", error->message); + + id = "org.gnome.evolution.webview"; + e_plugin_ui_register_manager (ui_manager, id, web_view); + e_plugin_ui_enable_manager (ui_manager, id); +} + +GType +e_web_view_get_type (void) +{ + static GType type = 0; + + if (G_UNLIKELY (type == 0)) { + static const GTypeInfo type_info = { + sizeof (EWebViewClass), + (GBaseInitFunc) NULL, + (GBaseFinalizeFunc) NULL, + (GClassInitFunc) web_view_class_init, + (GClassFinalizeFunc) NULL, + NULL, /* class_data */ + sizeof (EWebView), + 0, /* n_preallocs */ + (GInstanceInitFunc) web_view_init, + NULL /* value_table */ + }; + + type = g_type_register_static ( + GTK_TYPE_HTML, "EWebView", &type_info, 0); + } + + return type; +} + +GtkWidget * +e_web_view_new (void) +{ + return g_object_new (E_TYPE_WEB_VIEW, NULL); +} + +void +e_web_view_clear (EWebView *web_view) +{ + g_return_if_fail (E_IS_WEB_VIEW (web_view)); + + gtk_html_load_empty (GTK_HTML (web_view)); +} + +void +e_web_view_load_string (EWebView *web_view, + const gchar *string) +{ + g_return_if_fail (E_IS_WEB_VIEW (web_view)); + + if (string != NULL && *string != '\0') + gtk_html_load_from_string (GTK_HTML (web_view), string, -1); + else + e_web_view_clear (web_view); +} + +gboolean +e_web_view_get_animate (EWebView *web_view) +{ + /* XXX This is just here to maintain symmetry + * with e_web_view_set_animate(). */ + + g_return_val_if_fail (E_IS_WEB_VIEW (web_view), FALSE); + + return gtk_html_get_animate (GTK_HTML (web_view)); +} + +void +e_web_view_set_animate (EWebView *web_view, + gboolean animate) +{ + /* XXX GtkHTML does not utilize GObject properties as well + * as it could. This just wraps gtk_html_set_animate() + * so we can get a "notify::animate" signal. */ + + g_return_if_fail (E_IS_WEB_VIEW (web_view)); + + gtk_html_set_animate (GTK_HTML (web_view), animate); + + g_object_notify (G_OBJECT (web_view), "animate"); +} + +gboolean +e_web_view_get_caret_mode (EWebView *web_view) +{ + /* XXX This is just here to maintain symmetry + * with e_web_view_set_caret_mode(). */ + + g_return_val_if_fail (E_IS_WEB_VIEW (web_view), FALSE); + + return gtk_html_get_caret_mode (GTK_HTML (web_view)); +} + +void +e_web_view_set_caret_mode (EWebView *web_view, + gboolean caret_mode) +{ + /* XXX GtkHTML does not utilize GObject properties as well + * as it could. This just wraps gtk_html_set_caret_mode() + * so we can get a "notify::caret-mode" signal. */ + + g_return_if_fail (E_IS_WEB_VIEW (web_view)); + + gtk_html_set_caret_mode (GTK_HTML (web_view), caret_mode); + + g_object_notify (G_OBJECT (web_view), "caret-mode"); +} + +const gchar * +e_web_view_get_selected_uri (EWebView *web_view) +{ + g_return_val_if_fail (E_IS_WEB_VIEW (web_view), NULL); + + return web_view->priv->selected_uri; +} + +void +e_web_view_set_selected_uri (EWebView *web_view, + const gchar *selected_uri) +{ + g_return_if_fail (E_IS_WEB_VIEW (web_view)); + + g_free (web_view->priv->selected_uri); + web_view->priv->selected_uri = g_strdup (selected_uri); + + g_object_notify (G_OBJECT (web_view), "selected-uri"); +} + +GtkAction * +e_web_view_get_action (EWebView *web_view, + const gchar *action_name) +{ + GtkUIManager *ui_manager; + + g_return_val_if_fail (E_IS_WEB_VIEW (web_view), NULL); + g_return_val_if_fail (action_name != NULL, NULL); + + ui_manager = e_web_view_get_ui_manager (web_view); + + return e_lookup_action (ui_manager, action_name); +} + +GtkActionGroup * +e_web_view_get_action_group (EWebView *web_view, + const gchar *group_name) +{ + GtkUIManager *ui_manager; + + g_return_val_if_fail (E_IS_WEB_VIEW (web_view), NULL); + g_return_val_if_fail (group_name != NULL, NULL); + + ui_manager = e_web_view_get_ui_manager (web_view); + + return e_lookup_action_group (ui_manager, group_name); +} + +gchar * +e_web_view_extract_uri (EWebView *web_view, + GdkEventButton *event, + GtkHTML *frame) +{ + EWebViewClass *class; + + g_return_val_if_fail (E_IS_WEB_VIEW (web_view), NULL); + + if (frame == NULL) + frame = GTK_HTML (web_view); + + class = E_WEB_VIEW_GET_CLASS (web_view); + g_return_val_if_fail (class->extract_uri != NULL, NULL); + + return class->extract_uri (web_view, event, frame); +} + +gboolean +e_web_view_scroll_forward (EWebView *web_view) +{ + g_return_val_if_fail (E_IS_WEB_VIEW (web_view), FALSE); + + return gtk_html_command (GTK_HTML (web_view), "scroll-forward"); +} + +gboolean +e_web_view_scroll_backward (EWebView *web_view) +{ + g_return_val_if_fail (E_IS_WEB_VIEW (web_view), FALSE); + + return gtk_html_command (GTK_HTML (web_view), "scroll-backward"); +} + +GtkUIManager * +e_web_view_get_ui_manager (EWebView *web_view) +{ + g_return_val_if_fail (E_IS_WEB_VIEW (web_view), NULL); + + return web_view->priv->ui_manager; +} + +GtkWidget * +e_web_view_get_popup_menu (EWebView *web_view) +{ + GtkUIManager *ui_manager; + GtkWidget *menu; + + g_return_val_if_fail (E_IS_WEB_VIEW (web_view), NULL); + + ui_manager = e_web_view_get_ui_manager (web_view); + menu = gtk_ui_manager_get_widget (ui_manager, "/context"); + g_return_val_if_fail (GTK_IS_MENU (menu), NULL); + + return menu; +} + +void +e_web_view_show_popup_menu (EWebView *web_view, + GdkEventButton *event, + GtkMenuPositionFunc func, + gpointer user_data) +{ + GtkWidget *menu; + + g_return_if_fail (E_IS_WEB_VIEW (web_view)); + + e_web_view_update_actions (web_view); + + menu = e_web_view_get_popup_menu (web_view); + + if (event != NULL) + gtk_menu_popup ( + GTK_MENU (menu), NULL, NULL, func, + user_data, event->button, event->time); + else + gtk_menu_popup ( + GTK_MENU (menu), NULL, NULL, func, + user_data, 0, gtk_get_current_event_time ()); +} + +void +e_web_view_status_message (EWebView *web_view, + const gchar *status_message) +{ + g_return_if_fail (E_IS_WEB_VIEW (web_view)); + + g_signal_emit (web_view, signals[STATUS_MESSAGE], 0, status_message); +} + +void +e_web_view_stop_loading (EWebView *web_view) +{ + g_return_if_fail (E_IS_WEB_VIEW (web_view)); + + g_signal_emit (web_view, signals[STOP_LOADING], 0); +} + +void +e_web_view_update_actions (EWebView *web_view) +{ + g_return_if_fail (E_IS_WEB_VIEW (web_view)); + + g_signal_emit (web_view, signals[UPDATE_ACTIONS], 0); +} diff --git a/widgets/misc/e-web-view.h b/widgets/misc/e-web-view.h new file mode 100644 index 0000000000..3bce2b4887 --- /dev/null +++ b/widgets/misc/e-web-view.h @@ -0,0 +1,119 @@ +/* + * e-web-view.h + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) version 3. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with the program; if not, see <http://www.gnu.org/licenses/> + * + * + * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com) + * + */ + +/* This is intended to serve as a common base class for all HTML viewing + * needs in Evolution. Currently based on GtkHTML, the idea is to wrap + * the GtkHTML API enough that we no longer have to make direct calls to + * it. This should help smooth the transition to WebKit/GTK+. + * + * This class handles basic tasks like mouse hovers over links, clicked + * links, and servicing URI requests asynchronously via GIO. */ + +#ifndef E_WEB_VIEW_H +#define E_WEB_VIEW_H + +#include <gtkhtml/gtkhtml.h> + +/* Standard GObject macros */ +#define E_TYPE_WEB_VIEW \ + (e_web_view_get_type ()) +#define E_WEB_VIEW(obj) \ + (G_TYPE_CHECK_INSTANCE_CAST \ + ((obj), E_TYPE_WEB_VIEW, EWebView)) +#define E_WEB_VIEW_CLASS(cls) \ + (G_TYPE_CHECK_CLASS_CAST \ + ((cls), E_TYPE_WEB_VIEW, EWebViewClass)) +#define E_IS_WEB_VIEW(obj) \ + (G_TYPE_CHECK_INSTANCE_TYPE \ + ((obj), E_TYPE_WEB_VIEW)) +#define E_IS_WEB_VIEW_CLASS(cls) \ + (G_TYPE_CHECK_CLASS_TYPE \ + ((cls), E_TYPE_WEB_VIEW)) +#define E_WEB_VIEW_GET_CLASS(obj) \ + (G_TYPE_INSTANCE_GET_CLASS \ + ((obj), E_TYPE_WEB_VIEW, EWebViewClass)) + +G_BEGIN_DECLS + +typedef struct _EWebView EWebView; +typedef struct _EWebViewClass EWebViewClass; +typedef struct _EWebViewPrivate EWebViewPrivate; + +struct _EWebView { + GtkHTML parent; + EWebViewPrivate *priv; +}; + +struct _EWebViewClass { + GtkHTMLClass parent_class; + + /* Methods */ + gchar * (*extract_uri) (EWebView *web_view, + GdkEventButton *event, + GtkHTML *frame); + + /* Signals */ + gboolean (*popup_event) (EWebView *web_view, + GdkEventButton *event, + const gchar *uri); + void (*status_message) (EWebView *web_view, + const gchar *status_message); + void (*stop_loading) (EWebView *web_view); + void (*update_actions) (EWebView *web_view); +}; + +GType e_web_view_get_type (void); +GtkWidget * e_web_view_new (void); +void e_web_view_clear (EWebView *web_view); +void e_web_view_load_string (EWebView *web_view, + const gchar *string); +gboolean e_web_view_get_animate (EWebView *web_view); +void e_web_view_set_animate (EWebView *web_view, + gboolean animate); +gboolean e_web_view_get_caret_mode (EWebView *web_view); +void e_web_view_set_caret_mode (EWebView *web_view, + gboolean caret_mode); +const gchar * e_web_view_get_selected_uri (EWebView *web_view); +void e_web_view_set_selected_uri (EWebView *web_view, + const gchar *selected_uri); +GtkAction * e_web_view_get_action (EWebView *web_view, + const gchar *action_name); +GtkActionGroup *e_web_view_get_action_group (EWebView *web_view, + const gchar *group_name); +gchar * e_web_view_extract_uri (EWebView *web_view, + GdkEventButton *event, + GtkHTML *frame); +gboolean e_web_view_scroll_forward (EWebView *web_view); +gboolean e_web_view_scroll_backward (EWebView *web_view); +GtkUIManager * e_web_view_get_ui_manager (EWebView *web_view); +GtkWidget * e_web_view_get_popup_menu (EWebView *web_view); +void e_web_view_show_popup_menu (EWebView *web_view, + GdkEventButton *event, + GtkMenuPositionFunc func, + gpointer user_data); +void e_web_view_status_message (EWebView *web_view, + const gchar *status_message); +void e_web_view_stop_loading (EWebView *web_view); +void e_web_view_update_actions (EWebView *web_view); + +G_END_DECLS + +#endif /* E_WEB_VIEW_H */ |