unofficial mirror of emacs-devel@gnu.org 
 help / color / mirror / code / Atom feed
From: "Noé Lopez via Emacs development discussions." <emacs-devel@gnu.org>
To: Po Lu <luangruo@yahoo.com>
Cc: emacs-devel@gnu.org
Subject: Re: moving xwidget-webkit to WPE
Date: Fri, 12 Jul 2024 22:06:39 +0200	[thread overview]
Message-ID: <1998.92895050056$1720850229@news.gmane.org> (raw)
In-Reply-To: <87ikyogq8s.fsf@yahoo.com> (message from Po Lu on Wed, 05 Jun 2024 08:58:11 +0800)

[-- Attachment #1: Type: text/plain, Size: 726 bytes --]

Hi,

I've started looking into WPE Webkit. To try to understand the code
better and because I think it would be beneficial for future xwidgets, I
separated the xwidget code related to webkit and moved it to a new file
called xwidget-webkit.c.  I have also recovered my school's Mac
mini (2009) to test changes on MacOS, which I will do next week.

I learned important things from making this patch which was the main
point, so if these changes seem pointless or something else I can revert
it no problem and continue from upstream.

Looking into WPE Webkit, I think we can use the FDO backend as it allows
rendering off-screen to SHM (shared memory?).  Do you have any other
ideas?

Have a nice day,
Noé


[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #2: 0001-Separate-xwidget-webkit-from-xwidgets-code.patch --]
[-- Type: text/x-patch, Size: 93988 bytes --]

From 9838a4fb2bc90f0008782c439594cfff311cfa41 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?No=C3=A9=20Lopez?= <noelopez@free.fr>
Date: Mon, 8 Jul 2024 23:35:12 +0200
Subject: [PATCH] Separate xwidget-webkit from xwidgets code

Move functions and code related to webkit from xwidget.c to a
new file xwidget-webkit.c.  This is to make the xwidget code
more generic and ease the creation of new xwidget types like
WPE webkit.

* configure.ac: Compile xwidget-webkit.c.

* lisp/xwidget.el (xwidget-webkit-execute-script)
(xwidget-webkit-uri, xwidget-webkit-title)
(xwidget-webkit-goto-uri, xwidget-webkit-goto-history)
(xwidget-webkit-zoom, xwidget-webkit-back-forward-list)
(xwidget-webkit-estimated-load-progress)
(xwidget-webkit-set-cookie-storage-file)
(xwidget-webkit-stop-loading): Change source file to
xwidget-webkit.c.

* src/emacs.c (main): Define symbols for xwidget-webkit.
* src/xwidget-webkit.c: New file with xwidget-webkit functions
from xwidget.c.
* src/xwidget-webkit.h: New file with xwidget-webkit functions
from xwidget.c.

* src/xwidget.h (internal_xwidget_view_list)
(internal_xwidget_list, XSETXWIDGET, XSETXWIDGET_VIEW)
(find_xwidget_for_offscreen_window, kill_xwidget)
(store_xwidget_display_event): Make public for xwidget-webkit.

* src/xwidget.c: (internal_xwidget_view_list)
(internal_xwidget_list, XSETXWIDGET, XSETXWIDGET_VIEW)
(find_xwidget_for_offscreen_window, kill_xwidget)
(store_xwidget_display_event): Make public for xwidget-webkit.

* src/xwidget.c: Remove unused includes.
(make-xwidget): Move webkit related code to
xwidget_webkit_make_widget.
(cursor_for_hit, define_cursors, mouse_target_changed)
(run_file_chooser_cb, webkit_ready_to_show, webkit_create_cb_1)
(webkit_create_cb, webkit_view_load_changed_cb)
(webkit_js_to_lisp, webkit_javascript_finished_cb)
(webkit_download_cb, webkit_decide_policy_cb)
(webkit_script_dialog_cb, CHECK_WEBKIT_WIDGET, WEBKIT_FN_INIT)
(xwidget-webkit-uri, xwidget-webkit-title)
(xwidget-webkit-estimated-load-progress)
(xwidget-webkit-goto-uri, xwidget-webkit-goto-history)
(xwidget-webkit-zoom, xwidget-webkit-execute-script)
(xwidget-webkit-search, xwidget-webkit-next-result)
(xwidget-webkit-previous-result, xwidget-webkit-finish-search)
(xwidget-webkit-load-html, xwidget-webkit-back-forward-list)
(xwidget-webkit-set-cookie-storage-file)
(xwidget-webkit-stop-loading): Move to xwidget-webkit.c.
All callers changed.
(syms_of_xwidget): Move webkit related symbols to
syms_of_xwidget_webkit.
---
 configure.ac         |    4 +-
 lisp/xwidget.el      |   23 +-
 src/emacs.c          |    2 +
 src/xwidget-webkit.c | 1225 ++++++++++++++++++++++++++++++++++++++++
 src/xwidget-webkit.h |   35 ++
 src/xwidget.c        | 1279 ++----------------------------------------
 src/xwidget.h        |   12 +
 7 files changed, 1341 insertions(+), 1239 deletions(-)
 create mode 100644 src/xwidget-webkit.c
 create mode 100644 src/xwidget-webkit.h

diff --git a/configure.ac b/configure.ac
index f0437d6f8cb..75855ceca87 100644
--- a/configure.ac
+++ b/configure.ac
@@ -4465,7 +4465,7 @@ AC_DEFUN
       EMACS_CHECK_MODULES([WEBKIT], [$WEBKIT_MODULES])
     fi
     HAVE_XWIDGETS=$HAVE_WEBKIT
-    XWIDGETS_OBJ="xwidget.o"
+    XWIDGETS_OBJ="xwidget.o xwidget-webkit.o"
     if test "$HAVE_X_WINDOWS" = "yes" && test "${with_cairo}" = "no"; then
       CAIRO_XLIB_MODULES="cairo >= 1.8.0 cairo-xlib >= 1.8.0"
       EMACS_CHECK_MODULES([CAIRO_XLIB], [$CAIRO_XLIB_MODULES])
@@ -4485,7 +4485,7 @@ AC_DEFUN
     WEBKIT_CFLAGS="-I/System/Library/Frameworks/WebKit.framework/Headers"
     HAVE_WEBKIT="yes"
     HAVE_XWIDGETS=$HAVE_WEBKIT
-    XWIDGETS_OBJ="xwidget.o"
+    XWIDGETS_OBJ="xwidget.o xwidget-webkit.o"
     NS_OBJC_OBJ="$NS_OBJC_OBJ nsxwidget.o"
     dnl Update NS_OBJC_OBJ with added nsxwidget.o
     AC_SUBST([NS_OBJC_OBJ])
diff --git a/lisp/xwidget.el b/lisp/xwidget.el
index bf5987d742f..da50005c17a 100644
--- a/lisp/xwidget.el
+++ b/lisp/xwidget.el
@@ -41,13 +41,6 @@
 (declare-function set-xwidget-buffer "xwidget.c" (xwidget buffer))
 (declare-function xwidget-size-request "xwidget.c" (xwidget))
 (declare-function xwidget-resize "xwidget.c" (xwidget new-width new-height))
-(declare-function xwidget-webkit-execute-script "xwidget.c"
-                  (xwidget script &optional callback))
-(declare-function xwidget-webkit-uri "xwidget.c" (xwidget))
-(declare-function xwidget-webkit-title "xwidget.c" (xwidget))
-(declare-function xwidget-webkit-goto-uri "xwidget.c" (xwidget uri))
-(declare-function xwidget-webkit-goto-history "xwidget.c" (xwidget rel-pos))
-(declare-function xwidget-webkit-zoom "xwidget.c" (xwidget factor))
 (declare-function xwidget-plist "xwidget.c" (xwidget))
 (declare-function set-xwidget-plist "xwidget.c" (xwidget plist))
 (declare-function xwidget-view-window "xwidget.c" (xwidget-view))
@@ -55,13 +48,21 @@
 (declare-function delete-xwidget-view "xwidget.c" (xwidget-view))
 (declare-function get-buffer-xwidgets "xwidget.c" (buffer))
 (declare-function xwidget-query-on-exit-flag "xwidget.c" (xwidget))
-(declare-function xwidget-webkit-back-forward-list "xwidget.c" (xwidget &optional limit))
-(declare-function xwidget-webkit-estimated-load-progress "xwidget.c" (xwidget))
-(declare-function xwidget-webkit-set-cookie-storage-file "xwidget.c" (xwidget file))
 (declare-function xwidget-live-p "xwidget.c" (xwidget))
-(declare-function xwidget-webkit-stop-loading "xwidget.c" (xwidget))
 (declare-function xwidget-info "xwidget.c" (xwidget))
 
+(declare-function xwidget-webkit-back-forward-list "xwidget-webkit.c" (xwidget &optional limit))
+(declare-function xwidget-webkit-estimated-load-progress "xwidget-webkit.c" (xwidget))
+(declare-function xwidget-webkit-set-cookie-storage-file "xwidget-webkit.c" (xwidget file))
+(declare-function xwidget-webkit-stop-loading "xwidget-webkit.c" (xwidget))
+(declare-function xwidget-webkit-execute-script "xwidget-webkit.c"
+                  (xwidget script &optional callback))
+(declare-function xwidget-webkit-uri "xwidget-webkit.c" (xwidget))
+(declare-function xwidget-webkit-title "xwidget-webkit.c" (xwidget))
+(declare-function xwidget-webkit-goto-uri "xwidget-webkit.c" (xwidget uri))
+(declare-function xwidget-webkit-goto-history "xwidget-webkit.c" (xwidget rel-pos))
+(declare-function xwidget-webkit-zoom "xwidget-webkit.c" (xwidget factor))
+
 (defgroup xwidget nil
   "Displaying native widgets in Emacs buffers."
   :group 'widgets)
diff --git a/src/emacs.c b/src/emacs.c
index 22b7a4f1038..b5f4cc015d1 100644
--- a/src/emacs.c
+++ b/src/emacs.c
@@ -97,6 +97,7 @@ #define MAIN_PROGRAM
 #include "buffer.h"
 #include "window.h"
 #include "xwidget.h"
+#include "xwidget-webkit.h"
 #include "atimer.h"
 #include "blockinput.h"
 #include "syssignal.h"
@@ -2471,6 +2472,7 @@ main (int argc, char **argv)
 #endif /* WINDOWSNT */
 
       syms_of_xwidget ();
+      syms_of_xwidget_webkit ();
       syms_of_threads ();
       syms_of_profiler ();
       syms_of_pdumper ();
diff --git a/src/xwidget-webkit.c b/src/xwidget-webkit.c
new file mode 100644
index 00000000000..5d98bfc758f
--- /dev/null
+++ b/src/xwidget-webkit.c
@@ -0,0 +1,1225 @@
+/* WebkitGTK xwidget for embedding a graphical web browser.
+
+Copyright (C) 2011-2024 Free Software Foundation, Inc.
+
+This file is part of GNU Emacs.
+
+GNU Emacs is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or (at
+your option) any later version.
+
+GNU Emacs 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 General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Emacs.  If not, see <https://www.gnu.org/licenses/>.  */
+
+#include <config.h>
+
+#include "coding.h"
+#include "xwidget.h"
+#include "xwidget-webkit.h"
+#include "lisp.h"
+#include "blockinput.h"
+#include "frame.h"
+#include "process.h"
+
+/* Include xwidget bottom end headers.  */
+#ifdef USE_GTK
+#include <webkit2/webkit2.h>
+#include <JavaScriptCore/JavaScript.h>
+#endif
+
+#ifdef USE_GTK
+static gboolean webkit_script_dialog_cb (WebKitWebView *, WebKitScriptDialog *,
+					 gpointer);
+
+static void webkit_view_load_changed_cb (WebKitWebView *,
+                                         WebKitLoadEvent,
+                                         gpointer);
+static void webkit_javascript_finished_cb (GObject *,
+                                           GAsyncResult *,
+                                           gpointer);
+static gboolean webkit_download_cb (WebKitWebContext *, WebKitDownload *, gpointer);
+static GtkWidget *webkit_create_cb (WebKitWebView *, WebKitNavigationAction *, gpointer);
+static gboolean
+webkit_decide_policy_cb (WebKitWebView *,
+                         WebKitPolicyDecision *,
+                         WebKitPolicyDecisionType,
+                         gpointer);
+static gboolean run_file_chooser_cb (WebKitWebView *,
+				     WebKitFileChooserRequest *,
+				     gpointer);
+#endif
+
+#ifdef HAVE_PGTK
+static void mouse_target_changed (WebKitWebView *, WebKitHitTestResult *, guint,
+				  gpointer);
+#endif
+
+void
+xwidget_webkit_make_widget (struct xwidget *xw, Lisp_Object related)
+{
+  WebKitWebView *related_view;
+  WebKitSettings *settings;
+  WebKitWebContext *webkit_context = webkit_web_context_get_default ();
+
+# if WEBKIT_CHECK_VERSION (2, 26, 0)
+  if (!webkit_web_context_get_sandbox_enabled (webkit_context))
+    webkit_web_context_set_sandbox_enabled (webkit_context, TRUE);
+# endif
+
+  if (NILP (related)
+      || !XWIDGETP (related)
+      || !EQ (XXWIDGET (related)->type, Qwebkit))
+    {
+      WebKitWebContext *ctx = webkit_web_context_new ();
+      xw->widget_osr = webkit_web_view_new_with_context (ctx);
+      g_object_unref (ctx);
+
+      g_signal_connect (G_OBJECT (ctx),
+			"download-started",
+			G_CALLBACK (webkit_download_cb), xw);
+
+      webkit_web_view_load_uri (WEBKIT_WEB_VIEW (xw->widget_osr),
+				"about:blank");
+      /* webkitgtk uses GSubprocess which sets sigaction causing
+	 Emacs to not catch SIGCHLD with its usual handle setup in
+	 'catch_child_signal'.  This resets the SIGCHLD sigaction.  */
+      catch_child_signal ();
+    }
+  else
+    {
+      related_view = WEBKIT_WEB_VIEW (XXWIDGET (related)->widget_osr);
+      xw->widget_osr = webkit_web_view_new_with_related_view (related_view);
+    }
+
+  /* Enable the developer extras.  */
+  settings = webkit_web_view_get_settings (WEBKIT_WEB_VIEW (xw->widget_osr));
+  g_object_set (G_OBJECT (settings), "enable-developer-extras", TRUE, NULL);
+  g_object_set (G_OBJECT (settings), "enable-javascript",
+		(gboolean) (!xwidget_webkit_disable_javascript), NULL);
+}
+
+void
+xwidget_webkit_connect_signals (struct xwidget *xw)
+{
+  g_signal_connect (G_OBJECT (xw->widget_osr),
+		    "load-changed",
+		    G_CALLBACK (webkit_view_load_changed_cb), xw);
+
+  g_signal_connect (G_OBJECT (xw->widget_osr),
+		    "decide-policy",
+		    G_CALLBACK
+		    (webkit_decide_policy_cb),
+		    xw);
+#ifdef HAVE_PGTK
+  g_signal_connect (G_OBJECT (xw->widget_osr),
+		    "mouse-target-changed",
+		    G_CALLBACK (mouse_target_changed),
+		    xw);
+#endif
+  g_signal_connect (G_OBJECT (xw->widget_osr),
+		    "create",
+		    G_CALLBACK (webkit_create_cb),
+		    xw);
+  g_signal_connect (G_OBJECT (xw->widget_osr),
+		    "script-dialog",
+		    G_CALLBACK (webkit_script_dialog_cb),
+		    NULL);
+  g_signal_connect (G_OBJECT (xw->widget_osr),
+		    "run-file-chooser",
+		    G_CALLBACK (run_file_chooser_cb),
+		    NULL);
+}
+
+#ifdef HAVE_PGTK
+Emacs_Cursor
+xwidget_webkit_cursor_for_hit (guint result, struct frame *frame)
+{
+  Emacs_Cursor cursor = FRAME_OUTPUT_DATA (frame)->nontext_cursor;
+
+  if ((result & WEBKIT_HIT_TEST_RESULT_CONTEXT_EDITABLE)
+      || (result & WEBKIT_HIT_TEST_RESULT_CONTEXT_SELECTION)
+      || (result & WEBKIT_HIT_TEST_RESULT_CONTEXT_DOCUMENT))
+    cursor = FRAME_X_OUTPUT (frame)->text_cursor;
+
+  if (result & WEBKIT_HIT_TEST_RESULT_CONTEXT_SCROLLBAR)
+    cursor = FRAME_X_OUTPUT (frame)->vertical_drag_cursor;
+
+  if (result & WEBKIT_HIT_TEST_RESULT_CONTEXT_LINK)
+    cursor = FRAME_X_OUTPUT (frame)->hand_cursor;
+
+  return cursor;
+}
+
+static void
+define_cursors (struct xwidget *xw, WebKitHitTestResult *res)
+{
+  struct xwidget_view *xvw;
+  GdkWindow *wdesc;
+
+  xw->hit_result = webkit_hit_test_result_get_context (res);
+
+  for (Lisp_Object tem = internal_xwidget_view_list; CONSP (tem);
+       tem = XCDR (tem))
+    {
+      if (XWIDGET_VIEW_P (XCAR (tem)))
+	{
+	  xvw = XXWIDGET_VIEW (XCAR (tem));
+
+	  if (XXWIDGET (xvw->model) == xw)
+	    {
+	      xvw->cursor = xwidget_webkit_cursor_for_hit (xw->hit_result, xvw->frame);
+
+	      if (gtk_widget_get_realized (xvw->widget))
+		{
+		  wdesc = gtk_widget_get_window (xvw->widget);
+		  gdk_window_set_cursor (wdesc, xvw->cursor);
+		}
+	    }
+	}
+    }
+}
+
+static void
+mouse_target_changed (WebKitWebView *webview,
+		      WebKitHitTestResult *hitresult,
+		      guint modifiers, gpointer xw)
+{
+  define_cursors (xw, hitresult);
+}
+#endif
+
+static gboolean
+run_file_chooser_cb (WebKitWebView *webview,
+		     WebKitFileChooserRequest *request,
+		     gpointer user_data)
+{
+  struct frame *f = SELECTED_FRAME ();
+  GtkFileChooserNative *chooser;
+  GtkFileFilter *filter;
+  bool select_multiple_p;
+  guint response;
+  GSList *filenames;
+  GSList *tem;
+  int i, len;
+  gchar **files;
+
+  /* Return TRUE to prevent WebKit from showing the default script
+     dialog in the offscreen window, which runs a nested main loop
+     Emacs can't respond to, and as such can't pass X events to.  */
+  if (!FRAME_WINDOW_P (f))
+    return TRUE;
+
+  chooser = gtk_file_chooser_native_new ("Select file",
+					 GTK_WINDOW (FRAME_GTK_OUTER_WIDGET (f)),
+					 GTK_FILE_CHOOSER_ACTION_OPEN, "Select",
+					 "Cancel");
+  filter = webkit_file_chooser_request_get_mime_types_filter (request);
+  select_multiple_p = webkit_file_chooser_request_get_select_multiple (request);
+
+  gtk_file_chooser_set_select_multiple (GTK_FILE_CHOOSER (chooser),
+					select_multiple_p);
+  gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (chooser), filter);
+  response = gtk_native_dialog_run (GTK_NATIVE_DIALOG (chooser));
+
+  if (response != GTK_RESPONSE_ACCEPT)
+    {
+      gtk_native_dialog_destroy (GTK_NATIVE_DIALOG (chooser));
+      webkit_file_chooser_request_cancel (request);
+
+      return TRUE;
+    }
+
+  filenames = gtk_file_chooser_get_filenames (GTK_FILE_CHOOSER (chooser));
+  len = g_slist_length (filenames);
+  files = alloca (sizeof *files * (len + 1));
+
+  for (tem = filenames, i = 0; tem; tem = tem->next, ++i)
+    files[i] = tem->data;
+  files[len] = NULL;
+
+  g_slist_free (filenames);
+  webkit_file_chooser_request_select_files (request, (const gchar **) files);
+
+  for (i = 0; i < len; ++i)
+    g_free (files[i]);
+
+  gtk_native_dialog_destroy (GTK_NATIVE_DIALOG (chooser));
+
+  return TRUE;
+}
+
+#ifdef USE_GTK
+static void
+webkit_ready_to_show (WebKitWebView *new_view,
+		      gpointer user_data)
+{
+  Lisp_Object tem;
+  struct xwidget *xw;
+  struct xwidget *src;
+
+  src = find_xwidget_for_offscreen_window (GDK_WINDOW (user_data));
+
+  for (tem = internal_xwidget_list; CONSP (tem); tem = XCDR (tem))
+    {
+      if (XWIDGETP (XCAR (tem)))
+	{
+	  xw = XXWIDGET (XCAR (tem));
+
+	  if (EQ (xw->type, Qwebkit)
+	      && WEBKIT_WEB_VIEW (xw->widget_osr) == new_view)
+	    {
+	      /* The source widget was destroyed before we had a
+		 chance to display the new widget.  */
+	      if (!src)
+		kill_xwidget (xw);
+	      else
+		store_xwidget_display_event (xw, src);
+	    }
+	}
+    }
+}
+
+static GtkWidget *
+webkit_create_cb_1 (WebKitWebView *webview,
+		    struct xwidget *xv)
+{
+  Lisp_Object related;
+  Lisp_Object xwidget;
+  GtkWidget *widget;
+
+  XSETXWIDGET (related, xv);
+  xwidget = Fmake_xwidget (Qwebkit, Qnil, make_fixnum (0),
+			   make_fixnum (0), Qnil,
+			   build_string (" *detached xwidget buffer*"),
+			   related);
+
+  if (NILP (xwidget))
+    return NULL;
+
+  widget = XXWIDGET (xwidget)->widget_osr;
+
+  g_signal_connect (G_OBJECT (widget), "ready-to-show",
+		    G_CALLBACK (webkit_ready_to_show),
+		    gtk_widget_get_window (xv->widgetwindow_osr));
+
+  return widget;
+}
+
+static GtkWidget *
+webkit_create_cb (WebKitWebView *webview,
+		  WebKitNavigationAction *nav_action,
+		  gpointer user_data)
+{
+  switch (webkit_navigation_action_get_navigation_type (nav_action))
+    {
+    case WEBKIT_NAVIGATION_TYPE_OTHER:
+      return webkit_create_cb_1 (webview, user_data);
+
+    case WEBKIT_NAVIGATION_TYPE_BACK_FORWARD:
+    case WEBKIT_NAVIGATION_TYPE_RELOAD:
+    case WEBKIT_NAVIGATION_TYPE_FORM_SUBMITTED:
+    case WEBKIT_NAVIGATION_TYPE_FORM_RESUBMITTED:
+    case WEBKIT_NAVIGATION_TYPE_LINK_CLICKED:
+    default:
+      return NULL;
+    }
+}
+
+void
+webkit_view_load_changed_cb (WebKitWebView *webkitwebview,
+                             WebKitLoadEvent load_event,
+                             gpointer data)
+{
+  struct xwidget *xw = g_object_get_data (G_OBJECT (webkitwebview),
+					  XG_XWIDGET);
+
+  switch (load_event)
+    {
+    case WEBKIT_LOAD_FINISHED:
+      store_xwidget_event_string (xw, "load-changed", "load-finished");
+      break;
+    case WEBKIT_LOAD_STARTED:
+      store_xwidget_event_string (xw, "load-changed", "load-started");
+      break;
+    case WEBKIT_LOAD_REDIRECTED:
+      store_xwidget_event_string (xw, "load-changed", "load-redirected");
+      break;
+    case WEBKIT_LOAD_COMMITTED:
+      store_xwidget_event_string (xw, "load-changed", "load-committed");
+      break;
+    }
+}
+
+/* Recursively convert a JavaScript value to a Lisp value. */
+static Lisp_Object
+webkit_js_to_lisp (JSCValue *value)
+{
+  if (jsc_value_is_string (value))
+    {
+      gchar *str_value = jsc_value_to_string (value);
+      Lisp_Object ret = build_string (str_value);
+      g_free (str_value);
+
+      return ret;
+    }
+  else if (jsc_value_is_boolean (value))
+    {
+      return (jsc_value_to_boolean (value)) ? Qt : Qnil;
+    }
+  else if (jsc_value_is_number (value))
+    {
+      return make_fixnum (jsc_value_to_int32 (value));
+    }
+  else if (jsc_value_is_array (value))
+    {
+      JSCValue *len = jsc_value_object_get_property (value, "length");
+      const gint32 dlen = jsc_value_to_int32 (len);
+
+      Lisp_Object obj;
+      if (! (0 <= dlen && dlen < G_MAXINT32))
+	memory_full (SIZE_MAX);
+
+      ptrdiff_t n = dlen;
+      struct Lisp_Vector *p = allocate_nil_vector (n);
+
+      for (ptrdiff_t i = 0; i < n; ++i)
+	{
+	  p->contents[i] =
+	    webkit_js_to_lisp (jsc_value_object_get_property_at_index (value, i));
+	}
+      XSETVECTOR (obj, p);
+      return obj;
+    }
+  else if (jsc_value_is_object (value))
+    {
+      char **properties_names = jsc_value_object_enumerate_properties (value);
+      guint n = g_strv_length (properties_names);
+
+      Lisp_Object obj;
+      if (PTRDIFF_MAX < n)
+	memory_full (n);
+      struct Lisp_Vector *p = allocate_nil_vector (n);
+
+      for (ptrdiff_t i = 0; i < n; ++i)
+	{
+	  const char *name = properties_names[i];
+	  JSCValue *property = jsc_value_object_get_property (value, name);
+
+	  p->contents[i] =
+	    Fcons (build_string (name), webkit_js_to_lisp (property));
+	}
+
+      g_strfreev (properties_names);
+
+      XSETVECTOR (obj, p);
+      return obj;
+    }
+
+  return Qnil;
+}
+
+static void
+webkit_javascript_finished_cb (GObject      *webview,
+                               GAsyncResult *result,
+                               gpointer      arg)
+{
+  GError *error = NULL;
+  struct xwidget *xw = g_object_get_data (G_OBJECT (webview), XG_XWIDGET);
+
+  ptrdiff_t script_idx = (intptr_t) arg;
+  Lisp_Object script_callback = AREF (xw->script_callbacks, script_idx);
+  ASET (xw->script_callbacks, script_idx, Qnil);
+  if (!NILP (script_callback))
+    xfree (xmint_pointer (XCAR (script_callback)));
+
+  WebKitJavascriptResult *js_result =
+    webkit_web_view_run_javascript_finish
+    (WEBKIT_WEB_VIEW (webview), result, &error);
+
+  if (!js_result)
+    {
+      if (error)
+	g_error_free (error);
+      return;
+    }
+
+  if (!NILP (script_callback) && !NILP (XCDR (script_callback)))
+    {
+      JSCValue *value = webkit_javascript_result_get_js_value (js_result);
+
+      Lisp_Object lisp_value = webkit_js_to_lisp (value);
+
+      /* Register an xwidget event here, which then runs the callback.
+	 This ensures that the callback runs in sync with the Emacs
+	 event loop.  */
+      store_xwidget_js_callback_event (xw, XCDR (script_callback), lisp_value);
+    }
+
+  webkit_javascript_result_unref (js_result);
+}
+
+
+gboolean
+webkit_download_cb (WebKitWebContext *webkitwebcontext,
+                    WebKitDownload *arg1,
+                    gpointer data)
+{
+  WebKitWebView *view = webkit_download_get_web_view(arg1);
+  WebKitURIRequest *request = webkit_download_get_request(arg1);
+  struct xwidget *xw = g_object_get_data (G_OBJECT (view),
+                                          XG_XWIDGET);
+
+  store_xwidget_event_string (xw, "download-started",
+                              webkit_uri_request_get_uri(request));
+  return FALSE;
+}
+
+static gboolean
+webkit_decide_policy_cb (WebKitWebView *webView,
+                         WebKitPolicyDecision *decision,
+                         WebKitPolicyDecisionType type,
+                         gpointer user_data)
+{
+  switch (type) {
+  case WEBKIT_POLICY_DECISION_TYPE_RESPONSE:
+    /* This function makes webkit send a download signal for all unknown
+       mime types.  TODO: Defer the decision to Lisp, so that it's
+       possible to make Emacs handle mime text for instance.  */
+    {
+      WebKitResponsePolicyDecision *response =
+        WEBKIT_RESPONSE_POLICY_DECISION (decision);
+      if (!webkit_response_policy_decision_is_mime_type_supported (response))
+        {
+          webkit_policy_decision_download (decision);
+          return TRUE;
+        }
+      else
+        return FALSE;
+      break;
+    }
+  case WEBKIT_POLICY_DECISION_TYPE_NEW_WINDOW_ACTION:
+    {
+      WebKitNavigationPolicyDecision *navigation_decision =
+        WEBKIT_NAVIGATION_POLICY_DECISION (decision);
+      WebKitNavigationAction *navigation_action =
+        webkit_navigation_policy_decision_get_navigation_action (navigation_decision);
+      WebKitURIRequest *request =
+        webkit_navigation_action_get_request (navigation_action);
+      WebKitWebView *newview;
+      struct xwidget *xw = g_object_get_data (G_OBJECT (webView), XG_XWIDGET);
+      Lisp_Object val, new_xwidget;
+
+      XSETXWIDGET (val, xw);
+
+      new_xwidget = Fmake_xwidget (Qwebkit, Qnil, make_fixnum (0),
+				   make_fixnum (0), Qnil,
+				   build_string (" *detached xwidget buffer*"),
+				   val);
+
+      if (NILP (new_xwidget))
+	return FALSE;
+
+      newview = WEBKIT_WEB_VIEW (XXWIDGET (new_xwidget)->widget_osr);
+      webkit_web_view_load_request (newview, request);
+
+      store_xwidget_display_event (XXWIDGET (new_xwidget), xw);
+      return TRUE;
+    }
+  case WEBKIT_POLICY_DECISION_TYPE_NAVIGATION_ACTION:
+    {
+      WebKitNavigationPolicyDecision *navigation_decision =
+        WEBKIT_NAVIGATION_POLICY_DECISION (decision);
+      WebKitNavigationAction *navigation_action =
+        webkit_navigation_policy_decision_get_navigation_action (navigation_decision);
+      WebKitURIRequest *request =
+        webkit_navigation_action_get_request (navigation_action);
+
+      struct xwidget *xw = g_object_get_data (G_OBJECT (webView), XG_XWIDGET);
+      store_xwidget_event_string (xw, "decide-policy",
+                                  webkit_uri_request_get_uri (request));
+      return FALSE;
+      break;
+    }
+  default:
+    return FALSE;
+  }
+}
+
+static gboolean
+webkit_script_dialog_cb (WebKitWebView *webview,
+			 WebKitScriptDialog *script_dialog,
+			 gpointer user)
+{
+  struct frame *f = SELECTED_FRAME ();
+  WebKitScriptDialogType type;
+  GtkWidget *widget;
+  GtkWidget *dialog;
+  GtkWidget *entry;
+  GtkWidget *content_area;
+  GtkWidget *box;
+  GtkWidget *label;
+  const gchar *content;
+  const gchar *message;
+  gint result;
+
+  /* Return TRUE to prevent WebKit from showing the default script
+     dialog in the offscreen window, which runs a nested main loop
+     Emacs can't respond to, and as such can't pass X events to.  */
+  if (!FRAME_WINDOW_P (f))
+    return TRUE;
+
+  type = webkit_script_dialog_get_dialog_type (script_dialog);;
+  widget = FRAME_GTK_OUTER_WIDGET (f);
+  content = webkit_script_dialog_get_message (script_dialog);
+
+  if (type == WEBKIT_SCRIPT_DIALOG_ALERT)
+    dialog = gtk_dialog_new_with_buttons ("Alert", GTK_WINDOW (widget),
+					  GTK_DIALOG_MODAL,
+					  "Dismiss", 1, NULL);
+  else
+    dialog = gtk_dialog_new_with_buttons ("Question", GTK_WINDOW (widget),
+					  GTK_DIALOG_MODAL,
+					  "OK", 0, "Cancel", 1, NULL);
+
+  box = gtk_box_new (GTK_ORIENTATION_VERTICAL, 8);
+  label = gtk_label_new (content);
+  content_area = gtk_dialog_get_content_area (GTK_DIALOG (dialog));
+  gtk_container_add (GTK_CONTAINER (content_area), box);
+
+  gtk_widget_show (box);
+  gtk_widget_show (label);
+
+  gtk_box_pack_start (GTK_BOX (box), label, TRUE, TRUE, 0);
+
+  if (type == WEBKIT_SCRIPT_DIALOG_PROMPT)
+    {
+      entry = gtk_entry_new ();
+      message = webkit_script_dialog_prompt_get_default_text (script_dialog);
+
+      gtk_widget_show (entry);
+      gtk_entry_set_text (GTK_ENTRY (entry), message);
+      gtk_box_pack_end (GTK_BOX (box), entry, TRUE, TRUE, 0);
+    }
+
+  result = gtk_dialog_run (GTK_DIALOG (dialog));
+
+  if (type == WEBKIT_SCRIPT_DIALOG_CONFIRM
+      || type == WEBKIT_SCRIPT_DIALOG_BEFORE_UNLOAD_CONFIRM)
+    webkit_script_dialog_confirm_set_confirmed (script_dialog, result == 0);
+
+  if (type == WEBKIT_SCRIPT_DIALOG_PROMPT)
+    webkit_script_dialog_prompt_set_text (script_dialog,
+					  gtk_entry_get_text (GTK_ENTRY (entry)));
+
+  gtk_widget_destroy (GTK_WIDGET (dialog));
+
+  return TRUE;
+}
+#endif /* USE_GTK */
+
+
+#define CHECK_WEBKIT_WIDGET(xw)				\
+  if (NILP (xw->buffer) || !EQ (xw->type, Qwebkit))	\
+    error ("Not a WebKit widget")
+
+/* Macro that checks xwidget hold webkit web view first.  */
+#define WEBKIT_FN_INIT()						\
+  CHECK_LIVE_XWIDGET (xwidget);						\
+  struct xwidget *xw = XXWIDGET (xwidget);				\
+  CHECK_WEBKIT_WIDGET (xw)
+
+DEFUN ("xwidget-webkit-uri",
+       Fxwidget_webkit_uri, Sxwidget_webkit_uri,
+       1, 1, 0,
+       doc: /* Get the current URL of XWIDGET webkit.  */)
+  (Lisp_Object xwidget)
+{
+  WEBKIT_FN_INIT ();
+#ifdef USE_GTK
+  WebKitWebView *wkwv = WEBKIT_WEB_VIEW (xw->widget_osr);
+  const gchar *uri = webkit_web_view_get_uri (wkwv);
+  if (!uri)
+    return build_string ("");
+  return build_string (uri);
+#elif defined NS_IMPL_COCOA
+  return nsxwidget_webkit_uri (xw);
+#endif
+}
+
+DEFUN ("xwidget-webkit-title",
+       Fxwidget_webkit_title, Sxwidget_webkit_title,
+       1, 1, 0,
+       doc: /* Get the current title of XWIDGET webkit.  */)
+  (Lisp_Object xwidget)
+{
+  WEBKIT_FN_INIT ();
+#ifdef USE_GTK
+  WebKitWebView *wkwv = WEBKIT_WEB_VIEW (xw->widget_osr);
+  const gchar *title = webkit_web_view_get_title (wkwv);
+
+  return build_string (title ? title : "");
+#elif defined NS_IMPL_COCOA
+  return nsxwidget_webkit_title (xw);
+#endif
+}
+
+DEFUN ("xwidget-webkit-estimated-load-progress",
+       Fxwidget_webkit_estimated_load_progress, Sxwidget_webkit_estimated_load_progress,
+       1, 1, 0, doc: /* Get the estimated load progress of XWIDGET, a WebKit widget.
+Return a value ranging from 0.0 to 1.0, based on how close XWIDGET
+is to completely loading its page.  */)
+  (Lisp_Object xwidget)
+{
+  struct xwidget *xw;
+#ifdef USE_GTK
+  WebKitWebView *webview;
+#endif
+  double value;
+
+  CHECK_LIVE_XWIDGET (xwidget);
+  xw = XXWIDGET (xwidget);
+  CHECK_WEBKIT_WIDGET (xw);
+
+  block_input ();
+#ifdef USE_GTK
+  webview = WEBKIT_WEB_VIEW (xw->widget_osr);
+  value = webkit_web_view_get_estimated_load_progress (webview);
+#elif defined NS_IMPL_COCOA
+  value = nsxwidget_webkit_estimated_load_progress (xw);
+#endif
+
+  unblock_input ();
+
+  return make_float (value);
+}
+
+DEFUN ("xwidget-webkit-goto-uri",
+       Fxwidget_webkit_goto_uri, Sxwidget_webkit_goto_uri,
+       2, 2, 0,
+       doc: /* Make the xwidget webkit instance referenced by XWIDGET browse URI.  */)
+  (Lisp_Object xwidget, Lisp_Object uri)
+{
+  WEBKIT_FN_INIT ();
+  CHECK_STRING (uri);
+  uri = ENCODE_FILE (uri);
+#ifdef USE_GTK
+  webkit_web_view_load_uri (WEBKIT_WEB_VIEW (xw->widget_osr), SSDATA (uri));
+  catch_child_signal ();
+#elif defined NS_IMPL_COCOA
+  nsxwidget_webkit_goto_uri (xw, SSDATA (uri));
+#endif
+  return Qnil;
+}
+
+DEFUN ("xwidget-webkit-goto-history",
+       Fxwidget_webkit_goto_history, Sxwidget_webkit_goto_history,
+       2, 2, 0,
+       doc: /* Make the XWIDGET webkit the REL-POSth element in load history.
+
+If REL-POS is 0, the widget will be just reload the current element in
+history.  If REL-POS is more or less than 0, the widget will load the
+REL-POSth element around the current spot in the load history. */)
+  (Lisp_Object xwidget, Lisp_Object rel_pos)
+{
+  WEBKIT_FN_INIT ();
+  CHECK_FIXNUM (rel_pos);
+
+#ifdef USE_GTK
+  WebKitWebView *wkwv = WEBKIT_WEB_VIEW (xw->widget_osr);
+  WebKitBackForwardList *list;
+  WebKitBackForwardListItem *it;
+
+  if (XFIXNUM (rel_pos) == 0)
+    webkit_web_view_reload (wkwv);
+  else
+    {
+      list = webkit_web_view_get_back_forward_list (wkwv);
+      it = webkit_back_forward_list_get_nth_item (list, XFIXNUM (rel_pos));
+
+      if (!it)
+	error ("There is no item at this index");
+
+      webkit_web_view_go_to_back_forward_list_item (wkwv, it);
+    }
+#elif defined NS_IMPL_COCOA
+  nsxwidget_webkit_goto_history (xw, XFIXNAT (rel_pos));
+#endif
+  return Qnil;
+}
+
+DEFUN ("xwidget-webkit-zoom",
+       Fxwidget_webkit_zoom, Sxwidget_webkit_zoom,
+       2, 2, 0,
+       doc: /* Change the zoom factor of the xwidget webkit instance referenced by XWIDGET.  */)
+  (Lisp_Object xwidget, Lisp_Object factor)
+{
+  WEBKIT_FN_INIT ();
+  if (FLOATP (factor))
+    {
+      double zoom_change = XFLOAT_DATA (factor);
+#ifdef USE_GTK
+      webkit_web_view_set_zoom_level
+        (WEBKIT_WEB_VIEW (xw->widget_osr),
+         webkit_web_view_get_zoom_level
+         (WEBKIT_WEB_VIEW (xw->widget_osr)) + zoom_change);
+#elif defined NS_IMPL_COCOA
+      nsxwidget_webkit_zoom (xw, zoom_change);
+#endif
+    }
+  return Qnil;
+}
+
+#ifdef USE_GTK
+/* Save script and fun in the script/callback save vector and return
+   its index.  */
+static ptrdiff_t
+save_script_callback (struct xwidget *xw, Lisp_Object script, Lisp_Object fun)
+{
+  Lisp_Object cbs = xw->script_callbacks;
+  if (NILP (cbs))
+    xw->script_callbacks = cbs = make_nil_vector (32);
+
+  /* Find first free index.  */
+  ptrdiff_t idx;
+  for (idx = 0; !NILP (AREF (cbs, idx)); idx++)
+    if (idx + 1 == ASIZE (cbs))
+      {
+	xw->script_callbacks = cbs = larger_vector (cbs, 1, -1);
+	break;
+      }
+
+  ASET (cbs, idx, Fcons (make_mint_ptr (xlispstrdup (script)), fun));
+  return idx;
+}
+#endif
+
+DEFUN ("xwidget-webkit-execute-script",
+       Fxwidget_webkit_execute_script, Sxwidget_webkit_execute_script,
+       2, 3, 0,
+       doc: /* Make the Webkit XWIDGET execute JavaScript SCRIPT.
+If FUN is provided, feed the JavaScript return value to the single
+argument procedure FUN.*/)
+  (Lisp_Object xwidget, Lisp_Object script, Lisp_Object fun)
+{
+  WEBKIT_FN_INIT ();
+  CHECK_STRING (script);
+  if (!NILP (fun) && !FUNCTIONP (fun))
+    wrong_type_argument (Qinvalid_function, fun);
+
+  script = ENCODE_SYSTEM (script);
+
+#ifdef USE_GTK
+  /* Protect script and fun during GC.  */
+  intptr_t idx = save_script_callback (xw, script, fun);
+
+  /* JavaScript execution happens asynchronously.  If an elisp
+     callback function is provided we pass it to the C callback
+     procedure that retrieves the return value.  */
+  gchar *script_string
+    = xmint_pointer (XCAR (AREF (xw->script_callbacks, idx)));
+  webkit_web_view_run_javascript (WEBKIT_WEB_VIEW (xw->widget_osr),
+				  script_string,
+                                  NULL, /* cancelable */
+                                  webkit_javascript_finished_cb,
+				  (gpointer) idx);
+#elif defined NS_IMPL_COCOA
+  nsxwidget_webkit_execute_script (xw, SSDATA (script), fun);
+#endif
+  return Qnil;
+}
+
+
+DEFUN ("xwidget-webkit-search", Fxwidget_webkit_search, Sxwidget_webkit_search,
+       2, 5, 0,
+       doc: /* Begin an incremental search operation in an xwidget.
+QUERY should be a string containing the text to search for.  XWIDGET
+should be a WebKit xwidget where the search will take place.  When the
+search operation is complete, callers should also call
+`xwidget-webkit-finish-search' to complete the search operation.
+
+CASE-INSENSITIVE, when non-nil, will cause the search to ignore the
+case of characters inside QUERY.  BACKWARDS, when non-nil, will cause
+the search to proceed towards the beginning of the widget's contents.
+WRAP-AROUND, when nil, will cause the search to stop upon hitting the
+end of the widget's contents.
+
+It is OK to call this function even when a search is already in
+progress.  In that case, the previous search query will be replaced
+with QUERY.  */)
+  (Lisp_Object query, Lisp_Object xwidget, Lisp_Object case_insensitive,
+   Lisp_Object backwards, Lisp_Object wrap_around)
+{
+#ifdef USE_GTK
+  WebKitWebView *webview;
+  WebKitFindController *controller;
+  WebKitFindOptions opt;
+  struct xwidget *xw;
+  gchar *g_query;
+#endif
+
+  CHECK_STRING (query);
+  CHECK_LIVE_XWIDGET (xwidget);
+
+#ifdef USE_GTK
+  xw = XXWIDGET (xwidget);
+  CHECK_WEBKIT_WIDGET (xw);
+
+  webview = WEBKIT_WEB_VIEW (xw->widget_osr);
+  query = ENCODE_UTF_8 (query);
+  opt = WEBKIT_FIND_OPTIONS_NONE;
+  g_query = xstrdup (SSDATA (query));
+
+  if (!NILP (case_insensitive))
+    opt |= WEBKIT_FIND_OPTIONS_CASE_INSENSITIVE;
+  if (!NILP (backwards))
+    opt |= WEBKIT_FIND_OPTIONS_BACKWARDS;
+  if (!NILP (wrap_around))
+    opt |= WEBKIT_FIND_OPTIONS_WRAP_AROUND;
+
+  if (xw->find_text)
+    xfree (xw->find_text);
+  xw->find_text = g_query;
+
+  block_input ();
+  controller = webkit_web_view_get_find_controller (webview);
+  webkit_find_controller_search (controller, g_query, opt, G_MAXUINT);
+  unblock_input ();
+#endif
+
+  return Qnil;
+}
+
+DEFUN ("xwidget-webkit-next-result", Fxwidget_webkit_next_result,
+       Sxwidget_webkit_next_result, 1, 1, 0,
+       doc: /* Show the next result matching the current search query.
+
+XWIDGET should be an xwidget that currently has a search query.
+Before calling this function, you should start a search operation
+using `xwidget-webkit-search'.  */)
+  (Lisp_Object xwidget)
+{
+  struct xwidget *xw;
+#ifdef USE_GTK
+  WebKitWebView *webview;
+  WebKitFindController *controller;
+#endif
+
+  CHECK_LIVE_XWIDGET (xwidget);
+  xw = XXWIDGET (xwidget);
+  CHECK_WEBKIT_WIDGET (xw);
+
+  if (!xw->find_text)
+    error ("Widget has no ongoing search operation");
+
+#ifdef USE_GTK
+  block_input ();
+  webview = WEBKIT_WEB_VIEW (xw->widget_osr);
+  controller = webkit_web_view_get_find_controller (webview);
+  webkit_find_controller_search_next (controller);
+  unblock_input ();
+#endif
+
+  return Qnil;
+}
+
+DEFUN ("xwidget-webkit-previous-result", Fxwidget_webkit_previous_result,
+       Sxwidget_webkit_previous_result, 1, 1, 0,
+       doc: /* Show the previous result matching the current search query.
+
+XWIDGET should be an xwidget that currently has a search query.
+Before calling this function, you should start a search operation
+using `xwidget-webkit-search'.  */)
+  (Lisp_Object xwidget)
+{
+  struct xwidget *xw;
+#ifdef USE_GTK
+  WebKitWebView *webview;
+  WebKitFindController *controller;
+#endif
+
+  CHECK_LIVE_XWIDGET (xwidget);
+  xw = XXWIDGET (xwidget);
+  CHECK_WEBKIT_WIDGET (xw);
+
+  if (!xw->find_text)
+    error ("Widget has no ongoing search operation");
+
+#ifdef USE_GTK
+  block_input ();
+  webview = WEBKIT_WEB_VIEW (xw->widget_osr);
+  controller = webkit_web_view_get_find_controller (webview);
+  webkit_find_controller_search_previous (controller);
+  unblock_input ();
+#endif
+
+  return Qnil;
+}
+
+DEFUN ("xwidget-webkit-finish-search", Fxwidget_webkit_finish_search,
+       Sxwidget_webkit_finish_search, 1, 1, 0,
+       doc: /* Finish XWIDGET's search operation.
+
+XWIDGET should be an xwidget that currently has a search query.
+Before calling this function, you should start a search operation
+using `xwidget-webkit-search'.  */)
+  (Lisp_Object xwidget)
+{
+  struct xwidget *xw;
+#ifdef USE_GTK
+  WebKitWebView *webview;
+  WebKitFindController *controller;
+#endif
+
+  CHECK_LIVE_XWIDGET (xwidget);
+  xw = XXWIDGET (xwidget);
+  CHECK_WEBKIT_WIDGET (xw);
+
+  if (!xw->find_text)
+    error ("Widget has no ongoing search operation");
+
+#ifdef USE_GTK
+  block_input ();
+  webview = WEBKIT_WEB_VIEW (xw->widget_osr);
+  controller = webkit_web_view_get_find_controller (webview);
+  webkit_find_controller_search_finish (controller);
+
+  if (xw->find_text)
+    {
+      xfree (xw->find_text);
+      xw->find_text = NULL;
+    }
+  unblock_input ();
+#endif
+
+  return Qnil;
+}
+
+#ifdef USE_GTK
+DEFUN ("xwidget-webkit-load-html", Fxwidget_webkit_load_html,
+       Sxwidget_webkit_load_html, 2, 3, 0,
+       doc: /* Make XWIDGET's WebKit widget render TEXT.
+XWIDGET should be a WebKit xwidget, that will receive TEXT.  TEXT
+should be a string that will be displayed by XWIDGET as HTML markup.
+BASE-URI should be a string containing a URI that is used to locate
+resources with relative URLs, and if not specified, defaults
+to "about:blank".  */)
+  (Lisp_Object xwidget, Lisp_Object text, Lisp_Object base_uri)
+{
+  struct xwidget *xw;
+  WebKitWebView *webview;
+  char *data, *uri;
+
+  CHECK_LIVE_XWIDGET (xwidget);
+  CHECK_STRING (text);
+  if (NILP (base_uri))
+    base_uri = build_string ("about:blank");
+  else
+    CHECK_STRING (base_uri);
+
+  base_uri = ENCODE_UTF_8 (base_uri);
+  text = ENCODE_UTF_8 (text);
+  xw = XXWIDGET (xwidget);
+  CHECK_WEBKIT_WIDGET (xw);
+
+  data = SSDATA (text);
+  uri = SSDATA (base_uri);
+  webview = WEBKIT_WEB_VIEW (xw->widget_osr);
+
+  block_input ();
+  webkit_web_view_load_html (webview, data, uri);
+  unblock_input ();
+
+  return Qnil;
+}
+
+DEFUN ("xwidget-webkit-back-forward-list", Fxwidget_webkit_back_forward_list,
+       Sxwidget_webkit_back_forward_list, 1, 2, 0,
+       doc: /* Return the navigation history of XWIDGET, a WebKit xwidget.
+
+Return the history as a list of the form (BACK HERE FORWARD), where
+HERE is the current navigation item, while BACK and FORWARD are lists
+of history items of the form (IDX TITLE URI).  Here, IDX is an index
+that can be passed to `xwidget-webkit-goto-history', TITLE is a string
+containing the human-readable title of the history item, and URI is
+the URI of the history item.
+
+BACK, HERE, and FORWARD can all be nil depending on the state of the
+navigation history.
+
+BACK and FORWARD will each not contain more elements than LIMIT.  If
+LIMIT is not specified or nil, it is treated as `50'.  */)
+  (Lisp_Object xwidget, Lisp_Object limit)
+{
+  struct xwidget *xw;
+  Lisp_Object back, here, forward;
+  WebKitWebView *webview;
+  WebKitBackForwardList *list;
+  WebKitBackForwardListItem *item;
+  GList *parent, *tem;
+  int i;
+  unsigned int lim;
+  Lisp_Object title, uri;
+  const gchar *item_title, *item_uri;
+
+  back = Qnil;
+  here = Qnil;
+  forward = Qnil;
+
+  if (NILP (limit))
+    limit = make_fixnum (50);
+  else
+    CHECK_FIXNAT (limit);
+
+  CHECK_LIVE_XWIDGET (xwidget);
+  xw = XXWIDGET (xwidget);
+
+  webview = WEBKIT_WEB_VIEW (xw->widget_osr);
+  list = webkit_web_view_get_back_forward_list (webview);
+  item = webkit_back_forward_list_get_current_item (list);
+  lim = XFIXNAT (limit);
+
+  if (item)
+    {
+      item_title = webkit_back_forward_list_item_get_title (item);
+      item_uri = webkit_back_forward_list_item_get_uri (item);
+      here = list3 (make_fixnum (0),
+		    build_string_from_utf8 (item_title ? item_title : ""),
+		    build_string_from_utf8 (item_uri ? item_uri : ""));
+    }
+  parent = webkit_back_forward_list_get_back_list_with_limit (list, lim);
+
+  if (parent)
+    {
+      for (i = 1, tem = parent; tem; tem = tem->next, ++i)
+	{
+	  item = tem->data;
+	  item_title = webkit_back_forward_list_item_get_title (item);
+	  item_uri = webkit_back_forward_list_item_get_uri (item);
+	  title = build_string_from_utf8 (item_title ? item_title : "");
+	  uri = build_string_from_utf8 (item_uri ? item_uri : "");
+	  back = Fcons (list3 (make_fixnum (-i), title, uri), back);
+	}
+    }
+
+  back = Fnreverse (back);
+  g_list_free (parent);
+
+  parent = webkit_back_forward_list_get_forward_list_with_limit (list, lim);
+
+  if (parent)
+    {
+      for (i = 1, tem = parent; tem; tem = tem->next, ++i)
+	{
+	  item = tem->data;
+	  item_title = webkit_back_forward_list_item_get_title (item);
+	  item_uri = webkit_back_forward_list_item_get_uri (item);
+	  title = build_string_from_utf8 (item_title ? item_title : "");
+	  uri = build_string_from_utf8 (item_uri ? item_uri : "");
+	  forward = Fcons (list3 (make_fixnum (i), title, uri), forward);
+	}
+    }
+
+  forward = Fnreverse (forward);
+  g_list_free (parent);
+
+  return list3 (back, here, forward);
+}
+
+#endif
+
+DEFUN ("xwidget-webkit-set-cookie-storage-file",
+       Fxwidget_webkit_set_cookie_storage_file, Sxwidget_webkit_set_cookie_storage_file,
+       2, 2, 0, doc: /* Make the WebKit widget XWIDGET load and store cookies in FILE.
+
+Cookies will be stored as plain text in FILE, which must be an
+absolute file name.  All xwidgets related to XWIDGET will also
+store cookies in FILE and load them from there.  */)
+  (Lisp_Object xwidget, Lisp_Object file)
+{
+#ifdef USE_GTK
+  struct xwidget *xw;
+  WebKitWebView *webview;
+  WebKitWebContext *context;
+  WebKitCookieManager *manager;
+
+  CHECK_LIVE_XWIDGET (xwidget);
+  xw = XXWIDGET (xwidget);
+  CHECK_WEBKIT_WIDGET (xw);
+  CHECK_STRING (file);
+
+  block_input ();
+  webview = WEBKIT_WEB_VIEW (xw->widget_osr);
+  context = webkit_web_view_get_context (webview);
+  manager = webkit_web_context_get_cookie_manager (context);
+  webkit_cookie_manager_set_persistent_storage (manager,
+						SSDATA (ENCODE_UTF_8 (file)),
+						WEBKIT_COOKIE_PERSISTENT_STORAGE_TEXT);
+  unblock_input ();
+#endif
+
+  return Qnil;
+}
+
+DEFUN ("xwidget-webkit-stop-loading", Fxwidget_webkit_stop_loading,
+       Sxwidget_webkit_stop_loading,
+       1, 1, 0, doc: /* Stop loading data in the WebKit widget XWIDGET.
+This will stop any data transfer that may still be in progress inside
+XWIDGET as part of loading a page.  */)
+  (Lisp_Object xwidget)
+{
+  struct xwidget *xw;
+#ifdef USE_GTK
+  WebKitWebView *webview;
+#endif
+
+  CHECK_LIVE_XWIDGET (xwidget);
+  xw = XXWIDGET (xwidget);
+  CHECK_WEBKIT_WIDGET (xw);
+
+  block_input ();
+#ifdef USE_GTK
+  webview = WEBKIT_WEB_VIEW (xw->widget_osr);
+  webkit_web_view_stop_loading (webview);
+#elif defined NS_IMPL_COCOA
+  nsxwidget_webkit_stop_loading (xw);
+#endif
+  unblock_input ();
+
+  return Qnil;
+}
+
+void
+syms_of_xwidget_webkit (void)
+{
+  defsubr (&Sxwidget_webkit_uri);
+  defsubr (&Sxwidget_webkit_title);
+  defsubr (&Sxwidget_webkit_goto_uri);
+  defsubr (&Sxwidget_webkit_goto_history);
+  defsubr (&Sxwidget_webkit_zoom);
+  defsubr (&Sxwidget_webkit_execute_script);
+
+  defsubr (&Sxwidget_webkit_search);
+  defsubr (&Sxwidget_webkit_finish_search);
+  defsubr (&Sxwidget_webkit_next_result);
+  defsubr (&Sxwidget_webkit_previous_result);
+  defsubr (&Sxwidget_webkit_set_cookie_storage_file);
+  defsubr (&Sxwidget_webkit_stop_loading);
+  #ifdef USE_GTK
+  defsubr (&Sxwidget_webkit_load_html);
+  defsubr (&Sxwidget_webkit_back_forward_list);
+  #endif
+  defsubr (&Sxwidget_webkit_estimated_load_progress);
+
+  DEFVAR_BOOL ("xwidget-webkit-disable-javascript", xwidget_webkit_disable_javascript,
+    doc: /* If non-nil, disable execution of JavaScript in xwidget WebKit widgets.
+Modifications to this setting do not take effect in existing WebKit
+widgets; kill all xwidget-webkit buffers for changes in this setting
+to take effect.  */);
+  xwidget_webkit_disable_javascript = false;
+}
diff --git a/src/xwidget-webkit.h b/src/xwidget-webkit.h
new file mode 100644
index 00000000000..b6b157dfd34
--- /dev/null
+++ b/src/xwidget-webkit.h
@@ -0,0 +1,35 @@
+/* WebkitGTK xwidget for embedding a graphical web browser.
+
+Copyright (C) 2011-2024 Free Software Foundation, Inc.
+
+This file is part of GNU Emacs.
+
+GNU Emacs is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or (at
+your option) any later version.
+
+GNU Emacs 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 General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Emacs.  If not, see <https://www.gnu.org/licenses/>.  */
+
+#ifndef XWIDGET_WEBKIT_H_INCLUDED
+#define XWIDGET_WEBKIT_H_INCLUDED
+
+#include "xwidget.h"
+
+#ifdef HAVE_XWIDGETS
+void xwidget_webkit_make_widget (struct xwidget *xw, Lisp_Object related);
+void xwidget_webkit_connect_signals (struct xwidget *xw);
+void syms_of_xwidget_webkit (void);
+#ifdef HAVE_PGTK
+Emacs_Cursor
+xwidget_webkit_cursor_for_hit (guint result, struct frame *frame);
+#endif
+#endif
+
+#endif /* XWIDGET_WEBKIT_H_INCLUDED */
diff --git a/src/xwidget.c b/src/xwidget.c
index 5093e0c1e00..01919c431ce 100644
--- a/src/xwidget.c
+++ b/src/xwidget.c
@@ -20,8 +20,8 @@ Copyright (C) 2011-2024 Free Software Foundation, Inc.
 #include <config.h>
 
 #include "buffer.h"
-#include "coding.h"
 #include "xwidget.h"
+#include "xwidget-webkit.h"
 #include "lisp.h"
 #include "blockinput.h"
 #include "dispextern.h"
@@ -36,10 +36,7 @@ Copyright (C) 2011-2024 Free Software Foundation, Inc.
 /* Include xwidget bottom end headers.  */
 #ifdef USE_GTK
 #include <webkit2/webkit2.h>
-#include <JavaScriptCore/JavaScript.h>
-#include <cairo.h>
 #ifndef HAVE_PGTK
-#include <cairo-xlib.h>
 #include <X11/Xlib.h>
 #else
 #include <gtk/gtk.h>
@@ -54,8 +51,8 @@ Copyright (C) 2011-2024 Free Software Foundation, Inc.
 #include <math.h>
 
 static Lisp_Object id_to_xwidget_map;
-static Lisp_Object internal_xwidget_view_list;
-static Lisp_Object internal_xwidget_list;
+Lisp_Object internal_xwidget_view_list;
+Lisp_Object internal_xwidget_list;
 static uint32_t xwidget_counter = 0;
 
 #ifdef USE_GTK
@@ -68,8 +65,6 @@ Copyright (C) 2011-2024 Free Software Foundation, Inc.
 static gboolean offscreen_damage_event (GtkWidget *, GdkEvent *, gpointer);
 static void synthesize_focus_in_event (GtkWidget *);
 static GdkDevice *find_suitable_keyboard (struct frame *);
-static gboolean webkit_script_dialog_cb (WebKitWebView *, WebKitScriptDialog *,
-					 gpointer);
 static void record_osr_embedder (struct xwidget_view *);
 static void from_embedder (GdkWindow *, double, double, gpointer, gpointer, gpointer);
 static void to_embedder (GdkWindow *, double, double, gpointer, gpointer, gpointer);
@@ -88,32 +83,10 @@ allocate_xwidget_view (void)
   return ALLOCATE_PSEUDOVECTOR (struct xwidget_view, w, PVEC_XWIDGET_VIEW);
 }
 
-#define XSETXWIDGET(a, b) XSETPSEUDOVECTOR (a, b, PVEC_XWIDGET)
-#define XSETXWIDGET_VIEW(a, b) XSETPSEUDOVECTOR (a, b, PVEC_XWIDGET_VIEW)
-
 static struct xwidget_view *xwidget_view_lookup (struct xwidget *,
 						 struct window *);
-static void kill_xwidget (struct xwidget *);
 
 #ifdef USE_GTK
-static void webkit_view_load_changed_cb (WebKitWebView *,
-                                         WebKitLoadEvent,
-                                         gpointer);
-static void webkit_javascript_finished_cb (GObject *,
-                                           GAsyncResult *,
-                                           gpointer);
-static gboolean webkit_download_cb (WebKitWebContext *, WebKitDownload *, gpointer);
-static GtkWidget *webkit_create_cb (WebKitWebView *, WebKitNavigationAction *, gpointer);
-static gboolean
-webkit_decide_policy_cb (WebKitWebView *,
-                         WebKitPolicyDecision *,
-                         WebKitPolicyDecisionType,
-                         gpointer);
-static GtkWidget *find_widget_at_pos (GtkWidget *, int, int, int *, int *, bool,
-				      struct xwidget_view *);
-static gboolean run_file_chooser_cb (WebKitWebView *,
-				     WebKitFileChooserRequest *,
-				     gpointer);
 
 struct widget_search_data
 {
@@ -125,11 +98,11 @@ webkit_decide_policy_cb (WebKitWebView *,
 };
 
 static void find_widget (GtkWidget *t, struct widget_search_data *);
+static GtkWidget *find_widget_at_pos (GtkWidget *, int, int, int *, int *, bool,
+				      struct xwidget_view *);
 #endif
 
 #ifdef HAVE_PGTK
-static void mouse_target_changed (WebKitWebView *, WebKitHitTestResult *, guint,
-				  gpointer);
 
 static int
 xw_forward_event_translate (GdkEvent *event, struct xwidget_view *xv,
@@ -330,128 +303,61 @@ DEFUN ("make-xwidget",
   xw->widgetwindow_osr = NULL;
   xw->widget_osr = NULL;
   xw->hit_result = 0;
-  if (EQ (xw->type, Qwebkit))
-    {
-      block_input ();
-      WebKitSettings *settings;
-      WebKitWebContext *webkit_context = webkit_web_context_get_default ();
-
-# if WEBKIT_CHECK_VERSION (2, 26, 0)
-      if (!webkit_web_context_get_sandbox_enabled (webkit_context))
-	webkit_web_context_set_sandbox_enabled (webkit_context, TRUE);
-# endif
-
-      xw->widgetwindow_osr = gtk_offscreen_window_new ();
-      gtk_window_resize (GTK_WINDOW (xw->widgetwindow_osr), xw->width,
-                         xw->height);
-      gtk_container_check_resize (GTK_CONTAINER (xw->widgetwindow_osr));
-
-      if (EQ (xw->type, Qwebkit))
-        {
-	  WebKitWebView *related_view;
+    block_input ();
 
-	  if (NILP (related)
-	      || !XWIDGETP (related)
-	      || !EQ (XXWIDGET (related)->type, Qwebkit))
-	    {
-	      WebKitWebContext *ctx = webkit_web_context_new ();
-	      xw->widget_osr = webkit_web_view_new_with_context (ctx);
-	      g_object_unref (ctx);
-
-	      g_signal_connect (G_OBJECT (ctx),
-				"download-started",
-				G_CALLBACK (webkit_download_cb), xw);
-
-	      webkit_web_view_load_uri (WEBKIT_WEB_VIEW (xw->widget_osr),
-					"about:blank");
-	      /* webkitgtk uses GSubprocess which sets sigaction causing
-		 Emacs to not catch SIGCHLD with its usual handle setup in
-		 'catch_child_signal'.  This resets the SIGCHLD sigaction.  */
-	      catch_child_signal ();
-	    }
-	  else
-	    {
-	      related_view = WEBKIT_WEB_VIEW (XXWIDGET (related)->widget_osr);
-	      xw->widget_osr = webkit_web_view_new_with_related_view (related_view);
-	    }
+  xw->widgetwindow_osr = gtk_offscreen_window_new ();
+  gtk_window_resize (GTK_WINDOW (xw->widgetwindow_osr), xw->width,
+		     xw->height);
+  gtk_container_check_resize (GTK_CONTAINER (xw->widgetwindow_osr));
 
-	  /* Enable the developer extras.  */
-	  settings = webkit_web_view_get_settings (WEBKIT_WEB_VIEW (xw->widget_osr));
-	  g_object_set (G_OBJECT (settings), "enable-developer-extras", TRUE, NULL);
-	  g_object_set (G_OBJECT (settings), "enable-javascript",
-		        (gboolean) (!xwidget_webkit_disable_javascript), NULL);
-	}
+  if (EQ (xw->type, Qwebkit))
+    {
+      xwidget_webkit_make_widget (xw, related);
+    }
 
-      gtk_widget_set_size_request (GTK_WIDGET (xw->widget_osr), xw->width,
-                                   xw->height);
-      gtk_widget_queue_allocate (GTK_WIDGET (xw->widget_osr));
+  gtk_widget_set_size_request (GTK_WIDGET (xw->widget_osr), xw->width,
+			       xw->height);
+  gtk_widget_queue_allocate (GTK_WIDGET (xw->widget_osr));
 
-      if (EQ (xw->type, Qwebkit))
-        {
-          gtk_container_add (GTK_CONTAINER (xw->widgetwindow_osr),
-                             GTK_WIDGET (WEBKIT_WEB_VIEW (xw->widget_osr)));
-        }
-      else
-        {
-          gtk_container_add (GTK_CONTAINER (xw->widgetwindow_osr),
-                             xw->widget_osr);
-        }
+  if (EQ (xw->type, Qwebkit))
+    {
+      gtk_container_add (GTK_CONTAINER (xw->widgetwindow_osr),
+			 GTK_WIDGET (WEBKIT_WEB_VIEW (xw->widget_osr)));
+    }
+  else
+    {
+      gtk_container_add (GTK_CONTAINER (xw->widgetwindow_osr),
+			 xw->widget_osr);
+    }
 
-      gtk_widget_show (xw->widget_osr);
-      gtk_widget_show (xw->widgetwindow_osr);
+  gtk_widget_show (xw->widget_osr);
+  gtk_widget_show (xw->widgetwindow_osr);
 #if !defined HAVE_XINPUT2 && !defined HAVE_PGTK
-      synthesize_focus_in_event (xw->widgetwindow_osr);
+  synthesize_focus_in_event (xw->widgetwindow_osr);
 #endif
 
-      g_signal_connect (G_OBJECT (gtk_widget_get_window (xw->widgetwindow_osr)),
-			"from-embedder", G_CALLBACK (from_embedder), NULL);
-      g_signal_connect (G_OBJECT (gtk_widget_get_window (xw->widgetwindow_osr)),
-			"to-embedder", G_CALLBACK (to_embedder), NULL);
-      g_signal_connect (G_OBJECT (gtk_widget_get_window (xw->widgetwindow_osr)),
-			"pick-embedded-child", G_CALLBACK (pick_embedded_child), NULL);
+  g_signal_connect (G_OBJECT (gtk_widget_get_window (xw->widgetwindow_osr)),
+		    "from-embedder", G_CALLBACK (from_embedder), NULL);
+  g_signal_connect (G_OBJECT (gtk_widget_get_window (xw->widgetwindow_osr)),
+		    "to-embedder", G_CALLBACK (to_embedder), NULL);
+  g_signal_connect (G_OBJECT (gtk_widget_get_window (xw->widgetwindow_osr)),
+		    "pick-embedded-child", G_CALLBACK (pick_embedded_child), NULL);
 
-      /* Store some xwidget data in the gtk widgets for convenient
-         retrieval in the event handlers.  */
-      g_object_set_data (G_OBJECT (xw->widget_osr), XG_XWIDGET, xw);
-      g_object_set_data (G_OBJECT (xw->widgetwindow_osr), XG_XWIDGET, xw);
+  /* Store some xwidget data in the gtk widgets for convenient
+     retrieval in the event handlers.  */
+  g_object_set_data (G_OBJECT (xw->widget_osr), XG_XWIDGET, xw);
+  g_object_set_data (G_OBJECT (xw->widgetwindow_osr), XG_XWIDGET, xw);
 
-      /* signals */
-      if (EQ (xw->type, Qwebkit))
-        {
-          g_signal_connect (G_OBJECT (xw->widget_osr),
-                            "load-changed",
-                            G_CALLBACK (webkit_view_load_changed_cb), xw);
-
-          g_signal_connect (G_OBJECT (xw->widget_osr),
-                            "decide-policy",
-                            G_CALLBACK
-                            (webkit_decide_policy_cb),
-                            xw);
-#ifdef HAVE_PGTK
-	  g_signal_connect (G_OBJECT (xw->widget_osr),
-			    "mouse-target-changed",
-			    G_CALLBACK (mouse_target_changed),
-			    xw);
-#endif
-	  g_signal_connect (G_OBJECT (xw->widget_osr),
-			    "create",
-			    G_CALLBACK (webkit_create_cb),
-			    xw);
-	  g_signal_connect (G_OBJECT (xw->widget_osr),
-			    "script-dialog",
-			    G_CALLBACK (webkit_script_dialog_cb),
-			    NULL);
-	  g_signal_connect (G_OBJECT (xw->widget_osr),
-			    "run-file-chooser",
-			    G_CALLBACK (run_file_chooser_cb),
-			    NULL);
-        }
+  /* signals */
+  if (EQ (xw->type, Qwebkit))
+    {
+      xwidget_webkit_connect_signals (xw);
+    }
 
-      g_signal_connect (G_OBJECT (xw->widgetwindow_osr), "damage-event",
-			G_CALLBACK (offscreen_damage_event), xw);
+  g_signal_connect (G_OBJECT (xw->widgetwindow_osr), "damage-event",
+		    G_CALLBACK (offscreen_damage_event), xw);
 
-      unblock_input ();
-    }
+  unblock_input ();
 #elif defined NS_IMPL_COCOA
   nsxwidget_init (xw);
 #endif
@@ -761,7 +667,7 @@ record_osr_embedder (struct xwidget_view *view)
   xw->embedder_view = view;
 }
 
-static struct xwidget *
+struct xwidget *
 find_xwidget_for_offscreen_window (GdkWindow *window)
 {
   Lisp_Object tem;
@@ -1041,124 +947,6 @@ find_widget_at_pos (GtkWidget *w, int x, int y,
   return NULL;
 }
 
-#ifdef HAVE_PGTK
-static Emacs_Cursor
-cursor_for_hit (guint result, struct frame *frame)
-{
-  Emacs_Cursor cursor = FRAME_OUTPUT_DATA (frame)->nontext_cursor;
-
-  if ((result & WEBKIT_HIT_TEST_RESULT_CONTEXT_EDITABLE)
-      || (result & WEBKIT_HIT_TEST_RESULT_CONTEXT_SELECTION)
-      || (result & WEBKIT_HIT_TEST_RESULT_CONTEXT_DOCUMENT))
-    cursor = FRAME_X_OUTPUT (frame)->text_cursor;
-
-  if (result & WEBKIT_HIT_TEST_RESULT_CONTEXT_SCROLLBAR)
-    cursor = FRAME_X_OUTPUT (frame)->vertical_drag_cursor;
-
-  if (result & WEBKIT_HIT_TEST_RESULT_CONTEXT_LINK)
-    cursor = FRAME_X_OUTPUT (frame)->hand_cursor;
-
-  return cursor;
-}
-
-static void
-define_cursors (struct xwidget *xw, WebKitHitTestResult *res)
-{
-  struct xwidget_view *xvw;
-  GdkWindow *wdesc;
-
-  xw->hit_result = webkit_hit_test_result_get_context (res);
-
-  for (Lisp_Object tem = internal_xwidget_view_list; CONSP (tem);
-       tem = XCDR (tem))
-    {
-      if (XWIDGET_VIEW_P (XCAR (tem)))
-	{
-	  xvw = XXWIDGET_VIEW (XCAR (tem));
-
-	  if (XXWIDGET (xvw->model) == xw)
-	    {
-	      xvw->cursor = cursor_for_hit (xw->hit_result, xvw->frame);
-
-	      if (gtk_widget_get_realized (xvw->widget))
-		{
-		  wdesc = gtk_widget_get_window (xvw->widget);
-		  gdk_window_set_cursor (wdesc, xvw->cursor);
-		}
-	    }
-	}
-    }
-}
-
-static void
-mouse_target_changed (WebKitWebView *webview,
-		      WebKitHitTestResult *hitresult,
-		      guint modifiers, gpointer xw)
-{
-  define_cursors (xw, hitresult);
-}
-#endif
-
-static gboolean
-run_file_chooser_cb (WebKitWebView *webview,
-		     WebKitFileChooserRequest *request,
-		     gpointer user_data)
-{
-  struct frame *f = SELECTED_FRAME ();
-  GtkFileChooserNative *chooser;
-  GtkFileFilter *filter;
-  bool select_multiple_p;
-  guint response;
-  GSList *filenames;
-  GSList *tem;
-  int i, len;
-  gchar **files;
-
-  /* Return TRUE to prevent WebKit from showing the default script
-     dialog in the offscreen window, which runs a nested main loop
-     Emacs can't respond to, and as such can't pass X events to.  */
-  if (!FRAME_WINDOW_P (f))
-    return TRUE;
-
-  chooser = gtk_file_chooser_native_new ("Select file",
-					 GTK_WINDOW (FRAME_GTK_OUTER_WIDGET (f)),
-					 GTK_FILE_CHOOSER_ACTION_OPEN, "Select",
-					 "Cancel");
-  filter = webkit_file_chooser_request_get_mime_types_filter (request);
-  select_multiple_p = webkit_file_chooser_request_get_select_multiple (request);
-
-  gtk_file_chooser_set_select_multiple (GTK_FILE_CHOOSER (chooser),
-					select_multiple_p);
-  gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (chooser), filter);
-  response = gtk_native_dialog_run (GTK_NATIVE_DIALOG (chooser));
-
-  if (response != GTK_RESPONSE_ACCEPT)
-    {
-      gtk_native_dialog_destroy (GTK_NATIVE_DIALOG (chooser));
-      webkit_file_chooser_request_cancel (request);
-
-      return TRUE;
-    }
-
-  filenames = gtk_file_chooser_get_filenames (GTK_FILE_CHOOSER (chooser));
-  len = g_slist_length (filenames);
-  files = alloca (sizeof *files * (len + 1));
-
-  for (tem = filenames, i = 0; tem; tem = tem->next, ++i)
-    files[i] = tem->data;
-  files[len] = NULL;
-
-  g_slist_free (filenames);
-  webkit_file_chooser_request_select_files (request, (const gchar **) files);
-
-  for (i = 0; i < len; ++i)
-    g_free (files[i]);
-
-  gtk_native_dialog_destroy (GTK_NATIVE_DIALOG (chooser));
-
-  return TRUE;
-}
-
 #ifdef HAVE_X_WINDOWS
 
 static void
@@ -2311,7 +2099,7 @@ store_xwidget_js_callback_event (struct xwidget *xw,
 
 
 #ifdef USE_GTK
-static void
+void
 store_xwidget_display_event (struct xwidget *xw,
 			     struct xwidget *src)
 {
@@ -2326,375 +2114,7 @@ store_xwidget_display_event (struct xwidget *xw,
   evt.arg = list2 (val, src_val);
   kbd_buffer_store_event (&evt);
 }
-
-static void
-webkit_ready_to_show (WebKitWebView *new_view,
-		      gpointer user_data)
-{
-  Lisp_Object tem;
-  struct xwidget *xw;
-  struct xwidget *src;
-
-  src = find_xwidget_for_offscreen_window (GDK_WINDOW (user_data));
-
-  for (tem = internal_xwidget_list; CONSP (tem); tem = XCDR (tem))
-    {
-      if (XWIDGETP (XCAR (tem)))
-	{
-	  xw = XXWIDGET (XCAR (tem));
-
-	  if (EQ (xw->type, Qwebkit)
-	      && WEBKIT_WEB_VIEW (xw->widget_osr) == new_view)
-	    {
-	      /* The source widget was destroyed before we had a
-		 chance to display the new widget.  */
-	      if (!src)
-		kill_xwidget (xw);
-	      else
-		store_xwidget_display_event (xw, src);
-	    }
-	}
-    }
-}
-
-static GtkWidget *
-webkit_create_cb_1 (WebKitWebView *webview,
-		    struct xwidget *xv)
-{
-  Lisp_Object related;
-  Lisp_Object xwidget;
-  GtkWidget *widget;
-
-  XSETXWIDGET (related, xv);
-  xwidget = Fmake_xwidget (Qwebkit, Qnil, make_fixnum (0),
-			   make_fixnum (0), Qnil,
-			   build_string (" *detached xwidget buffer*"),
-			   related);
-
-  if (NILP (xwidget))
-    return NULL;
-
-  widget = XXWIDGET (xwidget)->widget_osr;
-
-  g_signal_connect (G_OBJECT (widget), "ready-to-show",
-		    G_CALLBACK (webkit_ready_to_show),
-		    gtk_widget_get_window (xv->widgetwindow_osr));
-
-  return widget;
-}
-
-static GtkWidget *
-webkit_create_cb (WebKitWebView *webview,
-		  WebKitNavigationAction *nav_action,
-		  gpointer user_data)
-{
-  switch (webkit_navigation_action_get_navigation_type (nav_action))
-    {
-    case WEBKIT_NAVIGATION_TYPE_OTHER:
-      return webkit_create_cb_1 (webview, user_data);
-
-    case WEBKIT_NAVIGATION_TYPE_BACK_FORWARD:
-    case WEBKIT_NAVIGATION_TYPE_RELOAD:
-    case WEBKIT_NAVIGATION_TYPE_FORM_SUBMITTED:
-    case WEBKIT_NAVIGATION_TYPE_FORM_RESUBMITTED:
-    case WEBKIT_NAVIGATION_TYPE_LINK_CLICKED:
-    default:
-      return NULL;
-    }
-}
-
-void
-webkit_view_load_changed_cb (WebKitWebView *webkitwebview,
-                             WebKitLoadEvent load_event,
-                             gpointer data)
-{
-  struct xwidget *xw = g_object_get_data (G_OBJECT (webkitwebview),
-					  XG_XWIDGET);
-
-  switch (load_event)
-    {
-    case WEBKIT_LOAD_FINISHED:
-      store_xwidget_event_string (xw, "load-changed", "load-finished");
-      break;
-    case WEBKIT_LOAD_STARTED:
-      store_xwidget_event_string (xw, "load-changed", "load-started");
-      break;
-    case WEBKIT_LOAD_REDIRECTED:
-      store_xwidget_event_string (xw, "load-changed", "load-redirected");
-      break;
-    case WEBKIT_LOAD_COMMITTED:
-      store_xwidget_event_string (xw, "load-changed", "load-committed");
-      break;
-    }
-}
-
-/* Recursively convert a JavaScript value to a Lisp value. */
-static Lisp_Object
-webkit_js_to_lisp (JSCValue *value)
-{
-  if (jsc_value_is_string (value))
-    {
-      gchar *str_value = jsc_value_to_string (value);
-      Lisp_Object ret = build_string (str_value);
-      g_free (str_value);
-
-      return ret;
-    }
-  else if (jsc_value_is_boolean (value))
-    {
-      return (jsc_value_to_boolean (value)) ? Qt : Qnil;
-    }
-  else if (jsc_value_is_number (value))
-    {
-      return make_fixnum (jsc_value_to_int32 (value));
-    }
-  else if (jsc_value_is_array (value))
-    {
-      JSCValue *len = jsc_value_object_get_property (value, "length");
-      const gint32 dlen = jsc_value_to_int32 (len);
-
-      Lisp_Object obj;
-      if (! (0 <= dlen && dlen < G_MAXINT32))
-	memory_full (SIZE_MAX);
-
-      ptrdiff_t n = dlen;
-      struct Lisp_Vector *p = allocate_nil_vector (n);
-
-      for (ptrdiff_t i = 0; i < n; ++i)
-	{
-	  p->contents[i] =
-	    webkit_js_to_lisp (jsc_value_object_get_property_at_index (value, i));
-	}
-      XSETVECTOR (obj, p);
-      return obj;
-    }
-  else if (jsc_value_is_object (value))
-    {
-      char **properties_names = jsc_value_object_enumerate_properties (value);
-      guint n = g_strv_length (properties_names);
-
-      Lisp_Object obj;
-      if (PTRDIFF_MAX < n)
-	memory_full (n);
-      struct Lisp_Vector *p = allocate_nil_vector (n);
-
-      for (ptrdiff_t i = 0; i < n; ++i)
-	{
-	  const char *name = properties_names[i];
-	  JSCValue *property = jsc_value_object_get_property (value, name);
-
-	  p->contents[i] =
-	    Fcons (build_string (name), webkit_js_to_lisp (property));
-	}
-
-      g_strfreev (properties_names);
-
-      XSETVECTOR (obj, p);
-      return obj;
-    }
-
-  return Qnil;
-}
-
-static void
-webkit_javascript_finished_cb (GObject      *webview,
-                               GAsyncResult *result,
-                               gpointer      arg)
-{
-  GError *error = NULL;
-  struct xwidget *xw = g_object_get_data (G_OBJECT (webview), XG_XWIDGET);
-
-  ptrdiff_t script_idx = (intptr_t) arg;
-  Lisp_Object script_callback = AREF (xw->script_callbacks, script_idx);
-  ASET (xw->script_callbacks, script_idx, Qnil);
-  if (!NILP (script_callback))
-    xfree (xmint_pointer (XCAR (script_callback)));
-
-  WebKitJavascriptResult *js_result =
-    webkit_web_view_run_javascript_finish
-    (WEBKIT_WEB_VIEW (webview), result, &error);
-
-  if (!js_result)
-    {
-      if (error)
-	g_error_free (error);
-      return;
-    }
-
-  if (!NILP (script_callback) && !NILP (XCDR (script_callback)))
-    {
-      JSCValue *value = webkit_javascript_result_get_js_value (js_result);
-
-      Lisp_Object lisp_value = webkit_js_to_lisp (value);
-
-      /* Register an xwidget event here, which then runs the callback.
-	 This ensures that the callback runs in sync with the Emacs
-	 event loop.  */
-      store_xwidget_js_callback_event (xw, XCDR (script_callback), lisp_value);
-    }
-
-  webkit_javascript_result_unref (js_result);
-}
-
-
-gboolean
-webkit_download_cb (WebKitWebContext *webkitwebcontext,
-                    WebKitDownload *arg1,
-                    gpointer data)
-{
-  WebKitWebView *view = webkit_download_get_web_view(arg1);
-  WebKitURIRequest *request = webkit_download_get_request(arg1);
-  struct xwidget *xw = g_object_get_data (G_OBJECT (view),
-                                          XG_XWIDGET);
-
-  store_xwidget_event_string (xw, "download-started",
-                              webkit_uri_request_get_uri(request));
-  return FALSE;
-}
-
-static gboolean
-webkit_decide_policy_cb (WebKitWebView *webView,
-                         WebKitPolicyDecision *decision,
-                         WebKitPolicyDecisionType type,
-                         gpointer user_data)
-{
-  switch (type) {
-  case WEBKIT_POLICY_DECISION_TYPE_RESPONSE:
-    /* This function makes webkit send a download signal for all unknown
-       mime types.  TODO: Defer the decision to Lisp, so that it's
-       possible to make Emacs handle mime text for instance.  */
-    {
-      WebKitResponsePolicyDecision *response =
-        WEBKIT_RESPONSE_POLICY_DECISION (decision);
-      if (!webkit_response_policy_decision_is_mime_type_supported (response))
-        {
-          webkit_policy_decision_download (decision);
-          return TRUE;
-        }
-      else
-        return FALSE;
-      break;
-    }
-  case WEBKIT_POLICY_DECISION_TYPE_NEW_WINDOW_ACTION:
-    {
-      WebKitNavigationPolicyDecision *navigation_decision =
-        WEBKIT_NAVIGATION_POLICY_DECISION (decision);
-      WebKitNavigationAction *navigation_action =
-        webkit_navigation_policy_decision_get_navigation_action (navigation_decision);
-      WebKitURIRequest *request =
-        webkit_navigation_action_get_request (navigation_action);
-      WebKitWebView *newview;
-      struct xwidget *xw = g_object_get_data (G_OBJECT (webView), XG_XWIDGET);
-      Lisp_Object val, new_xwidget;
-
-      XSETXWIDGET (val, xw);
-
-      new_xwidget = Fmake_xwidget (Qwebkit, Qnil, make_fixnum (0),
-				   make_fixnum (0), Qnil,
-				   build_string (" *detached xwidget buffer*"),
-				   val);
-
-      if (NILP (new_xwidget))
-	return FALSE;
-
-      newview = WEBKIT_WEB_VIEW (XXWIDGET (new_xwidget)->widget_osr);
-      webkit_web_view_load_request (newview, request);
-
-      store_xwidget_display_event (XXWIDGET (new_xwidget), xw);
-      return TRUE;
-    }
-  case WEBKIT_POLICY_DECISION_TYPE_NAVIGATION_ACTION:
-    {
-      WebKitNavigationPolicyDecision *navigation_decision =
-        WEBKIT_NAVIGATION_POLICY_DECISION (decision);
-      WebKitNavigationAction *navigation_action =
-        webkit_navigation_policy_decision_get_navigation_action (navigation_decision);
-      WebKitURIRequest *request =
-        webkit_navigation_action_get_request (navigation_action);
-
-      struct xwidget *xw = g_object_get_data (G_OBJECT (webView), XG_XWIDGET);
-      store_xwidget_event_string (xw, "decide-policy",
-                                  webkit_uri_request_get_uri (request));
-      return FALSE;
-      break;
-    }
-  default:
-    return FALSE;
-  }
-}
-
-static gboolean
-webkit_script_dialog_cb (WebKitWebView *webview,
-			 WebKitScriptDialog *script_dialog,
-			 gpointer user)
-{
-  struct frame *f = SELECTED_FRAME ();
-  WebKitScriptDialogType type;
-  GtkWidget *widget;
-  GtkWidget *dialog;
-  GtkWidget *entry;
-  GtkWidget *content_area;
-  GtkWidget *box;
-  GtkWidget *label;
-  const gchar *content;
-  const gchar *message;
-  gint result;
-
-  /* Return TRUE to prevent WebKit from showing the default script
-     dialog in the offscreen window, which runs a nested main loop
-     Emacs can't respond to, and as such can't pass X events to.  */
-  if (!FRAME_WINDOW_P (f))
-    return TRUE;
-
-  type = webkit_script_dialog_get_dialog_type (script_dialog);;
-  widget = FRAME_GTK_OUTER_WIDGET (f);
-  content = webkit_script_dialog_get_message (script_dialog);
-
-  if (type == WEBKIT_SCRIPT_DIALOG_ALERT)
-    dialog = gtk_dialog_new_with_buttons ("Alert", GTK_WINDOW (widget),
-					  GTK_DIALOG_MODAL,
-					  "Dismiss", 1, NULL);
-  else
-    dialog = gtk_dialog_new_with_buttons ("Question", GTK_WINDOW (widget),
-					  GTK_DIALOG_MODAL,
-					  "OK", 0, "Cancel", 1, NULL);
-
-  box = gtk_box_new (GTK_ORIENTATION_VERTICAL, 8);
-  label = gtk_label_new (content);
-  content_area = gtk_dialog_get_content_area (GTK_DIALOG (dialog));
-  gtk_container_add (GTK_CONTAINER (content_area), box);
-
-  gtk_widget_show (box);
-  gtk_widget_show (label);
-
-  gtk_box_pack_start (GTK_BOX (box), label, TRUE, TRUE, 0);
-
-  if (type == WEBKIT_SCRIPT_DIALOG_PROMPT)
-    {
-      entry = gtk_entry_new ();
-      message = webkit_script_dialog_prompt_get_default_text (script_dialog);
-
-      gtk_widget_show (entry);
-      gtk_entry_set_text (GTK_ENTRY (entry), message);
-      gtk_box_pack_end (GTK_BOX (box), entry, TRUE, TRUE, 0);
-    }
-
-  result = gtk_dialog_run (GTK_DIALOG (dialog));
-
-  if (type == WEBKIT_SCRIPT_DIALOG_CONFIRM
-      || type == WEBKIT_SCRIPT_DIALOG_BEFORE_UNLOAD_CONFIRM)
-    webkit_script_dialog_confirm_set_confirmed (script_dialog, result == 0);
-
-  if (type == WEBKIT_SCRIPT_DIALOG_PROMPT)
-    webkit_script_dialog_prompt_set_text (script_dialog,
-					  gtk_entry_get_text (GTK_ENTRY (entry)));
-
-  gtk_widget_destroy (GTK_WIDGET (dialog));
-
-  return TRUE;
-}
-#endif /* USE_GTK */
-
+#endif
 
 /* Initializes and does initial placement of an xwidget view on screen.  */
 static struct xwidget_view *
@@ -2759,7 +2179,7 @@ xwidget_init_view (struct xwidget *xww,
   xv->clip_bottom = xww->height;
 
   xv->frame = s->f;
-  xv->cursor = cursor_for_hit (xww->hit_result, s->f);
+  xv->cursor = xwidget_webkit_cursor_for_hit (xww->hit_result, s->f);
   xv->just_resized = false;
 #elif defined NS_IMPL_COCOA
   nsxwidget_init_view (xv, xww, s, x, y);
@@ -3019,216 +2439,6 @@ x_draw_xwidget_glyph_string (struct glyph_string *s)
 #endif
 }
 
-#define CHECK_WEBKIT_WIDGET(xw)				\
-  if (NILP (xw->buffer) || !EQ (xw->type, Qwebkit))	\
-    error ("Not a WebKit widget")
-
-/* Macro that checks xwidget hold webkit web view first.  */
-#define WEBKIT_FN_INIT()						\
-  CHECK_LIVE_XWIDGET (xwidget);						\
-  struct xwidget *xw = XXWIDGET (xwidget);				\
-  CHECK_WEBKIT_WIDGET (xw)
-
-DEFUN ("xwidget-webkit-uri",
-       Fxwidget_webkit_uri, Sxwidget_webkit_uri,
-       1, 1, 0,
-       doc: /* Get the current URL of XWIDGET webkit.  */)
-  (Lisp_Object xwidget)
-{
-  WEBKIT_FN_INIT ();
-#ifdef USE_GTK
-  WebKitWebView *wkwv = WEBKIT_WEB_VIEW (xw->widget_osr);
-  const gchar *uri = webkit_web_view_get_uri (wkwv);
-  if (!uri)
-    return build_string ("");
-  return build_string (uri);
-#elif defined NS_IMPL_COCOA
-  return nsxwidget_webkit_uri (xw);
-#endif
-}
-
-DEFUN ("xwidget-webkit-title",
-       Fxwidget_webkit_title, Sxwidget_webkit_title,
-       1, 1, 0,
-       doc: /* Get the current title of XWIDGET webkit.  */)
-  (Lisp_Object xwidget)
-{
-  WEBKIT_FN_INIT ();
-#ifdef USE_GTK
-  WebKitWebView *wkwv = WEBKIT_WEB_VIEW (xw->widget_osr);
-  const gchar *title = webkit_web_view_get_title (wkwv);
-
-  return build_string (title ? title : "");
-#elif defined NS_IMPL_COCOA
-  return nsxwidget_webkit_title (xw);
-#endif
-}
-
-DEFUN ("xwidget-webkit-estimated-load-progress",
-       Fxwidget_webkit_estimated_load_progress, Sxwidget_webkit_estimated_load_progress,
-       1, 1, 0, doc: /* Get the estimated load progress of XWIDGET, a WebKit widget.
-Return a value ranging from 0.0 to 1.0, based on how close XWIDGET
-is to completely loading its page.  */)
-  (Lisp_Object xwidget)
-{
-  struct xwidget *xw;
-#ifdef USE_GTK
-  WebKitWebView *webview;
-#endif
-  double value;
-
-  CHECK_LIVE_XWIDGET (xwidget);
-  xw = XXWIDGET (xwidget);
-  CHECK_WEBKIT_WIDGET (xw);
-
-  block_input ();
-#ifdef USE_GTK
-  webview = WEBKIT_WEB_VIEW (xw->widget_osr);
-  value = webkit_web_view_get_estimated_load_progress (webview);
-#elif defined NS_IMPL_COCOA
-  value = nsxwidget_webkit_estimated_load_progress (xw);
-#endif
-
-  unblock_input ();
-
-  return make_float (value);
-}
-
-DEFUN ("xwidget-webkit-goto-uri",
-       Fxwidget_webkit_goto_uri, Sxwidget_webkit_goto_uri,
-       2, 2, 0,
-       doc: /* Make the xwidget webkit instance referenced by XWIDGET browse URI.  */)
-  (Lisp_Object xwidget, Lisp_Object uri)
-{
-  WEBKIT_FN_INIT ();
-  CHECK_STRING (uri);
-  uri = ENCODE_FILE (uri);
-#ifdef USE_GTK
-  webkit_web_view_load_uri (WEBKIT_WEB_VIEW (xw->widget_osr), SSDATA (uri));
-  catch_child_signal ();
-#elif defined NS_IMPL_COCOA
-  nsxwidget_webkit_goto_uri (xw, SSDATA (uri));
-#endif
-  return Qnil;
-}
-
-DEFUN ("xwidget-webkit-goto-history",
-       Fxwidget_webkit_goto_history, Sxwidget_webkit_goto_history,
-       2, 2, 0,
-       doc: /* Make the XWIDGET webkit the REL-POSth element in load history.
-
-If REL-POS is 0, the widget will be just reload the current element in
-history.  If REL-POS is more or less than 0, the widget will load the
-REL-POSth element around the current spot in the load history. */)
-  (Lisp_Object xwidget, Lisp_Object rel_pos)
-{
-  WEBKIT_FN_INIT ();
-  CHECK_FIXNUM (rel_pos);
-
-#ifdef USE_GTK
-  WebKitWebView *wkwv = WEBKIT_WEB_VIEW (xw->widget_osr);
-  WebKitBackForwardList *list;
-  WebKitBackForwardListItem *it;
-
-  if (XFIXNUM (rel_pos) == 0)
-    webkit_web_view_reload (wkwv);
-  else
-    {
-      list = webkit_web_view_get_back_forward_list (wkwv);
-      it = webkit_back_forward_list_get_nth_item (list, XFIXNUM (rel_pos));
-
-      if (!it)
-	error ("There is no item at this index");
-
-      webkit_web_view_go_to_back_forward_list_item (wkwv, it);
-    }
-#elif defined NS_IMPL_COCOA
-  nsxwidget_webkit_goto_history (xw, XFIXNAT (rel_pos));
-#endif
-  return Qnil;
-}
-
-DEFUN ("xwidget-webkit-zoom",
-       Fxwidget_webkit_zoom, Sxwidget_webkit_zoom,
-       2, 2, 0,
-       doc: /* Change the zoom factor of the xwidget webkit instance referenced by XWIDGET.  */)
-  (Lisp_Object xwidget, Lisp_Object factor)
-{
-  WEBKIT_FN_INIT ();
-  if (FLOATP (factor))
-    {
-      double zoom_change = XFLOAT_DATA (factor);
-#ifdef USE_GTK
-      webkit_web_view_set_zoom_level
-        (WEBKIT_WEB_VIEW (xw->widget_osr),
-         webkit_web_view_get_zoom_level
-         (WEBKIT_WEB_VIEW (xw->widget_osr)) + zoom_change);
-#elif defined NS_IMPL_COCOA
-      nsxwidget_webkit_zoom (xw, zoom_change);
-#endif
-    }
-  return Qnil;
-}
-
-#ifdef USE_GTK
-/* Save script and fun in the script/callback save vector and return
-   its index.  */
-static ptrdiff_t
-save_script_callback (struct xwidget *xw, Lisp_Object script, Lisp_Object fun)
-{
-  Lisp_Object cbs = xw->script_callbacks;
-  if (NILP (cbs))
-    xw->script_callbacks = cbs = make_nil_vector (32);
-
-  /* Find first free index.  */
-  ptrdiff_t idx;
-  for (idx = 0; !NILP (AREF (cbs, idx)); idx++)
-    if (idx + 1 == ASIZE (cbs))
-      {
-	xw->script_callbacks = cbs = larger_vector (cbs, 1, -1);
-	break;
-      }
-
-  ASET (cbs, idx, Fcons (make_mint_ptr (xlispstrdup (script)), fun));
-  return idx;
-}
-#endif
-
-DEFUN ("xwidget-webkit-execute-script",
-       Fxwidget_webkit_execute_script, Sxwidget_webkit_execute_script,
-       2, 3, 0,
-       doc: /* Make the Webkit XWIDGET execute JavaScript SCRIPT.
-If FUN is provided, feed the JavaScript return value to the single
-argument procedure FUN.*/)
-  (Lisp_Object xwidget, Lisp_Object script, Lisp_Object fun)
-{
-  WEBKIT_FN_INIT ();
-  CHECK_STRING (script);
-  if (!NILP (fun) && !FUNCTIONP (fun))
-    wrong_type_argument (Qinvalid_function, fun);
-
-  script = ENCODE_SYSTEM (script);
-
-#ifdef USE_GTK
-  /* Protect script and fun during GC.  */
-  intptr_t idx = save_script_callback (xw, script, fun);
-
-  /* JavaScript execution happens asynchronously.  If an elisp
-     callback function is provided we pass it to the C callback
-     procedure that retrieves the return value.  */
-  gchar *script_string
-    = xmint_pointer (XCAR (AREF (xw->script_callbacks, idx)));
-  webkit_web_view_run_javascript (WEBKIT_WEB_VIEW (xw->widget_osr),
-				  script_string,
-                                  NULL, /* cancelable */
-                                  webkit_javascript_finished_cb,
-				  (gpointer) idx);
-#elif defined NS_IMPL_COCOA
-  nsxwidget_webkit_execute_script (xw, SSDATA (script), fun);
-#endif
-  return Qnil;
-}
-
 DEFUN ("xwidget-resize", Fxwidget_resize, Sxwidget_resize, 3, 3, 0,
        doc: /* Resize XWIDGET to NEW_WIDTH, NEW_HEIGHT.  */ )
   (Lisp_Object xwidget, Lisp_Object new_width, Lisp_Object new_height)
@@ -3526,171 +2736,6 @@ DEFUN ("xwidget-query-on-exit-flag",
   return (XXWIDGET (xwidget)->kill_without_query ? Qnil : Qt);
 }
 
-DEFUN ("xwidget-webkit-search", Fxwidget_webkit_search, Sxwidget_webkit_search,
-       2, 5, 0,
-       doc: /* Begin an incremental search operation in an xwidget.
-QUERY should be a string containing the text to search for.  XWIDGET
-should be a WebKit xwidget where the search will take place.  When the
-search operation is complete, callers should also call
-`xwidget-webkit-finish-search' to complete the search operation.
-
-CASE-INSENSITIVE, when non-nil, will cause the search to ignore the
-case of characters inside QUERY.  BACKWARDS, when non-nil, will cause
-the search to proceed towards the beginning of the widget's contents.
-WRAP-AROUND, when nil, will cause the search to stop upon hitting the
-end of the widget's contents.
-
-It is OK to call this function even when a search is already in
-progress.  In that case, the previous search query will be replaced
-with QUERY.  */)
-  (Lisp_Object query, Lisp_Object xwidget, Lisp_Object case_insensitive,
-   Lisp_Object backwards, Lisp_Object wrap_around)
-{
-#ifdef USE_GTK
-  WebKitWebView *webview;
-  WebKitFindController *controller;
-  WebKitFindOptions opt;
-  struct xwidget *xw;
-  gchar *g_query;
-#endif
-
-  CHECK_STRING (query);
-  CHECK_LIVE_XWIDGET (xwidget);
-
-#ifdef USE_GTK
-  xw = XXWIDGET (xwidget);
-  CHECK_WEBKIT_WIDGET (xw);
-
-  webview = WEBKIT_WEB_VIEW (xw->widget_osr);
-  query = ENCODE_UTF_8 (query);
-  opt = WEBKIT_FIND_OPTIONS_NONE;
-  g_query = xstrdup (SSDATA (query));
-
-  if (!NILP (case_insensitive))
-    opt |= WEBKIT_FIND_OPTIONS_CASE_INSENSITIVE;
-  if (!NILP (backwards))
-    opt |= WEBKIT_FIND_OPTIONS_BACKWARDS;
-  if (!NILP (wrap_around))
-    opt |= WEBKIT_FIND_OPTIONS_WRAP_AROUND;
-
-  if (xw->find_text)
-    xfree (xw->find_text);
-  xw->find_text = g_query;
-
-  block_input ();
-  controller = webkit_web_view_get_find_controller (webview);
-  webkit_find_controller_search (controller, g_query, opt, G_MAXUINT);
-  unblock_input ();
-#endif
-
-  return Qnil;
-}
-
-DEFUN ("xwidget-webkit-next-result", Fxwidget_webkit_next_result,
-       Sxwidget_webkit_next_result, 1, 1, 0,
-       doc: /* Show the next result matching the current search query.
-
-XWIDGET should be an xwidget that currently has a search query.
-Before calling this function, you should start a search operation
-using `xwidget-webkit-search'.  */)
-  (Lisp_Object xwidget)
-{
-  struct xwidget *xw;
-#ifdef USE_GTK
-  WebKitWebView *webview;
-  WebKitFindController *controller;
-#endif
-
-  CHECK_LIVE_XWIDGET (xwidget);
-  xw = XXWIDGET (xwidget);
-  CHECK_WEBKIT_WIDGET (xw);
-
-  if (!xw->find_text)
-    error ("Widget has no ongoing search operation");
-
-#ifdef USE_GTK
-  block_input ();
-  webview = WEBKIT_WEB_VIEW (xw->widget_osr);
-  controller = webkit_web_view_get_find_controller (webview);
-  webkit_find_controller_search_next (controller);
-  unblock_input ();
-#endif
-
-  return Qnil;
-}
-
-DEFUN ("xwidget-webkit-previous-result", Fxwidget_webkit_previous_result,
-       Sxwidget_webkit_previous_result, 1, 1, 0,
-       doc: /* Show the previous result matching the current search query.
-
-XWIDGET should be an xwidget that currently has a search query.
-Before calling this function, you should start a search operation
-using `xwidget-webkit-search'.  */)
-  (Lisp_Object xwidget)
-{
-  struct xwidget *xw;
-#ifdef USE_GTK
-  WebKitWebView *webview;
-  WebKitFindController *controller;
-#endif
-
-  CHECK_LIVE_XWIDGET (xwidget);
-  xw = XXWIDGET (xwidget);
-  CHECK_WEBKIT_WIDGET (xw);
-
-  if (!xw->find_text)
-    error ("Widget has no ongoing search operation");
-
-#ifdef USE_GTK
-  block_input ();
-  webview = WEBKIT_WEB_VIEW (xw->widget_osr);
-  controller = webkit_web_view_get_find_controller (webview);
-  webkit_find_controller_search_previous (controller);
-  unblock_input ();
-#endif
-
-  return Qnil;
-}
-
-DEFUN ("xwidget-webkit-finish-search", Fxwidget_webkit_finish_search,
-       Sxwidget_webkit_finish_search, 1, 1, 0,
-       doc: /* Finish XWIDGET's search operation.
-
-XWIDGET should be an xwidget that currently has a search query.
-Before calling this function, you should start a search operation
-using `xwidget-webkit-search'.  */)
-  (Lisp_Object xwidget)
-{
-  struct xwidget *xw;
-#ifdef USE_GTK
-  WebKitWebView *webview;
-  WebKitFindController *controller;
-#endif
-
-  CHECK_LIVE_XWIDGET (xwidget);
-  xw = XXWIDGET (xwidget);
-  CHECK_WEBKIT_WIDGET (xw);
-
-  if (!xw->find_text)
-    error ("Widget has no ongoing search operation");
-
-#ifdef USE_GTK
-  block_input ();
-  webview = WEBKIT_WEB_VIEW (xw->widget_osr);
-  controller = webkit_web_view_get_find_controller (webview);
-  webkit_find_controller_search_finish (controller);
-
-  if (xw->find_text)
-    {
-      xfree (xw->find_text);
-      xw->find_text = NULL;
-    }
-  unblock_input ();
-#endif
-
-  return Qnil;
-}
-
 DEFUN ("kill-xwidget", Fkill_xwidget, Skill_xwidget,
        1, 1, 0,
        doc: /* Kill the specified XWIDGET.
@@ -3710,200 +2755,6 @@ DEFUN ("kill-xwidget", Fkill_xwidget, Skill_xwidget,
   return Qnil;
 }
 
-#ifdef USE_GTK
-DEFUN ("xwidget-webkit-load-html", Fxwidget_webkit_load_html,
-       Sxwidget_webkit_load_html, 2, 3, 0,
-       doc: /* Make XWIDGET's WebKit widget render TEXT.
-XWIDGET should be a WebKit xwidget, that will receive TEXT.  TEXT
-should be a string that will be displayed by XWIDGET as HTML markup.
-BASE-URI should be a string containing a URI that is used to locate
-resources with relative URLs, and if not specified, defaults
-to "about:blank".  */)
-  (Lisp_Object xwidget, Lisp_Object text, Lisp_Object base_uri)
-{
-  struct xwidget *xw;
-  WebKitWebView *webview;
-  char *data, *uri;
-
-  CHECK_LIVE_XWIDGET (xwidget);
-  CHECK_STRING (text);
-  if (NILP (base_uri))
-    base_uri = build_string ("about:blank");
-  else
-    CHECK_STRING (base_uri);
-
-  base_uri = ENCODE_UTF_8 (base_uri);
-  text = ENCODE_UTF_8 (text);
-  xw = XXWIDGET (xwidget);
-  CHECK_WEBKIT_WIDGET (xw);
-
-  data = SSDATA (text);
-  uri = SSDATA (base_uri);
-  webview = WEBKIT_WEB_VIEW (xw->widget_osr);
-
-  block_input ();
-  webkit_web_view_load_html (webview, data, uri);
-  unblock_input ();
-
-  return Qnil;
-}
-
-DEFUN ("xwidget-webkit-back-forward-list", Fxwidget_webkit_back_forward_list,
-       Sxwidget_webkit_back_forward_list, 1, 2, 0,
-       doc: /* Return the navigation history of XWIDGET, a WebKit xwidget.
-
-Return the history as a list of the form (BACK HERE FORWARD), where
-HERE is the current navigation item, while BACK and FORWARD are lists
-of history items of the form (IDX TITLE URI).  Here, IDX is an index
-that can be passed to `xwidget-webkit-goto-history', TITLE is a string
-containing the human-readable title of the history item, and URI is
-the URI of the history item.
-
-BACK, HERE, and FORWARD can all be nil depending on the state of the
-navigation history.
-
-BACK and FORWARD will each not contain more elements than LIMIT.  If
-LIMIT is not specified or nil, it is treated as `50'.  */)
-  (Lisp_Object xwidget, Lisp_Object limit)
-{
-  struct xwidget *xw;
-  Lisp_Object back, here, forward;
-  WebKitWebView *webview;
-  WebKitBackForwardList *list;
-  WebKitBackForwardListItem *item;
-  GList *parent, *tem;
-  int i;
-  unsigned int lim;
-  Lisp_Object title, uri;
-  const gchar *item_title, *item_uri;
-
-  back = Qnil;
-  here = Qnil;
-  forward = Qnil;
-
-  if (NILP (limit))
-    limit = make_fixnum (50);
-  else
-    CHECK_FIXNAT (limit);
-
-  CHECK_LIVE_XWIDGET (xwidget);
-  xw = XXWIDGET (xwidget);
-
-  webview = WEBKIT_WEB_VIEW (xw->widget_osr);
-  list = webkit_web_view_get_back_forward_list (webview);
-  item = webkit_back_forward_list_get_current_item (list);
-  lim = XFIXNAT (limit);
-
-  if (item)
-    {
-      item_title = webkit_back_forward_list_item_get_title (item);
-      item_uri = webkit_back_forward_list_item_get_uri (item);
-      here = list3 (make_fixnum (0),
-		    build_string_from_utf8 (item_title ? item_title : ""),
-		    build_string_from_utf8 (item_uri ? item_uri : ""));
-    }
-  parent = webkit_back_forward_list_get_back_list_with_limit (list, lim);
-
-  if (parent)
-    {
-      for (i = 1, tem = parent; tem; tem = tem->next, ++i)
-	{
-	  item = tem->data;
-	  item_title = webkit_back_forward_list_item_get_title (item);
-	  item_uri = webkit_back_forward_list_item_get_uri (item);
-	  title = build_string_from_utf8 (item_title ? item_title : "");
-	  uri = build_string_from_utf8 (item_uri ? item_uri : "");
-	  back = Fcons (list3 (make_fixnum (-i), title, uri), back);
-	}
-    }
-
-  back = Fnreverse (back);
-  g_list_free (parent);
-
-  parent = webkit_back_forward_list_get_forward_list_with_limit (list, lim);
-
-  if (parent)
-    {
-      for (i = 1, tem = parent; tem; tem = tem->next, ++i)
-	{
-	  item = tem->data;
-	  item_title = webkit_back_forward_list_item_get_title (item);
-	  item_uri = webkit_back_forward_list_item_get_uri (item);
-	  title = build_string_from_utf8 (item_title ? item_title : "");
-	  uri = build_string_from_utf8 (item_uri ? item_uri : "");
-	  forward = Fcons (list3 (make_fixnum (i), title, uri), forward);
-	}
-    }
-
-  forward = Fnreverse (forward);
-  g_list_free (parent);
-
-  return list3 (back, here, forward);
-}
-
-#endif
-
-DEFUN ("xwidget-webkit-set-cookie-storage-file",
-       Fxwidget_webkit_set_cookie_storage_file, Sxwidget_webkit_set_cookie_storage_file,
-       2, 2, 0, doc: /* Make the WebKit widget XWIDGET load and store cookies in FILE.
-
-Cookies will be stored as plain text in FILE, which must be an
-absolute file name.  All xwidgets related to XWIDGET will also
-store cookies in FILE and load them from there.  */)
-  (Lisp_Object xwidget, Lisp_Object file)
-{
-#ifdef USE_GTK
-  struct xwidget *xw;
-  WebKitWebView *webview;
-  WebKitWebContext *context;
-  WebKitCookieManager *manager;
-
-  CHECK_LIVE_XWIDGET (xwidget);
-  xw = XXWIDGET (xwidget);
-  CHECK_WEBKIT_WIDGET (xw);
-  CHECK_STRING (file);
-
-  block_input ();
-  webview = WEBKIT_WEB_VIEW (xw->widget_osr);
-  context = webkit_web_view_get_context (webview);
-  manager = webkit_web_context_get_cookie_manager (context);
-  webkit_cookie_manager_set_persistent_storage (manager,
-						SSDATA (ENCODE_UTF_8 (file)),
-						WEBKIT_COOKIE_PERSISTENT_STORAGE_TEXT);
-  unblock_input ();
-#endif
-
-  return Qnil;
-}
-
-DEFUN ("xwidget-webkit-stop-loading", Fxwidget_webkit_stop_loading,
-       Sxwidget_webkit_stop_loading,
-       1, 1, 0, doc: /* Stop loading data in the WebKit widget XWIDGET.
-This will stop any data transfer that may still be in progress inside
-XWIDGET as part of loading a page.  */)
-  (Lisp_Object xwidget)
-{
-  struct xwidget *xw;
-#ifdef USE_GTK
-  WebKitWebView *webview;
-#endif
-
-  CHECK_LIVE_XWIDGET (xwidget);
-  xw = XXWIDGET (xwidget);
-  CHECK_WEBKIT_WIDGET (xw);
-
-  block_input ();
-#ifdef USE_GTK
-  webview = WEBKIT_WEB_VIEW (xw->widget_osr);
-  webkit_web_view_stop_loading (webview);
-#elif defined NS_IMPL_COCOA
-  nsxwidget_webkit_stop_loading (xw);
-#endif
-  unblock_input ();
-
-  return Qnil;
-}
-
 void
 syms_of_xwidget (void)
 {
@@ -3924,12 +2775,6 @@ syms_of_xwidget (void)
   defsubr (&Sxwidget_query_on_exit_flag);
   defsubr (&Sset_xwidget_query_on_exit_flag);
 
-  defsubr (&Sxwidget_webkit_uri);
-  defsubr (&Sxwidget_webkit_title);
-  defsubr (&Sxwidget_webkit_goto_uri);
-  defsubr (&Sxwidget_webkit_goto_history);
-  defsubr (&Sxwidget_webkit_zoom);
-  defsubr (&Sxwidget_webkit_execute_script);
   DEFSYM (Qwebkit, "webkit");
 
   defsubr (&Sxwidget_size_request);
@@ -3939,19 +2784,8 @@ syms_of_xwidget (void)
   defsubr (&Sxwidget_buffer);
   defsubr (&Sset_xwidget_plist);
   defsubr (&Sxwidget_perform_lispy_event);
-  defsubr (&Sxwidget_webkit_search);
-  defsubr (&Sxwidget_webkit_finish_search);
-  defsubr (&Sxwidget_webkit_next_result);
-  defsubr (&Sxwidget_webkit_previous_result);
   defsubr (&Sset_xwidget_buffer);
-  defsubr (&Sxwidget_webkit_set_cookie_storage_file);
-  defsubr (&Sxwidget_webkit_stop_loading);
-#ifdef USE_GTK
-  defsubr (&Sxwidget_webkit_load_html);
-  defsubr (&Sxwidget_webkit_back_forward_list);
-#endif
 
-  defsubr (&Sxwidget_webkit_estimated_load_progress);
   defsubr (&Skill_xwidget);
 
   DEFSYM (QCxwidget, ":xwidget");
@@ -3973,13 +2807,6 @@ syms_of_xwidget (void)
 	       doc: /* List of all xwidget views.  */);
   Vxwidget_view_list = Qnil;
 
-  DEFVAR_BOOL ("xwidget-webkit-disable-javascript", xwidget_webkit_disable_javascript,
-    doc: /* If non-nil, disable execution of JavaScript in xwidget WebKit widgets.
-Modifications to this setting do not take effect in existing WebKit
-widgets; kill all xwidget-webkit buffers for changes in this setting
-to take effect.  */);
-  xwidget_webkit_disable_javascript = false;
-
   Fprovide (intern ("xwidget-internal"), Qnil);
 
   id_to_xwidget_map = CALLN (Fmake_hash_table, QCtest, Qeq,
@@ -4223,7 +3050,7 @@ kill_frame_xwidget_views (struct frame *f)
 }
 #endif
 
-static void
+void
 kill_xwidget (struct xwidget *xw)
 {
   Lisp_Object val;
diff --git a/src/xwidget.h b/src/xwidget.h
index 34cae383abf..f81a88d9017 100644
--- a/src/xwidget.h
+++ b/src/xwidget.h
@@ -30,6 +30,9 @@ #define XWIDGET_H_INCLUDED
 
 #ifdef HAVE_XWIDGETS
 
+extern Lisp_Object internal_xwidget_view_list;
+extern Lisp_Object internal_xwidget_list;
+
 #if defined (USE_GTK)
 #include <gtk/gtk.h>
 #ifndef HAVE_PGTK
@@ -160,6 +163,8 @@ #define XWIDGETP(x) PSEUDOVECTORP (x, PVEC_XWIDGET)
 #define XXWIDGET(a) (eassert (XWIDGETP (a)), \
 		     XUNTAG (a, Lisp_Vectorlike, struct xwidget))
 
+#define XSETXWIDGET(a, b) XSETPSEUDOVECTOR (a, b, PVEC_XWIDGET)
+
 #define XWIDGET_LIVE_P(w) (!NILP ((w)->buffer))
 
 #define CHECK_XWIDGET(x) \
@@ -174,6 +179,7 @@ #define CHECK_LIVE_XWIDGET(x)				\
 #define XWIDGET_VIEW_P(x) PSEUDOVECTORP (x, PVEC_XWIDGET_VIEW)
 #define XXWIDGET_VIEW(a) (eassert (XWIDGET_VIEW_P (a)), \
 			  XUNTAG (a, Lisp_Vectorlike, struct xwidget_view))
+#define XSETXWIDGET_VIEW(a, b) XSETPSEUDOVECTOR (a, b, PVEC_XWIDGET_VIEW)
 
 #define CHECK_XWIDGET_VIEW(x) \
   CHECK_TYPE (XWIDGET_VIEW_P (x), Qxwidget_view_p, x)
@@ -182,12 +188,14 @@ #define XG_XWIDGET "emacs_xwidget"
 #define XG_XWIDGET_VIEW "emacs_xwidget_view"
 
 #ifdef HAVE_XWIDGETS
+struct xwidget *find_xwidget_for_offscreen_window (GdkWindow *window);
 void syms_of_xwidget (void);
 bool valid_xwidget_spec_p (Lisp_Object);
 void xwidget_view_delete_all_in_window (struct window *);
 void x_draw_xwidget_glyph_string (struct glyph_string *);
 struct xwidget *lookup_xwidget (Lisp_Object spec);
 void xwidget_end_redisplay (struct window *, struct glyph_matrix *);
+void kill_xwidget (struct xwidget *);
 void kill_buffer_xwidgets (Lisp_Object);
 /* Defined in 'xwidget.c'.  */
 void store_xwidget_event_string (struct xwidget *xw,
@@ -202,6 +210,10 @@ #define XG_XWIDGET_VIEW "emacs_xwidget_view"
 void store_xwidget_js_callback_event (struct xwidget *xw,
                                       Lisp_Object proc,
                                       Lisp_Object argument);
+#ifdef USE_GTK
+void store_xwidget_display_event (struct xwidget *xw,
+				  struct xwidget *src);
+#endif
 
 extern struct xwidget *xwidget_from_id (uint32_t id);
 
-- 
2.45.2


  parent reply	other threads:[~2024-07-12 20:06 UTC|newest]

Thread overview: 11+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2024-06-02 21:37 moving xwidget-webkit to WPE Noé Lopez via Emacs development discussions.
2024-06-05  0:58 ` Po Lu
2024-06-08  2:56   ` Richard Stallman
2024-07-12 20:06   ` Noé Lopez via Emacs development discussions. [this message]
     [not found] <87sewdzu2g.fsf.ref@yahoo.com>
     [not found] ` <878qy6fk8g.fsf@>
2024-07-13  6:26   ` Po Lu
     [not found] <66921710.050a0220.68c57.0065SMTPIN_ADDED_BROKEN@mx.google.com>
2024-07-24 20:08 ` Stefan Kangas
2024-07-25  1:22   ` Po Lu
  -- strict thread matches above, loose matches on Subject: below --
2024-07-27 19:20 Noé Lopez via Emacs development discussions.
     [not found] <87plqyprq2.fsf@>
2024-07-27 19:51 ` joakim
2024-07-27 20:09   ` joakim
2024-07-27 22:07   ` Noé Lopez via Emacs development discussions.

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

  List information: https://www.gnu.org/software/emacs/

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to='1998.92895050056$1720850229@news.gmane.org' \
    --to=emacs-devel@gnu.org \
    --cc=luangruo@yahoo.com \
    --cc=noe@xn--no-cja.eu \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
Code repositories for project(s) associated with this public inbox

	https://git.savannah.gnu.org/cgit/emacs.git

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).