From 9838a4fb2bc90f0008782c439594cfff311cfa41 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?No=C3=A9=20Lopez?= 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 . */ + +#include + +#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 +#include +#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 . */ + +#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 #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 -#include -#include #ifndef HAVE_PGTK -#include #include #else #include @@ -54,8 +51,8 @@ Copyright (C) 2011-2024 Free Software Foundation, Inc. #include 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 #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