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