unofficial mirror of emacs-devel@gnu.org 
 help / color / mirror / code / Atom feed
* moving xwidget-webkit to WPE
@ 2024-06-02 21:37 Noé Lopez via Emacs development discussions.
  2024-06-05  0:58 ` Po Lu
  0 siblings, 1 reply; 11+ messages in thread
From: Noé Lopez via Emacs development discussions. @ 2024-06-02 21:37 UTC (permalink / raw)
  To: luangruo; +Cc: emacs-devel

Hi Po,

A few months ago, when I sent a patch to disable javascript in
xwidget-webkit you mentionned that it needed to be rewritten/adapted for
WPE Webkit. Does that still stand true ?

If so, I would like to take on that task during the summer holidays,
because I want to, and because my school will compensate the work for
credits on the next year, this is great for me as it will allow me to do
fun stuff and get a head start on the next school year.

I think I can handle the WebKit magic, but I will probably need a little
bit of guidance with the Emacs programming.

Have a great day,
Noé Lopez



^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: moving xwidget-webkit to WPE
  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.
  0 siblings, 2 replies; 11+ messages in thread
From: Po Lu @ 2024-06-05  0:58 UTC (permalink / raw)
  To: Noé Lopez; +Cc: emacs-devel

Noé Lopez <noe@noé.eu> writes:

> A few months ago, when I sent a patch to disable javascript in
> xwidget-webkit you mentionned that it needed to be rewritten/adapted for
> WPE Webkit. Does that still stand true ?

Yes, nothing has changed.

> If so, I would like to take on that task during the summer holidays,
> because I want to, and because my school will compensate the work for
> credits on the next year, this is great for me as it will allow me to do
> fun stuff and get a head start on the next school year.
>
> I think I can handle the WebKit magic, but I will probably need a little
> bit of guidance with the Emacs programming.

OK, please approach us with any question you will.



^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: moving xwidget-webkit to WPE
  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.
  1 sibling, 0 replies; 11+ messages in thread
From: Richard Stallman @ 2024-06-08  2:56 UTC (permalink / raw)
  To: noe; +Cc: emacs-devel

[[[ To any NSA and FBI agents reading my email: please consider    ]]]
[[[ whether defending the US Constitution against all enemies,     ]]]
[[[ foreign or domestic, requires you to follow Snowden's example. ]]]

Disabling Javascript is a very important thing,
Thanks for offering to work on it.

-- 
Dr Richard Stallman (https://stallman.org)
Chief GNUisance of the GNU Project (https://gnu.org)
Founder, Free Software Foundation (https://fsf.org)
Internet Hall-of-Famer (https://internethalloffame.org)





^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: moving xwidget-webkit to WPE
  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.
  1 sibling, 0 replies; 11+ messages in thread
From: Noé Lopez via Emacs development discussions. @ 2024-07-12 20:06 UTC (permalink / raw)
  To: Po Lu; +Cc: emacs-devel

[-- 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


^ permalink raw reply related	[flat|nested] 11+ messages in thread

* Re: moving xwidget-webkit to WPE
       [not found] ` <878qy6fk8g.fsf@>
@ 2024-07-13  6:26   ` Po Lu
  0 siblings, 0 replies; 11+ messages in thread
From: Po Lu @ 2024-07-13  6:26 UTC (permalink / raw)
  To: Noé Lopez via Emacs development discussions.; +Cc: Noé Lopez

Noé Lopez via "Emacs development discussions." <emacs-devel@gnu.org>
writes:

> 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.

It appears alright.

> 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?

No, the FDO backend is a perfect fit.  Thanks.



^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: moving xwidget-webkit to WPE
       [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
  0 siblings, 1 reply; 11+ messages in thread
From: Stefan Kangas @ 2024-07-24 20:08 UTC (permalink / raw)
  To: Noé Lopez, Po Lu; +Cc: emacs-devel

Noé Lopez via "Emacs development discussions." <emacs-devel@gnu.org>
writes:

> 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.

Should we install this?  Po Lu?



^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: moving xwidget-webkit to WPE
  2024-07-24 20:08 ` Stefan Kangas
