changeset 2978:d84182f0054e

GTK4: Support for dw_html_javascript_add() and DW_SIGNAL_HTML_MESSAGE. Also add support for the stable WebKitGTK 6.0 for GTK4. They changed a lot including the package name, add USE_WEBKIT6 for this.
author bsmith@81767d24-ef19-dc11-ae90-00e081727c95
date Fri, 24 Mar 2023 23:04:39 +0000
parents 7d6773c474d0
children b59103280114
files configure configure.ac dwconfig.h.in gtk4/dw.c mac/dw.m
diffstat 5 files changed, 163 insertions(+), 18 deletions(-) [+]
line wrap: on
line diff
--- a/configure	Fri Mar 24 17:35:53 2023 +0000
+++ b/configure	Fri Mar 24 23:04:39 2023 +0000
@@ -7151,8 +7151,9 @@
          fi
          if test x"$GTK_LIBS" != x; then
             DW_DIR=gtk4
-            # WebKit2GTK built for GTK4 becomes 5.0
-            WEBKIT_PKG="webkit2gtk-5.0"
+            # WebKit2GTK built for GTK4 becomes 5.0 or 6.0
+            WEBKIT_PKG="webkitgtk-6.0"
+            WEBKIT_ALT_PKG="webkit2gtk-5.0"
          fi
       else
          # Put the GTK2 test here since --with-gtk2 is mutually
@@ -7208,6 +7209,11 @@
 printf "%s\n" "#define USE_WEBKIT2 1" >>confdefs.h
 
          fi
+         if test "$WEBKIT_PKG" = "webkitgtk-6.0"; then
+
+printf "%s\n" "#define USE_WEBKIT6 1" >>confdefs.h
+
+         fi
       fi
       if test x"$RPATH" != x; then
          RPATH="-Wl,-R$RPATH"
--- a/configure.ac	Fri Mar 24 17:35:53 2023 +0000
+++ b/configure.ac	Fri Mar 24 23:04:39 2023 +0000
@@ -231,8 +231,9 @@
          fi
          if test x"$GTK_LIBS" != x; then 
             DW_DIR=gtk4
-            # WebKit2GTK built for GTK4 becomes 5.0
-            WEBKIT_PKG="webkit2gtk-5.0"
+            # WebKit2GTK built for GTK4 becomes 5.0 or 6.0
+            WEBKIT_PKG="webkitgtk-6.0"
+            WEBKIT_ALT_PKG="webkit2gtk-5.0"
          fi
       else
          # Put the GTK2 test here since --with-gtk2 is mutually
@@ -282,6 +283,9 @@
          if test "$WEBKIT_PKG" = "webkit2gtk-4.0"; then
             AC_DEFINE(USE_WEBKIT2,1,Uses WebKit 2)
          fi
+         if test "$WEBKIT_PKG" = "webkitgtk-6.0"; then
+            AC_DEFINE(USE_WEBKIT6,1,Uses WebKit 6)
+         fi
       fi
       if test x"$RPATH" != x; then
          RPATH="-Wl,-R$RPATH"
--- a/dwconfig.h.in	Fri Mar 24 17:35:53 2023 +0000
+++ b/dwconfig.h.in	Fri Mar 24 23:04:39 2023 +0000
@@ -106,5 +106,8 @@
 /* Uses WebKit 2 */
 #undef USE_WEBKIT2
 
+/* Uses WebKit 6 */
+#undef USE_WEBKIT6
+
 /* Define to 1 if the X Window System is missing or not being used. */
 #undef X_DISPLAY_MISSING
--- a/gtk4/dw.c	Fri Mar 24 17:35:53 2023 +0000
+++ b/gtk4/dw.c	Fri Mar 24 23:04:39 2023 +0000
@@ -34,8 +34,12 @@
 #endif
 
 #ifdef USE_WEBKIT
+#ifdef USE_WEBKIT6
+#include <webkit/webkit.h>
+#else
 #include <webkit2/webkit2.h>
 #endif
+#endif
 
 #include <gdk-pixbuf/gdk-pixbuf.h>
 
@@ -477,6 +481,11 @@
 #ifdef USE_WEBKIT
 static void _dw_html_result_event(GObject *object, GAsyncResult *result, gpointer script_data);
 static void _dw_html_changed_event(WebKitWebView  *web_view, WebKitLoadEvent load_event, gpointer data);
+#ifdef USE_WEBKIT6
+static void _dw_html_message_event(WebKitUserContentManager *manager, JSCValue *result, gpointer *data);
+#else
+static void _dw_html_message_event(WebKitUserContentManager *manager, WebKitJavascriptResult *result, gpointer *data);
+#endif
 #endif
 static void _dw_signal_disconnect(gpointer data, GClosure *closure);
 static void _dw_event_coordinates_to_window(GtkWidget *widget, double *x, double *y);
@@ -522,7 +531,7 @@
 
 } DWSignalHandler;
 
