[balsa/imap-improvements] fix using static LibBalsaWebKitInfo, enable HTTP cache




commit 2bd4b9869e68d9e451aca9918db18a298be32a8d
Author: Albrecht Dreß <albrecht dress arcor de>
Date:   Sun May 2 18:15:43 2021 +0200

    fix using static LibBalsaWebKitInfo, enable HTTP cache
    
    Instead of using a static var to pass LibBalsaWebKitInfo to the
    WebKitURISchemeRequestCallback use the object attached anyway to the
    WebKitWebView.
    
    Create a WebKitWebContext with the cache enabled so external images etc.
    are downloaded only once.  Add a button in the prefs to clear the cache.
    
    * libbalsa/html.[ch]: do not use the static var in lbh_cid_cb(); add
      method to create a context w/ caching enabled, and use it to create a
      new web view; add methods to view the cache size and to clear it
    * src/pref-manager.c: view cache size, add button to clear it
    
    Signed-off-by: Albrecht Dreß <albrecht dress arcor de>

 libbalsa/html.c    | 70 ++++++++++++++++++++++++++++++++++++++----------------
 libbalsa/html.h    |  3 +++
 src/pref-manager.c | 39 ++++++++++++++++++++++++++++++
 3 files changed, 91 insertions(+), 21 deletions(-)
---
diff --git a/libbalsa/html.c b/libbalsa/html.c
index 0822a0575..5bd3615cb 100644
--- a/libbalsa/html.c
+++ b/libbalsa/html.c
@@ -47,6 +47,9 @@
 /* use a negative lookahead assertion to match "src=" *not* followed by "cid:" */
 #define SRC_REGEX      "<[^>]*src\\s*=\\s*(?!['\"]?\\s*cid:)"
 
+/* HTTP cache folder in ~/.balsa */
+#define CACHE_DIR      "http-cache"
+
 /* approximate image resolution for printing */
 #define HTML_PRINT_DPI                 200.0
 /* zoom level for printing */
