]> git.eshelyaron.com Git - emacs.git/commitdiff
Make "open in new window" from an xwidget's context menu work
authorPo Lu <luangruo@yahoo.com>
Sat, 6 Nov 2021 12:59:08 +0000 (20:59 +0800)
committerLars Ingebrigtsen <larsi@gnus.org>
Sun, 7 Nov 2021 01:59:42 +0000 (02:59 +0100)
* doc/lispref/commands.texi (Xwidget Events): Document new event type.
* doc/lisprefdisplay.texi (Xwidgets): Document new argument to
make-xwidget, and new function.
* etc/NEWS: Document changes.
* lisp/xwidget.el: Bind xwidget-display-event to
xwidget-webkit-display-event.

(xwidget-webkit-import-widget): New function.
(xwidget-webkit-display-event): New command.
* src/keyboard.c (kbd_buffer_get_event): New event type.
(make_lispy_event): Handle XWIDGET_DISPLAY_EVENTs.
(syms_f_keyboard): Define new symbol.
* src/termhooks.h (enum event_kind): New enum XWIDGET_DISPLAY_EVENT.

* src/xwidget.c (webkit_create_cb)
(store_xwidget_display_event)
(webkit_ready_to_show)
(webkit_create_cb_1, webkit_create_cb)
(Fset_xwidget_buffer): New functions.

(Fmake_xwidget): Add internal argument RELATED and connect create
signal.
(syms_of_xwidget): Define now subrs.

doc/lispref/commands.texi
doc/lispref/display.texi
etc/NEWS
lisp/xwidget.el
src/keyboard.c
src/termhooks.h
src/xwidget.c

index ca594759f843ac08a0bd96f6ec7a618182db8134..832b570b6a4fd2d3a8c168bb2d6775c695fecb30 100644 (file)
@@ -1931,6 +1931,15 @@ An event with @var{kind} set to @code{javascript-callback} contains
 JavaScript callback data.  These events are used internally by
 @code{xwidget-webkit-execute-script}.
 
+@cindex @code{xwidget-display-event} event
+@item (xwidget-display-event @var{xwidget})
+This event is sent whenever an xwidget requests that another xwidget
+be displayed.  @var{xwidget} is the xwidget that should be displayed.
+
+@var{xwidget}'s buffer will be set to a temporary buffer.  When
+displaying the widget, care should be taken to replace the buffer with
+the buffer in which the xwidget will be displayed, using
+@code{set-xwidget-buffer}  (@pxref{Xwidgets}).
 @end table
 
 @node Misc Events
index b780263fe00d443f34d2c6d0b96782c5b24e0dfe..37f07c4f28a9a190a29192b480ea886afdd231c6 100644 (file)
@@ -6787,7 +6787,7 @@ Property}).
   Embedded widgets can send events notifying Lisp code about changes
 occurring within them.  (@pxref{Xwidget Events}).
 
-@defun make-xwidget type title width height arguments &optional buffer
+@defun make-xwidget type title width height arguments &optional buffer related
 This creates and returns an xwidget object.  If
 @var{buffer} is omitted or @code{nil}, it defaults to the current
 buffer.  If @var{buffer} names a buffer that doesn't exist, it will be
@@ -6800,7 +6800,9 @@ The WebKit component.
 @end table
 
 The @var{width} and @var{height} arguments specify the widget size in
-pixels, and @var{title}, a string, specifies its title.
+pixels, and @var{title}, a string, specifies its title.  @var{related}
+is used internally by the WebKit widget, and is not of interest to the
+programmer.
 @end defun
 
 @defun xwidgetp object
@@ -6821,6 +6823,10 @@ property list given by @var{plist}.
 This function returns the buffer of @var{xwidget}.
 @end defun
 
+@defun set-xwidget-buffer xwidget buffer
+This function sets the buffer of @var{xwidget} to @var{buffer}.
+@end defun
+
 @defun get-buffer-xwidgets buffer
 This function returns a list of xwidget objects associated with the
 @var{buffer}, which can be specified as a buffer object or a name of
index 0cbddeba8ddca29a6056274f353e69a860babf60..0e5caa4825d43b1ee21ba23546dcee14a43fa208 100644 (file)
--- a/etc/NEWS
+++ b/etc/NEWS
@@ -514,6 +514,12 @@ to `C-s' and `C-r'.
 To access the inspector, right click on the widget and select "Inspect
 Element".
 
+---
+*** "Open in New Window" in a WebKit widget's context menu now works.
+The newly created buffer will be displayed via display-buffer, which
+can be customized through the usual mechanism of display-buffer-alist
+and friends.
+
 \f
 * New Modes and Packages in Emacs 29.1
 
@@ -759,6 +765,12 @@ completed, `load-started' when a load first starts, `load-redirected'
 after a redirect, and `load-committed' when the WebKit widget first
 commits to the load.
 
++++
+** New event type `xwidget-display-event'.
+These events are sent whenever an xwidget requests that Emacs display
+another.  The only argument to this event is the xwidget that should
+be displayed.
+
 \f
 * Changes in Emacs 29.1 on Non-Free Operating Systems
 