-/* A list of signal forwarders, to account for paramater differences. */
+/* A list of signal forwarders, to account for parameter differences. */
 static DWSignalList DWSignalTranslate[] = {
    { _dw_configure_event,         DW_SIGNAL_CONFIGURE,      "resize",            NULL },
    { _dw_key_press_event,         DW_SIGNAL_KEY_PRESS,      "key-pressed",       _dw_key_setup },
@@ -544,6 +553,7 @@
 #ifdef USE_WEBKIT
    { _dw_html_changed_event,      DW_SIGNAL_HTML_CHANGED,    "load-changed",     NULL },
    { _dw_html_result_event,       DW_SIGNAL_HTML_RESULT,     "",                 _dw_html_setup },
+   { _dw_html_message_event,      DW_SIGNAL_HTML_MESSAGE,    "",                 _dw_html_setup },
 #endif
    { NULL,                        "",                        "",                 NULL }
 };
@@ -674,7 +684,9 @@
 static void _dw_html_result_event(GObject *object, GAsyncResult *result, gpointer script_data)
 {
     pthread_t saved_thread = _dw_thread;
+#ifndef USE_WEBKIT6
     WebKitJavascriptResult *js_result;
+#endif
     JSCValue *value;
     GError *error = NULL;
     int (*htmlresultfunc)(HWND, int, char *, void *, void *) = NULL;
@@ -684,10 +696,8 @@
     _dw_thread = (pthread_t)-1;
     if(handlerdata)
     {
-        DWSignalHandler work;
         void *params[3] = { GINT_TO_POINTER(handlerdata-1), 0, object };
-
-        work = _dw_get_signal_handler(params);
+        DWSignalHandler work = _dw_get_signal_handler(params);
 
         if(work.window)
         {
@@ -696,7 +706,11 @@
         }
     }
 
+#ifdef USE_WEBKIT6
+    if(!(value = webkit_web_view_evaluate_javascript_finish(WEBKIT_WEB_VIEW(object), result, &error)))
+#else
     if(!(js_result = webkit_web_view_run_javascript_finish(WEBKIT_WEB_VIEW(object), result, &error)))
+#endif
     {
         if(htmlresultfunc)
            htmlresultfunc((HWND)object, DW_ERROR_UNKNOWN, error->message, script_data, user_data);
@@ -705,7 +719,9 @@
         return;
     }
 
+#ifndef USE_WEBKIT6
     value = webkit_javascript_result_get_js_value(js_result);
+#endif
     if(jsc_value_is_string(value))
     {
         gchar *str_value = jsc_value_to_string(value);
@@ -722,10 +738,53 @@
     }
     else if(htmlresultfunc)
         htmlresultfunc((HWND)object, DW_ERROR_UNKNOWN, NULL, script_data, user_data);
+#ifndef USE_WEBKIT6
     webkit_javascript_result_unref (js_result);
+#endif
    _dw_thread = saved_thread;
 }
 
+#ifdef USE_WEBKIT6
+static void _dw_html_message_event(WebKitUserContentManager *manager, JSCValue *result, gpointer *data)
+#else
+static void _dw_html_message_event(WebKitUserContentManager *manager, WebKitJavascriptResult *result, gpointer *data)
+#endif
+{
+    HWND window = (HWND)data[0];
+    int (*htmlmessagefunc)(HWND, char *, char *, void *) = NULL;
+    void *user_data = NULL;
+    gchar *name = (gchar *)data[1];
+    gint handlerdata;
+
+    if(window && (handlerdata = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(window), "_dw_html_message_id"))))
+    {
+        void *params[3] = { GINT_TO_POINTER(handlerdata-1), 0, window };
+        DWSignalHandler work = _dw_get_signal_handler(params);
+
+        if(work.window)
+        {
+            htmlmessagefunc = work.func;
+            user_data = work.data;
+        }
+    }
+
+    if(jsc_value_is_string(result))
+    {
+        gchar *str_value = jsc_value_to_string(result);
+        JSCException *exception = jsc_context_get_exception(jsc_value_get_context(result));
+
+        if(htmlmessagefunc && !exception)
+            htmlmessagefunc(window, name, str_value, user_data);
+            
+        g_free(str_value);
+        
+        if(!exception)
+          return;
+    }
+    if(htmlmessagefunc)
+        htmlmessagefunc(window, name, NULL, user_data);
+}
+
 static void _dw_html_changed_event(WebKitWebView  *web_view, WebKitLoadEvent load_event, gpointer data)
 {
     DWSignalHandler work = _dw_get_signal_handler(data);
@@ -10518,14 +10577,76 @@
 #ifdef USE_WEBKIT
    WebKitWebView *web_view;
 
-   if((web_view = _dw_html_web_view(handle)))
+   if(script && (web_view = _dw_html_web_view(handle)))
+#ifdef USE_WEBKIT6
+      webkit_web_view_evaluate_javascript(web_view, script, strlen(script), NULL, NULL, NULL, _dw_html_result_event, scriptdata);
+#else
       webkit_web_view_run_javascript(web_view, script, NULL, _dw_html_result_event, scriptdata);
+#endif
    return DW_ERROR_NONE;
 #else
    return DW_ERROR_UNKNOWN;
 #endif
 }
 
