balsa r8011 - in trunk: . libbalsa src



Author: PeterB
Date: Mon Dec  1 23:07:26 2008
New Revision: 8011
URL: http://svn.gnome.org/viewvc/balsa?rev=8011&view=rev

Log:
initial experimental support for WebKit

Modified:
   trunk/ChangeLog
   trunk/configure.in
   trunk/libbalsa/html.c
   trunk/libbalsa/html.h
   trunk/src/balsa-mime-widget-text.c

Modified: trunk/configure.in
==============================================================================
--- trunk/configure.in	(original)
+++ trunk/configure.in	Mon Dec  1 23:07:26 2008
@@ -106,6 +106,14 @@
                   [use PATH as GnuPG application (default=gpg2 if >= 2.0.4, otherwise gpg 1.x)]),
 	          [ gpgapp=$withval ], [ gpgapp=no ])
 
+AC_ARG_WITH([webkit],
+              AC_HELP_STRING([--with-webkit],
+                [Use WebKit if available (default=no)]),[
+	use_webkit=$withval
+],[
+	use_webkit=no
+])
+
 AC_ARG_WITH([gtkhtml],
               AC_HELP_STRING([--with-gtkhtml],
                              [Preferred GtkHTML version, 2 or 3 (default=3)]),[
@@ -382,6 +390,22 @@
 AC_SUBST(BALSA_AB_LIBS)
 AC_SUBST(BALSA_DEFS)
 
+# WebKit
+#
+AC_MSG_CHECKING(whether to use WebKit)
+if test x"$use_webkit" != xno ; then
+    AC_MSG_RESULT([yes])
+    PKG_CHECK_MODULES(WEBKIT, [webkit-1.0])
+    AC_DEFINE(HAVE_WEBKIT,1,[Defined when WebKit can be used.])
+    AC_DEFINE(HAVE_GTKHTML,1,[Defined when GtkHtml can be used.])
+    BALSA_CFLAGS="$BALSA_CFLAGS $WEBKIT_CFLAGS"
+    BALSA_LIBS="$BALSA_LIBS $WEBKIT_LIBS"
+    BALSA_AB_LIBS="$BALSA_AB_LIBS $WEBKIT_LIBS"
+    use_gtkhtml=no
+else
+    AC_MSG_RESULT([no])
+fi
+
 # GtkHtml library.
 #
 if test x"$use_gtkhtml" != xno ; then
@@ -952,6 +976,7 @@
 echo "      Using multithreading: $use_threads"
 echo "   Enable compile warnings: $set_more_warnings"
 echo "                Use ESMTP : $with_esmtp"
+echo " Use WebKit (experimental): $use_webkit"
 echo "               Use GtkHTML: $use_gtkhtml"
 echo "                 Use GPGME: $gpgmecfg"
 echo "                  Use LDAP: $with_ldap"

Modified: trunk/libbalsa/html.c
==============================================================================
--- trunk/libbalsa/html.c	(original)
+++ trunk/libbalsa/html.c	Mon Dec  1 23:07:26 2008
@@ -49,12 +49,231 @@
  * including it indirectly through "libbalsa.h" doesn't! */
 #include "libbalsa.h"
 
+# if defined(HAVE_WEBKIT)
+
+/*
+ * Experimental support for WebKit.
+ *
+ * Issues as of WebKit 1.0.3:
+ *
+ * (a) no mechanism for satisfying "cid:" requests;
+ * (b) no assurance that remote servers named in "src=" attributes
+ *     will not be contacted.
+ *
+ * GtkHtml-{2,3} resolve both issues with the "url-requested" or
+ * "request-url" signal; WebKit does not have one.  We turn off its
+ * "auto-load-images" setting, which seems to mean that <img src="...">
+ * tags are ignored.  However, that is apparently intended to save
+ * bandwidth rather than to protect privacy.  The server in a <frame
+ * src="..."> is known to be contacted; whether "src=" attributes on
+ * other tags are followed is unknown.
+ *
+ * We do disable scripts, so the server in a <script src="..."> should
+ * not be contacted.
+ *
+ * The action taken on a <frame src="..."> tag seems buggy: it results
+ * in a "navigation-requested" signal, which is otherwise emitted when
+ * the user clicks on a link.  Consequently, we pass it to the Gnome
+ * browser without verifying that the user wants it.
+ *
+ * https://bugs.webkit.org/show_bug.cgi?id=17147 discusses these issues.
+ */
+
+#include <webkit/webkit.h>
+
+typedef struct {
+    LibBalsaHtmlCallback hover_cb;
+    LibBalsaHtmlCallback clicked_cb;
+    GtkObject *hadj, *vadj;
+} LibBalsaWebKitInfo;
+
+static void
+lbh_hovering_over_link_cb(GtkWidget   * web_view,
+                          const gchar * title,
+                          const gchar * uri,
+                          gpointer      data)
+{
+    LibBalsaWebKitInfo *info = data;
+
+    (*info->hover_cb)(uri);
+}
+
+static void
+lbh_size_request_cb(GtkWidget      * widget,
+                    GtkRequisition * requisition,
+                    gpointer         data)
+{
+    LibBalsaWebKitInfo *info = data;
+
+    requisition->width  = GTK_ADJUSTMENT(info->hadj)->upper;
+    requisition->height = GTK_ADJUSTMENT(info->vadj)->upper;
+}
+
+static WebKitNavigationResponse
+lbh_navigation_requested_cb(WebKitWebView        * web_view,
+                            WebKitWebFrame       * frame,
+                            WebKitNetworkRequest * request,
+                            gpointer               data)
+{
+    LibBalsaWebKitInfo *info = data;
+    const gchar *uri = webkit_network_request_get_uri(request);
+
+    g_print("%s %s\n", __func__, uri);
+    (*info->clicked_cb)(uri);
+
+    return WEBKIT_NAVIGATION_RESPONSE_IGNORE;
+}
+
+/* Create a new WebKitWebView widget:
+ * text			the HTML source;
+ * len			length of text;
+ * charset		ignored;
+ * message 		the LibBalsaMessage from which to extract any
+ *			HTML objects (by url); ignored if NULL;
+ * hover_cb             callback for link-hover signal;
+ * clicked_cb	        callback for the "link-clicked" signal; ignored
+ *			if NULL.
+ */
+
+GtkWidget *
+libbalsa_html_new(const gchar * text, size_t len,
+		  const gchar * charset,
+		  gpointer message,
+                  LibBalsaHtmlCallback hover_cb,
+                  LibBalsaHtmlCallback clicked_cb)
+{
+    GtkWidget *widget;
+    WebKitWebView *web_view;
+    LibBalsaWebKitInfo *info;
+
+    widget = webkit_web_view_new();
+    web_view = WEBKIT_WEB_VIEW(widget);
+
+    g_object_set(webkit_web_view_get_settings(web_view),
+                 "auto-load-images", FALSE,
+                 "enable-scripts",   FALSE,
+                 "enable-plugins",   FALSE,
+                 NULL);
+     
+    info = g_new(LibBalsaWebKitInfo, 1);
+    g_object_weak_ref(G_OBJECT(web_view), (GWeakNotify) g_free, info);
+
+    info->hadj = gtk_adjustment_new(0.0, 0.0, 0.0, 0.0, 0.0, 0.0);
+    info->vadj = gtk_adjustment_new(0.0, 0.0, 0.0, 0.0, 0.0, 0.0);
+    g_signal_emit_by_name(web_view, "set-scroll-adjustments",
+                          info->hadj, info->vadj);
+
+    info->hover_cb = hover_cb;
+    g_signal_connect(web_view, "hovering-over-link",
+                     G_CALLBACK(lbh_hovering_over_link_cb), info);
+
+    info->clicked_cb = clicked_cb;
+    g_signal_connect(web_view, "navigation-requested",
+                     G_CALLBACK(lbh_navigation_requested_cb), info);
+
+    g_signal_connect(web_view, "size-request",
+                     G_CALLBACK(lbh_size_request_cb), info);
+
+    g_signal_connect(web_view, "load-progress-changed",
+                     G_CALLBACK(gtk_widget_queue_resize), NULL);
+
+    webkit_web_view_load_html_string(web_view, text, NULL);
+
+    return widget;
+}
+
+void
+libbalsa_html_to_string(gchar ** text, size_t len)
+{
+    return; /* this widget does not support conversion to a string. The
+             * string won't be altered. Other alternative would be to set
+             * it to an empty string. */
+}
+
+gboolean
+libbalsa_html_can_zoom(GtkWidget * widget)
+{
+    return WEBKIT_IS_WEB_VIEW(widget);
+}
+
+void libbalsa_html_zoom(GtkWidget * widget, gint in_out)
+{
+    switch (in_out) {
+    case +1:
+	webkit_web_view_zoom_in(WEBKIT_WEB_VIEW(widget));
+	break;
+    case -1:
+	webkit_web_view_zoom_out(WEBKIT_WEB_VIEW(widget));
+	break;
+    case 0:
+	webkit_web_view_set_zoom_level(WEBKIT_WEB_VIEW(widget), 1.0);
+	break;
+    default:
+	break;
+    }
+}
+
+gboolean libbalsa_html_can_select(GtkWidget * widget)
+{
+    return WEBKIT_IS_WEB_VIEW(widget);
+}
+
+void libbalsa_html_select_all(GtkWidget * widget)
+{
+    webkit_web_view_select_all(WEBKIT_WEB_VIEW(widget));
+}
+
+void libbalsa_html_copy(GtkWidget * widget)
+{
+    webkit_web_view_copy_clipboard(WEBKIT_WEB_VIEW(widget));
+}
+
+# else                          /* defined(HAVE_WEBKIT) */
+
+/* Common code for both GtkHtml widgets. */
+
 /* Forward reference. */
 static gboolean libbalsa_html_url_requested(GtkWidget * html,
 					    const gchar * url,
 					    gpointer stream,
 					    LibBalsaMessage * msg);
 
+typedef struct {
+    LibBalsaHtmlCallback hover_cb;
+    LibBalsaHtmlCallback clicked_cb;
+} LibBalsaHTMLInfo;
+
+static void
+lbh_navigation_requested_cb(GtkWidget   * widget,
+                            const gchar * uri,
+                            gpointer      data)
+{
+    LibBalsaHTMLInfo *info = data;
+
+    if (info->clicked_cb)
+        (*info->clicked_cb)(uri);
+}
+
+static void
+lbh_hovering_over_link_cb(GtkWidget   * widget,
+                          const gchar * uri,
+                          gpointer      data)
+{
+    LibBalsaHTMLInfo *info = data;
+
+    if (info->hover_cb)
+        (*info->hover_cb) (uri);
+}
+
+static void
+lbh_size_request_cb(GtkWidget      * widget,
+                    GtkRequisition * requisition,
+                    gpointer         data)
+{
+    requisition->width  = GTK_LAYOUT(widget)->hadjustment->upper;
+    requisition->height = GTK_LAYOUT(widget)->vadjustment->upper;
+}
+
 # ifdef HAVE_GTKHTML3
 
 /* Code for GtkHTML-3 */
@@ -98,20 +317,12 @@
 static GtkWidget *
 lbh_new(const gchar * text, size_t len,
 	const gchar * charset,
-        GString * export_string,
-	gpointer message, GCallback link_clicked_cb)
+        GString * export_string)
 {
     GtkWidget *html;
     GtkHTMLStream *stream;
 
     html = gtk_html_new();
-    if (message)
-	g_signal_connect(G_OBJECT(html), "url-requested",
-			 G_CALLBACK(libbalsa_html_url_requested), message);
-    if (link_clicked_cb)
-	g_signal_connect(G_OBJECT(html), "link-clicked",
-			 link_clicked_cb, NULL);
-
     stream = gtk_html_begin(GTK_HTML(html));
     if (len > 0) {
         if (charset && g_ascii_strcasecmp(charset, "us-ascii") != 0
@@ -162,10 +373,33 @@
  */
 GtkWidget *
 libbalsa_html_new(const gchar * text, size_t len,
-		  const gchar * charset,
-		  gpointer message, GCallback link_clicked_cb)
+                  const gchar * charset,
+                  gpointer message,
+                  LibBalsaHtmlCallback hover_cb,
+                  LibBalsaHtmlCallback clicked_cb)
 {
-    return lbh_new(text, len, charset, NULL, message, link_clicked_cb);
+    GtkWidget *widget;
+    LibBalsaHTMLInfo *info;
+
+    widget = lbh_new(text, len, charset, NULL);
+    info = g_new(LibBalsaHTMLInfo, 1);
+    g_object_weak_ref(G_OBJECT(widget), (GWeakNotify) g_free, info);
+
+    info->hover_cb = hover_cb;
+    g_signal_connect(widget, "on-url",
+                     G_CALLBACK(lbh_hovering_over_link_cb), info);
+
+    info->clicked_cb = clicked_cb;
+    g_signal_connect(widget, "link-clicked",
+                     G_CALLBACK(lbh_navigation_requested_cb), info);
+
+    g_signal_connect(widget, "url-requested",
+                     G_CALLBACK(libbalsa_html_url_requested), message);
+
+    g_signal_connect(widget, "size-request",
+                     G_CALLBACK(lbh_size_request_cb), info);
+
+    return widget;
 }
 
 /* Use an HtmlView widget to convert html text to a (null-terminated) string:
@@ -180,7 +414,7 @@
     GString *str;
 
     str = g_string_new(NULL);	/* We want only the text, in str. */
-    html = lbh_new(*text, len, NULL, str, NULL, NULL);
+    html = lbh_new(*text, len, NULL, str);
     gtk_widget_destroy(html);
 
     g_free(*text);
@@ -349,24 +583,39 @@
 GtkWidget *
 libbalsa_html_new(const gchar * text, size_t len,
 		  const gchar * charset,
-		  gpointer message, GCallback link_clicked_cb)
+		  gpointer message,
+                  LibBalsaHtmlCallback hover_cb,
+                  LibBalsaHtmlCallback link_clicked_cb)
 {
     GtkWidget *html;
+    LibBalsaHTMLInfo *info;
     HtmlDocument *document;
 
     document = html_document_new();
+    info = g_new(LibBalsaHTMLInfo, 1);
+    g_object_weak_ref(G_OBJECT(document), (GWeakNotify) g_free, info);
+
     if (message)
-	g_signal_connect(G_OBJECT(document), "request-url",
+	g_signal_connect(document, "request-url",
 			 G_CALLBACK(libbalsa_html_url_requested), message);
+
+    info->clicked_cb = link_clicked_cb;
     if (link_clicked_cb)
-	g_signal_connect(G_OBJECT(document), "link-clicked",
-			 link_clicked_cb, NULL);
+        g_signal_connect(document, "link-clicked",
+                         G_CALLBACK(lbh_navigation_requested_cb), info);
 
     /* We need to first set_document and then do *_stream() operations
      * or gtkhtml2 will crash. */
     html = html_view_new();
     html_view_set_document(HTML_VIEW(html), document);
 
+    info->hover_cb = hover_cb;
+    g_signal_connect(html, "on-url",
+                     G_CALLBACK(lbh_hovering_over_link_cb), info);
+
+    g_signal_connect(html, "size-request",
+                     G_CALLBACK(lbh_size_request_cb), info);
+
     html_document_open_stream(document, "text/html");
     html_document_write_stream(document, text, len);
     html_document_close_stream(document);
@@ -509,6 +758,7 @@
 
     return TRUE;
 }
+# endif                         /* defined(HAVE_WEBKIT) */
 
 /* Filter text/enriched or text/richtext to text/html, if we have GMime
  * >= 2.1.0; free and reallocate the text. */

Modified: trunk/libbalsa/html.h
==============================================================================
--- trunk/libbalsa/html.h	(original)
+++ trunk/libbalsa/html.h	Mon Dec  1 23:07:26 2008
@@ -25,7 +25,7 @@
 
 #include "config.h"
 
-# ifndef HAVE_GTKHTML3
+# if defined(HAVE_GTKHTML2)
 /* gtkhtml2 uses deprecated api */
 #  undef GTK_DISABLE_DEPRECATED
 # endif
@@ -42,10 +42,13 @@
 
 # ifdef HAVE_GTKHTML
 
+typedef void (*LibBalsaHtmlCallback) (const gchar * uri);
+
 GtkWidget *libbalsa_html_new(const gchar * text, size_t len,
 			     const gchar * charset,
 			     gpointer message,
-			     GCallback link_clicked_cb);
+                             LibBalsaHtmlCallback hover_cb,
+                             LibBalsaHtmlCallback clicked_cb);
 void libbalsa_html_to_string(gchar ** text, size_t len);
 gboolean libbalsa_html_can_zoom(GtkWidget * widget);
 void libbalsa_html_zoom(GtkWidget * widget, gint in_out);

Modified: trunk/src/balsa-mime-widget-text.c
==============================================================================
--- trunk/src/balsa-mime-widget-text.c	(original)
+++ trunk/src/balsa-mime-widget-text.c	Mon Dec  1 23:07:26 2008
@@ -109,7 +109,7 @@
 static message_url_t * find_url(GtkWidget * widget, gint x, gint y, GList * url_list);
 static void handle_url(const message_url_t* url);
 static void free_url_list(GList * url_list);
-static void balsa_gtk_html_on_url(GtkWidget *html, const gchar *url);
+static void bm_widget_on_url(const gchar *url);
 static void phrase_highlight(GtkTextBuffer * buffer, const gchar * id,
 			     gunichar tag_char, const gchar * property,
 			     gint value);
@@ -802,10 +802,10 @@
     
     if (set) {
         gtk_text_buffer_apply_tag(buffer, tag, &start, &end);
-        balsa_gtk_html_on_url(NULL, url->url);
+        bm_widget_on_url(url->url);
     } else {
         gtk_text_buffer_remove_tag(buffer, tag, &start, &end);
-        balsa_gtk_html_on_url(NULL, NULL);
+        bm_widget_on_url(NULL);
     }
 }
 
@@ -1114,7 +1114,7 @@
 
 /* --- HTML related functions -- */
 static void
-balsa_gtk_html_on_url(GtkWidget *html, const gchar *url)
+bm_widget_on_url(const gchar *url)
 {
     GtkStatusbar *statusbar;
     guint context_id;
@@ -1204,22 +1204,8 @@
             ? balsa_gtk_html_popup(html, bm) : FALSE);
 }
 