index bd3c0876f591246bb7eec39331c9eb07a3a695bf..d427e70233113d8fcc73c6c25c190847639a8d37 100644 (file)
@@ -37,6 +37,7 @@
 (declare-function make-xwidget "xwidget.c"
                   (type title width height arguments &optional buffer))
 (declare-function xwidget-buffer "xwidget.c" (xwidget))
+(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"
@@ -701,6 +702,29 @@ For example, use this to display an anchor."
     (xwidget-webkit-mode)
     (xwidget-webkit-goto-uri (xwidget-webkit-last-session) url)))
 
+(defun xwidget-webkit-import-widget (xwidget)
+  "Create a new webkit session buffer from XWIDGET, an existing xwidget.
+Return the buffer."
+  (let* ((bufname (generate-new-buffer-name "*xwidget-webkit*"))
+         (callback #'xwidget-webkit-callback)
+         (buffer (get-buffer-create bufname)))
+    (with-current-buffer buffer
+      (save-excursion
+        (erase-buffer)
+        (insert ".")
+        (put-text-property (point-min) (point-max)
+                           'display (list 'xwidget :xwidget xwidget)))
+      (xwidget-put xwidget 'callback callback)
+      (set-xwidget-buffer xwidget buffer)
+      (xwidget-webkit-mode))
+    buffer))
+
+(defun xwidget-webkit-display-event (event)
+  "Import the xwidget inside EVENT and display it."
+  (interactive "e")
+  (display-buffer (xwidget-webkit-import-widget (nth 1 event))))
+
+(global-set-key [xwidget-display-event] 'xwidget-webkit-display-event)
 
 (defun xwidget-webkit-goto-url (url)
   "Goto URL with xwidget webkit."
index 46dce5755a876a9c31ada71161de76012557bb8d..c4a5671b104a9a97d1f817585f59b9d08d9cb3ea 100644 (file)
@@ -3993,6 +3993,7 @@ kbd_buffer_get_event (KBOARD **kbp,
 #endif
 #ifdef HAVE_XWIDGETS
       case XWIDGET_EVENT:
+      case XWIDGET_DISPLAY_EVENT:
 #endif
       case SAVE_SESSION_EVENT:
       case NO_EVENT:
@@ -6139,6 +6140,11 @@ make_lispy_event (struct input_event *event)
       {
         return Fcons (Qxwidget_event, event->arg);
       }
+
+    case XWIDGET_DISPLAY_EVENT:
+      {
+       return list2 (Qxwidget_display_event, event->arg);
+      }
 #endif
 
 #ifdef USE_FILE_NOTIFY
@@ -11732,6 +11738,7 @@ syms_of_keyboard (void)
 
 #ifdef HAVE_XWIDGETS
   DEFSYM (Qxwidget_event, "xwidget-event");
+  DEFSYM (Qxwidget_display_event, "xwidget-display-event");
 #endif
 
 #ifdef USE_FILE_NOTIFY
index 1d3cdc8fe8de6b13b21f3859d5b68d99ec52218f..e7539bbce2fdd4b0634b7295885f88678939ff75 100644 (file)
@@ -255,6 +255,8 @@ enum event_kind
 #ifdef HAVE_XWIDGETS
   /* events generated by xwidgets*/
    , XWIDGET_EVENT
+   /* Event generated when WebKit asks us to display another widget.  */
+   , XWIDGET_DISPLAY_EVENT
 #endif
 
 #ifdef USE_FILE_NOTIFY
index 10bb4ac8e450aed840d9992ff7c402388f9f1170..0a6d95a15730c6e0d69ead6ed3ae44916963cba4 100644 (file)
@@ -19,6 +19,7 @@ along with GNU Emacs.  If not, see <https://www.gnu.org/licenses/>.  */
 
 #include <config.h>
 
+#include "buffer.h"
 #include "xwidget.h"
 
 #include "lisp.h"
@@ -76,7 +77,7 @@ 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 *,
@@ -101,7 +102,7 @@ static void mouse_target_changed (WebKitWebView *, WebKitHitTestResult *, guint,
 
 DEFUN ("make-xwidget",
        Fmake_xwidget, Smake_xwidget,
-       5, 6, 0,
+       5, 7, 0,
        doc: /* Make an xwidget of TYPE.
 If BUFFER is nil, use the current buffer.
 If BUFFER is a string and no such buffer exists, create it.
@@ -109,10 +110,12 @@ TYPE is a symbol which can take one of the following values:
 
 - webkit
 
-Returns the newly constructed xwidget, or nil if construction fails.  */)
+RELATED is nil, or an xwidget.  This argument is used internally.
+Returns the newly constructed xwidget, or nil if construction
+fails.  */)
   (Lisp_Object type,
    Lisp_Object title, Lisp_Object width, Lisp_Object height,
-   Lisp_Object arguments, Lisp_Object buffer)
+   Lisp_Object arguments, Lisp_Object buffer, Lisp_Object related)
 {
 #ifdef USE_GTK
   if (!xg_gtk_initialized)
@@ -160,22 +163,33 @@ Returns the newly constructed xwidget, or nil if construction fails.  */)
 
       if (EQ (xw->type, Qwebkit))
         {
-          xw->widget_osr = webkit_web_view_new ();
-
-         /* 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);
-
-          /* 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.  */
-          struct sigaction old_action;
-          sigaction (SIGCHLD, NULL, &old_action);
-          webkit_web_view_load_uri(WEBKIT_WEB_VIEW (xw->widget_osr),
-                                   "about:blank");
-          sigaction (SIGCHLD, &old_action, NULL);
-        }
+         WebKitWebView *related_view;
+
+         if (NILP (related)
+             || !XWIDGETP (related)
+             || !EQ (XXWIDGET (related)->type, Qwebkit))
+           {
+             /* 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);
+             xw->widget_osr = webkit_web_view_new ();
+
+             /* 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.  */
+             struct sigaction old_action;
+             sigaction (SIGCHLD, NULL, &old_action);
+             webkit_web_view_load_uri (WEBKIT_WEB_VIEW (xw->widget_osr),
+                                       "about:blank");
+             sigaction (SIGCHLD, &old_action, NULL);
+           }
+         else
+           {
+             related_view = WEBKIT_WEB_VIEW (XXWIDGET (related)->widget_osr);
+             xw->widget_osr = webkit_web_view_new_with_related_view (related_view);
+           }
+       }
 
       gtk_widget_set_size_request (GTK_WIDGET (xw->widget_osr), xw->width,
                                    xw->height);
@@ -221,6 +235,10 @@ Returns the newly constructed xwidget, or nil if construction fails.  */)
                            "mouse-target-changed",
                            G_CALLBACK (mouse_target_changed),
                            xw);