@@ -530,16 +533,17 @@ lbh_web_process_terminated_cb(WebKitWebView                     *web_view,
  */
 static void
 lbh_cid_cb(WebKitURISchemeRequest * request,
-           gpointer                 data)
+           gpointer G_GNUC_UNUSED   data)
 {
-    LibBalsaWebKitInfo *info = *(LibBalsaWebKitInfo **) data;
+    LibBalsaWebKitInfo *info;
     const gchar *path;
     LibBalsaMessageBody *body;
 
     path = webkit_uri_scheme_request_get_path(request);
-    g_debug("%s path %s", __func__, path);
+    info = g_object_get_data(G_OBJECT(webkit_uri_scheme_request_get_web_view(request)), LIBBALSA_HTML_INFO);
+    g_debug("%s path %s, info %p", __func__, path, info);
 
-    if ((info->body != NULL) &&
+    if ((info != NULL) && (info->body != NULL) &&
        (body = libbalsa_message_get_part_by_id(info->body->message, path))) {
         gchar *content;
         gssize len;
@@ -585,6 +589,28 @@ lbh_context_menu_cb(WebKitWebView       * web_view,
     return retval;
 }
 
+static WebKitWebContext *
+lbh_get_web_view_context(void)
+{
+       static WebKitWebContext *context = NULL;
+
+       if (g_once_init_enter(&context)) {
+               WebKitWebsiteDataManager *data_manager;
+               WebKitWebContext *tmp;
+               gchar *cache_dir;
+
+               cache_dir = g_build_filename(g_get_home_dir(), ".balsa", CACHE_DIR, NULL);
+               data_manager = webkit_website_data_manager_new("base-cache-directory", cache_dir, NULL);
+               g_free(cache_dir);
+               tmp = webkit_web_context_new_with_website_data_manager(data_manager);
+               webkit_web_context_set_cache_model(tmp, WEBKIT_CACHE_MODEL_DOCUMENT_BROWSER);
+               webkit_web_context_register_uri_scheme(tmp, "cid", lbh_cid_cb, NULL, NULL);
+               g_debug("%s: registered “cid:” scheme", __func__);
+               g_once_init_leave(&context, tmp);
+       }
+       return context;
+}
+
 static WebKitWebView *
 lbh_web_view_new(LibBalsaWebKitInfo *info,
                                 gint                            width,
@@ -592,11 +618,8 @@ lbh_web_view_new(LibBalsaWebKitInfo *info,
 {
        WebKitWebView *view;
        WebKitSettings *settings;
-       static guint have_registered_cid = 0U;
-        static LibBalsaWebKitInfo *info_for_cid;
 
-        info_for_cid = info;
-       view = WEBKIT_WEB_VIEW(webkit_web_view_new());
+       view = WEBKIT_WEB_VIEW(webkit_web_view_new_with_context(lbh_get_web_view_context()));
     g_object_set_data_full(G_OBJECT(view), LIBBALSA_HTML_INFO, info, (GDestroyNotify) lbh_webkit_info_free);
     gtk_widget_set_size_request(GTK_WIDGET(view), width, LBH_NATURAL_SIZE);
     gtk_widget_set_vexpand(GTK_WIDGET(view), TRUE);
@@ -612,19 +635,6 @@ lbh_web_view_new(LibBalsaWebKitInfo *info,
        webkit_settings_set_enable_hyperlink_auditing(settings, TRUE);
        webkit_settings_set_auto_load_images(settings, auto_load_images);
 
-       if (g_atomic_int_or(&have_registered_cid, 1U) == 0U) {
-        WebKitWebContext *context;
-        /* Apparently, WebKitWebContext is static, and does not like to
-         * have the scheme registered many times (13? 15?), after which
-         * the web process crashes and does not get respawned.
-         * We register it once with the address of a static pointer to
-         * LibBalsaWebKitInfo. */
-
-        context = webkit_web_view_get_context(view);
-        webkit_web_context_register_uri_scheme(context, "cid", lbh_cid_cb, &info_for_cid, NULL);
-        g_debug("%s_ registered “cid:” scheme", __func__);
-       }
-
        g_signal_connect(view, "web-process-terminated", G_CALLBACK(lbh_web_process_terminated_cb), info);
     g_signal_connect(view, "decide-policy", G_CALLBACK(lbh_decide_policy_cb), info);
     g_signal_connect(view, "resource-load-started", G_CALLBACK(lbh_resource_load_started_cb), info);
@@ -1044,6 +1054,24 @@ libbalsa_html_search(GtkWidget                * widget,
     }
 }
 
+guint64
+libbalsa_html_cache_size(void)
+{
+       GFile *cache_dir;
+       guint64 result = 0;
+
+       cache_dir = g_file_new_build_filename(g_get_home_dir(), ".balsa", CACHE_DIR, NULL);
+       g_file_measure_disk_usage(cache_dir, G_FILE_MEASURE_NONE, NULL, NULL, NULL, &result, NULL, NULL, 
NULL);
+       g_object_unref(cache_dir);
+       return result;
+}
+
+void
+libbalsa_html_clear_cache(void)
+{
+       webkit_web_context_clear_cache(lbh_get_web_view_context());
+}
+
 /*
  * We do not need selection bounds.
  */
diff --git a/libbalsa/html.h b/libbalsa/html.h
index bd8cc4df3..d526d2bd4 100644
--- a/libbalsa/html.h
+++ b/libbalsa/html.h
@@ -70,6 +70,9 @@ gboolean libbalsa_html_get_selection_bounds(GtkWidget * widget,
 GtkWidget *libbalsa_html_popup_menu_widget(GtkWidget * widget);
 GtkWidget *libbalsa_html_get_view_widget(GtkWidget * widget);
 
+guint64 libbalsa_html_cache_size(void);
+void libbalsa_html_clear_cache(void);
+
 gboolean libbalsa_html_can_print(GtkWidget * widget);
 void libbalsa_html_print(GtkWidget * widget);
 cairo_surface_t *libbalsa_html_print_bitmap(LibBalsaMessageBody *body,
diff --git a/src/pref-manager.c b/src/pref-manager.c
index 383b7f54d..41f024f23 100644
--- a/src/pref-manager.c
+++ b/src/pref-manager.c
@@ -34,6 +34,7 @@
 #include "quote-color.h"
 #include "misc.h"
 #include "send.h"
+#include "html.h"
 #include "imap-server.h"
 
 #if HAVE_MACOSX_DESKTOP
@@ -2504,6 +2505,31 @@ pm_grid_add_quoted_group(GtkWidget * grid_widget)
     pm_grid_set_next_row(grid, ++row);
 }
 
+#ifdef HAVE_HTML_WIDGET
+static void
+set_html_cache_label_str(GtkLabel *label)
+{
+       gchar *size_str;
+       gchar *label_str;
+
+       size_str = g_format_size(libbalsa_html_cache_size());
+       label_str = g_strdup_printf(_("HTTP cache size: %s"), size_str);
+       g_free(size_str);
+       gtk_label_set_text(label, label_str);
+       g_free(label_str);
+}
+
+static void
+clear_html_cache_cb(GtkButton G_GNUC_UNUSED *button,
+                                       gpointer                                 user_data)
+{
+       libbalsa_html_clear_cache();
+       g_thread_yield();               /* ...give the webkit thread a chance to do the cleanup work */
+       g_usleep(2500);
+       set_html_cache_label_str(GTK_LABEL(user_data));
+}
+#endif
+
 /*
  * Multipart group
  */
@@ -2513,6 +2539,10 @@ pm_grid_add_alternative_group(GtkWidget * grid_widget)
 {
     GtkGrid *grid = (GtkGrid *) grid_widget;
     gint row = pm_grid_get_next_row(grid);
+#ifdef HAVE_HTML_WIDGET
+    GtkWidget *label;
+    GtkWidget *button;
+#endif
 
     /* handling of multipart/alternative */
 
@@ -2522,6 +2552,15 @@ pm_grid_add_alternative_group(GtkWidget * grid_widget)
     pui->display_alt_plain =
        pm_grid_attach_check(grid, 1, ++row, 1, 1, _("Prefer text/plain over HTML"));
 
+#ifdef HAVE_HTML_WIDGET
+    label = gtk_label_new(NULL);
+    set_html_cache_label_str(GTK_LABEL(label));
+    pm_grid_attach(grid, label, 1, ++row, 1, 1);
+    button = gtk_button_new_with_label(_("Clear HTTP cache…"));
+    pm_grid_attach(grid, button, 2, row, 1, 1);
+    g_signal_connect(button, "clicked", G_CALLBACK(clear_html_cache_cb), label);
+#endif
+
     pm_grid_set_next_row(grid, ++row);
 }
 


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