-/* balsa_gtk_html_size_request:
-   report the requested size of the HTML widget.
-*/
 static void
-balsa_gtk_html_size_request(GtkWidget * widget,
-                            GtkRequisition * requisition, gpointer data)
-{
-    g_return_if_fail(widget != NULL);
-    g_return_if_fail(requisition != NULL);
-
-    requisition->width  = GTK_LAYOUT(widget)->hadjustment->upper;
-    requisition->height = GTK_LAYOUT(widget)->vadjustment->upper;
-}
-
-static void
-balsa_gtk_html_link_clicked(GObject *obj, const gchar *url)
+bm_widget_link_clicked(const gchar *url)
 {
     GError *err = NULL;
 
@@ -1244,13 +1230,12 @@
         libbalsa_html_new(ptr, len,
 			  libbalsa_message_body_charset(mime_body),
 			  bm->message,
-                          G_CALLBACK(balsa_gtk_html_link_clicked));
+                          (LibBalsaHtmlCallback)
+                          bm_widget_on_url,
+                          (LibBalsaHtmlCallback)
+                          bm_widget_link_clicked);
     g_object_set_data(G_OBJECT(mw->widget), "mime-body", mime_body);
 
-    g_signal_connect(G_OBJECT(mw->widget), "size-request",
-                     G_CALLBACK(balsa_gtk_html_size_request), bm);
-    g_signal_connect(G_OBJECT(mw->widget), "on-url",
-                     G_CALLBACK(balsa_gtk_html_on_url), bm);
     g_signal_connect(G_OBJECT(mw->widget), "button-press-event",
                      G_CALLBACK(balsa_gtk_html_button_press_cb), bm);
     g_signal_connect(G_OBJECT(mw->widget), "key_press_event",



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]