@ 2024-07-25  1:22   ` Po Lu
  0 siblings, 0 replies; 11+ messages in thread
From: Po Lu @ 2024-07-25  1:22 UTC (permalink / raw)
  To: Stefan Kangas; +Cc: Noé Lopez, emacs-devel

Stefan Kangas <stefankangas@gmail.com> writes:

> Noé Lopez via "Emacs development discussions." <emacs-devel@gnu.org>
> writes:
>
>> 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.
>
> Should we install this?  Po Lu?

No, I would wait for the WPE port to emerge.



^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: moving xwidget-webkit to WPE
@ 2024-07-27 19:20 Noé Lopez via Emacs development discussions.
  0 siblings, 0 replies; 11+ messages in thread
From: Noé Lopez via Emacs development discussions. @ 2024-07-27 19:20 UTC (permalink / raw)
  To: Po Lu; +Cc: emacs-devel

Hi,

I've been testing with having a simple GtkButton/GtkLabel as an xwidget,
and it seems the event handling functions (for example
window_coords_from_toplevel) are expecting xwidget->widget_osr to be a
GdkWindow.

This is weird to me, as I understand xwidget->widgetwindow_osr is
already a GtkOffscreenWindow and contains xwidget->widget_osr. Why have
a window in a window?

For WPE I think I will use GtkDrawingArea which doesn't cause any issues
so I shouldn't need to change anything on this end, but I wonder if it
is a limitations of xwidgets or just something that you didn't need to
implement because the GTK WebkitView is a window.

All the best,
Noé Lopez



^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: moving xwidget-webkit to WPE
       [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.
  0 siblings, 2 replies; 11+ messages in thread
From: joakim @ 2024-07-27 19:51 UTC (permalink / raw)
  To: Noé Lopez via Emacs development discussions.; +Cc: Po Lu, Noé Lopez

Noé Lopez via "Emacs development discussions." <emacs-devel@gnu.org>
writes:

> Hi,
>
> I've been testing with having a simple GtkButton/GtkLabel as an xwidget,
> and it seems the event handling functions (for example
> window_coords_from_toplevel) are expecting xwidget->widget_osr to be a
> GdkWindow.
>
> This is weird to me, as I understand xwidget->widgetwindow_osr is
> already a GtkOffscreenWindow and contains xwidget->widget_osr. Why have
> a window in a window?
>
> For WPE I think I will use GtkDrawingArea which doesn't cause any issues
> so I shouldn't need to change anything on this end, but I wonder if it
> is a limitations of xwidgets or just something that you didn't need to
> implement because the GTK WebkitView is a window.
>
> All the best,
> Noé Lopez

FWIW the original idea of xwidgets was to allow for different widget
types.

Some rambling notes from way back about this are here:
https://github.com/jave/xwidget-aux

There was some code to test xwidgets sliders, buttons etc, and also an
attempt at a generic gobject elisp bridge.

That being said, the emacs maintainers have improved the code a lot
since then, so those notes are just a historical curiosity now.

Regards,
Joakim
>
-- 
Joakim Verona
joakim@verona.se



^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: moving xwidget-webkit to WPE
  2024-07-27 19:51 ` joakim
@ 2024-07-27 20:09   ` joakim
  2024-07-27 22:07   ` Noé Lopez via Emacs development discussions.
  1 sibling, 0 replies; 11+ messages in thread
From: joakim @ 2024-07-27 20:09 UTC (permalink / raw)
  To: Noé Lopez via Emacs development discussions.; +Cc: Po Lu, Noé Lopez

joakim@verona.se writes:

> Noé Lopez via "Emacs development discussions." <emacs-devel@gnu.org>
> writes:
>
>> Hi,
>>
>> I've been testing with having a simple GtkButton/GtkLabel as an xwidget,
>> and it seems the event handling functions (for example
>> window_coords_from_toplevel) are expecting xwidget->widget_osr to be a
>> GdkWindow.
>>
>> This is weird to me, as I understand xwidget->widgetwindow_osr is
>> already a GtkOffscreenWindow and contains xwidget->widget_osr. Why have
>> a window in a window?
>>
>> For WPE I think I will use GtkDrawingArea which doesn't cause any issues
>> so I shouldn't need to change anything on this end, but I wonder if it
>> is a limitations of xwidgets or just something that you didn't need to
>> implement because the GTK WebkitView is a window.
>>
>> All the best,
>> Noé Lopez
>
> FWIW the original idea of xwidgets was to allow for different widget
> types.
>
> Some rambling notes from way back about this are here:
> https://github.com/jave/xwidget-aux
>
> There was some code to test xwidgets sliders, buttons etc, and also an
> attempt at a generic gobject elisp bridge.
>
> That being said, the emacs maintainers have improved the code a lot
> since then, so those notes are just a historical curiosity now.

Also I found the old xwidget.c

https://github.com/jave/xwidget-emacs/blob/xwidget/src/xwidget.c

It has stuff for
- Button
- ToggleButton
- slider
- socket
- socket-osr
- cairo

All of it obsolete and outdated, but anyway, FWIW, etc.

Regards
/Joakim

>
> Regards,
> Joakim
>>
-- 
Joakim Verona
joakim@verona.se



^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: moving xwidget-webkit to WPE
  2024-07-27 19:51 ` joakim
  2024-07-27 20:09   ` joakim
@ 2024-07-27 22:07   ` Noé Lopez via Emacs development discussions.
  1 sibling, 0 replies; 11+ messages in thread
From: Noé Lopez via Emacs development discussions. @ 2024-07-27 22:07 UTC (permalink / raw)
  To: joakim; +Cc: emacs-devel, luangruo

joakim@verona.se writes:
>
> Some rambling notes from way back about this are here:
> https://github.com/jave/xwidget-aux
>
> There was some code to test xwidgets sliders, buttons etc, and also an
> attempt at a generic gobject elisp bridge.
>
> That being said, the emacs maintainers have improved the code a lot
> since then, so those notes are just a historical curiosity now.
>
> Regards,
> Joakim

Hi Joakim,

Thank you very much for reaching out, the readme contains valuable
information.  Its a shame some of it wasnt included along with the code.

Well, since WPE Webkit doesn't need gtk it might even be possible to
directly embed it without xwidgets, by using the display engine directly
similarly to how images and xwidgets work 🤔

Its very interesting seeing where things come from and what motivated
them.  Most emacs things happened before I was born 😵‍💫 so I have a lot
to learn from the past :)

Thanks,
Noé



^ permalink raw reply	[flat|nested] 11+ messages in thread

end of thread, other threads:[~2024-07-27 22:07 UTC | newest]

Thread overview: 11+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
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.
     [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.

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).