+/* Free the name when the signal disconnects */
+void _dw_html_message_disconnect(gpointer gdata, GClosure *closure)
+{
+    gpointer *data = (gpointer *)gdata;
+
+    if(data)
+    {
+        gchar *name = (gchar *)data[1];
+        
+        if(name)
+            g_free(name);
+        free(data);
+    }
+}
+
+/*
+ * Install a javascript function with name that can call native code.
+ * Parameters:
+ *       handle: Handle to the HTML window.
+ *       name: Javascript function name.
+ * Notes: A DW_SIGNAL_HTML_MESSAGE event will be raised with scriptdata.
+ * Returns:
+ *       DW_ERROR_NONE (0) on success.
+ */
+int API dw_html_javascript_add(HWND handle, const char *name)
+{
+#ifdef USE_WEBKIT
+   WebKitWebView *web_view= _dw_html_web_view(handle);
+   WebKitUserContentManager *manager;
+
+    if(web_view && (manager = webkit_web_view_get_user_content_manager(web_view)) && name) 
+    {
+        /* Script to inject that will call the handler we are adding */
+        gchar *script = g_strdup_printf("function %s(body) {window.webkit.messageHandlers.%s.postMessage(body);}", 
+                            name, name);
+        gchar *signal = g_strdup_printf("script-message-received::%s", name);
+        WebKitUserScript *userscript = webkit_user_script_new(script, WEBKIT_USER_CONTENT_INJECT_ALL_FRAMES,
+                                                              WEBKIT_USER_SCRIPT_INJECT_AT_DOCUMENT_START, NULL, NULL);
+        gpointer *data = calloc(sizeof(gpointer), 2);
+        
+        data[0] = handle;
+        data[1] = g_strdup(name);
+        g_signal_connect_data(manager, signal, G_CALLBACK(_dw_html_message_event), data, _dw_html_message_disconnect, 0);
+        webkit_user_content_manager_register_script_message_handler(manager, name
+#if USE_WEBKIT6
+                                                                    , NULL
+#endif
+        );
+        webkit_user_content_manager_add_script(manager, userscript);
+
+        g_free(script);
+        g_free(signal);
+        return DW_ERROR_NONE;
+    }
+#endif
+    return DW_ERROR_UNKNOWN;
+}
+
 /*
  * Create a new HTML window (widget) to be packed.
  * Parameters:
@@ -11090,14 +11211,26 @@
 #ifdef USE_WEBKIT
 GObject *_dw_html_setup(struct _dw_signal_list *signal, GObject *object, void *sigfunc, void *discfunc, void *data)
 {
-   if(WEBKIT_IS_WEB_VIEW(object) && strcmp(signal->name, DW_SIGNAL_HTML_RESULT) == 0)
-   {
-      /* We don't actually need a signal handler here... just need to assign the handler ID
-       * Since the handler is created in dw_html_javasript_run()
-       */
-      int sigid = _dw_set_signal_handler(object, (HWND)object, sigfunc, data, signal->func, discfunc);
-      g_object_set_data(object, "_dw_html_result_id", GINT_TO_POINTER(sigid+1));
-      return NULL;
+   if(WEBKIT_IS_WEB_VIEW(object))
+   {
+       if(strcmp(signal->name, DW_SIGNAL_HTML_RESULT) == 0)
+       {
+          /* We don't actually need a signal handler here... just need to assign the handler ID
+           * Since the handler is created in dw_html_javasript_run()
+           */
+          int sigid = _dw_set_signal_handler(object, (HWND)object, sigfunc, data, signal->func, discfunc);
+          g_object_set_data(object, "_dw_html_result_id", GINT_TO_POINTER(sigid+1));
+          return NULL;
+       }
+       else if(strcmp(signal->name, DW_SIGNAL_HTML_MESSAGE) == 0)
+       {
+          /* We don't actually need a signal handler here... just need to assign the handler ID
+           * Since the handler is created in dw_html_javasript_add()
+           */
+          int sigid = _dw_set_signal_handler(object, (HWND)object, sigfunc, data, signal->func, discfunc);
+          g_object_set_data(object, "_dw_html_message_id", GINT_TO_POINTER(sigid+1));
+          return NULL;
+      }
    }
    return object;
 }
--- a/mac/dw.m	Fri Mar 24 17:35:53 2023 +0000
+++ b/mac/dw.m	Fri Mar 24 23:04:39 2023 +0000
@@ -9514,7 +9514,6 @@
     return DW_ERROR_UNKNOWN;
 }
 
-
 /*
  * Create a new HTML window (widget) to be packed.
  * Not available under OS/2, eCS