+         g_signal_connect (G_OBJECT (xw->widget_osr),
+                           "create",
+                           G_CALLBACK (webkit_create_cb),
+                           xw);
         }
 
       g_signal_connect (G_OBJECT (xw->widgetwindow_osr), "damage-event",
@@ -927,6 +945,88 @@ store_xwidget_js_callback_event (struct xwidget *xw,
 
 
 #ifdef USE_GTK
+static void
+store_xwidget_display_event (struct xwidget *xw)
+{
+  struct input_event evt;
+  Lisp_Object val;
+
+  XSETXWIDGET (val, xw);
+  EVENT_INIT (evt);
+  evt.kind = XWIDGET_DISPLAY_EVENT;
+  evt.frame_or_window = Qnil;
+  evt.arg = val;
+  kbd_buffer_store_event (&evt);
+}
+
+static void
+webkit_ready_to_show (WebKitWebView *new_view,
+                     gpointer user_data)
+{
+  Lisp_Object tem;
+  struct xwidget *xw;
+
+  for (tem = Vxwidget_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)
+           store_xwidget_display_event (xw);
+       }
+    }
+}
+
+static GtkWidget *
+webkit_create_cb_1 (WebKitWebView *webview,
+                   struct xwidget_view *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), NULL);
+
+  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:
+      if (webkit_navigation_action_is_user_gesture (nav_action))
+       return NULL;
+
+      return webkit_create_cb_1 (webview, user_data);
+    case WEBKIT_NAVIGATION_TYPE_LINK_CLICKED:
+    case WEBKIT_NAVIGATION_TYPE_FORM_SUBMITTED:
+    case WEBKIT_NAVIGATION_TYPE_BACK_FORWARD:
+    case WEBKIT_NAVIGATION_TYPE_RELOAD:
+    case WEBKIT_NAVIGATION_TYPE_FORM_RESUBMITTED:
+      return webkit_create_cb_1 (webview, user_data);
+    default:
+      return NULL;
+    }
+}
+
 void
 webkit_view_load_changed_cb (WebKitWebView *webkitwebview,
                              WebKitLoadEvent load_event,
@@ -1722,6 +1822,19 @@ DEFUN ("xwidget-buffer",
   return XXWIDGET (xwidget)->buffer;
 }
 
+DEFUN ("set-xwidget-buffer",
+       Fset_xwidget_buffer, Sset_xwidget_buffer,
+       2, 2, 0,
+       doc: /* Set XWIDGET's buffer to BUFFER.  */)
+  (Lisp_Object xwidget, Lisp_Object buffer)
+{
+  CHECK_XWIDGET (xwidget);
+  CHECK_BUFFER (buffer);
+
+  XXWIDGET (xwidget)->buffer = buffer;
+  return Qnil;
+}
+
 DEFUN ("set-xwidget-plist",
        Fset_xwidget_plist, Sset_xwidget_plist,
        2, 2, 0,
@@ -1957,6 +2070,7 @@ syms_of_xwidget (void)
   defsubr (&Sxwidget_webkit_finish_search);
   defsubr (&Sxwidget_webkit_next_result);
   defsubr (&Sxwidget_webkit_previous_result);
+  defsubr (&Sset_xwidget_buffer);
 
   DEFSYM (QCxwidget, ":xwidget");
   DEFSYM (QCtitle, ":title");