unofficial mirror of emacs-devel@gnu.org 
 help / color / mirror / code / Atom feed
* [PATCH] Add user content APIs for WebKit Xwidgets
@ 2020-08-28  2:25 Qiantan Hong
  2020-08-28 14:37 ` Lars Ingebrigtsen
  2020-08-29  4:10 ` Richard Stallman
  0 siblings, 2 replies; 41+ messages in thread
From: Qiantan Hong @ 2020-08-28  2:25 UTC (permalink / raw)
  To: emacs-devel@gnu.org


[-- Attachment #1.1: Type: text/plain, Size: 604 bytes --]

Hi,

I implemented some primitives to expose some WebKit user content APIs
(user script and script message handlers) for WebKit Xwidgets, both
for WebKitGTK impl and NS/mac impl.

The user script API makes it possible to reliable and predictable injecting
script into a Webkit Xwidget, which is useful for customizing the WebView
behavior.

The script message handler API makes it possible to trigger event in emacs
from JavaScript, and can be used to implement procedure calling from
js to elisp. Currently only the other way around is possible.

The patch is attached.

Best,
Qiantan

qhong@mit.edu




[-- Attachment #1.2.1: Type: text/html, Size: 1114 bytes --]

[-- Attachment #1.2.2: 0002-Implment-some-user-content-APIs-for-WebKit-Xwidgets.txt --]
[-- Type: text/plain, Size: 18294 bytes --]

From cac4d244ef78e2bd77c758c4f13a501b07b28e33 Mon Sep 17 00:00:00 2001
From: Qiantan Hong <qhong@mit.edu>
Date: Thu, 27 Aug 2020 17:02:18 -0400
Subject: [PATCH 2/2] Implment some user content APIs for WebKit Xwidgets

Implement WebKit user scripts and script message handlers.
* src/xwidget.h (store_xwidget_script_message_event): store script
  message event into event queue
* src/xwidget.c (store_xwidget_script_message_event, make-xwidget,
  webkit_script_message_cb, xwidget-webkit-add-user-script,
  xwidget-webkit-remove-all-user-scripts,
  xwidget-webkit-register-script-message,
  xwidget-webkit-unregister-script-message): Implement user script
  and script message handler primitives.
* src/nsxwidget.c (nsxwidget_webkit_add_user_script,
  nsxwidget_webkit_remove_all_user_scripts,
  nsxwidget_webkit_register_script_message,
  nsxwidget_webkit_unregister_script_message,
  initWithFrame, initialize, userContentController): NS
  implementation. Changed naming of a previous used  script message
  handler to avoid namespace pollution.
* src/nsxwidget.h (nsxwidget_webkit_add_user_script,
  nsxwidget_webkit_remove_all_user_scripts,
  nsxwidget_webkit_register_script_message,
  nsxwidget_webkit_unregister_script_message): NS implementation
* lisp/xwidget.el (xwidget-webkit-callback,
  xwidget-webkit-add-script-message-handler,
  xwidget-webkit-remove-script-message-handler):
  let lisp recognize and dispatch script message events
---
 lisp/xwidget.el |  22 ++++++
 src/nsxwidget.h |   5 ++
 src/nsxwidget.m |  80 +++++++++++++++++++--
 src/xwidget.c   | 181 +++++++++++++++++++++++++++++++++++++++++++++++-
 src/xwidget.h   |   5 ++
 5 files changed, 285 insertions(+), 8 deletions(-)

diff --git a/lisp/xwidget.el b/lisp/xwidget.el
index 074320855c..0c202e5bc5 100644
--- a/lisp/xwidget.el
+++ b/lisp/xwidget.el
@@ -298,8 +298,30 @@ xwidget-webkit-callback
              (let ((proc (nth 3 last-input-event))
                    (arg  (nth 4 last-input-event)))
                (funcall proc arg)))
+            ((eq xwidget-event-type 'script-message)
+             (let ((name (nth 3 last-input-event))
+                   (value (nth 4 last-input-event)))
+               (let ((handler-pair (assq name (xwidget-get xwidget 'script-message-handlers))))
+                 (if handler-pair
+                     (funcall (cdr handler-pair) xwidget value)
+                   (xwidget-log "unhandled script message:%s" name)))))
             (t (xwidget-log "unhandled event:%s" xwidget-event-type))))))
 
+(defun xwidget-webkit-add-script-message-handler (xwidget name handler)
+  "Associate HANDLER with script messages of NAME for Webkit XWIDGET."
+  (xwidget-put xwidget 'script-message-handlers
+               (cons (cons name handler) (xwidget-get xwidget 'script-message-handlers))))
+
+(defun xwidget-webkit-remove-script-message-handler (xwidget name)
+  "Remove a handler associated with NAME for Webkit XWIDGET.
+Returns the removed (NAME . HANDLER) pair, or NIL if such handler is not found."
+  (let* ((old-alist (xwidget-get xwidget 'script-message-handlers))
+         (handler-pair (assq name old-alist)))
+    (when handler-pair
+      (xwidget-put xwidget 'script-message-handlers
+                   (delq handler-pair old-alist))
+      handler-pair)))
+
 (defvar bookmark-make-record-function)
 (when (memq window-system '(mac ns))
   (defvar xwidget-webkit-enable-plugins nil
diff --git a/src/nsxwidget.h b/src/nsxwidget.h
index 3d91594c34..f1dc53019a 100644
--- a/src/nsxwidget.h
+++ b/src/nsxwidget.h
@@ -40,6 +40,11 @@ #define NSXWIDGET_H_INCLUDED
 void nsxwidget_webkit_execute_script (struct xwidget *xw, const char *script,
                                       Lisp_Object fun);
 
+void nsxwidget_webkit_add_user_script (struct xwidget *xw, const char *script,
+                                       int injection_time_start, int main_frame_only);
+void nsxwidget_webkit_remove_all_user_scripts (struct xwidget *xw);
+Lisp_Object nsxwidget_webkit_register_script_message (struct xwidget *xw, const char *name);
+void nsxwidget_webkit_unregister_script_message (struct xwidget *xw, const char *name);
 /* Functions for xwidget model.  */
 
 #ifdef __OBJC__
diff --git a/src/nsxwidget.m b/src/nsxwidget.m
index e81ca7fc0c..6c9fb497e4 100644
--- a/src/nsxwidget.m
+++ b/src/nsxwidget.m
@@ -85,7 +85,7 @@ - (id)initWithFrame:(CGRect)frame
         @"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_6)"
         @" AppleWebKit/603.3.8 (KHTML, like Gecko)"
         @" Version/11.0.1 Safari/603.3.8";
-      [scriptor addScriptMessageHandler:self name:@"keyDown"];
+      [scriptor addScriptMessageHandler:self name:@"__xwidget_internal_keyDown"];
       [scriptor addUserScript:[[WKUserScript alloc]
                                 initWithSource:xwScript
                                  injectionTime:
@@ -272,23 +272,34 @@ + (void)initialize
       @"}"
       @"function xwKeyDown(event) {"
       @"  if (event.ctrlKey && event.key == 'g') {"
-      @"    window.webkit.messageHandlers.keyDown.postMessage('C-g');"
+      @"    window.webkit.messageHandlers.__xwidget_internal_keyDown.postMessage('C-g');"
       @"  }"
       @"}"
       @"document.addEventListener('keydown', xwKeyDown);"
       ;
 }
 
+static Lisp_Object js_to_lisp (id value);
+
 /* Confirming to WKScriptMessageHandler, listens concerning keyDown in
    webkit. Currently 'C-g'.  */
 - (void)userContentController:(WKUserContentController *)userContentController
       didReceiveScriptMessage:(WKScriptMessage *)message
 {
-  if ([message.body isEqualToString:@"C-g"])
+  if ([message.name isEqualToString:@"__xwidget_internal_keyDown"])
     {
-      /* Just give up focus, no relay "C-g" to emacs, another "C-g"
-         follows will be handled by emacs.  */
-      [self.window makeFirstResponder:self.xw->xv->emacswindow];
+      if ([message.body isEqualToString:@"C-g"])
+        {
+          /* Just give up focus, no relay "C-g" to emacs, another "C-g"
+             follows will be handled by emacs.  */
+          [self.window makeFirstResponder:self.xw->xv->emacswindow];
+        }
+    }
+  else
+    {
+      store_xwidget_script_message_event (self.xw,
+                                          message.name.UTF8String,
+                                          js_to_lisp (message.body));
     }
 }
 
@@ -445,6 +456,61 @@ - (void)userContentController:(WKUserContentController *)userContentController
     }];
 }
 
+void
+nsxwidget_webkit_add_user_script (struct xwidget *xw, const char *script,
+                                  int injection_time_start, int main_frame_only)
+{
+  XwWebView *xwWebView = (XwWebView *) xw->xwWidget;
+  WKUserContentController *scriptor = xwWebView.configuration.userContentController;
+
+  NSString *javascriptString = [NSString stringWithUTF8String:script];
+  WKUserScriptInjectionTime injectionTime = injection_time_start?
+    WKUserScriptInjectionTimeAtDocumentStart : WKUserScriptInjectionTimeAtDocumentEnd;
+  WKUserScript *userScript = [[WKUserScript alloc]
+                               initWithSource: javascriptString
+                                injectionTime: injectionTime
+                               forMainFrameOnly: main_frame_only];
+  [scriptor addUserScript: userScript];
+}
+
+void
+nsxwidget_webkit_remove_all_user_scripts (struct xwidget *xw)
+{
+  XwWebView *xwWebView = (XwWebView *) xw->xwWidget;
+  WKUserContentController *scriptor = xwWebView.configuration.userContentController;
+
+  [scriptor removeAllUserScripts];
+}
+
+Lisp_Object
+nsxwidget_webkit_register_script_message (struct xwidget *xw, const char *name)
+{
+  XwWebView *xwWebView = (XwWebView *) xw->xwWidget;
+  WKUserContentController *scriptor = xwWebView.configuration.userContentController;
+
+  NSString *messageName = [NSString stringWithUTF8String:name];
+
+  @try
+    {
+      [scriptor addScriptMessageHandler:xw->xwWidget name:messageName];
+    }
+  @catch (NSException *e)
+    {
+      return Qnil;
+    }
+  return Qt;
+}
+
+void
+nsxwidget_webkit_unregister_script_message (struct xwidget *xw, const char *name)
+{
+  XwWebView *xwWebView = (XwWebView *) xw->xwWidget;
+  WKUserContentController *scriptor = xwWebView.configuration.userContentController;
+
+  NSString *messageName = [NSString stringWithUTF8String:name];
+  [scriptor removeScriptMessageHandlerForName:messageName];
+}
+
 /* Window containing an xwidget.  */
 
 @implementation XwWindow
@@ -477,7 +543,7 @@ - (BOOL)isFlipped { return YES; }
       WKUserContentController *scriptor =
         ((XwWebView *) xw->xwWidget).configuration.userContentController;
       [scriptor removeAllUserScripts];
-      [scriptor removeScriptMessageHandlerForName:@"keyDown"];
+      [scriptor removeScriptMessageHandlerForName:@"__xwidget_internal_keyDown"];
       [scriptor release];
       if (xw->xv)
         xw->xv->model = Qnil; /* Make sure related view stale.  */
diff --git a/src/xwidget.c b/src/xwidget.c
index 154b3e9c82..d3524acd68 100644
--- a/src/xwidget.c
+++ b/src/xwidget.c
@@ -70,6 +70,15 @@ webkit_decide_policy_cb (WebKitWebView *,
                          WebKitPolicyDecision *,
                          WebKitPolicyDecisionType,
                          gpointer);
+
+struct webkit_script_message_cb_data
+{
+  struct xwidget *xw;
+  char name[0];
+};
+static void webkit_script_message_cb (WebKitUserContentManager *,
+                                          WebKitJavascriptResult *,
+                                          gpointer);
 #endif
 
 
@@ -120,7 +129,8 @@ DEFUN ("make-xwidget",
 
       if (EQ (xw->type, Qwebkit))
         {
-          xw->widget_osr = webkit_web_view_new ();
+          WebKitUserContentManager *scriptor = webkit_user_content_manager_new ();
+          xw->widget_osr = webkit_web_view_new_with_user_content_manager (scriptor);
         }
 
       gtk_widget_set_size_request (GTK_WIDGET (xw->widget_osr), xw->width,
@@ -293,6 +303,21 @@ store_xwidget_js_callback_event (struct xwidget *xw,
   kbd_buffer_store_event (&event);
 }
 
+void
+store_xwidget_script_message_event (struct xwidget *xw,
+                                         const char *name,
+                                         Lisp_Object body)
+{
+  struct input_event event;
+  Lisp_Object xwl;
+  XSETXWIDGET (xwl, xw);
+  EVENT_INIT (event);
+  event.kind = XWIDGET_EVENT;
+  event.frame_or_window = Qnil;
+  event.arg = list4 (intern ("script-message"), xwl, intern (name), body);
+  kbd_buffer_store_event (&event);
+}
+
 
 #ifdef USE_GTK
 void
@@ -481,6 +506,18 @@ webkit_decide_policy_cb (WebKitWebView *webView,
   }
 }
 
+static void webkit_script_message_cb (WebKitUserContentManager *scriptor,
+                                          WebKitJavascriptResult *js_result,
+                                          gpointer data)
+{
+  JSCValue *value = webkit_javascript_result_get_js_value (js_result);
+  struct webkit_script_message_cb_data *arg = data;
+
+  Lisp_Object lisp_value = webkit_js_to_lisp (value);
+  store_xwidget_script_message_event (arg->xw, arg->name, lisp_value);
+}
+
+
 
 /* For gtk3 offscreen rendered widgets.  */
 static gboolean
@@ -922,6 +959,140 @@ DEFUN ("xwidget-webkit-execute-script",
   return Qnil;
 }
 
+DEFUN ("xwidget-webkit-add-user-script",
+       Fxwidget_webkit_add_user_script, Sxwidget_webkit_add_user_script,
+       4, 4, 0,
+       doc: /* Add user SCRIPT to the Webkit XWIDGET.
+INJECTION-TIME is a symbol which can take one of the following values:
+
+- start: SCRIPT is injected when document starts loading
+- end: SCRIPT is injected when document finishes loading
+
+If MAIN_FRAME_ONLY is nil, SCRIPT is injected to all frames.
+Otherwise, SCRIPT is only injected to top frames.*/)
+  (Lisp_Object xwidget, Lisp_Object script,
+   Lisp_Object injection_time, Lisp_Object main_frame_only)
+{
+  WEBKIT_FN_INIT ();
+  CHECK_STRING (script);
+  CHECK_SYMBOL (injection_time);
+
+  script = ENCODE_SYSTEM(script);
+
+  int injection_time_start, mfo;
+  mfo = !NILP (main_frame_only);
+  if (EQ (injection_time, Qstart))
+    injection_time_start = 1;
+  else if (EQ (injection_time, Qend))
+    injection_time_start = 0;
+  else
+    error ("Unknown Xwidget Webkit user script injection time: %s",
+           SDATA (SYMBOL_NAME (injection_time)));
+
+#ifdef USE_GTK
+  WebKitWebView *wkwv = WEBKIT_WEB_VIEW (xw->widget_osr);
+  WebKitUserContentManager *scriptor = webkit_web_view_get_user_content_manager (wkwv);
+
+  int webkit_injected_frames = mfo?
+    WEBKIT_USER_CONTENT_INJECT_TOP_FRAME : WEBKIT_USER_CONTENT_INJECT_ALL_FRAMES;
+  int webkit_injection_time = injection_time_start?
+    WEBKIT_USER_SCRIPT_INJECT_AT_DOCUMENT_START : WEBKIT_USER_SCRIPT_INJECT_AT_DOCUMENT_END;
+  WebKitUserScript *userScript = webkit_user_script_new (SSDATA (script),
+                                                         webkit_injected_frames,
+                                                         webkit_injection_time,
+                                                         NULL, NULL);
+  webkit_user_content_manager_add_script (scriptor, userScript);
+  webkit_user_script_unref (userScript);
+#elif defined NS_IMPL_COCOA
+  nsxwidget_webkit_add_user_script (xw, SSDATA (script), injection_time_start, mfo);
+#endif
+  return Qnil;
+}
+
+DEFUN ("xwidget-webkit-remove-all-user-scripts",
+       Fxwidget_webkit_remove_all_user_scripts, Sxwidget_webkit_remove_all_user_scripts,
+       1, 1, 0,
+       doc: /* Remove all user scripts from XWIDGET.  */)
+  (Lisp_Object xwidget)
+{
+  WEBKIT_FN_INIT ();
+
+#ifdef USE_GTK
+  WebKitWebView *wkwv = WEBKIT_WEB_VIEW (xw->widget_osr);
+  WebKitUserContentManager *scriptor = webkit_web_view_get_user_content_manager (wkwv);
+
+  webkit_user_content_manager_remove_all_scripts (scriptor);
+#elif defined NS_IMPL_COCOA
+  nsxwidget_webkit_remove_all_user_scripts(xw);
+#endif
+  return Qnil;
+}
+
+DEFUN ("xwidget-webkit-register-script-message",
+       Fxwidget_webkit_register_script_message, Sxwidget_webkit_register_script_message,
+       2, 2, 0,
+       doc: /* Register script message with symbol NAME in Webkit XWIDGET.
+Returns T if the operation is successful, NIL otherwise.
+The cause of failure is usually that NAME has already been registered for XWIDGET.  */)
+  (Lisp_Object xwidget, Lisp_Object name)
+{
+  WEBKIT_FN_INIT ();
+  CHECK_SYMBOL (name);
+  const char *sname = SDATA( SYMBOL_NAME (name));
+
+#ifdef USE_GTK
+  WebKitWebView *wkwv = WEBKIT_WEB_VIEW (xw->widget_osr);
+  WebKitUserContentManager *scriptor = webkit_web_view_get_user_content_manager (wkwv);
+
+  gchar *signal_name = g_strconcat ("script-message-received::", sname, NULL);
+  size_t name_length = strlen (sname) + 1;
+  struct webkit_script_message_cb_data *arg = malloc (sizeof *arg + name_length);
+  arg->xw = xw;
+  g_strlcpy (arg->name, sname, name_length);
+  g_signal_connect_data(scriptor, signal_name, G_CALLBACK (webkit_script_message_cb),
+                        arg, (GClosureNotify)free, 0);
+  g_free (signal_name);
+  if (webkit_user_content_manager_register_script_message_handler (scriptor, sname))
+    {
+      return Qt;
+    }
+  else
+    {
+      g_signal_handlers_disconnect_matched  (scriptor,
+                                             G_SIGNAL_MATCH_DATA,
+                                             0, 0, 0, 0, arg);
+      return Qnil;
+    }
+#elif defined NS_IMPL_COCOA
+  return nsxwidget_webkit_register_script_message(xw, sname);
+#endif
+}
+
+DEFUN ("xwidget-webkit-unregister-script-message",
+       Fxwidget_webkit_unregister_script_message, Sxwidget_webkit_unregister_script_message,
+       2, 2, 0,
+       doc: /* Unregister script message with symbol NAME in Webkit XWIDGET.  */)
+  (Lisp_Object xwidget, Lisp_Object name)
+{
+  WEBKIT_FN_INIT ();
+  CHECK_SYMBOL (name);
+  const char *sname = SSDATA( SYMBOL_NAME (name));
+
+#ifdef USE_GTK
+  WebKitWebView *wkwv = WEBKIT_WEB_VIEW (xw->widget_osr);
+  WebKitUserContentManager *scriptor = webkit_web_view_get_user_content_manager (wkwv);
+
+  webkit_user_content_manager_unregister_script_message_handler (scriptor, sname);
+  g_signal_handlers_disconnect_matched  (scriptor,
+                                         G_SIGNAL_MATCH_FUNC,
+                                         0, g_quark_from_string (sname), 0,
+                                         G_CALLBACK (webkit_script_message_cb), 0);
+#elif defined NS_IMPL_COCOA
+  nsxwidget_webkit_unregister_script_message(xw, sname);
+#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)
@@ -1189,6 +1360,14 @@ syms_of_xwidget (void)
   defsubr (&Sxwidget_webkit_execute_script);
   DEFSYM (Qwebkit, "webkit");
 
+  defsubr (&Sxwidget_webkit_add_user_script);
+  DEFSYM (Qstart, "start");
+  DEFSYM (Qend, "end");
+  defsubr (&Sxwidget_webkit_remove_all_user_scripts);
+
+  defsubr (&Sxwidget_webkit_register_script_message);
+  defsubr (&Sxwidget_webkit_unregister_script_message);
+
   defsubr (&Sxwidget_size_request);
   defsubr (&Sdelete_xwidget_view);
 
diff --git a/src/xwidget.h b/src/xwidget.h
index 40ad8ae833..cfd0ebced6 100644
--- a/src/xwidget.h
+++ b/src/xwidget.h
@@ -162,6 +162,11 @@ #define XG_XWIDGET_VIEW "emacs_xwidget_view"
 void store_xwidget_js_callback_event (struct xwidget *xw,
                                       Lisp_Object proc,
                                       Lisp_Object argument);
+
+void store_xwidget_script_message_event (struct xwidget *xw,
+                                         const char *name,
+                                         Lisp_Object value);
+
 #else
 INLINE_HEADER_BEGIN
 INLINE void syms_of_xwidget (void) {}
-- 
2.20.1 (Apple Git-117)


[-- Attachment #1.2.3: Type: text/html, Size: 2497 bytes --]

[-- Attachment #2: smime.p7s --]
[-- Type: application/pkcs7-signature, Size: 1858 bytes --]

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

* Re: [PATCH] Add user content APIs for WebKit Xwidgets
  2020-08-28  2:25 [PATCH] Add user content " Qiantan Hong
@ 2020-08-28 14:37 ` Lars Ingebrigtsen
  2020-08-28 15:41   ` Qiantan Hong
  2020-08-29  4:07   ` Richard Stallman
  2020-08-29  4:10 ` Richard Stallman
  1 sibling, 2 replies; 41+ messages in thread
From: Lars Ingebrigtsen @ 2020-08-28 14:37 UTC (permalink / raw)
  To: Qiantan Hong; +Cc: emacs-devel@gnu.org

Qiantan Hong <qhong@mit.edu> writes:

> The user script API makes it possible to reliable and predictable injecting
> script into a Webkit Xwidget, which is useful for customizing the WebView
> behavior.

That sounds very useful.

> The script message handler API makes it possible to trigger event in emacs
> from JavaScript, and can be used to implement procedure calling from
> js to elisp. Currently only the other way around is possible.

That sounds really scary, though.  What are the security implications
here?

Anyway, this is a larger large patch, so to apply it to Emacs, we'd have
to have a copyright assignment to the FSF.  Would you be willing to sign
such paperwork?

-- 
(domestic pets only, the antidote for overdose, milk.)
   bloggy blog: http://lars.ingebrigtsen.no



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

* Re: [PATCH] Add user content APIs for WebKit Xwidgets
  2020-08-28 14:37 ` Lars Ingebrigtsen
@ 2020-08-28 15:41   ` Qiantan Hong
  2020-08-30 13:43     ` Lars Ingebrigtsen
  2020-08-29  4:07   ` Richard Stallman
  1 sibling, 1 reply; 41+ messages in thread
From: Qiantan Hong @ 2020-08-28 15:41 UTC (permalink / raw)
  To: larsi@gnus.org; +Cc: emacs-devel@gnu.org

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

>> The script message handler API makes it possible to trigger event in emacs
>> from JavaScript, and can be used to implement procedure calling from
>> js to elisp. Currently only the other way around is possible.
> 
> That sounds really scary, though.  What are the security implications
> here?

I think it doesn’t increase any security risk, but sure correct me if I’m wrong. 

The way this works is, Elisp side has to use
(xwidget-webkit-register-message xwidget message-name)
to register for an identifier — if nothing is registered, nothing can go to
Elisp.

After an identifier is registered, JavaScript can then use it to post
messages, which becomes an input event on Elisp side. This itself won’t
be able to call any Elisp procedure, but it’s possible to bind the input event
to some Elisp procedure that dispatches on message body and calls other
function to simulate an FFI interface from js to Elisp. In this case, 
that Elisp procedure should control which procedures are allowed to call.

> Anyway, this is a larger large patch, so to apply it to Emacs, we'd have
> to have a copyright assignment to the FSF.  Would you be willing to sign
> such paperwork?

Sure, I’m sending email.

[-- Attachment #2: smime.p7s --]
[-- Type: application/pkcs7-signature, Size: 1858 bytes --]

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

* Re: [PATCH] Add user content APIs for WebKit Xwidgets
  2020-08-28 14:37 ` Lars Ingebrigtsen
  2020-08-28 15:41   ` Qiantan Hong
@ 2020-08-29  4:07   ` Richard Stallman
  1 sibling, 0 replies; 41+ messages in thread
From: Richard Stallman @ 2020-08-29  4:07 UTC (permalink / raw)
  To: Lars Ingebrigtsen; +Cc: qhong, emacs-devel

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

  > > The script message handler API makes it possible to trigger event in emacs
  > > from JavaScript, and can be used to implement procedure calling from
  > > js to elisp. Currently only the other way around is possible.

  > That sounds really scary, though.  What are the security implications
  > here?

That is an important concern.

Another importan concern: what are the moral implications of making
Emacs a platform for running nonfree Javascript code that users get
from web sites?  It looks like that has in effect already been done;
is that so?

There should have been a discussion about _whether_ Emacs should
support that, and if so, how to include something comparable to
LibreJS.


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





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

* Re: [PATCH] Add user content APIs for WebKit Xwidgets
  2020-08-28  2:25 [PATCH] Add user content " Qiantan Hong
  2020-08-28 14:37 ` Lars Ingebrigtsen
@ 2020-08-29  4:10 ` Richard Stallman
  2020-08-29  4:45   ` Qiantan Hong
  1 sibling, 1 reply; 41+ messages in thread
From: Richard Stallman @ 2020-08-29  4:10 UTC (permalink / raw)
  To: Qiantan Hong; +Cc: emacs-devel

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

  > I implemented some primitives to expose some WebKit user content APIs
  > (user script and script message handlers)

I am not sure what those terms mean, but could we please not call them
"content"?

      for WebKit Xwidgets, both
  > for WebKitGTK impl and NS/mac impl.

Can you tell me what this has to do with Javascript?
Is Webkitgtk implemented using Javascript?

  > The script message handler API makes it possible to trigger event in emacs
  > from JavaScript, and can be used to implement procedure calling from
  > js to elisp. Currently only the other way around is possible.

If the Javascript code is free, or user-written, there's no harm in doing such
calls in either direction.  But when the language is Javascript, given the way
Javascript is usually used (running nonfree programs that random sites send,
often in obfuscated form), I'm concerned that we are opening the door
to vicious habits that we ought to be trying to discourage.


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





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

* Re: [PATCH] Add user content APIs for WebKit Xwidgets
  2020-08-29  4:10 ` Richard Stallman
@ 2020-08-29  4:45   ` Qiantan Hong
  0 siblings, 0 replies; 41+ messages in thread
From: Qiantan Hong @ 2020-08-29  4:45 UTC (permalink / raw)
  To: rms@gnu.org; +Cc: emacs-devel@gnu.org

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


>      for WebKit Xwidgets, both
>> for WebKitGTK impl and NS/mac impl.
> 
> Can you tell me what this has to do with Javascript?
> Is Webkitgtk implemented using Javascript?
No, but it’s a Javascript enabled web rendering engine,
and it provides API to interact with its Javascript interpreter.

> 
>> The script message handler API makes it possible to trigger event in emacs
>> from JavaScript, and can be used to implement procedure calling from
>> js to elisp. Currently only the other way around is possible.
> 
> If the Javascript code is free, or user-written, there's no harm in doing such
> calls in either direction.  But when the language is Javascript, given the way
> Javascript is usually used (running nonfree programs that random sites send,
> often in obfuscated form), I'm concerned that we are opening the door
> to vicious habits that we ought to be trying to discourage.
The Webkit itself supports Javascript and in current form that it's embedded in
Emacs, it either allows any Javascript execution, or Javascript can be completely 
disabled. This patch is about exposing more APIs to interact with Javascript,
and can be possibly used to control Javascript execution. 

I’m currently reading the source of librejs. It’s also written in 
Javascript and look like to let it run in Emacs and supervise the Webkit Xwidgets,
bidirectional calling between Elisp/JS is a necessity — which this patch
provides.



[-- Attachment #2: smime.p7s --]
[-- Type: application/pkcs7-signature, Size: 1858 bytes --]

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

* Re: [PATCH] Add user content APIs for WebKit Xwidgets
  2020-08-28 15:41   ` Qiantan Hong
@ 2020-08-30 13:43     ` Lars Ingebrigtsen
  0 siblings, 0 replies; 41+ messages in thread
From: Lars Ingebrigtsen @ 2020-08-30 13:43 UTC (permalink / raw)
  To: Qiantan Hong; +Cc: emacs-devel@gnu.org

Qiantan Hong <qhong@mit.edu> writes:

> After an identifier is registered, JavaScript can then use it to post
> messages, which becomes an input event on Elisp side. This itself won’t
> be able to call any Elisp procedure, but it’s possible to bind the input event
> to some Elisp procedure that dispatches on message body and calls other
> function to simulate an FFI interface from js to Elisp. In this case, 
> that Elisp procedure should control which procedures are allowed to call.

Oh, I see.  Yes, that seems like a sensible way to do this and should be
safe. 

-- 
(domestic pets only, the antidote for overdose, milk.)
   bloggy blog: http://lars.ingebrigtsen.no



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

* Re: [PATCH] Add user content APIs for WebKit Xwidgets
@ 2022-10-14  6:34 Qiantan Hong
  2022-10-14  7:01 ` Po Lu
  0 siblings, 1 reply; 41+ messages in thread
From: Qiantan Hong @ 2022-10-14  6:34 UTC (permalink / raw)
  To: Lars Ingebrigtsen; +Cc: emacs-devel@gnu.org

Hi,

Is there any chance to get this merged now?

Best,
Qiantan






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

* Re: [PATCH] Add user content APIs for WebKit Xwidgets
  2022-10-14  6:34 [PATCH] Add user content APIs for WebKit Xwidgets Qiantan Hong
@ 2022-10-14  7:01 ` Po Lu
  2022-10-14  7:12   ` Qiantan Hong
  0 siblings, 1 reply; 41+ messages in thread
From: Po Lu @ 2022-10-14  7:01 UTC (permalink / raw)
  To: Qiantan Hong; +Cc: Lars Ingebrigtsen, emacs-devel@gnu.org

Qiantan Hong <qthong@stanford.edu> writes:

> Hi,
>
> Is there any chance to get this merged now?
>
> Best,
> Qiantan

I don't see the patch.  :(



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

* Re: [PATCH] Add user content APIs for WebKit Xwidgets
  2022-10-14  7:01 ` Po Lu
@ 2022-10-14  7:12   ` Qiantan Hong
  2022-10-14  7:35     ` Po Lu
  0 siblings, 1 reply; 41+ messages in thread
From: Qiantan Hong @ 2022-10-14  7:12 UTC (permalink / raw)
  To: Po Lu; +Cc: Lars Ingebrigtsen, emacs-devel@gnu.org

Ah sorry, I’m replying to a really ancient thread in 2020, the patch is at
https://lists.gnu.org/archive/html/emacs-devel/2020-08/txtNrEQRJNtgd.txt

I hope the patch is still applicable… If it’s not I’ll find sometime this weekend to update it.

Best,
Qiantan



> On Oct 14, 2022, at 12:01 AM, Po Lu <luangruo@yahoo.com> wrote:
> 
> Qiantan Hong <qthong@stanford.edu> writes:
> 
>> Hi,
>> 
>> Is there any chance to get this merged now?
>> 
>> Best,
>> Qiantan
> 
> I don't see the patch.  :(


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

* Re: [PATCH] Add user content APIs for WebKit Xwidgets
  2022-10-14  7:12   ` Qiantan Hong
@ 2022-10-14  7:35     ` Po Lu
  2022-10-14 21:13       ` Qiantan Hong
  0 siblings, 1 reply; 41+ messages in thread
From: Po Lu @ 2022-10-14  7:35 UTC (permalink / raw)
  To: Qiantan Hong; +Cc: Lars Ingebrigtsen, emacs-devel@gnu.org

Qiantan Hong <qthong@stanford.edu> writes:

> Ah sorry, I’m replying to a really ancient thread in 2020, the patch is at
> https://lists.gnu.org/archive/html/emacs-devel/2020-08/txtNrEQRJNtgd.txt
>
> I hope the patch is still applicable… If it’s not I’ll find sometime this weekend to update it.

Thanks.  Please do that, and also fix the coding style to comply with
our coding guidelines.



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

* Re: [PATCH] Add user content APIs for WebKit Xwidgets
  2022-10-14  7:35     ` Po Lu
@ 2022-10-14 21:13       ` Qiantan Hong
  2022-10-15  1:37         ` Qiantan Hong
  0 siblings, 1 reply; 41+ messages in thread
From: Qiantan Hong @ 2022-10-14 21:13 UTC (permalink / raw)
  To: Po Lu; +Cc: Lars Ingebrigtsen, emacs-devel@gnu.org


[-- Attachment #1.1: Type: text/plain, Size: 553 bytes --]

Hi,

Here’s the updated patch.


Best,
Qiantan



> On Oct 14, 2022, at 12:35 AM, Po Lu <luangruo@yahoo.com> wrote:
>
> Qiantan Hong <qthong@stanford.edu> writes:
>
>> Ah sorry, I’m replying to a really ancient thread in 2020, the patch is at
>> https://lists.gnu.org/archive/html/emacs-devel/2020-08/txtNrEQRJNtgd.txt
>>
>> I hope the patch is still applicable… If it’s not I’ll find sometime this weekend to update it.
>
> Thanks.  Please do that, and also fix the coding style to comply with
> our coding guidelines.


[-- Attachment #1.2: Type: text/html, Size: 1168 bytes --]

[-- Attachment #2: 0001-Implment-some-user-content-APIs-for-WebKit-Xwidgets.txt --]
[-- Type: text/plain, Size: 18985 bytes --]

From d03d1b813c016e805fe8902500cdd20ade39ed53 Mon Sep 17 00:00:00 2001
From: Qiantan Hong <qhong@alum.mit.edu>
Date: Fri, 14 Oct 2022 14:08:40 -0700
Subject: [PATCH] Implment some user content APIs for WebKit Xwidgets

Implement WebKit user scripts and script message handlers.
* src/xwidget.h (store_xwidget_script_message_event): store script
  message event into event queue
* src/xwidget.c (store_xwidget_script_message_event, make-xwidget,
  webkit_script_message_cb, xwidget-webkit-add-user-script,
  xwidget-webkit-remove-all-user-scripts,
  xwidget-webkit-register-script-message,
  xwidget-webkit-unregister-script-message): Implement user script
  and script message handler primitives.
* src/nsxwidget.c (nsxwidget_webkit_add_user_script,
  nsxwidget_webkit_remove_all_user_scripts,
  nsxwidget_webkit_register_script_message,
  nsxwidget_webkit_unregister_script_message,
  initWithFrame, initialize, userContentController): NS
  implementation. Changed naming of a previous used  script message
  handler to avoid namespace pollution.
* src/nsxwidget.h (nsxwidget_webkit_add_user_script,
  nsxwidget_webkit_remove_all_user_scripts,
  nsxwidget_webkit_register_script_message,
  nsxwidget_webkit_unregister_script_message): NS implementation
* lisp/xwidget.el (xwidget-webkit-callback,
  xwidget-webkit-add-script-message-handler,
  xwidget-webkit-remove-script-message-handler):
  let lisp recognize and dispatch script message events
---
 lisp/xwidget.el |  32 +++++++++
 src/nsxwidget.h |   5 ++
 src/nsxwidget.m |  80 +++++++++++++++++++--
 src/xwidget.c   | 181 ++++++++++++++++++++++++++++++++++++++++++++++++
 src/xwidget.h   |   4 ++
 5 files changed, 295 insertions(+), 7 deletions(-)

diff --git a/lisp/xwidget.el b/lisp/xwidget.el
index 41a1190c64..02412a8808 100644
--- a/lisp/xwidget.el
+++ b/lisp/xwidget.el
@@ -485,8 +485,40 @@ xwidget-webkit-callback
            (let ((proc (nth 3 last-input-event))
                  (arg  (nth 4 last-input-event)))
              (funcall proc arg)))
+          ((eq xwidget-event-type 'script-message)
+           (let ((name (nth 3 last-input-event))
+                 (value (nth 4 last-input-event)))
+             (let ((handler-pair (assq name (xwidget-get xwidget 'script-message-handlers))))
+               (if handler-pair
+                   (funcall (cdr handler-pair) xwidget value)
+                 (xwidget-log "unhandled script message:%s" name)))))
           (t (xwidget-log "unhandled event:%s" xwidget-event-type)))))
 
+(defun xwidget-webkit-add-script-message-handler (xwidget name handler)
+  "Associate HANDLER with script messages under symbol NAME for Webkit XWIDGET.
+
+HANDLER will be called with two arguments: the Webkit XWIDGET and
+the javascript object passed from the script message converted to
+a Lisp object."
+  (xwidget-webkit-register-script-message (xwidget-webkit-current-session) name)
+  (xwidget-put xwidget 'script-message-handlers
+               (cons (cons name handler) (xwidget-get xwidget 'script-message-handlers)))
+  name)
+
+(defun xwidget-webkit-remove-script-message-handler (xwidget name)
+  "Remove a handler associated with symbol NAME for Webkit XWIDGET.
+
+Returns the removed (NAME . HANDLER) pair, or NIL if such handler
+is not found."
+  (let* ((old-alist (xwidget-get xwidget 'script-message-handlers))
+         (handler-pair (assq name old-alist)))
+    (when handler-pair
+      (let ((new-alist (delq handler-pair old-alist)))
+        (xwidget-put xwidget 'script-message-handlers new-alist)
+        (unless (assq name new-alist)
+          (xwidget-webkit-unregister-script-message (xwidget-webkit-current-session) name)))
+      handler-pair)))
+
 (defvar bookmark-make-record-function)
 (when (memq window-system '(mac ns))
   (defcustom xwidget-webkit-enable-plugins nil
diff --git a/src/nsxwidget.h b/src/nsxwidget.h
index 666509744a..cd1dc1bc2c 100644
--- a/src/nsxwidget.h
+++ b/src/nsxwidget.h
@@ -40,6 +40,11 @@ #define NSXWIDGET_H_INCLUDED
 void nsxwidget_webkit_execute_script (struct xwidget *xw, const char *script,
                                       Lisp_Object fun);
 
+void nsxwidget_webkit_add_user_script (struct xwidget *xw, const char *script,
+                                       int injection_time_start, int main_frame_only);
+void nsxwidget_webkit_remove_all_user_scripts (struct xwidget *xw);
+Lisp_Object nsxwidget_webkit_register_script_message (struct xwidget *xw, const char *name);
+void nsxwidget_webkit_unregister_script_message (struct xwidget *xw, const char *name);
 /* Functions for xwidget model.  */
 
 #ifdef __OBJC__
diff --git a/src/nsxwidget.m b/src/nsxwidget.m
index be0eba0bcb..e09759f754 100644
--- a/src/nsxwidget.m
+++ b/src/nsxwidget.m
@@ -88,7 +88,7 @@ - (id)initWithFrame:(CGRect)frame
         @"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_6)"
         @" AppleWebKit/603.3.8 (KHTML, like Gecko)"
         @" Version/11.0.1 Safari/603.3.8";
-      [scriptor addScriptMessageHandler:self name:@"keyDown"];
+      [scriptor addScriptMessageHandler:self name:@"__xwidget_internal_keyDown"];
       [scriptor addUserScript:[[WKUserScript alloc]
                                 initWithSource:xwScript
                                  injectionTime:
@@ -275,23 +275,34 @@ + (void)initialize
       @"}"
       @"function xwKeyDown(event) {"
       @"  if (event.ctrlKey && event.key == 'g') {"
-      @"    window.webkit.messageHandlers.keyDown.postMessage('C-g');"
+      @"    window.webkit.messageHandlers.__xwidget_internal_keyDown.postMessage('C-g');"
       @"  }"
       @"}"
       @"document.addEventListener('keydown', xwKeyDown);"
       ;
 }
 
+static Lisp_Object js_to_lisp (id value);
+
 /* Confirming to WKScriptMessageHandler, listens concerning keyDown in
    webkit. Currently 'C-g'.  */
 - (void)userContentController:(WKUserContentController *)userContentController
       didReceiveScriptMessage:(WKScriptMessage *)message
 {
-  if ([message.body isEqualToString:@"C-g"])
+  if ([message.name isEqualToString:@"__xwidget_internal_keyDown"])
     {
-      /* Just give up focus, no relay "C-g" to emacs, another "C-g"
-         follows will be handled by emacs.  */
-      [self.window makeFirstResponder:self.xw->xv->emacswindow];
+      if ([message.body isEqualToString:@"C-g"])
+        {
+          /* Just give up focus, no relay "C-g" to emacs, another "C-g"
+             follows will be handled by emacs.  */
+          [self.window makeFirstResponder:self.xw->xv->emacswindow];
+        }
+    }
+  else
+    {
+      store_xwidget_script_message_event (self.xw,
+                                          message.name.UTF8String,
+                                          js_to_lisp (message.body));
     }
 }
 
@@ -437,6 +448,61 @@ - (void)userContentController:(WKUserContentController *)userContentController
     }];
 }
 
+void
+nsxwidget_webkit_add_user_script (struct xwidget *xw, const char *script,
+                                  int injection_time_start, int main_frame_only)
+{
+  XwWebView *xwWebView = (XwWebView *) xw->xwWidget;
+  WKUserContentController *scriptor = xwWebView.configuration.userContentController;
+
+  NSString *javascriptString = [NSString stringWithUTF8String:script];
+  WKUserScriptInjectionTime injectionTime = injection_time_start?
+    WKUserScriptInjectionTimeAtDocumentStart : WKUserScriptInjectionTimeAtDocumentEnd;
+  WKUserScript *userScript = [[WKUserScript alloc]
+                               initWithSource: javascriptString
+                                injectionTime: injectionTime
+                               forMainFrameOnly: main_frame_only];
+  [scriptor addUserScript: userScript];
+}
+
+void
+nsxwidget_webkit_remove_all_user_scripts (struct xwidget *xw)
+{
+  XwWebView *xwWebView = (XwWebView *) xw->xwWidget;
+  WKUserContentController *scriptor = xwWebView.configuration.userContentController;
+
+  [scriptor removeAllUserScripts];
+}
+
+Lisp_Object
+nsxwidget_webkit_register_script_message (struct xwidget *xw, const char *name)
+{
+  XwWebView *xwWebView = (XwWebView *) xw->xwWidget;
+  WKUserContentController *scriptor = xwWebView.configuration.userContentController;
+
+  NSString *messageName = [NSString stringWithUTF8String:name];
+
+  @try
+    {
+      [scriptor addScriptMessageHandler:xwWebView name:messageName];
+    }
+  @catch (NSException *e)
+    {
+      return Qnil;
+    }
+  return Qt;
+}
+
+void
+nsxwidget_webkit_unregister_script_message (struct xwidget *xw, const char *name)
+{
+  XwWebView *xwWebView = (XwWebView *) xw->xwWidget;
+  WKUserContentController *scriptor = xwWebView.configuration.userContentController;
+
+  NSString *messageName = [NSString stringWithUTF8String:name];
+  [scriptor removeScriptMessageHandlerForName:messageName];
+}
+
 /* Window containing an xwidget.  */
 
 @implementation XwWindow
@@ -469,7 +535,7 @@ - (BOOL)isFlipped { return YES; }
       WKUserContentController *scriptor =
         ((XwWebView *) xw->xwWidget).configuration.userContentController;
       [scriptor removeAllUserScripts];
-      [scriptor removeScriptMessageHandlerForName:@"keyDown"];
+      [scriptor removeScriptMessageHandlerForName:@"__xwidget_internal_keyDown"];
       [scriptor release];
       if (xw->xv)
         xw->xv->model = Qnil; /* Make sure related view stale.  */
diff --git a/src/xwidget.c b/src/xwidget.c
index 8bdfab02fd..ea19264a18 100644
--- a/src/xwidget.c
+++ b/src/xwidget.c
@@ -226,6 +226,15 @@ xw_forward_event_from_view (GtkWidget *widget, GdkEvent *event,
   /* Don't propagate this event further.  */
   return TRUE;
 }
+
+struct webkit_script_message_cb_data
+{
+  struct xwidget *xw;
+  char name[0];
+};
+static void webkit_script_message_cb (WebKitUserContentManager *,
+                                          WebKitJavascriptResult *,
+                                          gpointer);
 #endif
 
 #ifdef HAVE_X_WINDOWS
@@ -380,6 +389,9 @@ DEFUN ("make-xwidget",
 	  settings = webkit_web_view_get_settings (WEBKIT_WEB_VIEW (xw->widget_osr));
 	  g_object_set (G_OBJECT (settings), "enable-developer-extras", TRUE, NULL);
 	}
+          WebKitUserContentManager *scriptor = webkit_user_content_manager_new ();
+          xw->widget_osr = webkit_web_view_new_with_user_content_manager (scriptor);
+        }
 
       gtk_widget_set_size_request (GTK_WIDGET (xw->widget_osr), xw->width,
                                    xw->height);
@@ -2308,6 +2320,21 @@ store_xwidget_js_callback_event (struct xwidget *xw,
   kbd_buffer_store_event (&event);
 }
 
+void
+store_xwidget_script_message_event (struct xwidget *xw,
+                                         const char *name,
+                                         Lisp_Object body)
+{
+  struct input_event event;
+  Lisp_Object xwl;
+  XSETXWIDGET (xwl, xw);
+  EVENT_INIT (event);
+  event.kind = XWIDGET_EVENT;
+  event.frame_or_window = Qnil;
+  event.arg = list4 (intern ("script-message"), xwl, intern (name), body);
+  kbd_buffer_store_event (&event);
+}
+
 
 #ifdef USE_GTK
 static void
@@ -2622,6 +2649,17 @@ webkit_decide_policy_cb (WebKitWebView *webView,
   }
 }
 
+static void webkit_script_message_cb (WebKitUserContentManager *scriptor,
+                                          WebKitJavascriptResult *js_result,
+                                          gpointer data)
+{
+  JSCValue *value = webkit_javascript_result_get_js_value (js_result);
+  struct webkit_script_message_cb_data *arg = data;
+
+  Lisp_Object lisp_value = webkit_js_to_lisp (value);
+  store_xwidget_script_message_event (arg->xw, arg->name, lisp_value);
+}
+
 static gboolean
 webkit_script_dialog_cb (WebKitWebView *webview,
 			 WebKitScriptDialog *script_dialog,
@@ -2717,6 +2755,7 @@ xwidget_init_view (struct xwidget *xww,
   XSETWINDOW (xv->w, s->w);
   XSETXWIDGET (xv->model, xww);
 
+
 #ifdef HAVE_X_WINDOWS
   xv->dpy = FRAME_X_DISPLAY (s->f);
 
@@ -3198,6 +3237,140 @@ DEFUN ("xwidget-webkit-execute-script",
   return Qnil;
 }
 
+DEFUN ("xwidget-webkit-add-user-script",
+       Fxwidget_webkit_add_user_script, Sxwidget_webkit_add_user_script,
+       4, 4, 0,
+       doc: /* Add user SCRIPT to the Webkit XWIDGET.
+INJECTION-TIME is a symbol which can take one of the following values:
+
+- start: SCRIPT is injected when document starts loading
+- end: SCRIPT is injected when document finishes loading
+
+If MAIN_FRAME_ONLY is nil, SCRIPT is injected to all frames.
+Otherwise, SCRIPT is only injected to top frames.*/)
+  (Lisp_Object xwidget, Lisp_Object script,
+   Lisp_Object injection_time, Lisp_Object main_frame_only)
+{
+  WEBKIT_FN_INIT ();
+  CHECK_STRING (script);
+  CHECK_SYMBOL (injection_time);
+
+  script = ENCODE_SYSTEM(script);
+
+  int injection_time_start, mfo;
+  mfo = !NILP (main_frame_only);
+  if (EQ (injection_time, Qstart))
+    injection_time_start = 1;
+  else if (EQ (injection_time, Qend))
+    injection_time_start = 0;
+  else
+    error ("Unknown Xwidget Webkit user script injection time: %s",
+           SDATA (SYMBOL_NAME (injection_time)));
+
+#ifdef USE_GTK
+  WebKitWebView *wkwv = WEBKIT_WEB_VIEW (xw->widget_osr);
+  WebKitUserContentManager *scriptor = webkit_web_view_get_user_content_manager (wkwv);
+
+  int webkit_injected_frames = mfo?
+    WEBKIT_USER_CONTENT_INJECT_TOP_FRAME : WEBKIT_USER_CONTENT_INJECT_ALL_FRAMES;
+  int webkit_injection_time = injection_time_start?
+    WEBKIT_USER_SCRIPT_INJECT_AT_DOCUMENT_START : WEBKIT_USER_SCRIPT_INJECT_AT_DOCUMENT_END;
+  WebKitUserScript *userScript = webkit_user_script_new (SSDATA (script),
+                                                         webkit_injected_frames,
+                                                         webkit_injection_time,
+                                                         NULL, NULL);
+  webkit_user_content_manager_add_script (scriptor, userScript);
+  webkit_user_script_unref (userScript);
+#elif defined NS_IMPL_COCOA
+  nsxwidget_webkit_add_user_script (xw, SSDATA (script), injection_time_start, mfo);
+#endif
+  return Qnil;
+}
+
+DEFUN ("xwidget-webkit-remove-all-user-scripts",
+       Fxwidget_webkit_remove_all_user_scripts, Sxwidget_webkit_remove_all_user_scripts,
+       1, 1, 0,
+       doc: /* Remove all user scripts from XWIDGET.  */)
+  (Lisp_Object xwidget)
+{
+  WEBKIT_FN_INIT ();
+
+#ifdef USE_GTK
+  WebKitWebView *wkwv = WEBKIT_WEB_VIEW (xw->widget_osr);
+  WebKitUserContentManager *scriptor = webkit_web_view_get_user_content_manager (wkwv);
+
+  webkit_user_content_manager_remove_all_scripts (scriptor);
+#elif defined NS_IMPL_COCOA
+  nsxwidget_webkit_remove_all_user_scripts(xw);
+#endif
+  return Qnil;
+}
+
+DEFUN ("xwidget-webkit-register-script-message",
+       Fxwidget_webkit_register_script_message, Sxwidget_webkit_register_script_message,
+       2, 2, 0,
+       doc: /* Register script message with symbol NAME in Webkit XWIDGET.
+Returns T if the operation is successful, NIL otherwise.
+The cause of failure is usually that NAME has already been registered for XWIDGET.  */)
+  (Lisp_Object xwidget, Lisp_Object name)
+{
+  WEBKIT_FN_INIT ();
+  CHECK_SYMBOL (name);
+  const char *sname = SDATA( SYMBOL_NAME (name));
+
+#ifdef USE_GTK
+  WebKitWebView *wkwv = WEBKIT_WEB_VIEW (xw->widget_osr);
+  WebKitUserContentManager *scriptor = webkit_web_view_get_user_content_manager (wkwv);
+
+  gchar *signal_name = g_strconcat ("script-message-received::", sname, NULL);
+  size_t name_length = strlen (sname) + 1;
+  struct webkit_script_message_cb_data *arg = malloc (sizeof *arg + name_length);
+  arg->xw = xw;
+  g_strlcpy (arg->name, sname, name_length);
+  g_signal_connect_data(scriptor, signal_name, G_CALLBACK (webkit_script_message_cb),
+                        arg, (GClosureNotify)free, 0);
+  g_free (signal_name);
+  if (webkit_user_content_manager_register_script_message_handler (scriptor, sname))
+    {
+      return Qt;
+    }
+  else
+    {
+      g_signal_handlers_disconnect_matched  (scriptor,
+                                             G_SIGNAL_MATCH_DATA,
+                                             0, 0, 0, 0, arg);
+      return Qnil;
+    }
+#elif defined NS_IMPL_COCOA
+  return nsxwidget_webkit_register_script_message(xw, sname);
+#endif
+}
+
+DEFUN ("xwidget-webkit-unregister-script-message",
+       Fxwidget_webkit_unregister_script_message, Sxwidget_webkit_unregister_script_message,
+       2, 2, 0,
+       doc: /* Unregister script message with symbol NAME in Webkit XWIDGET.  */)
+  (Lisp_Object xwidget, Lisp_Object name)
+{
+  WEBKIT_FN_INIT ();
+  CHECK_SYMBOL (name);
+  const char *sname = SSDATA( SYMBOL_NAME (name));
+
+#ifdef USE_GTK
+  WebKitWebView *wkwv = WEBKIT_WEB_VIEW (xw->widget_osr);
+  WebKitUserContentManager *scriptor = webkit_web_view_get_user_content_manager (wkwv);
+
+  webkit_user_content_manager_unregister_script_message_handler (scriptor, sname);
+  g_signal_handlers_disconnect_matched  (scriptor,
+                                         G_SIGNAL_MATCH_FUNC,
+                                         0, g_quark_from_string (sname), 0,
+                                         G_CALLBACK (webkit_script_message_cb), 0);
+#elif defined NS_IMPL_COCOA
+  nsxwidget_webkit_unregister_script_message(xw, sname);
+#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)
@@ -3919,6 +4092,14 @@ syms_of_xwidget (void)
   defsubr (&Sxwidget_webkit_execute_script);
   DEFSYM (Qwebkit, "webkit");
 
+  defsubr (&Sxwidget_webkit_add_user_script);
+  DEFSYM (Qstart, "start");
+  DEFSYM (Qend, "end");
+  defsubr (&Sxwidget_webkit_remove_all_user_scripts);
+
+  defsubr (&Sxwidget_webkit_register_script_message);
+  defsubr (&Sxwidget_webkit_unregister_script_message);
+
   defsubr (&Sxwidget_size_request);
   defsubr (&Sdelete_xwidget_view);
 
diff --git a/src/xwidget.h b/src/xwidget.h
index 502beb6765..e835f700bc 100644
--- a/src/xwidget.h
+++ b/src/xwidget.h
@@ -203,6 +203,10 @@ #define XG_XWIDGET_VIEW "emacs_xwidget_view"
                                       Lisp_Object proc,
                                       Lisp_Object argument);
 
+void store_xwidget_script_message_event (struct xwidget *xw,
+                                         const char *name,
+                                         Lisp_Object value);
+
 extern struct xwidget *xwidget_from_id (uint32_t id);
 
 #ifdef HAVE_X_WINDOWS
-- 
2.32.1 (Apple Git-133)


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

* Re: [PATCH] Add user content APIs for WebKit Xwidgets
  2022-10-14 21:13       ` Qiantan Hong
@ 2022-10-15  1:37         ` Qiantan Hong
  2022-10-15  7:53           ` Qiantan Hong
  0 siblings, 1 reply; 41+ messages in thread
From: Qiantan Hong @ 2022-10-15  1:37 UTC (permalink / raw)
  To: Po Lu; +Cc: Lars Ingebrigtsen, emacs-devel@gnu.org

Ah sorry for the noise, please don’t merge yet. I only tested it on NS before
and only tried it on GTK just now. It is broken on GTK. Will fix soon.

Best,
Qiantan



> On Oct 14, 2022, at 2:13 PM, Qiantan Hong <qthong@stanford.edu> wrote:
> 
> Hi,
> 
> Here’s the updated patch.
> <0001-Implment-some-user-content-APIs-for-WebKit-Xwidgets.txt>
> 
> Best,
> Qiantan
> 
> 
> 
>> On Oct 14, 2022, at 12:35 AM, Po Lu <luangruo@yahoo.com> wrote:
>> 
>> Qiantan Hong <qthong@stanford.edu> writes:
>> 
>>> Ah sorry, I’m replying to a really ancient thread in 2020, the patch is at
>>> https://lists.gnu.org/archive/html/emacs-devel/2020-08/txtNrEQRJNtgd.txt
>>> 
>>> I hope the patch is still applicable… If it’s not I’ll find sometime this weekend to update it.
>> 
>> Thanks.  Please do that, and also fix the coding style to comply with
>> our coding guidelines.
> 


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

* Re: [PATCH] Add user content APIs for WebKit Xwidgets
  2022-10-15  1:37         ` Qiantan Hong
@ 2022-10-15  7:53           ` Qiantan Hong
  2022-10-15 11:23             ` Po Lu
  2022-10-16 20:51             ` [PATCH] Add user extension " Richard Stallman
  0 siblings, 2 replies; 41+ messages in thread
From: Qiantan Hong @ 2022-10-15  7:53 UTC (permalink / raw)
  To: Po Lu; +Cc: Lars Ingebrigtsen, emacs-devel@gnu.org


[-- Attachment #1.1: Type: text/plain, Size: 1072 bytes --]

Here it goes, tested on GTK!



Best,
Qiantan



> On Oct 14, 2022, at 6:37 PM, Qiantan Hong <qthong@stanford.edu> wrote:
>
> Ah sorry for the noise, please don’t merge yet. I only tested it on NS before
> and only tried it on GTK just now. It is broken on GTK. Will fix soon.
>
> Best,
> Qiantan
>
>
>
>> On Oct 14, 2022, at 2:13 PM, Qiantan Hong <qthong@stanford.edu> wrote:
>>
>> Hi,
>>
>> Here’s the updated patch.
>> <0001-Implment-some-user-content-APIs-for-WebKit-Xwidgets.txt>
>>
>> Best,
>> Qiantan
>>
>>
>>
>>> On Oct 14, 2022, at 12:35 AM, Po Lu <luangruo@yahoo.com> wrote:
>>>
>>> Qiantan Hong <qthong@stanford.edu> writes:
>>>
>>>> Ah sorry, I’m replying to a really ancient thread in 2020, the patch is at
>>>> https://lists.gnu.org/archive/html/emacs-devel/2020-08/txtNrEQRJNtgd.txt
>>>>
>>>> I hope the patch is still applicable… If it’s not I’ll find sometime this weekend to update it.
>>>
>>> Thanks.  Please do that, and also fix the coding style to comply with
>>> our coding guidelines.
>>
>


[-- Attachment #1.2: Type: text/html, Size: 1987 bytes --]

[-- Attachment #2: 0002-Implment-some-user-content-APIs-for-WebKit-Xwidgets.txt --]
[-- Type: text/plain, Size: 19000 bytes --]

From aac249c4f0a3e0f21aae81e0a26c362b67336af2 Mon Sep 17 00:00:00 2001
From: Qiantan Hong <qhong@alum.mit.edu>
Date: Fri, 14 Oct 2022 14:08:40 -0700
Subject: [PATCH] Implment some user content APIs for WebKit Xwidgets

Implement WebKit user scripts and script message handlers.
* src/xwidget.h (store_xwidget_script_message_event): store script
  message event into event queue
* src/xwidget.c (store_xwidget_script_message_event, make-xwidget,
  webkit_script_message_cb, xwidget-webkit-add-user-script,
  xwidget-webkit-remove-all-user-scripts,
  xwidget-webkit-register-script-message,
  xwidget-webkit-unregister-script-message): Implement user script
  and script message handler primitives.
* src/nsxwidget.c (nsxwidget_webkit_add_user_script,
  nsxwidget_webkit_remove_all_user_scripts,
  nsxwidget_webkit_register_script_message,
  nsxwidget_webkit_unregister_script_message,
  initWithFrame, initialize, userContentController): NS
  implementation. Changed naming of a previous used  script message
  handler to avoid namespace pollution.
* src/nsxwidget.h (nsxwidget_webkit_add_user_script,
  nsxwidget_webkit_remove_all_user_scripts,
  nsxwidget_webkit_register_script_message,
  nsxwidget_webkit_unregister_script_message): NS implementation
* lisp/xwidget.el (xwidget-webkit-callback,
  xwidget-webkit-push-script-message-handler,
  xwidget-webkit-pop-script-message-handler):
  let lisp recognize and dispatch script message events

Acked-by: Qiantan Hong <qhong@mit.edu>
---
 lisp/xwidget.el |  32 +++++++++
 src/nsxwidget.h |   5 ++
 src/nsxwidget.m |  80 +++++++++++++++++++--
 src/xwidget.c   | 181 ++++++++++++++++++++++++++++++++++++++++++++++++
 src/xwidget.h   |   4 ++
 5 files changed, 295 insertions(+), 7 deletions(-)

diff --git a/lisp/xwidget.el b/lisp/xwidget.el
index 41a1190c64..79c9cc2afd 100644
--- a/lisp/xwidget.el
+++ b/lisp/xwidget.el
@@ -485,8 +485,40 @@ xwidget-webkit-callback
            (let ((proc (nth 3 last-input-event))
                  (arg  (nth 4 last-input-event)))
              (funcall proc arg)))
+          ((eq xwidget-event-type 'script-message)
+           (let ((name (nth 3 last-input-event))
+                 (value (nth 4 last-input-event)))
+             (let ((handler-pair (assq name (xwidget-get xwidget 'script-message-handlers))))
+               (if handler-pair
+                   (funcall (cdr handler-pair) xwidget value)
+                 (xwidget-log "unhandled script message:%s" name)))))
           (t (xwidget-log "unhandled event:%s" xwidget-event-type)))))
 
+(defun xwidget-webkit-push-script-message-handler (xwidget name handler)
+  "Associate HANDLER with script messages under symbol NAME for Webkit XWIDGET.
+
+HANDLER will be called with two arguments: the Webkit XWIDGET and
+the javascript object passed from the script message converted to
+a Lisp object."
+  (xwidget-webkit-register-script-message (xwidget-webkit-current-session) name)
+  (xwidget-put xwidget 'script-message-handlers
+               (cons (cons name handler) (xwidget-get xwidget 'script-message-handlers)))
+  name)
+
+(defun xwidget-webkit-pop-script-message-handler (xwidget name)
+  "Remove a handler associated with symbol NAME for Webkit XWIDGET.
+
+Returns the removed handler function, or NIL if such handler is
+not found."
+  (let* ((old-alist (xwidget-get xwidget 'script-message-handlers))
+         (handler-pair (assq name old-alist)))
+    (when handler-pair
+      (let ((new-alist (delq handler-pair old-alist)))
+        (xwidget-put xwidget 'script-message-handlers new-alist)
+        (unless (assq name new-alist)
+          (xwidget-webkit-unregister-script-message (xwidget-webkit-current-session) name)))
+      (cdr handler-pair))))
+
 (defvar bookmark-make-record-function)
 (when (memq window-system '(mac ns))
   (defcustom xwidget-webkit-enable-plugins nil
diff --git a/src/nsxwidget.h b/src/nsxwidget.h
index 666509744a..cd1dc1bc2c 100644
--- a/src/nsxwidget.h
+++ b/src/nsxwidget.h
@@ -40,6 +40,11 @@ #define NSXWIDGET_H_INCLUDED
 void nsxwidget_webkit_execute_script (struct xwidget *xw, const char *script,
                                       Lisp_Object fun);
 
+void nsxwidget_webkit_add_user_script (struct xwidget *xw, const char *script,
+                                       int injection_time_start, int main_frame_only);
+void nsxwidget_webkit_remove_all_user_scripts (struct xwidget *xw);
+Lisp_Object nsxwidget_webkit_register_script_message (struct xwidget *xw, const char *name);
+void nsxwidget_webkit_unregister_script_message (struct xwidget *xw, const char *name);
 /* Functions for xwidget model.  */
 
 #ifdef __OBJC__
diff --git a/src/nsxwidget.m b/src/nsxwidget.m
index be0eba0bcb..e09759f754 100644
--- a/src/nsxwidget.m
+++ b/src/nsxwidget.m
@@ -88,7 +88,7 @@ - (id)initWithFrame:(CGRect)frame
         @"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_6)"
         @" AppleWebKit/603.3.8 (KHTML, like Gecko)"
         @" Version/11.0.1 Safari/603.3.8";
-      [scriptor addScriptMessageHandler:self name:@"keyDown"];
+      [scriptor addScriptMessageHandler:self name:@"__xwidget_internal_keyDown"];
       [scriptor addUserScript:[[WKUserScript alloc]
                                 initWithSource:xwScript
                                  injectionTime:
@@ -275,23 +275,34 @@ + (void)initialize
       @"}"
       @"function xwKeyDown(event) {"
       @"  if (event.ctrlKey && event.key == 'g') {"
-      @"    window.webkit.messageHandlers.keyDown.postMessage('C-g');"
+      @"    window.webkit.messageHandlers.__xwidget_internal_keyDown.postMessage('C-g');"
       @"  }"
       @"}"
       @"document.addEventListener('keydown', xwKeyDown);"
       ;
 }
 
+static Lisp_Object js_to_lisp (id value);
+
 /* Confirming to WKScriptMessageHandler, listens concerning keyDown in
    webkit. Currently 'C-g'.  */
 - (void)userContentController:(WKUserContentController *)userContentController
       didReceiveScriptMessage:(WKScriptMessage *)message
 {
-  if ([message.body isEqualToString:@"C-g"])
+  if ([message.name isEqualToString:@"__xwidget_internal_keyDown"])
     {
-      /* Just give up focus, no relay "C-g" to emacs, another "C-g"
-         follows will be handled by emacs.  */
-      [self.window makeFirstResponder:self.xw->xv->emacswindow];
+      if ([message.body isEqualToString:@"C-g"])
+        {
+          /* Just give up focus, no relay "C-g" to emacs, another "C-g"
+             follows will be handled by emacs.  */
+          [self.window makeFirstResponder:self.xw->xv->emacswindow];
+        }
+    }
+  else
+    {
+      store_xwidget_script_message_event (self.xw,
+                                          message.name.UTF8String,
+                                          js_to_lisp (message.body));
     }
 }
 
@@ -437,6 +448,61 @@ - (void)userContentController:(WKUserContentController *)userContentController
     }];
 }
 
+void
+nsxwidget_webkit_add_user_script (struct xwidget *xw, const char *script,
+                                  int injection_time_start, int main_frame_only)
+{
+  XwWebView *xwWebView = (XwWebView *) xw->xwWidget;
+  WKUserContentController *scriptor = xwWebView.configuration.userContentController;
+
+  NSString *javascriptString = [NSString stringWithUTF8String:script];
+  WKUserScriptInjectionTime injectionTime = injection_time_start?
+    WKUserScriptInjectionTimeAtDocumentStart : WKUserScriptInjectionTimeAtDocumentEnd;
+  WKUserScript *userScript = [[WKUserScript alloc]
+                               initWithSource: javascriptString
+                                injectionTime: injectionTime
+                               forMainFrameOnly: main_frame_only];
+  [scriptor addUserScript: userScript];
+}
+
+void
+nsxwidget_webkit_remove_all_user_scripts (struct xwidget *xw)
+{
+  XwWebView *xwWebView = (XwWebView *) xw->xwWidget;
+  WKUserContentController *scriptor = xwWebView.configuration.userContentController;
+
+  [scriptor removeAllUserScripts];
+}
+
+Lisp_Object
+nsxwidget_webkit_register_script_message (struct xwidget *xw, const char *name)
+{
+  XwWebView *xwWebView = (XwWebView *) xw->xwWidget;
+  WKUserContentController *scriptor = xwWebView.configuration.userContentController;
+
+  NSString *messageName = [NSString stringWithUTF8String:name];
+
+  @try
+    {
+      [scriptor addScriptMessageHandler:xwWebView name:messageName];
+    }
+  @catch (NSException *e)
+    {
+      return Qnil;
+    }
+  return Qt;
+}
+
+void
+nsxwidget_webkit_unregister_script_message (struct xwidget *xw, const char *name)
+{
+  XwWebView *xwWebView = (XwWebView *) xw->xwWidget;
+  WKUserContentController *scriptor = xwWebView.configuration.userContentController;
+
+  NSString *messageName = [NSString stringWithUTF8String:name];
+  [scriptor removeScriptMessageHandlerForName:messageName];
+}
+
 /* Window containing an xwidget.  */
 
 @implementation XwWindow
@@ -469,7 +535,7 @@ - (BOOL)isFlipped { return YES; }
       WKUserContentController *scriptor =
         ((XwWebView *) xw->xwWidget).configuration.userContentController;
       [scriptor removeAllUserScripts];
-      [scriptor removeScriptMessageHandlerForName:@"keyDown"];
+      [scriptor removeScriptMessageHandlerForName:@"__xwidget_internal_keyDown"];
       [scriptor release];
       if (xw->xv)
         xw->xv->model = Qnil; /* Make sure related view stale.  */
diff --git a/src/xwidget.c b/src/xwidget.c
index 8bdfab02fd..e4250065b9 100644
--- a/src/xwidget.c
+++ b/src/xwidget.c
@@ -126,6 +126,16 @@ webkit_decide_policy_cb (WebKitWebView *,
 };
 
 static void find_widget (GtkWidget *t, struct widget_search_data *);
+
+struct webkit_script_message_cb_data
+{
+  struct xwidget *xw;
+  char name[0];
+};
+static void webkit_script_message_cb (WebKitUserContentManager *,
+                                          WebKitJavascriptResult *,
+                                          gpointer);
+
 #endif
 
 #ifdef HAVE_PGTK
@@ -380,6 +390,8 @@ DEFUN ("make-xwidget",
 	  settings = webkit_web_view_get_settings (WEBKIT_WEB_VIEW (xw->widget_osr));
 	  g_object_set (G_OBJECT (settings), "enable-developer-extras", TRUE, NULL);
 	}
+      WebKitUserContentManager *scriptor = webkit_user_content_manager_new ();
+      xw->widget_osr = webkit_web_view_new_with_user_content_manager (scriptor);
 
       gtk_widget_set_size_request (GTK_WIDGET (xw->widget_osr), xw->width,
                                    xw->height);
@@ -2308,6 +2320,21 @@ store_xwidget_js_callback_event (struct xwidget *xw,
   kbd_buffer_store_event (&event);
 }
 
+void
+store_xwidget_script_message_event (struct xwidget *xw,
+                                         const char *name,
+                                         Lisp_Object body)
+{
+  struct input_event event;
+  Lisp_Object xwl;
+  XSETXWIDGET (xwl, xw);
+  EVENT_INIT (event);
+  event.kind = XWIDGET_EVENT;
+  event.frame_or_window = Qnil;
+  event.arg = list4 (intern ("script-message"), xwl, intern (name), body);
+  kbd_buffer_store_event (&event);
+}
+
 
 #ifdef USE_GTK
 static void
@@ -2622,6 +2649,17 @@ webkit_decide_policy_cb (WebKitWebView *webView,
   }
 }
 
+static void webkit_script_message_cb (WebKitUserContentManager *scriptor,
+                                          WebKitJavascriptResult *js_result,
+                                          gpointer data)
+{
+  JSCValue *value = webkit_javascript_result_get_js_value (js_result);
+  struct webkit_script_message_cb_data *arg = data;
+
+  Lisp_Object lisp_value = webkit_js_to_lisp (value);
+  store_xwidget_script_message_event (arg->xw, arg->name, lisp_value);
+}
+
 static gboolean
 webkit_script_dialog_cb (WebKitWebView *webview,
 			 WebKitScriptDialog *script_dialog,
@@ -2717,6 +2755,7 @@ xwidget_init_view (struct xwidget *xww,
   XSETWINDOW (xv->w, s->w);
   XSETXWIDGET (xv->model, xww);
 
+
 #ifdef HAVE_X_WINDOWS
   xv->dpy = FRAME_X_DISPLAY (s->f);
 
@@ -3198,6 +3237,140 @@ DEFUN ("xwidget-webkit-execute-script",
   return Qnil;
 }
 
+DEFUN ("xwidget-webkit-add-user-script",
+       Fxwidget_webkit_add_user_script, Sxwidget_webkit_add_user_script,
+       4, 4, 0,
+       doc: /* Add user SCRIPT to the Webkit XWIDGET.
+INJECTION-TIME is a symbol which can take one of the following values:
+
+- start: SCRIPT is injected when document starts loading
+- end: SCRIPT is injected when document finishes loading
+
+If MAIN_FRAME_ONLY is nil, SCRIPT is injected to all frames.
+Otherwise, SCRIPT is only injected to top frames.*/)
+  (Lisp_Object xwidget, Lisp_Object script,
+   Lisp_Object injection_time, Lisp_Object main_frame_only)
+{
+  WEBKIT_FN_INIT ();
+  CHECK_STRING (script);
+  CHECK_SYMBOL (injection_time);
+
+  script = ENCODE_SYSTEM(script);
+
+  int injection_time_start, mfo;
+  mfo = !NILP (main_frame_only);
+  if (EQ (injection_time, Qstart))
+    injection_time_start = 1;
+  else if (EQ (injection_time, Qend))
+    injection_time_start = 0;
+  else
+    error ("Unknown Xwidget Webkit user script injection time: %s",
+           SDATA (SYMBOL_NAME (injection_time)));
+
+#ifdef USE_GTK
+  WebKitWebView *wkwv = WEBKIT_WEB_VIEW (xw->widget_osr);
+  WebKitUserContentManager *scriptor = webkit_web_view_get_user_content_manager (wkwv);
+
+  int webkit_injected_frames = mfo?
+    WEBKIT_USER_CONTENT_INJECT_TOP_FRAME : WEBKIT_USER_CONTENT_INJECT_ALL_FRAMES;
+  int webkit_injection_time = injection_time_start?
+    WEBKIT_USER_SCRIPT_INJECT_AT_DOCUMENT_START : WEBKIT_USER_SCRIPT_INJECT_AT_DOCUMENT_END;
+  WebKitUserScript *userScript = webkit_user_script_new (SSDATA (script),
+                                                         webkit_injected_frames,
+                                                         webkit_injection_time,
+                                                         NULL, NULL);
+  webkit_user_content_manager_add_script (scriptor, userScript);
+  webkit_user_script_unref (userScript);
+#elif defined NS_IMPL_COCOA
+  nsxwidget_webkit_add_user_script (xw, SSDATA (script), injection_time_start, mfo);
+#endif
+  return Qnil;
+}
+
+DEFUN ("xwidget-webkit-remove-all-user-scripts",
+       Fxwidget_webkit_remove_all_user_scripts, Sxwidget_webkit_remove_all_user_scripts,
+       1, 1, 0,
+       doc: /* Remove all user scripts from XWIDGET.  */)
+  (Lisp_Object xwidget)
+{
+  WEBKIT_FN_INIT ();
+
+#ifdef USE_GTK
+  WebKitWebView *wkwv = WEBKIT_WEB_VIEW (xw->widget_osr);
+  WebKitUserContentManager *scriptor = webkit_web_view_get_user_content_manager (wkwv);
+
+  webkit_user_content_manager_remove_all_scripts (scriptor);
+#elif defined NS_IMPL_COCOA
+  nsxwidget_webkit_remove_all_user_scripts(xw);
+#endif
+  return Qnil;
+}
+
+DEFUN ("xwidget-webkit-register-script-message",
+       Fxwidget_webkit_register_script_message, Sxwidget_webkit_register_script_message,
+       2, 2, 0,
+       doc: /* Register script message with symbol NAME in Webkit XWIDGET.
+Returns T if the operation is successful, NIL otherwise.
+The cause of failure is usually that NAME has already been registered for XWIDGET.  */)
+  (Lisp_Object xwidget, Lisp_Object name)
+{
+  WEBKIT_FN_INIT ();
+  CHECK_SYMBOL (name);
+  const char *sname = SSDATA( SYMBOL_NAME (name));
+
+#ifdef USE_GTK
+  WebKitWebView *wkwv = WEBKIT_WEB_VIEW (xw->widget_osr);
+  WebKitUserContentManager *scriptor = webkit_web_view_get_user_content_manager (wkwv);
+
+  gchar *signal_name = g_strconcat ("script-message-received::", sname, NULL);
+  size_t name_length = strlen (sname) + 1;
+  struct webkit_script_message_cb_data *arg = malloc (sizeof *arg + name_length);
+  arg->xw = xw;
+  g_strlcpy (arg->name, sname, name_length);
+  g_signal_connect_data(scriptor, signal_name, G_CALLBACK (webkit_script_message_cb),
+                        arg, (GClosureNotify)free, 0);
+  g_free (signal_name);
+  if (webkit_user_content_manager_register_script_message_handler (scriptor, sname))
+    {
+      return Qt;
+    }
+  else
+    {
+      g_signal_handlers_disconnect_matched  (scriptor,
+                                             G_SIGNAL_MATCH_DATA,
+                                             0, 0, 0, 0, arg);
+      return Qnil;
+    }
+#elif defined NS_IMPL_COCOA
+  return nsxwidget_webkit_register_script_message(xw, sname);
+#endif
+}
+
+DEFUN ("xwidget-webkit-unregister-script-message",
+       Fxwidget_webkit_unregister_script_message, Sxwidget_webkit_unregister_script_message,
+       2, 2, 0,
+       doc: /* Unregister script message with symbol NAME in Webkit XWIDGET.  */)
+  (Lisp_Object xwidget, Lisp_Object name)
+{
+  WEBKIT_FN_INIT ();
+  CHECK_SYMBOL (name);
+  const char *sname = SSDATA( SYMBOL_NAME (name));
+
+#ifdef USE_GTK
+  WebKitWebView *wkwv = WEBKIT_WEB_VIEW (xw->widget_osr);
+  WebKitUserContentManager *scriptor = webkit_web_view_get_user_content_manager (wkwv);
+
+  webkit_user_content_manager_unregister_script_message_handler (scriptor, sname);
+  g_signal_handlers_disconnect_matched  (scriptor,
+                                         G_SIGNAL_MATCH_FUNC | G_SIGNAL_MATCH_DETAIL,
+                                         0, g_quark_from_string (sname), 0,
+                                         G_CALLBACK (webkit_script_message_cb), 0);
+#elif defined NS_IMPL_COCOA
+  nsxwidget_webkit_unregister_script_message(xw, sname);
+#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)
@@ -3919,6 +4092,14 @@ syms_of_xwidget (void)
   defsubr (&Sxwidget_webkit_execute_script);
   DEFSYM (Qwebkit, "webkit");
 
+  defsubr (&Sxwidget_webkit_add_user_script);
+  DEFSYM (Qstart, "start");
+  DEFSYM (Qend, "end");
+  defsubr (&Sxwidget_webkit_remove_all_user_scripts);
+
+  defsubr (&Sxwidget_webkit_register_script_message);
+  defsubr (&Sxwidget_webkit_unregister_script_message);
+
   defsubr (&Sxwidget_size_request);
   defsubr (&Sdelete_xwidget_view);
 
diff --git a/src/xwidget.h b/src/xwidget.h
index 502beb6765..e835f700bc 100644
--- a/src/xwidget.h
+++ b/src/xwidget.h
@@ -203,6 +203,10 @@ #define XG_XWIDGET_VIEW "emacs_xwidget_view"
                                       Lisp_Object proc,
                                       Lisp_Object argument);
 
+void store_xwidget_script_message_event (struct xwidget *xw,
+                                         const char *name,
+                                         Lisp_Object value);
+
 extern struct xwidget *xwidget_from_id (uint32_t id);
 
 #ifdef HAVE_X_WINDOWS
-- 
2.26.2


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

* Re: [PATCH] Add user content APIs for WebKit Xwidgets
  2022-10-15  7:53           ` Qiantan Hong
@ 2022-10-15 11:23             ` Po Lu
  2022-10-15 18:29               ` Qiantan Hong
  2022-10-15 23:33               ` Qiantan Hong
  2022-10-16 20:51             ` [PATCH] Add user extension " Richard Stallman
  1 sibling, 2 replies; 41+ messages in thread
From: Po Lu @ 2022-10-15 11:23 UTC (permalink / raw)
  To: Qiantan Hong; +Cc: Lars Ingebrigtsen, emacs-devel@gnu.org

Qiantan Hong <qthong@stanford.edu> writes:

> Implement WebKit user scripts and script message handlers.
> * src/xwidget.h (store_xwidget_script_message_event): store script
>   message event into event queue
> * src/xwidget.c (store_xwidget_script_message_event, make-xwidget,
>   webkit_script_message_cb, xwidget-webkit-add-user-script,
>   xwidget-webkit-remove-all-user-scripts,
>   xwidget-webkit-register-script-message,
>   xwidget-webkit-unregister-script-message): Implement user script
>   and script message handler primitives.
> * src/nsxwidget.c (nsxwidget_webkit_add_user_script,
>   nsxwidget_webkit_remove_all_user_scripts,
>   nsxwidget_webkit_register_script_message,
>   nsxwidget_webkit_unregister_script_message,
>   initWithFrame, initialize, userContentController): NS
>   implementation. Changed naming of a previous used  script message
>   handler to avoid namespace pollution.
> * src/nsxwidget.h (nsxwidget_webkit_add_user_script,
>   nsxwidget_webkit_remove_all_user_scripts,
>   nsxwidget_webkit_register_script_message,
>   nsxwidget_webkit_unregister_script_message): NS implementation
> * lisp/xwidget.el (xwidget-webkit-callback,
>   xwidget-webkit-push-script-message-handler,
>   xwidget-webkit-pop-script-message-handler):
>   let lisp recognize and dispatch script message events

Thanks; this is not how we write commit messages.  It should be:

* src/xwidget.h (store_xwidget_script_message_event):
* src/xwidget.c (store_xwidget_script_message_event):
(xwidget_script_message_cb):
(Fxwidget_webkit_add_user_script): Store script message event
into event queue.

and so on.  Pay attention to how the name of the C function is written
for defuns, how continuing lines in each message are not indented, and
how brackets are placed around functions.

> Acked-by: Qiantan Hong <qhong@mit.edu>

Please remove this extraneous line from the comment message.

> +          ((eq xwidget-event-type 'script-message)
> +           (let ((name (nth 3 last-input-event))
> +                 (value (nth 4 last-input-event)))
> +             (let ((handler-pair (assq name (xwidget-get xwidget 'script-message-handlers))))
> +               (if handler-pair
> +                   (funcall (cdr handler-pair) xwidget value)
> +                 (xwidget-log "unhandled script message:%s" name)))))

Please place a space between : and " ".

> +(defun xwidget-webkit-push-script-message-handler (xwidget name handler)
> +  "Associate HANDLER with script messages under symbol NAME for Webkit XWIDGET.
> +
> +HANDLER will be called with two arguments: the Webkit XWIDGET and
> +the javascript object passed from the script message converted to
> +a Lisp object."
> +  (xwidget-webkit-register-script-message (xwidget-webkit-current-session) name)

80 columns alert!  That aside, this does not explain what "script
messages" are.  "Webkit" and "javascript" should also be capitalized
"WebKit" and "JavaScript" respectively.

> +(defun xwidget-webkit-pop-script-message-handler (xwidget name)
> +  "Remove a handler associated with symbol NAME for Webkit XWIDGET.
> +
> +Returns the removed handler function, or NIL if such handler is
> +not found."
> +  (let* ((old-alist (xwidget-get xwidget 'script-message-handlers))
> +         (handler-pair (assq name old-alist)))
> +    (when handler-pair
> +      (let ((new-alist (delq handler-pair old-alist)))
> +        (xwidget-put xwidget 'script-message-handlers new-alist)
> +        (unless (assq name new-alist)
> +          (xwidget-webkit-unregister-script-message (xwidget-webkit-current-session) name)))

80 columns alert!  What I said about documentation above applies here as
well.

> +  @try
> +    {
> +      [scriptor addScriptMessageHandler:xwWebView name:messageName];
> +    }
> +  @catch (NSException *e)
> +    {
> +      return Qnil;
> +    }

Please remove the unnecessary braces here.

> diff --git a/src/xwidget.c b/src/xwidget.c
> index 8bdfab02fd..e4250065b9 100644
> --- a/src/xwidget.c
> +++ b/src/xwidget.c
> @@ -126,6 +126,16 @@ webkit_decide_policy_cb (WebKitWebView *,
>  };
>  
>  static void find_widget (GtkWidget *t, struct widget_search_data *);
> +
> +struct webkit_script_message_cb_data
> +{
> +  struct xwidget *xw;
> +  char name[0];
> +};
> +static void webkit_script_message_cb (WebKitUserContentManager *,
> +                                          WebKitJavascriptResult *,
> +                                          gpointer);
> +

Zero-length arrays are not portable, and it is bad style to store string
data in arrays that way.  Please allocate a separate string, and free it
manually in the GDestroyNotify.  In addition, please write a comment
above each field describing its meaning.

> +      WebKitUserContentManager *scriptor = webkit_user_content_manager_new ();
> +      xw->widget_osr = webkit_web_view_new_with_user_content_manager (scriptor);

scriptor is leaked, as WebKitUserContentManager not GInitiallyUnowned.
Did you forget a g_object_unref?

> +void
> +store_xwidget_script_message_event (struct xwidget *xw,
> +                                         const char *name,
> +                                         Lisp_Object body)
> +{
> +  struct input_event event;
> +  Lisp_Object xwl;
> +  XSETXWIDGET (xwl, xw);
> +  EVENT_INIT (event);
> +  event.kind = XWIDGET_EVENT;
> +  event.frame_or_window = Qnil;
> +  event.arg = list4 (intern ("script-message"), xwl, intern (name), body);
> +  kbd_buffer_store_event (&event);
> +}

Calling intern with a static string is bad style.  Please write this as
a DEFSYM instead, in syms_of_xwidget:

  DEFSYM (Qscript_message, "script-message");

and use Qscript_message.

> +static void webkit_script_message_cb (WebKitUserContentManager *scriptor,
> +                                          WebKitJavascriptResult *js_result,
> +                                          gpointer data)
> +{
> +  JSCValue *value = webkit_javascript_result_get_js_value (js_result);
> +  struct webkit_script_message_cb_data *arg = data;
> +
> +  Lisp_Object lisp_value = webkit_js_to_lisp (value);
> +  store_xwidget_script_message_event (arg->xw, arg->name, lisp_value);
> +}

Please add a newline after "static void".  It is also very ugly to put a
newline between "arg" and "lisp_value"; I would prefer this be written:

  JSCValue *value;
  struct webkit_script_message_cb_data *arg;
  Lisp_Object lisp_value;

  value = webkit_javascript...

In addition, don't you have to call webkit_javascript_result_unref?

> +
>  #ifdef HAVE_X_WINDOWS
>    xv->dpy = FRAME_X_DISPLAY (s->f);
>  

Please remove this whitespace change.

> +       doc: /* Add user SCRIPT to the Webkit XWIDGET.

This should be read "Add the user script SCRIPT to the WebKit XWIDGET.",
followed by a short summary of what userscripts are, and what the script
argument should be.

> +INJECTION-TIME is a symbol which can take one of the following values:

"WHEN is one of the following values, and specifies when the script is run:"

> +- start: SCRIPT is injected when document starts loading
> +- end: SCRIPT is injected when document finishes loading

"  - `start', which means the script is run upon first loading a document.
   - `end', which means the script is run after a document loads."

> +If MAIN_FRAME_ONLY is nil, SCRIPT is injected to all frames.

"If MAIN-FRAME-ONLY is non-nil, run SCRIPT for all frames."  (Followed
by a description of what "frames" are.)

> +Otherwise, SCRIPT is only injected to top frames.

What are top frames?

> +  script = ENCODE_SYSTEM(script);

Are you sure that is the right coding system?  WebKit APIs usually take
UTF-8 strings.

In any case, this should be:

  script = ENCODE_SYSTEM (script);

> +  int injection_time_start, mfo;
> +  mfo = !NILP (main_frame_only);

What is the purpose of those two variables?  In either case, `mfo'
should be named something else, as that name carries no meaning.

When chosing variable names, try to avoid truncating words, or worse,
simply making up acronyms.  Consider the following:

  Bool window_data_exists;

  window_data_exists = (XGetWindowProperty ....

or even

  Bool data_exists;

  data_exists = (XGetWindowProperty ....

and note how much clearer it is compared to:

  Bool wde;

  wde = (XGetWindowProperty ...

or

  Bool dat_p;

  dat_p = (XGetWindowProperty ...

> +  if (EQ (injection_time, Qstart))
> +    injection_time_start = 1;
> +  else if (EQ (injection_time, Qend))
> +    injection_time_start = 0;
> +
> +    error ("Unknown Xwidget Webkit user script injection time: %s",
> +           SDATA (SYMBOL_NAME (injection_time)));

Since there are only two values, how about replacing `injection-time'
with a single boolean argument `start', which determines whether to run
the user script at or after page load?

> +  int webkit_injected_frames = mfo?
> +    WEBKIT_USER_CONTENT_INJECT_TOP_FRAME : WEBKIT_USER_CONTENT_INJECT_ALL_FRAMES;

This is not our coding style.  It should be:

  (!NILP (main_frame_only)
   ? WEBKIT_USER_CONTENT_INJECT_TOP_FRAME
   : WEBKIT_USER_CONTENT_INJECT_ALL_FRAMES)

further more, the type is not int, it is enum
WebKitUserContentInjectedFrames.

> +  int webkit_injection_time = injection_time_start?
> +    WEBKIT_USER_SCRIPT_INJECT_AT_DOCUMENT_START : WEBKIT_USER_SCRIPT_INJECT_AT_DOCUMENT_END;

Likewise.  enum WebKitUserScriptInjectionTime.

> +  WebKitUserScript *userScript = webkit_user_script_new (SSDATA (script),
> +                                                         webkit_injected_frames,
> +                                                         webkit_injection_time,
> +                                                         NULL, NULL);

80 columns alert!  Please name the variable "user_script" instead; this
piece of code should probably be written as follows:

  WebKitUserScript *user_script
    = webkit_user_script_new (SSDATA (script),
			      webkit_injected_frames,
			      webkit_injection_time,
			      NULL, NULL);

> +DEFUN ("xwidget-webkit-register-script-message",
> +       Fxwidget_webkit_register_script_message, Sxwidget_webkit_register_script_message,
> +       2, 2, 0,
> +       doc: /* Register script message with symbol NAME in Webkit
> XWIDGET.

What was said about capitalization above also applies here.  Please fill
everything to 80 columns as well.

> +Returns T if the operation is successful, NIL otherwise.

Emacs Lisp is not Common Lisp, and does not capitalize symbol names by
default.

> +The cause of failure is usually that NAME has already been registered for XWIDGET.  */)

This belongs in the Lisp reference manual, and is likely redundant in
any case.  Also, the function should signal an error if NAME has already
been used, instead of simply returning nil.

> +  const char *sname = SSDATA( SYMBOL_NAME (name));

This is a pointer to string data.  It is not safe to assume GC does not
happen and relocate it below, due to the multitude of GLib callbacks
installed that can call GC.  Consider using xlispstrdup instead.

In addition to that, please make "name" a string; I see no reason for it
to be a symbol.

> +#ifdef USE_GTK
> +  WebKitWebView *wkwv = WEBKIT_WEB_VIEW (xw->widget_osr);

Please name this variable view, not "wkwv", for the reasons explained
above.

> +  gchar *signal_name = g_strconcat ("script-message-received::", sname, NULL);

Please consider using alloca or SAFE_ALLOCA to allocate this buffer, and
then using strncpy or lispstpcpy to copy the data over.

SAFE_ALLOCA is used like this, when there are no conflicting specbinds:

void
function_using_safe_alloca (void)
{
  char *mybuffer;

  USE_SAFE_ALLOCA;
  mybuffer = SAFE_ALLOCA (size_of_buffer);

  /* Do stuff with mybuffer... Finally: */

  SAFE_FREE ();
}

> +  struct webkit_script_message_cb_data *arg = malloc (sizeof *arg + name_length);
> +  arg->xw = xw;
> +  g_strlcpy (arg->name, sname, name_length);

Recall what I said about zero-length or variable length arrays being bad
style here.  Please allocate arg->name separately, probably with
lispstpcpy...

> +  g_signal_connect_data(scriptor, signal_name, G_CALLBACK (webkit_script_message_cb),
> +                        arg, (GClosureNotify)free, 0);
                                                ^^^^

and free it in the destroy_data callback.  In addition, please put a
space between the cast and the type, and use G_CONNECT_DEFAULT as
opposed to 0.

In addition, xw is a Lisp object.  It should be marked for garbage
collection as long as the signal handler is attached, as making
assumptions about when signals are run is not safe.

> +  if (webkit_user_content_manager_register_script_message_handler (scriptor, sname))
> +    {
> +      return Qt;
> +    }
> +  else
> +    {
> +      g_signal_handlers_disconnect_matched  (scriptor,
                                             ^

Extra whitespace.  Please also remove the redundant braces above.

> +  WebKitWebView *wkwv = WEBKIT_WEB_VIEW (xw->widget_osr);

"WebKitWebView *view = WEBKIT_WEB_VIEW (..."

> +  WebKitUserContentManager *scriptor = webkit_web_view_get_user_content_manager (wkwv);

How about naming all the "scriptor" variables "content_manager", or
"manager" instead?  Also, please fill this function to 80 columns as
well.

> +  g_signal_handlers_disconnect_matched  (scriptor,
> +                                         G_SIGNAL_MATCH_FUNC | G_SIGNAL_MATCH_DETAIL,
> +                                         0, g_quark_from_string (sname), 0,
> +                                         G_CALLBACK (webkit_script_message_cb), 0);

There is extra whitespace here.  

> +
>  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)
> @@ -3919,6 +4092,14 @@ syms_of_xwidget (void)
>    defsubr (&Sxwidget_webkit_execute_script);
>    DEFSYM (Qwebkit, "webkit");
>  
> +  defsubr (&Sxwidget_webkit_add_user_script);
> +  DEFSYM (Qstart, "start");
> +  DEFSYM (Qend, "end");
> +  defsubr (&Sxwidget_webkit_remove_all_user_scripts);
> +
> +  defsubr (&Sxwidget_webkit_register_script_message);
> +  defsubr (&Sxwidget_webkit_unregister_script_message);
> +
>    defsubr (&Sxwidget_size_request);
>    defsubr (&Sdelete_xwidget_view);

Why are none of the new xwidget event and all of these new functions
documented in the Lisp reference manual?

I did not look at the NS code very closely, but I also can't see where
anything is deallocated there.  If you wrote that code assuming
Objective-C automatic reference counting is used in Emacs, it will have
to be rewritten to use manual memory management, as Objective-C features
not supported by GCC are not allowed in Emacs.




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

* Re: [PATCH] Add user content APIs for WebKit Xwidgets
  2022-10-15 11:23             ` Po Lu
@ 2022-10-15 18:29               ` Qiantan Hong
  2022-10-16  0:26                 ` Po Lu
  2022-10-15 23:33               ` Qiantan Hong
  1 sibling, 1 reply; 41+ messages in thread
From: Qiantan Hong @ 2022-10-15 18:29 UTC (permalink / raw)
  To: Po Lu; +Cc: Lars Ingebrigtsen, emacs-devel@gnu.org

Thanks for the detailed comments! A few questions:

>> +void
>> +store_xwidget_script_message_event (struct xwidget *xw,
>> +                                         const char *name,
>> +                                         Lisp_Object body)
>> +{
>> +  struct input_event event;
>> +  Lisp_Object xwl;
>> +  XSETXWIDGET (xwl, xw);
>> +  EVENT_INIT (event);
>> +  event.kind = XWIDGET_EVENT;
>> +  event.frame_or_window = Qnil;
>> +  event.arg = list4 (intern ("script-message"), xwl, intern (name), body);
>> +  kbd_buffer_store_event (&event);
>> +}
> 
> Calling intern with a static string is bad style.  Please write this as
> a DEFSYM instead, in syms_of_xwidget:
> 
>  DEFSYM (Qscript_message, "script-message");
> 
> and use Qscript_message.

I see similar intern usage for "xwidget-internal”, "download-callback”
and "javascript-callback” in xwidget.c. I was trying to be consistent.
If I’m changing to Qscript_message should those be changed too?

> In addition to that, please make "name" a string; I see no reason for it
> to be a symbol.
name is used as a symbol/identifier in a namespace in JavaScript. 
It is used in the form of “messageHandlers.name”. Therefore I wanted
to map it to something conceptually similar in Lisp, i.e. a Lisp symbol.
That way we get efficient comparison and EQ lookup (useful for identifiers!)
by sacrificing string-manipulating operations (not that often for identifiers!).
For example, I need to lookup a handler in an ALIST for every script-message.
Does that make sense?

Best,
Qiantan



> On Oct 15, 2022, at 4:23 AM, Po Lu <luangruo@yahoo.com> wrote:
> 
> Qiantan Hong <qthong@stanford.edu> writes:
> 
>> Implement WebKit user scripts and script message handlers.
>> * src/xwidget.h (store_xwidget_script_message_event): store script
>>  message event into event queue
>> * src/xwidget.c (store_xwidget_script_message_event, make-xwidget,
>>  webkit_script_message_cb, xwidget-webkit-add-user-script,
>>  xwidget-webkit-remove-all-user-scripts,
>>  xwidget-webkit-register-script-message,
>>  xwidget-webkit-unregister-script-message): Implement user script
>>  and script message handler primitives.
>> * src/nsxwidget.c (nsxwidget_webkit_add_user_script,
>>  nsxwidget_webkit_remove_all_user_scripts,
>>  nsxwidget_webkit_register_script_message,
>>  nsxwidget_webkit_unregister_script_message,
>>  initWithFrame, initialize, userContentController): NS
>>  implementation. Changed naming of a previous used  script message
>>  handler to avoid namespace pollution.
>> * src/nsxwidget.h (nsxwidget_webkit_add_user_script,
>>  nsxwidget_webkit_remove_all_user_scripts,
>>  nsxwidget_webkit_register_script_message,
>>  nsxwidget_webkit_unregister_script_message): NS implementation
>> * lisp/xwidget.el (xwidget-webkit-callback,
>>  xwidget-webkit-push-script-message-handler,
>>  xwidget-webkit-pop-script-message-handler):
>>  let lisp recognize and dispatch script message events
> 
> Thanks; this is not how we write commit messages.  It should be:
> 
> * src/xwidget.h (store_xwidget_script_message_event):
> * src/xwidget.c (store_xwidget_script_message_event):
> (xwidget_script_message_cb):
> (Fxwidget_webkit_add_user_script): Store script message event
> into event queue.
> 
> and so on.  Pay attention to how the name of the C function is written
> for defuns, how continuing lines in each message are not indented, and
> how brackets are placed around functions.
> 
>> Acked-by: Qiantan Hong <qhong@mit.edu>
> 
> Please remove this extraneous line from the comment message.
> 
>> +          ((eq xwidget-event-type 'script-message)
>> +           (let ((name (nth 3 last-input-event))
>> +                 (value (nth 4 last-input-event)))
>> +             (let ((handler-pair (assq name (xwidget-get xwidget 'script-message-handlers))))
>> +               (if handler-pair
>> +                   (funcall (cdr handler-pair) xwidget value)
>> +                 (xwidget-log "unhandled script message:%s" name)))))
> 
> Please place a space between : and " ".
> 
>> +(defun xwidget-webkit-push-script-message-handler (xwidget name handler)
>> +  "Associate HANDLER with script messages under symbol NAME for Webkit XWIDGET.
>> +
>> +HANDLER will be called with two arguments: the Webkit XWIDGET and
>> +the javascript object passed from the script message converted to
>> +a Lisp object."
>> +  (xwidget-webkit-register-script-message (xwidget-webkit-current-session) name)
> 
> 80 columns alert!  That aside, this does not explain what "script
> messages" are.  "Webkit" and "javascript" should also be capitalized
> "WebKit" and "JavaScript" respectively.
> 
>> +(defun xwidget-webkit-pop-script-message-handler (xwidget name)
>> +  "Remove a handler associated with symbol NAME for Webkit XWIDGET.
>> +
>> +Returns the removed handler function, or NIL if such handler is
>> +not found."
>> +  (let* ((old-alist (xwidget-get xwidget 'script-message-handlers))
>> +         (handler-pair (assq name old-alist)))
>> +    (when handler-pair
>> +      (let ((new-alist (delq handler-pair old-alist)))
>> +        (xwidget-put xwidget 'script-message-handlers new-alist)
>> +        (unless (assq name new-alist)
>> +          (xwidget-webkit-unregister-script-message (xwidget-webkit-current-session) name)))
> 
> 80 columns alert!  What I said about documentation above applies here as
> well.
> 
>> +  @try
>> +    {
>> +      [scriptor addScriptMessageHandler:xwWebView name:messageName];
>> +    }
>> +  @catch (NSException *e)
>> +    {
>> +      return Qnil;
>> +    }
> 
> Please remove the unnecessary braces here.
> 
>> diff --git a/src/xwidget.c b/src/xwidget.c
>> index 8bdfab02fd..e4250065b9 100644
>> --- a/src/xwidget.c
>> +++ b/src/xwidget.c
>> @@ -126,6 +126,16 @@ webkit_decide_policy_cb (WebKitWebView *,
>> };
>> 
>> static void find_widget (GtkWidget *t, struct widget_search_data *);
>> +
>> +struct webkit_script_message_cb_data
>> +{
>> +  struct xwidget *xw;
>> +  char name[0];
>> +};
>> +static void webkit_script_message_cb (WebKitUserContentManager *,
>> +                                          WebKitJavascriptResult *,
>> +                                          gpointer);
>> +
> 
> Zero-length arrays are not portable, and it is bad style to store string
> data in arrays that way.  Please allocate a separate string, and free it
> manually in the GDestroyNotify.  In addition, please write a comment
> above each field describing its meaning.
> 
>> +      WebKitUserContentManager *scriptor = webkit_user_content_manager_new ();
>> +      xw->widget_osr = webkit_web_view_new_with_user_content_manager (scriptor);
> 
> scriptor is leaked, as WebKitUserContentManager not GInitiallyUnowned.
> Did you forget a g_object_unref?
> 
>> +void
>> +store_xwidget_script_message_event (struct xwidget *xw,
>> +                                         const char *name,
>> +                                         Lisp_Object body)
>> +{
>> +  struct input_event event;
>> +  Lisp_Object xwl;
>> +  XSETXWIDGET (xwl, xw);
>> +  EVENT_INIT (event);
>> +  event.kind = XWIDGET_EVENT;
>> +  event.frame_or_window = Qnil;
>> +  event.arg = list4 (intern ("script-message"), xwl, intern (name), body);
>> +  kbd_buffer_store_event (&event);
>> +}
> 
> Calling intern with a static string is bad style.  Please write this as
> a DEFSYM instead, in syms_of_xwidget:
> 
>  DEFSYM (Qscript_message, "script-message");
> 
> and use Qscript_message.
> 
>> +static void webkit_script_message_cb (WebKitUserContentManager *scriptor,
>> +                                          WebKitJavascriptResult *js_result,
>> +                                          gpointer data)
>> +{
>> +  JSCValue *value = webkit_javascript_result_get_js_value (js_result);
>> +  struct webkit_script_message_cb_data *arg = data;
>> +
>> +  Lisp_Object lisp_value = webkit_js_to_lisp (value);
>> +  store_xwidget_script_message_event (arg->xw, arg->name, lisp_value);
>> +}
> 
> Please add a newline after "static void".  It is also very ugly to put a
> newline between "arg" and "lisp_value"; I would prefer this be written:
> 
>  JSCValue *value;
>  struct webkit_script_message_cb_data *arg;
>  Lisp_Object lisp_value;
> 
>  value = webkit_javascript...
> 
> In addition, don't you have to call webkit_javascript_result_unref?
> 
>> +
>> #ifdef HAVE_X_WINDOWS
>>   xv->dpy = FRAME_X_DISPLAY (s->f);
>> 
> 
> Please remove this whitespace change.
> 
>> +       doc: /* Add user SCRIPT to the Webkit XWIDGET.
> 
> This should be read "Add the user script SCRIPT to the WebKit XWIDGET.",
> followed by a short summary of what userscripts are, and what the script
> argument should be.
> 
>> +INJECTION-TIME is a symbol which can take one of the following values:
> 
> "WHEN is one of the following values, and specifies when the script is run:"
> 
>> +- start: SCRIPT is injected when document starts loading
>> +- end: SCRIPT is injected when document finishes loading
> 
> "  - `start', which means the script is run upon first loading a document.
>   - `end', which means the script is run after a document loads."
> 
>> +If MAIN_FRAME_ONLY is nil, SCRIPT is injected to all frames.
> 
> "If MAIN-FRAME-ONLY is non-nil, run SCRIPT for all frames."  (Followed
> by a description of what "frames" are.)
> 
>> +Otherwise, SCRIPT is only injected to top frames.
> 
> What are top frames?
> 
>> +  script = ENCODE_SYSTEM(script);
> 
> Are you sure that is the right coding system?  WebKit APIs usually take
> UTF-8 strings.
> 
> In any case, this should be:
> 
>  script = ENCODE_SYSTEM (script);
> 
>> +  int injection_time_start, mfo;
>> +  mfo = !NILP (main_frame_only);
> 
> What is the purpose of those two variables?  In either case, `mfo'
> should be named something else, as that name carries no meaning.
> 
> When chosing variable names, try to avoid truncating words, or worse,
> simply making up acronyms.  Consider the following:
> 
>  Bool window_data_exists;
> 
>  window_data_exists = (XGetWindowProperty ....
> 
> or even
> 
>  Bool data_exists;
> 
>  data_exists = (XGetWindowProperty ....
> 
> and note how much clearer it is compared to:
> 
>  Bool wde;
> 
>  wde = (XGetWindowProperty ...
> 
> or
> 
>  Bool dat_p;
> 
>  dat_p = (XGetWindowProperty ...
> 
>> +  if (EQ (injection_time, Qstart))
>> +    injection_time_start = 1;
>> +  else if (EQ (injection_time, Qend))
>> +    injection_time_start = 0;
>> +
>> +    error ("Unknown Xwidget Webkit user script injection time: %s",
>> +           SDATA (SYMBOL_NAME (injection_time)));
> 
> Since there are only two values, how about replacing `injection-time'
> with a single boolean argument `start', which determines whether to run
> the user script at or after page load?
> 
>> +  int webkit_injected_frames = mfo?
>> +    WEBKIT_USER_CONTENT_INJECT_TOP_FRAME : WEBKIT_USER_CONTENT_INJECT_ALL_FRAMES;
> 
> This is not our coding style.  It should be:
> 
>  (!NILP (main_frame_only)
>   ? WEBKIT_USER_CONTENT_INJECT_TOP_FRAME
>   : WEBKIT_USER_CONTENT_INJECT_ALL_FRAMES)
> 
> further more, the type is not int, it is enum
> WebKitUserContentInjectedFrames.
> 
>> +  int webkit_injection_time = injection_time_start?
>> +    WEBKIT_USER_SCRIPT_INJECT_AT_DOCUMENT_START : WEBKIT_USER_SCRIPT_INJECT_AT_DOCUMENT_END;
> 
> Likewise.  enum WebKitUserScriptInjectionTime.
> 
>> +  WebKitUserScript *userScript = webkit_user_script_new (SSDATA (script),
>> +                                                         webkit_injected_frames,
>> +                                                         webkit_injection_time,
>> +                                                         NULL, NULL);
> 
> 80 columns alert!  Please name the variable "user_script" instead; this
> piece of code should probably be written as follows:
> 
>  WebKitUserScript *user_script
>    = webkit_user_script_new (SSDATA (script),
> 			      webkit_injected_frames,
> 			      webkit_injection_time,
> 			      NULL, NULL);
> 
>> +DEFUN ("xwidget-webkit-register-script-message",
>> +       Fxwidget_webkit_register_script_message, Sxwidget_webkit_register_script_message,
>> +       2, 2, 0,
>> +       doc: /* Register script message with symbol NAME in Webkit
>> XWIDGET.
> 
> What was said about capitalization above also applies here.  Please fill
> everything to 80 columns as well.
> 
>> +Returns T if the operation is successful, NIL otherwise.
> 
> Emacs Lisp is not Common Lisp, and does not capitalize symbol names by
> default.
> 
>> +The cause of failure is usually that NAME has already been registered for XWIDGET.  */)
> 
> This belongs in the Lisp reference manual, and is likely redundant in
> any case.  Also, the function should signal an error if NAME has already
> been used, instead of simply returning nil.
> 
>> +  const char *sname = SSDATA( SYMBOL_NAME (name));
> 
> This is a pointer to string data.  It is not safe to assume GC does not
> happen and relocate it below, due to the multitude of GLib callbacks
> installed that can call GC.  Consider using xlispstrdup instead.
> 
> In addition to that, please make "name" a string; I see no reason for it
> to be a symbol.
> 
>> +#ifdef USE_GTK
>> +  WebKitWebView *wkwv = WEBKIT_WEB_VIEW (xw->widget_osr);
> 
> Please name this variable view, not "wkwv", for the reasons explained
> above.
> 
>> +  gchar *signal_name = g_strconcat ("script-message-received::", sname, NULL);
> 
> Please consider using alloca or SAFE_ALLOCA to allocate this buffer, and
> then using strncpy or lispstpcpy to copy the data over.
> 
> SAFE_ALLOCA is used like this, when there are no conflicting specbinds:
> 
> void
> function_using_safe_alloca (void)
> {
>  char *mybuffer;
> 
>  USE_SAFE_ALLOCA;
>  mybuffer = SAFE_ALLOCA (size_of_buffer);
> 
>  /* Do stuff with mybuffer... Finally: */
> 
>  SAFE_FREE ();
> }
> 
>> +  struct webkit_script_message_cb_data *arg = malloc (sizeof *arg + name_length);
>> +  arg->xw = xw;
>> +  g_strlcpy (arg->name, sname, name_length);
> 
> Recall what I said about zero-length or variable length arrays being bad
> style here.  Please allocate arg->name separately, probably with
> lispstpcpy...
> 
>> +  g_signal_connect_data(scriptor, signal_name, G_CALLBACK (webkit_script_message_cb),
>> +                        arg, (GClosureNotify)free, 0);
>                                                ^^^^
> 
> and free it in the destroy_data callback.  In addition, please put a
> space between the cast and the type, and use G_CONNECT_DEFAULT as
> opposed to 0.
> 
> In addition, xw is a Lisp object.  It should be marked for garbage
> collection as long as the signal handler is attached, as making
> assumptions about when signals are run is not safe.
> 
>> +  if (webkit_user_content_manager_register_script_message_handler (scriptor, sname))
>> +    {
>> +      return Qt;
>> +    }
>> +  else
>> +    {
>> +      g_signal_handlers_disconnect_matched  (scriptor,
>                                             ^
> 
> Extra whitespace.  Please also remove the redundant braces above.
> 
>> +  WebKitWebView *wkwv = WEBKIT_WEB_VIEW (xw->widget_osr);
> 
> "WebKitWebView *view = WEBKIT_WEB_VIEW (..."
> 
>> +  WebKitUserContentManager *scriptor = webkit_web_view_get_user_content_manager (wkwv);
> 
> How about naming all the "scriptor" variables "content_manager", or
> "manager" instead?  Also, please fill this function to 80 columns as
> well.
> 
>> +  g_signal_handlers_disconnect_matched  (scriptor,
>> +                                         G_SIGNAL_MATCH_FUNC | G_SIGNAL_MATCH_DETAIL,
>> +                                         0, g_quark_from_string (sname), 0,
>> +                                         G_CALLBACK (webkit_script_message_cb), 0);
> 
> There is extra whitespace here.  
> 
>> +
>> 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)
>> @@ -3919,6 +4092,14 @@ syms_of_xwidget (void)
>>   defsubr (&Sxwidget_webkit_execute_script);
>>   DEFSYM (Qwebkit, "webkit");
>> 
>> +  defsubr (&Sxwidget_webkit_add_user_script);
>> +  DEFSYM (Qstart, "start");
>> +  DEFSYM (Qend, "end");
>> +  defsubr (&Sxwidget_webkit_remove_all_user_scripts);
>> +
>> +  defsubr (&Sxwidget_webkit_register_script_message);
>> +  defsubr (&Sxwidget_webkit_unregister_script_message);
>> +
>>   defsubr (&Sxwidget_size_request);
>>   defsubr (&Sdelete_xwidget_view);
> 
> Why are none of the new xwidget event and all of these new functions
> documented in the Lisp reference manual?
> 
> I did not look at the NS code very closely, but I also can't see where
> anything is deallocated there.  If you wrote that code assuming
> Objective-C automatic reference counting is used in Emacs, it will have
> to be rewritten to use manual memory management, as Objective-C features
> not supported by GCC are not allowed in Emacs.
> 


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

* Re: [PATCH] Add user content APIs for WebKit Xwidgets
  2022-10-15 11:23             ` Po Lu
  2022-10-15 18:29               ` Qiantan Hong
@ 2022-10-15 23:33               ` Qiantan Hong
  2022-10-16  4:32                 ` Po Lu
  1 sibling, 1 reply; 41+ messages in thread
From: Qiantan Hong @ 2022-10-15 23:33 UTC (permalink / raw)
  To: Po Lu; +Cc: Lars Ingebrigtsen, emacs-devel@gnu.org

More questions:

> 
>> + WebKitWebView *wkwv = WEBKIT_WEB_VIEW (xw->widget_osr);
> 
> "WebKitWebView *view = WEBKIT_WEB_VIEW (…"

Some existing code in xwidget.c use this naming as well.
Should I make a separate patch to fix those?
Should I also include the fix to some capitalization error
and the runtime symbol usage in that same patch?

> In addition, xw is a Lisp object. It should be marked for garbage
> collection as long as the signal handler is attached, as making
> assumptions about when signals are run is not safe.
How do I mark it?

> I did not look at the NS code very closely, but I also can't see where
> anything is deallocated there. If you wrote that code assuming
> Objective-C automatic reference counting is used in Emacs, it will have
> to be rewritten to use manual memory management, as Objective-C features
> not supported by GCC are not allowed in Emacs.
I’m imitating the usage pattern of what is already in nsxwidget.m.
I think if I’m leaking memory then the current code must also have been
(which could be the case)...

Best,
Qiantan

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

* Re: [PATCH] Add user content APIs for WebKit Xwidgets
  2022-10-15 18:29               ` Qiantan Hong
@ 2022-10-16  0:26                 ` Po Lu
  0 siblings, 0 replies; 41+ messages in thread
From: Po Lu @ 2022-10-16  0:26 UTC (permalink / raw)
  To: Qiantan Hong; +Cc: Lars Ingebrigtsen, emacs-devel@gnu.org

Qiantan Hong <qthong@stanford.edu> writes:

> I see similar intern usage for "xwidget-internal”, "download-callback”
> and "javascript-callback” in xwidget.c. I was trying to be consistent.
> If I’m changing to Qscript_message should those be changed too?

Sure.

> name is used as a symbol/identifier in a namespace in JavaScript. 
> It is used in the form of “messageHandlers.name”. Therefore I wanted
> to map it to something conceptually similar in Lisp, i.e. a Lisp symbol.
> That way we get efficient comparison and EQ lookup (useful for identifiers!)
> by sacrificing string-manipulating operations (not that often for identifiers!).
> For example, I need to lookup a handler in an ALIST for every script-message.
> Does that make sense?

assoc is fast unless you have lots of handlers, in which case I'd be
more worried about using an alist.

Anyway, you proceed to copy the symbol name into a string and intern it
later.  That is not correct, since the symbol given may be uninterned.



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

* Re: [PATCH] Add user content APIs for WebKit Xwidgets
  2022-10-15 23:33               ` Qiantan Hong
@ 2022-10-16  4:32                 ` Po Lu
  2022-10-16  6:29                   ` Qiantan Hong
  0 siblings, 1 reply; 41+ messages in thread
From: Po Lu @ 2022-10-16  4:32 UTC (permalink / raw)
  To: Qiantan Hong; +Cc: Lars Ingebrigtsen, emacs-devel@gnu.org

Qiantan Hong <qthong@stanford.edu> writes:

> Some existing code in xwidget.c use this naming as well.
> Should I make a separate patch to fix those?

No, I'd rather avoid extraneous style changes to existing contents of
the file.  At the very least it makes vc-annotate a pain.

> Should I also include the fix to some capitalization error
> and the runtime symbol usage in that same patch?

BTW, there are many other problems with your patch, aside from
capitalization and interning symbols with a static string.  Please read
through the entirety of my reply.

> How do I mark it?

I suggest linking each callback data struct into a list, each element of
which is then marked in a "mark_xwidget" function that should be called
by garbage_collect in alloc.c.

> I’m imitating the usage pattern of what is already in nsxwidget.m.
> I think if I’m leaking memory then the current code must also have been
> (which could be the case)...

I guess that should be fixed.

Thanks.



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

* Re: [PATCH] Add user content APIs for WebKit Xwidgets
  2022-10-16  4:32                 ` Po Lu
@ 2022-10-16  6:29                   ` Qiantan Hong
  2022-10-16  6:41                     ` Po Lu
  0 siblings, 1 reply; 41+ messages in thread
From: Qiantan Hong @ 2022-10-16  6:29 UTC (permalink / raw)
  To: Po Lu; +Cc: Lars Ingebrigtsen, emacs-devel@gnu.org

> BTW, there are many other problems with your patch, aside from
> capitalization and interning symbols with a static string.  Please read
> through the entirety of my reply.
Yes I’m aware. I was fixing them one by one.

>> How do I mark it?
> 
> I suggest linking each callback data struct into a list, each element of
> which is then marked in a "mark_xwidget" function that should be called
> by garbage_collect in alloc.c.
It seems that existing code is connecting signal without adding the marking
code, guess that should be fixed too...

> 
>> I’m imitating the usage pattern of what is already in nsxwidget.m.
>> I think if I’m leaking memory then the current code must also have been
>> (which could be the case)...
> 
> I guess that should be fixed.

Those two problems above, I don’t have any existing code to imitate, so it
would take a while to learn the codebase for me to be able to fix them.
I’m also not sure if I should just make my part conforming or also fix all existing code.
Is it acceptable that I submit a patch (with other problems fixed) first,
and work on fixing these two classes of problems later?

Best,
Qiantan




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

* Re: [PATCH] Add user content APIs for WebKit Xwidgets
  2022-10-16  6:29                   ` Qiantan Hong
@ 2022-10-16  6:41                     ` Po Lu
  2022-10-16  6:45                       ` Po Lu
  2022-10-23  9:11                       ` Qiantan Hong
  0 siblings, 2 replies; 41+ messages in thread
From: Po Lu @ 2022-10-16  6:41 UTC (permalink / raw)
  To: Qiantan Hong; +Cc: Lars Ingebrigtsen, emacs-devel@gnu.org

Qiantan Hong <qthong@stanford.edu> writes:

> Yes I’m aware. I was fixing them one by one.

Thanks.

> It seems that existing code is connecting signal without adding the marking
> code, guess that should be fixed too...

Where?  Existing code should not connect signals to anything other than
`widget_osr' which is destroyed upon the xwidget being killed, a
prerequisite for being marked by GC.

> Those two problems above, I don’t have any existing code to imitate, so it
> would take a while to learn the codebase for me to be able to fix them.
> I’m also not sure if I should just make my part conforming or also fix all existing code.
> Is it acceptable that I submit a patch (with other problems fixed) first,
> and work on fixing these two classes of problems later?

I'd rather not install code with known memory management issues,
especially not this close to the Emacs 29 release.



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

* Re: [PATCH] Add user content APIs for WebKit Xwidgets
  2022-10-16  6:41                     ` Po Lu
@ 2022-10-16  6:45                       ` Po Lu
  2022-10-23  9:11                       ` Qiantan Hong
  1 sibling, 0 replies; 41+ messages in thread
From: Po Lu @ 2022-10-16  6:45 UTC (permalink / raw)
  To: Qiantan Hong; +Cc: Lars Ingebrigtsen, emacs-devel@gnu.org

Po Lu <luangruo@yahoo.com> writes:

> Where?  Existing code should not connect signals to anything other than
> `widget_osr' which is destroyed upon the xwidget being killed, a
> prerequisite for being marked by GC.
                         ^^^^^^

That should've been "destroyed", sorry.



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

* Re: [PATCH] Add user extension APIs for WebKit Xwidgets
  2022-10-15  7:53           ` Qiantan Hong
  2022-10-15 11:23             ` Po Lu
@ 2022-10-16 20:51             ` Richard Stallman
  2022-10-16 21:13               ` Alan Mackenzie
  2022-10-17  5:31               ` Eli Zaretskii
  1 sibling, 2 replies; 41+ messages in thread
From: Richard Stallman @ 2022-10-16 20:51 UTC (permalink / raw)
  To: Qiantan Hong; +Cc: luangruo, larsi, emacs-devel

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

While we're installing this, please remove the word "content"
from everything except the external interface symbol names where
its use is unavoidable.  Let's not get sucked into spreading the idea
that everything people publish or communicate is merely stuff to
fill a box.

See https://gnu.org/philosophy/words-to-avoid.html#Content.

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





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

* Re: [PATCH] Add user extension APIs for WebKit Xwidgets
  2022-10-16 20:51             ` [PATCH] Add user extension " Richard Stallman
@ 2022-10-16 21:13               ` Alan Mackenzie
  2022-10-18 11:58                 ` Richard Stallman
  2022-10-17  5:31               ` Eli Zaretskii
  1 sibling, 1 reply; 41+ messages in thread
From: Alan Mackenzie @ 2022-10-16 21:13 UTC (permalink / raw)
  To: Richard Stallman; +Cc: Qiantan Hong, luangruo, larsi, emacs-devel

Hello, Richard.

On Sun, Oct 16, 2022 at 16:51:34 -0400, Richard Stallman wrote:
> [[[ To any NSA and FBI agents reading my email: please consider    ]]]
> [[[ whether defending the US Constitution against all enemies,     ]]]
> [[[ foreign or domestic, requires you to follow Snowden's example. ]]]

> While we're installing this, please remove the word "content"
> from everything except the external interface symbol names where
> its use is unavoidable.  Let's not get sucked into spreading the idea
> that everything people publish or communicate is merely stuff to
> fill a box.

Now is the autumn of our discontent.  :-)

> See https://gnu.org/philosophy/words-to-avoid.html#Content.

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

-- 
Alan Mackenzie (Nuremberg, Germany).



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

* Re: [PATCH] Add user extension APIs for WebKit Xwidgets
  2022-10-16 20:51             ` [PATCH] Add user extension " Richard Stallman
  2022-10-16 21:13               ` Alan Mackenzie
@ 2022-10-17  5:31               ` Eli Zaretskii
  2022-10-17  8:28                 ` Jean Louis
  2022-10-20 19:46                 ` Richard Stallman
  1 sibling, 2 replies; 41+ messages in thread
From: Eli Zaretskii @ 2022-10-17  5:31 UTC (permalink / raw)
  To: rms; +Cc: emacs-devel

> From: Richard Stallman <rms@gnu.org>
> Cc: luangruo@yahoo.com, larsi@gnus.org, emacs-devel@gnu.org
> Date: Sun, 16 Oct 2022 16:51:34 -0400
> 
> See https://gnu.org/philosophy/words-to-avoid.html#Content.

That section fails to suggest good replacements for this term,
AFAICT.  Which makes that part of the article less useful than it
could be, perhaps.

And, of course, we frequently say stuff like "file's contents" or
"buffer contents", which is perfectly OK, IMO.  This usage is not
mentioned in that article, so someone, especially non-native speakers,
could think such uses are part of the problem -- perhaps another minor
issue that should be mentioned there, but isn't.



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

* Re: [PATCH] Add user extension APIs for WebKit Xwidgets
  2022-10-17  5:31               ` Eli Zaretskii
@ 2022-10-17  8:28                 ` Jean Louis
  2022-10-19 17:04                   ` Richard Stallman
  2022-10-20 19:46                 ` Richard Stallman
  1 sibling, 1 reply; 41+ messages in thread
From: Jean Louis @ 2022-10-17  8:28 UTC (permalink / raw)
  To: Eli Zaretskii; +Cc: rms, emacs-devel

* Eli Zaretskii <eliz@gnu.org> [2022-10-17 08:33]:
> > From: Richard Stallman <rms@gnu.org>
> > Cc: luangruo@yahoo.com, larsi@gnus.org, emacs-devel@gnu.org
> > Date: Sun, 16 Oct 2022 16:51:34 -0400
> > 
> > See https://gnu.org/philosophy/words-to-avoid.html#Content.
> 
> That section fails to suggest good replacements for this term,
> AFAICT.  Which makes that part of the article less useful than it
> could be, perhaps.
> 
> And, of course, we frequently say stuff like "file's contents" or
> "buffer contents", which is perfectly OK, IMO.  This usage is not
> mentioned in that article, so someone, especially non-native speakers,
> could think such uses are part of the problem -- perhaps another minor
> issue that should be mentioned there, but isn't.

The description on
https://gnu.org/philosophy/words-to-avoid.html#Content speaks of works
and publications, thus it does not relate to file contents or buffer
contents which is something else but work or publication. Just the
Emacs Info manual has many mentionings of "contents", in their correct
context -- which is correct, as those are smaller pieces of
information or data not referring to works or publications as whole.


English Wordnet dictionary:

* Overview of noun content

The noun content has 7 senses (first 6 from tagged texts)
1. (12) content -- (everything that is included in a collection and that is held or included in something; "he emptied the contents of his pockets"; "the two groups were similar in content")
2. (8) message, content, subject matter, substance -- (what a communication that is about something is about)
3. (3) content -- (the proportion of a substance that is contained in a mixture or alloy etc.)
4. (2) capacity, content -- (the amount that can be contained; "the gas tank has a capacity of 12 gallons")
5. (2) content, cognitive content, mental object -- (the sum or range of what has been perceived, discovered, or learned)
6. (1) contentedness, content -- (the state of being contented with your situation in life; "he relaxed in sleepy contentedness"; "they could read to their heart's content")
7. subject, content, depicted object -- (something (a person or object or scene) selected by an artist or photographer for graphic representation; "a moving picture of a train is more dramatic than a still picture of the same subject")



--
Jean

Take action in Free Software Foundation campaigns:
https://www.fsf.org/campaigns

In support of Richard M. Stallman
https://stallmansupport.org/



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

* Re: [PATCH] Add user extension APIs for WebKit Xwidgets
  2022-10-16 21:13               ` Alan Mackenzie
@ 2022-10-18 11:58                 ` Richard Stallman
  0 siblings, 0 replies; 41+ messages in thread
From: Richard Stallman @ 2022-10-18 11:58 UTC (permalink / raw)
  To: Alan Mackenzie; +Cc: qthong, luangruo, larsi, emacs-devel

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

  > Now is the autumn of our discontent.  :-)

You know I'm a malcontent provider ;-}.
That's the root of the Free Software Movement.
-- 
Dr Richard Stallman (https://stallman.org)
Chief GNUisance of the GNU Project (https://gnu.org)
Founder, Free Software Foundation (https://fsf.org)
Internet Hall-of-Famer (https://internethalloffame.org)





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

* Re: [PATCH] Add user extension APIs for WebKit Xwidgets
  2022-10-17  8:28                 ` Jean Louis
@ 2022-10-19 17:04                   ` Richard Stallman
  2022-10-19 19:06                     ` Eli Zaretskii
  0 siblings, 1 reply; 41+ messages in thread
From: Richard Stallman @ 2022-10-19 17:04 UTC (permalink / raw)
  To: Jean Louis; +Cc: eliz, emacs-devel

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

  > The description on
  > https://gnu.org/philosophy/words-to-avoid.html#Content speaks of works
  > and publications, thus it does not relate to file contents or buffer
  > contents which is something else but work or publication.

That's correct.  Indeed, these are two different usages: one is
"content" and the other is "contents".  "Contents" is used in regard
to one specific work, and there is no problem with that usage.

"Content" is an abstraction use to generalkize and equate _all_
publications and communications, of whatever kind of medium.
The range of generalization is what makes it a problem.

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





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

* Re: [PATCH] Add user extension APIs for WebKit Xwidgets
  2022-10-19 17:04                   ` Richard Stallman
@ 2022-10-19 19:06                     ` Eli Zaretskii
  0 siblings, 0 replies; 41+ messages in thread
From: Eli Zaretskii @ 2022-10-19 19:06 UTC (permalink / raw)
  To: rms; +Cc: bugs, emacs-devel

> From: Richard Stallman <rms@gnu.org>
> Cc: eliz@gnu.org, emacs-devel@gnu.org
> Date: Wed, 19 Oct 2022 13:04:21 -0400
> 
>   > The description on
>   > https://gnu.org/philosophy/words-to-avoid.html#Content speaks of works
>   > and publications, thus it does not relate to file contents or buffer
>   > contents which is something else but work or publication.
> 
> That's correct.  Indeed, these are two different usages: one is
> "content" and the other is "contents".  "Contents" is used in regard
> to one specific work, and there is no problem with that usage.
> 
> "Content" is an abstraction use to generalkize and equate _all_
> publications and communications, of whatever kind of medium.
> The range of generalization is what makes it a problem.

IME, non-native English speakers frequently don't distinguish between
"content" and "contents", and use the former when they mean the
latter.  That's why I made my comment, and that's why I also think the
article should take that into account, so it avoids one possible
confusion.



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

* Re: [PATCH] Add user extension APIs for WebKit Xwidgets
  2022-10-17  5:31               ` Eli Zaretskii
  2022-10-17  8:28                 ` Jean Louis
@ 2022-10-20 19:46                 ` Richard Stallman
  2022-10-21  5:51                   ` Eli Zaretskii
  1 sibling, 1 reply; 41+ messages in thread
From: Richard Stallman @ 2022-10-20 19:46 UTC (permalink / raw)
  To: Eli Zaretskii; +Cc: emacs-devel

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

  > That section fails to suggest good replacements for this term,
  > AFAICT.

It suggests "works" and "publications."

I will add "messages", because in some context that is the category
of things that people are referring to.

  > And, of course, we frequently say stuff like "file's contents" or
  > "buffer contents", which is perfectly OK, IMO.  This usage is not
  > mentioned in that article, so someone, especially non-native speakers,
  > could think such uses are part of the problem -- perhaps another minor
  > issue that should be mentioned there, but isn't.

I will add text about that in
https://gnu.org/philosophy/words-to-avoid.html.  Thanks.

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





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

* Re: [PATCH] Add user extension APIs for WebKit Xwidgets
  2022-10-20 19:46                 ` Richard Stallman
@ 2022-10-21  5:51                   ` Eli Zaretskii
  2022-10-21  6:02                     ` Po Lu
  2022-10-23 19:14                     ` Richard Stallman
  0 siblings, 2 replies; 41+ messages in thread
From: Eli Zaretskii @ 2022-10-21  5:51 UTC (permalink / raw)
  To: rms; +Cc: emacs-devel

> From: Richard Stallman <rms@gnu.org>
> Cc: emacs-devel@gnu.org
> Date: Thu, 20 Oct 2022 15:46:30 -0400
> 
>   > That section fails to suggest good replacements for this term,
>   > AFAICT.
> 
> It suggests "works" and "publications."
> 
> I will add "messages", because in some context that is the category
> of things that people are referring to.

Thanks.  But I think this doesn't cover well the electronic media:
audio, video, and images.



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

* Re: [PATCH] Add user extension APIs for WebKit Xwidgets
  2022-10-21  5:51                   ` Eli Zaretskii
@ 2022-10-21  6:02                     ` Po Lu
  2022-10-23 19:14                     ` Richard Stallman
  1 sibling, 0 replies; 41+ messages in thread
From: Po Lu @ 2022-10-21  6:02 UTC (permalink / raw)
  To: Eli Zaretskii; +Cc: rms, emacs-devel

Eli Zaretskii <eliz@gnu.org> writes:

> Thanks.  But I think this doesn't cover well the electronic media:
> audio, video, and images.

Here, "content" refers to the contents of the web view widget.  That is,
the contents of the relevant system and graphics memory.

I fail to see how the "content" in "content manager" has any kind of
semantic implication about when not to use the word "content".



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

* Re: [PATCH] Add user content APIs for WebKit Xwidgets
  2022-10-16  6:41                     ` Po Lu
  2022-10-16  6:45                       ` Po Lu
@ 2022-10-23  9:11                       ` Qiantan Hong
  2022-10-23 10:58                         ` Po Lu
  1 sibling, 1 reply; 41+ messages in thread
From: Qiantan Hong @ 2022-10-23  9:11 UTC (permalink / raw)
  To: Po Lu, Andrew De Angelis; +Cc: emacs-devel@gnu.org


[-- Attachment #1.1: Type: text/plain, Size: 1543 bytes --]

Hi Po,

I tried to fix these problems, and I've attached my updated patch.

Some remaining questions/issues:

1. I think that connecting signal to scriptor (now called manager)
doesn't require xw to be marked, because it is also destroyed when xw
is killed? Suppose that now I reference count correctly, manager
should be owned by xw, just like the WebKitWebContext at line 363.
2. I didn't fix the ARC assumption in NS port. I hope it can be fixed
in one batch by Andrew. Thank you Andrew!

Best,
Qiantan


> On Oct 15, 2022, at 11:41 PM, Po Lu <luangruo@yahoo.com> wrote:
>
> Qiantan Hong <qthong@stanford.edu> writes:
>
>> Yes I’m aware. I was fixing them one by one.
>
> Thanks.
>
>> It seems that existing code is connecting signal without adding the marking
>> code, guess that should be fixed too...
>
> Where?  Existing code should not connect signals to anything other than
> `widget_osr' which is destroyed upon the xwidget being killed, a
> prerequisite for being marked by GC.
>
>> Those two problems above, I don’t have any existing code to imitate, so it
>> would take a while to learn the codebase for me to be able to fix them.
>> I’m also not sure if I should just make my part conforming or also fix all existing code.
>> Is it acceptable that I submit a patch (with other problems fixed) first,
>> and work on fixing these two classes of problems later?
>
> I'd rather not install code with known memory management issues,
> especially not this close to the Emacs 29 release.


[-- Attachment #1.2: Type: text/html, Size: 2196 bytes --]

[-- Attachment #2: 0001-Implement-WebKit-user-scripts-and-script-message-han.txt --]
[-- Type: text/plain, Size: 20864 bytes --]

From fb375e5e3582a5c9cfe3d11c1036fe9affe1b12f Mon Sep 17 00:00:00 2001
From: Qiantan Hong <qhong@alum.mit.edu>
Date: Sun, 23 Oct 2022 01:55:53 -0700
Subject: [PATCH] Implement WebKit user scripts and script message handlers.

* src/xwidget.h (store_xwidget_script_message_event): store script
message event into event queue
* src/xwidget.c (store_xwidget_script_message_event):
(Fxwidget_webkit_add_user_script):
(Fxwidget_webkit_remove_all_user_scripts): user script primitives
(Fxwidget_webkit_register_script_message):
(Fxwidget_webkit_unregister_script_message): script message handler
primitives.
* src/nsxwidget.c (nsxwidget_webkit_add_user_script):
(nsxwidget_webkit_remove_all_user_scripts):
(nsxwidget_webkit_register_script_message):
(nsxwidget_webkit_unregister_script_message): NS implementation of
user script and script message handler. Changed naming of a previous
used script message handler to avoid namespace pollution.
* src/nsxwidget.h (nsxwidget_webkit_add_user_script):
(nsxwidget_webkit_remove_all_user_scripts):
(nsxwidget_webkit_register_script_message):
(nsxwidget_webkit_unregister_script_message):
* lisp/xwidget.el (xwidget-webkit-callback):
(xwidget-webkit-push-script-message-handler):
(xwidget-webkit-pop-script-message-handler): let lisp recognize and
dispatch script message events
* doc/lispref/display.texi: document user script and script message
handler
---
 doc/lispref/display.texi |  52 +++++++++++
 lisp/xwidget.el          |  36 +++++++-
 src/nsxwidget.h          |   5 +
 src/nsxwidget.m          |  80 ++++++++++++++--
 src/xwidget.c            | 192 +++++++++++++++++++++++++++++++++++++++
 src/xwidget.h            |   4 +
 6 files changed, 361 insertions(+), 8 deletions(-)

diff --git a/doc/lispref/display.texi b/doc/lispref/display.texi
index 15cd5518d9..48b38ff837 100644
--- a/doc/lispref/display.texi
+++ b/doc/lispref/display.texi
@@ -7279,6 +7279,58 @@ Xwidgets
 @var{default} was omitted.
 @end defun
 
+@defun xwidget-webkit-add-user-script xwidget script when main-frame-only
+This function adds the specified user script @code{script} to the
+browser widget specified by @var{xwidget}.
+
+User scripts are custom JavaScript code that is automatically run in
+the pages of the browser widget.  The @var{when} argument specifies
+when @var{script} is run, it can be one of the following:
+
+@table @code
+@item start
+@var{script} is run upon first loading a document.
+@item end
+@var{script} is run after a document loads.
+@end table
+
+The @var{main-frame-only} argument specifies which HTML frames run
+@var{script}.  If @var{main-frame-only} is @code{nil}, @var{script} is
+run in all HTML frames.  Otherwise, @var{script} is only run in
+top-level HTML frames.
+@end defun
+
+@defun xwidget-webkit-remove-all-user-scripts xwidget
+This functions removes all user scripts from the browser widget
+specified by @var{xwidget}.
+@end defun
+
+@defun xwidget-webkit-push-script-message-handler xwidget name handler
+This function registers @var{handler} to handle script messages with
+namespace specified by string @var{name} for the browser widget
+specified by @var{xwidget}.
+
+Script message enables JavaScript code run in browser widgets to pass
+data to Emacs.  After @var{handler} is registered with @var{name},
+running the following JavaScript code
+
+@example
+window.webkit.messageHandlers.@var{name}.postMessage(@var{JSObject});
+@end example
+
+@noindent causes @var{handler} to be called with two arguments: @var{xwidget}
+and @var{JSObject} converted to a Lisp object.
+@end defun
+
+@defun xwidget-webkit-pop-script-message-handler
+This functions removes a handler registered with namespace specified
+by string @var{name} for the browser widget specified by
+@var{xwidget}.
+
+The returned value is the removed handler function, or @code{nil} if
+no such handler is found.
+@end defun
+
 @defun xwidget-webkit-get-title xwidget
 This function returns the title of @var{xwidget} as a string.
 @end defun
diff --git a/lisp/xwidget.el b/lisp/xwidget.el
index 41a1190c64..418a9f3acc 100644
--- a/lisp/xwidget.el
+++ b/lisp/xwidget.el
@@ -485,7 +485,41 @@ xwidget-webkit-callback
            (let ((proc (nth 3 last-input-event))
                  (arg  (nth 4 last-input-event)))
              (funcall proc arg)))
-          (t (xwidget-log "unhandled event:%s" xwidget-event-type)))))
+          ((eq xwidget-event-type 'script-message)
+           (let ((name (nth 3 last-input-event))
+                 (value (nth 4 last-input-event)))
+             (let ((handler-pair (assoc name (xwidget-get xwidget 'script-message-handlers))))
+               (if handler-pair
+                   (funcall (cdr handler-pair) xwidget value)
+                 (xwidget-log "unhandled script message: %s" name)))))
+          (t (xwidget-log "unhandled event: %s" xwidget-event-type)))))
+
+(defun xwidget-webkit-push-script-message-handler (xwidget name handler)
+  "Register HANDLER to handle script messages with NAME for WebKit XWIDGET.
+
+HANDLER will be called with two arguments: the WebKit XWIDGET and
+the JavaScript object passed from the script message converted to
+a Lisp object."
+  (let ((old-alist (xwidget-get xwidget 'script-message-handlers)))
+    (unless (assoc name old-alist)
+      (xwidget-webkit-register-script-message (xwidget-webkit-current-session) name))
+    (xwidget-put xwidget 'script-message-handlers
+                 (cons (cons name handler) old-alist)))
+  name)
+
+(defun xwidget-webkit-pop-script-message-handler (xwidget name)
+  "Remove a handler registered with NAME for WebKit XWIDGET.
+
+Return the removed handler function, or NIL if no such handler is
+found."
+  (let* ((old-alist (xwidget-get xwidget 'script-message-handlers))
+         (handler-pair (assoc name old-alist)))
+    (when handler-pair
+      (let ((new-alist (delq handler-pair old-alist)))
+        (xwidget-put xwidget 'script-message-handlers new-alist)
+        (unless (assoc name new-alist)
+          (xwidget-webkit-unregister-script-message (xwidget-webkit-current-session) name)))
+      (cdr handler-pair))))
 
 (defvar bookmark-make-record-function)
 (when (memq window-system '(mac ns))
diff --git a/src/nsxwidget.h b/src/nsxwidget.h
index 666509744a..cd1dc1bc2c 100644
--- a/src/nsxwidget.h
+++ b/src/nsxwidget.h
@@ -40,6 +40,11 @@ #define NSXWIDGET_H_INCLUDED
 void nsxwidget_webkit_execute_script (struct xwidget *xw, const char *script,
                                       Lisp_Object fun);
 
+void nsxwidget_webkit_add_user_script (struct xwidget *xw, const char *script,
+                                       int injection_time_start, int main_frame_only);
+void nsxwidget_webkit_remove_all_user_scripts (struct xwidget *xw);
+Lisp_Object nsxwidget_webkit_register_script_message (struct xwidget *xw, const char *name);
+void nsxwidget_webkit_unregister_script_message (struct xwidget *xw, const char *name);
 /* Functions for xwidget model.  */
 
 #ifdef __OBJC__
diff --git a/src/nsxwidget.m b/src/nsxwidget.m
index be0eba0bcb..901277f9a3 100644
--- a/src/nsxwidget.m
+++ b/src/nsxwidget.m
@@ -88,7 +88,7 @@ - (id)initWithFrame:(CGRect)frame
         @"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_6)"
         @" AppleWebKit/603.3.8 (KHTML, like Gecko)"
         @" Version/11.0.1 Safari/603.3.8";
-      [scriptor addScriptMessageHandler:self name:@"keyDown"];
+      [scriptor addScriptMessageHandler:self name:@"__xwidget_internal_keyDown"];
       [scriptor addUserScript:[[WKUserScript alloc]
                                 initWithSource:xwScript
                                  injectionTime:
@@ -275,23 +275,34 @@ + (void)initialize
       @"}"
       @"function xwKeyDown(event) {"
       @"  if (event.ctrlKey && event.key == 'g') {"
-      @"    window.webkit.messageHandlers.keyDown.postMessage('C-g');"
+      @"    window.webkit.messageHandlers.__xwidget_internal_keyDown.postMessage('C-g');"
       @"  }"
       @"}"
       @"document.addEventListener('keydown', xwKeyDown);"
       ;
 }
 
+static Lisp_Object js_to_lisp (id value);
+
 /* Confirming to WKScriptMessageHandler, listens concerning keyDown in
    webkit. Currently 'C-g'.  */
 - (void)userContentController:(WKUserContentController *)userContentController
       didReceiveScriptMessage:(WKScriptMessage *)message
 {
-  if ([message.body isEqualToString:@"C-g"])
+  if ([message.name isEqualToString:@"__xwidget_internal_keyDown"])
     {
-      /* Just give up focus, no relay "C-g" to emacs, another "C-g"
-         follows will be handled by emacs.  */
-      [self.window makeFirstResponder:self.xw->xv->emacswindow];
+      if ([message.body isEqualToString:@"C-g"])
+        {
+          /* Just give up focus, no relay "C-g" to emacs, another "C-g"
+             follows will be handled by emacs.  */
+          [self.window makeFirstResponder:self.xw->xv->emacswindow];
+        }
+    }
+  else
+    {
+      store_xwidget_script_message_event (self.xw,
+                                          message.name.UTF8String,
+                                          js_to_lisp (message.body));
     }
 }
 
@@ -437,6 +448,61 @@ - (void)userContentController:(WKUserContentController *)userContentController
     }];
 }
 
+void
+nsxwidget_webkit_add_user_script (struct xwidget *xw, const char *script,
+                                  int injection_time_start, int main_frame_only)
+{
+  XwWebView *xwWebView = (XwWebView *) xw->xwWidget;
+  WKUserContentController *scriptor = xwWebView.configuration.userContentController;
+
+  NSString *javascriptString = [NSString stringWithUTF8String:script];
+  WKUserScriptInjectionTime injectionTime = injection_time_start?
+    WKUserScriptInjectionTimeAtDocumentStart : WKUserScriptInjectionTimeAtDocumentEnd;
+  WKUserScript *userScript = [[WKUserScript alloc]
+                               initWithSource: javascriptString
+                                injectionTime: injectionTime
+                               forMainFrameOnly: main_frame_only];
+  [scriptor addUserScript: userScript];
+}
+
+void
+nsxwidget_webkit_remove_all_user_scripts (struct xwidget *xw)
+{
+  XwWebView *xwWebView = (XwWebView *) xw->xwWidget;
+  WKUserContentController *scriptor = xwWebView.configuration.userContentController;
+
+  [scriptor removeAllUserScripts];
+}
+
+Lisp_Object
+nsxwidget_webkit_register_script_message (struct xwidget *xw, const char *name)
+{
+  XwWebView *xwWebView = (XwWebView *) xw->xwWidget;
+  WKUserContentController *scriptor = xwWebView.configuration.userContentController;
+
+  NSString *messageName = [NSString stringWithUTF8String:name];
+
+  @try
+    {
+      [scriptor addScriptMessageHandler:xwWebView name:messageName];
+    }
+  @catch (NSException *e)
+    {
+      error ("Failed to register WebKit script message handler");
+    }
+  return Qnil;
+}
+
+void
+nsxwidget_webkit_unregister_script_message (struct xwidget *xw, const char *name)
+{
+  XwWebView *xwWebView = (XwWebView *) xw->xwWidget;
+  WKUserContentController *scriptor = xwWebView.configuration.userContentController;
+
+  NSString *messageName = [NSString stringWithUTF8String:name];
+  [scriptor removeScriptMessageHandlerForName:messageName];
+}
+
 /* Window containing an xwidget.  */
 
 @implementation XwWindow
@@ -469,7 +535,7 @@ - (BOOL)isFlipped { return YES; }
       WKUserContentController *scriptor =
         ((XwWebView *) xw->xwWidget).configuration.userContentController;
       [scriptor removeAllUserScripts];
-      [scriptor removeScriptMessageHandlerForName:@"keyDown"];
+      [scriptor removeScriptMessageHandlerForName:@"__xwidget_internal_keyDown"];
       [scriptor release];
       if (xw->xv)
         xw->xv->model = Qnil; /* Make sure related view stale.  */
diff --git a/src/xwidget.c b/src/xwidget.c
index 8bdfab02fd..3cdd95f970 100644
--- a/src/xwidget.c
+++ b/src/xwidget.c
@@ -126,6 +126,11 @@ webkit_decide_policy_cb (WebKitWebView *,
 };
 
 static void find_widget (GtkWidget *t, struct widget_search_data *);
+
+static void webkit_script_message_cb (WebKitUserContentManager *,
+                                          WebKitJavascriptResult *,
+                                          gpointer);
+
 #endif
 
 #ifdef HAVE_PGTK
@@ -380,6 +385,9 @@ DEFUN ("make-xwidget",
 	  settings = webkit_web_view_get_settings (WEBKIT_WEB_VIEW (xw->widget_osr));
 	  g_object_set (G_OBJECT (settings), "enable-developer-extras", TRUE, NULL);
 	}
+      WebKitUserContentManager *manager = webkit_user_content_manager_new ();
+      xw->widget_osr = webkit_web_view_new_with_user_content_manager (manager);
+      g_object_unref (manager);
 
       gtk_widget_set_size_request (GTK_WIDGET (xw->widget_osr), xw->width,
                                    xw->height);
@@ -2308,6 +2316,21 @@ store_xwidget_js_callback_event (struct xwidget *xw,
   kbd_buffer_store_event (&event);
 }
 
+void
+store_xwidget_script_message_event (struct xwidget *xw,
+				    const char *name,
+				    Lisp_Object body)
+{
+  struct input_event event;
+  Lisp_Object xwl;
+  XSETXWIDGET (xwl, xw);
+  EVENT_INIT (event);
+  event.kind = XWIDGET_EVENT;
+  event.frame_or_window = Qnil;
+  event.arg = list4 (Qscript_message, xwl, build_string (name), body);
+  kbd_buffer_store_event (&event);
+}
+
 
 #ifdef USE_GTK
 static void
@@ -2622,6 +2645,21 @@ webkit_decide_policy_cb (WebKitWebView *webView,
   }
 }
 
+static void
+webkit_script_message_cb (WebKitUserContentManager *manager,
+			  WebKitJavascriptResult *js_result,
+			  gpointer data)
+{
+  struct xwidget *xw = g_object_get_data (G_OBJECT (manager),
+					  XG_XWIDGET);
+  JSCValue *value = webkit_javascript_result_get_js_value (js_result);
+  const char *arg = data;
+  Lisp_Object lisp_value = webkit_js_to_lisp (value);
+  store_xwidget_script_message_event (xw, arg, lisp_value);
+
+  webkit_javascript_result_unref (js_result);
+}
+
 static gboolean
 webkit_script_dialog_cb (WebKitWebView *webview,
 			 WebKitScriptDialog *script_dialog,
@@ -3198,6 +3236,151 @@ DEFUN ("xwidget-webkit-execute-script",
   return Qnil;
 }
 
+DEFUN ("xwidget-webkit-add-user-script",
+       Fxwidget_webkit_add_user_script, Sxwidget_webkit_add_user_script,
+       4, 4, 0,
+       doc: /* Add the user script SCRIPT to the WebKit XWIDGET.
+
+WHEN is one of the following values, and specifies when the script is
+run:
+- `start', which means the script is run upon first loading a document.
+- `end', which means the script is run after a document loads.
+
+If MAIN_FRAME_ONLY is nil, SCRIPT is run in all HTML frames.
+Otherwise, SCRIPT is only run in top-level HTML frames.  */)
+  (Lisp_Object xwidget, Lisp_Object script,
+   Lisp_Object when, Lisp_Object main_frame_only)
+{
+  WEBKIT_FN_INIT ();
+  CHECK_STRING (script);
+  CHECK_SYMBOL (when);
+
+  script = ENCODE_UTF_8 (script);
+
+  Bool start;
+  if (EQ (when, Qstart))
+    start = true;
+  else if (EQ (when, Qend))
+    start = false;
+  else
+    error ("Unknown Xwidget Webkit user script injection time: %s",
+           SDATA (SYMBOL_NAME (when)));
+
+#ifdef USE_GTK
+  WebKitWebView *view = WEBKIT_WEB_VIEW (xw->widget_osr);
+  WebKitUserContentManager *manager = webkit_web_view_get_user_content_manager (view);
+
+  WebKitUserContentInjectedFrames webkit_injected_frames
+    = (!NILP (main_frame_only))
+    ? WEBKIT_USER_CONTENT_INJECT_TOP_FRAME
+    : WEBKIT_USER_CONTENT_INJECT_ALL_FRAMES;
+  WebKitUserScriptInjectionTime webkit_injection_time = start
+    ? WEBKIT_USER_SCRIPT_INJECT_AT_DOCUMENT_START
+    : WEBKIT_USER_SCRIPT_INJECT_AT_DOCUMENT_END;
+  WebKitUserScript *user_script
+    = webkit_user_script_new (SSDATA (script),
+			      webkit_injected_frames,
+			      webkit_injection_time,
+			      NULL, NULL);
+  webkit_user_content_manager_add_script (manager, user_script);
+  webkit_user_script_unref (user_script);
+#elif defined NS_IMPL_COCOA
+  nsxwidget_webkit_add_user_script (xw, SSDATA (script), injection_time_start, mfo);
+#endif
+  return Qnil;
+}
+
+DEFUN ("xwidget-webkit-remove-all-user-scripts",
+       Fxwidget_webkit_remove_all_user_scripts, Sxwidget_webkit_remove_all_user_scripts,
+       1, 1, 0,
+       doc: /* Remove all user scripts from WebKit XWIDGET.  */)
+  (Lisp_Object xwidget)
+{
+  WEBKIT_FN_INIT ();
+
+#ifdef USE_GTK
+  WebKitWebView *view = WEBKIT_WEB_VIEW (xw->widget_osr);
+  WebKitUserContentManager *manager = webkit_web_view_get_user_content_manager (view);
+
+  webkit_user_content_manager_remove_all_scripts (manager);
+#elif defined NS_IMPL_COCOA
+  nsxwidget_webkit_remove_all_user_scripts(xw);
+#endif
+  return Qnil;
+}
+
+DEFUN ("xwidget-webkit-register-script-message",
+       Fxwidget_webkit_register_script_message, Sxwidget_webkit_register_script_message,
+       2, 2, 0,
+       doc: /* Register script message with NAME in WebKit XWIDGET.
+
+This operation fails if NAME has already been registered for XWIDGET.  */)
+  (Lisp_Object xwidget, Lisp_Object name)
+{
+  WEBKIT_FN_INIT ();
+  CHECK_STRING (name);
+  char *sname = xlispstrdup (name);
+
+#ifdef USE_GTK
+  WebKitWebView *view = WEBKIT_WEB_VIEW (xw->widget_osr);
+  WebKitUserContentManager *manager = webkit_web_view_get_user_content_manager (view);
+
+  USE_SAFE_ALLOCA;
+  gchar *signal_name = SAFE_ALLOCA (strlen ("script-message-received::") + strlen (sname) + 1);
+  stpcpy (stpcpy (signal_name, "script-message-received::"), sname);
+  g_signal_connect_data (manager, signal_name, G_CALLBACK (webkit_script_message_cb),
+			 sname, (GClosureNotify) xfree, 0);
+  SAFE_FREE ();
+
+  if (webkit_user_content_manager_register_script_message_handler (manager, sname))
+    {
+      g_object_set_data (G_OBJECT (manager), XG_XWIDGET, xw);
+    }
+  else
+    {
+      g_signal_handlers_disconnect_matched (manager,
+					    G_SIGNAL_MATCH_DATA,
+					    0, 0, NULL, NULL, sname);
+      error ("Failed to register WebKit script message handler");
+    }
+#elif defined NS_IMPL_COCOA
+  nsxwidget_webkit_register_script_message (xw, sname);
+  xfree (sname);
+#endif
+  return Qnil;
+}
+
+DEFUN ("xwidget-webkit-unregister-script-message",
+       Fxwidget_webkit_unregister_script_message, Sxwidget_webkit_unregister_script_message,
+       2, 2, 0,
+       doc: /* Unregister script message with NAME in Webkit XWIDGET.  */)
+  (Lisp_Object xwidget, Lisp_Object name)
+{
+  WEBKIT_FN_INIT ();
+  CHECK_STRING (name);
+
+  USE_SAFE_ALLOCA;
+  char *sname;
+  SAFE_ALLOCA_STRING (sname, name);
+
+#ifdef USE_GTK
+  WebKitWebView *view = WEBKIT_WEB_VIEW (xw->widget_osr);
+  WebKitUserContentManager *manager
+    = webkit_web_view_get_user_content_manager (view);
+
+  webkit_user_content_manager_unregister_script_message_handler (manager, sname);
+  g_signal_handlers_disconnect_matched (manager,
+					G_SIGNAL_MATCH_FUNC | G_SIGNAL_MATCH_DETAIL,
+					0, g_quark_from_string (sname), 0,
+					G_CALLBACK (webkit_script_message_cb), 0);
+#elif defined NS_IMPL_COCOA
+  nsxwidget_webkit_unregister_script_message(xw, sname);
+#endif
+
+  SAFE_FREE();
+  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)
@@ -3919,6 +4102,15 @@ syms_of_xwidget (void)
   defsubr (&Sxwidget_webkit_execute_script);
   DEFSYM (Qwebkit, "webkit");
 
+  defsubr (&Sxwidget_webkit_add_user_script);
+  DEFSYM (Qstart, "start");
+  DEFSYM (Qend, "end");
+  defsubr (&Sxwidget_webkit_remove_all_user_scripts);
+
+  DEFSYM (Qscript_message, "script-message");
+  defsubr (&Sxwidget_webkit_register_script_message);
+  defsubr (&Sxwidget_webkit_unregister_script_message);
+
   defsubr (&Sxwidget_size_request);
   defsubr (&Sdelete_xwidget_view);
 
diff --git a/src/xwidget.h b/src/xwidget.h
index 502beb6765..e835f700bc 100644
--- a/src/xwidget.h
+++ b/src/xwidget.h
@@ -203,6 +203,10 @@ #define XG_XWIDGET_VIEW "emacs_xwidget_view"
                                       Lisp_Object proc,
                                       Lisp_Object argument);
 
+void store_xwidget_script_message_event (struct xwidget *xw,
+                                         const char *name,
+                                         Lisp_Object value);
+
 extern struct xwidget *xwidget_from_id (uint32_t id);
 
 #ifdef HAVE_X_WINDOWS
-- 
2.32.1 (Apple Git-133)


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

* Re: [PATCH] Add user content APIs for WebKit Xwidgets
  2022-10-23  9:11                       ` Qiantan Hong
@ 2022-10-23 10:58                         ` Po Lu
  2022-10-23 22:16                           ` Qiantan Hong
  0 siblings, 1 reply; 41+ messages in thread
From: Po Lu @ 2022-10-23 10:58 UTC (permalink / raw)
  To: Qiantan Hong; +Cc: Andrew De Angelis, emacs-devel@gnu.org

Qiantan Hong <qthong@stanford.edu> writes:

> 1. I think that connecting signal to scriptor (now called manager)
> doesn't require xw to be marked, because it is also destroyed when xw
> is killed? Suppose that now I reference count correctly, manager
> should be owned by xw, just like the WebKitWebContext at line 363.

No, because webkit_web_view_new_with_related_view is used to create
WebKitWebView objects when an existing live xwidget is specified as the
related argument to `make-xwidget', and those will hold further
references to the content manager beyond the lifetime of the
WebKitWebView holding the initial reference to said content manager.  In
fact, won't userscripts apply to every WebKitWebView with the same
content manager?

I think I would prefer documenting and implementing userscripts as
applying to all related xwidgets: you could link each related xwidget
onto a circular queue, designate one as the "head", and hold a reference
to the head, replacing it with a different xwidget on the queue each
time the head is killed, until there are no more xwidgets on that queue,
at which point it becomes safe to free the userscript data.

> 2. I didn't fix the ARC assumption in NS port. I hope it can be fixed
> in one batch by Andrew. Thank you Andrew!

Sure, but please fix the redundant braces here:

> +      if ([message.body isEqualToString:@"C-g"])
> +        {
> +          /* Just give up focus, no relay "C-g" to emacs, another "C-g"
> +             follows will be handled by emacs.  */
> +          [self.window makeFirstResponder:self.xw->xv->emacswindow];
> +        }
> +    }
> +  else
> +    {
> +      store_xwidget_script_message_event (self.xw,
> +                                          message.name.UTF8String,
> +                                          js_to_lisp (message.body));
>      }

And some more comments below:

> +User scripts are custom JavaScript code that is automatically run in

This should read "User scripts are custom JavaScript code automatically
run in designated WebKit xwidgets as pages are being loaded".

> +void nsxwidget_webkit_add_user_script (struct xwidget *xw, const char *script,
> +                                       int injection_time_start, int main_frame_only);

I have a feeling the types here are also not supposed to be "int".

> +  WKUserScriptInjectionTime injectionTime = injection_time_start?
> +    WKUserScriptInjectionTimeAtDocumentStart : WKUserScriptInjectionTimeAtDocumentEnd;

Coding style warning: this should probably be

  (injection_time_start
   ? WKUserScriptInjectionTimeAtDocumentStart
   : WKUserScriptInjectionTimeAtDocumentEnd)

> +  Bool start;

Why this X library type, and not `bool'?

> +  if (EQ (when, Qstart))
> +    start = true;
> +  else if (EQ (when, Qend))
> +    start = false;

If you are going to use Bool, then the boolean constants used should be
True and False, but since Bool is only available on X Windows, that is
likely not what you want.

> +  else
> +    error ("Unknown Xwidget Webkit user script injection time: %s",
> +           SDATA (SYMBOL_NAME (when)));

"Xwidget Webkit" is not the correct capitalization.  The error message
should probably also be reworded, as I think I explained earlier.  Also,
since there are only two possible values here, this should be a boolean.

> +    = (!NILP (main_frame_only))
> +    ? WEBKIT_USER_CONTENT_INJECT_TOP_FRAME
> +    : WEBKIT_USER_CONTENT_INJECT_ALL_FRAMES;

This should be:

  = (!NILP (main_frame_only)
     ? WEBKIT_USER_CONTENT_INJECT_TOP_FRAME
     : WEBKIT_USER_CONTENT_INJECT_ALL_FRAMES)

> +  WebKitUserScriptInjectionTime webkit_injection_time = start
> +    ? WEBKIT_USER_SCRIPT_INJECT_AT_DOCUMENT_START
> +    : WEBKIT_USER_SCRIPT_INJECT_AT_DOCUMENT_END;

Likewise.  (!NILP (start)
            ? WEBKIT_USER_SCRIPT_INJECT_AT_DOCUMENT_START
            : WEBKIT_USER_SCRIPT_INJECT_AT_DOCUMENT_END)

> +#elif defined NS_IMPL_COCOA
> +  nsxwidget_webkit_add_user_script (xw, SSDATA (script), injection_time_start, mfo);
> +#endif

80 columns alert; I thought I also explained why not to use variable
names such as "mfo".

> +#elif defined NS_IMPL_COCOA
> +  nsxwidget_webkit_remove_all_user_scripts(xw);
> +#endif

Please put a space between the "ts" and "(".

> +This operation fails if NAME has already been registered for XWIDGET.  */)

Fails?  How?  This should mention that an error is signalled under that
situation.

> +  stpcpy (stpcpy (signal_name, "script-message-received::"), sname);

Maybe lispstpcpy is what you want here.

> +  if (webkit_user_content_manager_register_script_message_handler (manager, sname))
> +    {
> +      g_object_set_data (G_OBJECT (manager), XG_XWIDGET, xw);
> +    }

The braces here are redundant.  Please remove them.

> +DEFUN ("xwidget-webkit-unregister-script-message",
> +       Fxwidget_webkit_unregister_script_message, Sxwidget_webkit_unregister_script_message,
> +       2, 2, 0,
> +       doc: /* Unregister script message with NAME in Webkit XWIDGET.  */)
> +  (Lisp_Object xwidget, Lisp_Object name)

"Unregister the script message named NAME from the given WebKit widget..."

The library we use is capitalized "WebKit", not "Webkit".

> +  nsxwidget_webkit_unregister_script_message(xw, sname);

As I said earlier, there should be a space here.

> +  SAFE_FREE();

And here.

> +  defsubr (&Sxwidget_webkit_add_user_script);
> +  DEFSYM (Qstart, "start");
> +  DEFSYM (Qend, "end");
> +  defsubr (&Sxwidget_webkit_remove_all_user_scripts);
> +
> +  DEFSYM (Qscript_message, "script-message");
> +  defsubr (&Sxwidget_webkit_register_script_message);
> +  defsubr (&Sxwidget_webkit_unregister_script_message);

Why not make it so the DEFSYMS are placed together, away from the
defsubrs?



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

* Re: [PATCH] Add user extension APIs for WebKit Xwidgets
  2022-10-21  5:51                   ` Eli Zaretskii
  2022-10-21  6:02                     ` Po Lu
@ 2022-10-23 19:14                     ` Richard Stallman
  1 sibling, 0 replies; 41+ messages in thread
From: Richard Stallman @ 2022-10-23 19:14 UTC (permalink / raw)
  To: Eli Zaretskii; +Cc: emacs-devel

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

  > Thanks.  But I think this doesn't cover well the electronic media:
  > audio, video, and images.

The words "works" and "publications" include all kinds of media,
includinmg audio and video.  "Works" is a normal term for artists'
paintings and photos, and all sorts of music.

I added a few more suggestions that might fit certain circumstances.
I also explained that "contents" is a fine word to use because
it means something different.  I checked in the changes just now in
https://gnu.org/philosophy/words-to-avoid.html.

  > Here, "content" refers to the contents of the web view widget.  That is,
  > the contents of the relevant system and graphics memory.

This would be a place to use the word "contents".

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





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

* Re: [PATCH] Add user content APIs for WebKit Xwidgets
  2022-10-23 10:58                         ` Po Lu
@ 2022-10-23 22:16                           ` Qiantan Hong
  2022-10-24  0:30                             ` Po Lu
  0 siblings, 1 reply; 41+ messages in thread
From: Qiantan Hong @ 2022-10-23 22:16 UTC (permalink / raw)
  To: Po Lu; +Cc: Andrew De Angelis, emacs-devel@gnu.org

>> 1. I think that connecting signal to scriptor (now called manager)
>> doesn't require xw to be marked, because it is also destroyed when xw
>> is killed? Suppose that now I reference count correctly, manager
>> should be owned by xw, just like the WebKitWebContext at line 363.
> 
> No, because webkit_web_view_new_with_related_view is used to create
> WebKitWebView objects when an existing live xwidget is specified as the
> related argument to `make-xwidget', and those will hold further
> references to the content manager beyond the lifetime of the
> WebKitWebView holding the initial reference to said content manager.  In
> fact, won't userscripts apply to every WebKitWebView with the same
> content manager?
> 
> I think I would prefer documenting and implementing userscripts as
> applying to all related xwidgets: you could link each related xwidget
> onto a circular queue, designate one as the "head", and hold a reference
> to the head, replacing it with a different xwidget on the queue each
> time the head is killed, until there are no more xwidgets on that queue,
> at which point it becomes safe to free the userscript data.

Applying to all related Xwidgets sound like a good idea. I think we should
formalize the "group of related Xwidgets" as some kind of object? Maybe
a record type implemented in Lisp, or a pseudo vector (which I don't know
much about how to implement). An alternative is to expose content manager
as a pseudovector, which will in fact have 1-to-1 correspondence with "related
group", but I like related group more because it feels like a nicer abstraction.

What do you think?

If that is implemented I believe we also don't need extra marking, as the
manager will hold a reference to the related group object, but the related
group object will be collected only all related xwdigets are already killed.

Best,
Qiantan



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

* Re: [PATCH] Add user content APIs for WebKit Xwidgets
  2022-10-23 22:16                           ` Qiantan Hong
@ 2022-10-24  0:30                             ` Po Lu
  2022-10-24  4:17                               ` Qiantan Hong
  0 siblings, 1 reply; 41+ messages in thread
From: Po Lu @ 2022-10-24  0:30 UTC (permalink / raw)
  To: Qiantan Hong; +Cc: Andrew De Angelis, emacs-devel@gnu.org

Qiantan Hong <qthong@stanford.edu> writes:

> Applying to all related Xwidgets sound like a good idea. I think we should
> formalize the "group of related Xwidgets" as some kind of object? Maybe
> a record type implemented in Lisp, or a pseudo vector (which I don't know
> much about how to implement). An alternative is to expose content manager
> as a pseudovector, which will in fact have 1-to-1 correspondence with "related
> group", but I like related group more because it feels like a nicer abstraction.

I don't think that is necessary.  There should at most be a function
that returns a list of all related xwidgets.

Pseudovector types are a limited resource.  There can only be 64 at any
given time, so it would be a good idea not to waste them on such
trivialities.



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

* Re: [PATCH] Add user content APIs for WebKit Xwidgets
  2022-10-24  0:30                             ` Po Lu
@ 2022-10-24  4:17                               ` Qiantan Hong
  2022-10-24  5:38                                 ` Po Lu
  0 siblings, 1 reply; 41+ messages in thread
From: Qiantan Hong @ 2022-10-24  4:17 UTC (permalink / raw)
  To: Po Lu; +Cc: Andrew De Angelis, emacs-devel@gnu.org

Currently, I store the ALIST of handlers on xwidget-plist.  If we're
going to have it for groups of related Xwidgets, what is the best
place to store it? On the xwidget-plist of the head xwidget? Then we
have to inspect the xwidget-plist in the C function kill_xwidget and
migrate a specific subset of properties...

Or we should add another slot and provide xwidget-group-plist and
set-xwidget-group-plist, which will only have non-NULL value on the
head xwidget and is migrated automatically?

Best,
Qiantan



> On Oct 23, 2022, at 5:30 PM, Po Lu <luangruo@yahoo.com> wrote:
> 
> Qiantan Hong <qthong@stanford.edu> writes:
> 
>> Applying to all related Xwidgets sound like a good idea. I think we should
>> formalize the "group of related Xwidgets" as some kind of object? Maybe
>> a record type implemented in Lisp, or a pseudo vector (which I don't know
>> much about how to implement). An alternative is to expose content manager
>> as a pseudovector, which will in fact have 1-to-1 correspondence with "related
>> group", but I like related group more because it feels like a nicer abstraction.
> 
> I don't think that is necessary.  There should at most be a function
> that returns a list of all related xwidgets.
> 
> Pseudovector types are a limited resource.  There can only be 64 at any
> given time, so it would be a good idea not to waste them on such
> trivialities.




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

* Re: [PATCH] Add user content APIs for WebKit Xwidgets
  2022-10-24  4:17                               ` Qiantan Hong
@ 2022-10-24  5:38                                 ` Po Lu
  2022-10-24  5:44                                   ` Qiantan Hong
  0 siblings, 1 reply; 41+ messages in thread
From: Po Lu @ 2022-10-24  5:38 UTC (permalink / raw)
  To: Qiantan Hong; +Cc: Andrew De Angelis, emacs-devel@gnu.org

Qiantan Hong <qthong@stanford.edu> writes:

> Currently, I store the ALIST of handlers on xwidget-plist.  If we're
> going to have it for groups of related Xwidgets, what is the best
> place to store it? On the xwidget-plist of the head xwidget?

In a C data structure (not the plist!) attached to the "head" xwidget.
It does not have to be accessible to Lisp.

> Or we should add another slot and provide xwidget-group-plist and
> set-xwidget-group-plist, which will only have non-NULL value on the
> head xwidget and is migrated automatically?

What slot?

I don't think it has to be exposed to Lisp at all.  It's just an
implementation detail, after all.



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

* Re: [PATCH] Add user content APIs for WebKit Xwidgets
  2022-10-24  5:38                                 ` Po Lu
@ 2022-10-24  5:44                                   ` Qiantan Hong
  2022-10-24  7:20                                     ` Po Lu
  0 siblings, 1 reply; 41+ messages in thread
From: Qiantan Hong @ 2022-10-24  5:44 UTC (permalink / raw)
  To: Po Lu; +Cc: emacs-devel@gnu.org

>> Currently, I store the ALIST of handlers on xwidget-plist.  If we're
>> going to have it for groups of related Xwidgets, what is the best
>> place to store it? On the xwidget-plist of the head xwidget?
> 
> In a C data structure (not the plist!) attached to the "head" xwidget.
> It does not have to be accessible to Lisp.
> 
>> Or we should add another slot and provide xwidget-group-plist and
>> set-xwidget-group-plist, which will only have non-NULL value on the
>> head xwidget and is migrated automatically?
> 
> What slot?
> 
> I don't think it has to be exposed to Lisp at all.  It's just an
> implementation detail, after all.

Sure. In that case, would it be appropriate for the script_message_cb
to call the handler directly? Or should it emit an event and let
xwidget-webkit-callback call it on Lisp side? I'm not sure how well
does the former approach (which is more direct) interact with error
handling/Lisp debugger.



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

* Re: [PATCH] Add user content APIs for WebKit Xwidgets
  2022-10-24  5:44                                   ` Qiantan Hong
@ 2022-10-24  7:20                                     ` Po Lu
  0 siblings, 0 replies; 41+ messages in thread
From: Po Lu @ 2022-10-24  7:20 UTC (permalink / raw)
  To: Qiantan Hong; +Cc: emacs-devel@gnu.org

Qiantan Hong <qthong@stanford.edu> writes:

> Sure. In that case, would it be appropriate for the script_message_cb
> to call the handler directly?

No, it is not safe to call Lisp there.

> Or should it emit an event and let xwidget-webkit-callback call it on
> Lisp side?

Yes.

> I'm not sure how well does the former approach (which is more direct)
> interact with error handling/Lisp debugger.

Badly, unless you use safe_call, but that's not the place for safe_call.



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

end of thread, other threads:[~2022-10-24  7:20 UTC | newest]

Thread overview: 41+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2022-10-14  6:34 [PATCH] Add user content APIs for WebKit Xwidgets Qiantan Hong
2022-10-14  7:01 ` Po Lu
2022-10-14  7:12   ` Qiantan Hong
2022-10-14  7:35     ` Po Lu
2022-10-14 21:13       ` Qiantan Hong
2022-10-15  1:37         ` Qiantan Hong
2022-10-15  7:53           ` Qiantan Hong
2022-10-15 11:23             ` Po Lu
2022-10-15 18:29               ` Qiantan Hong
2022-10-16  0:26                 ` Po Lu
2022-10-15 23:33               ` Qiantan Hong
2022-10-16  4:32                 ` Po Lu
2022-10-16  6:29                   ` Qiantan Hong
2022-10-16  6:41                     ` Po Lu
2022-10-16  6:45                       ` Po Lu
2022-10-23  9:11                       ` Qiantan Hong
2022-10-23 10:58                         ` Po Lu
2022-10-23 22:16                           ` Qiantan Hong
2022-10-24  0:30                             ` Po Lu
2022-10-24  4:17                               ` Qiantan Hong
2022-10-24  5:38                                 ` Po Lu
2022-10-24  5:44                                   ` Qiantan Hong
2022-10-24  7:20                                     ` Po Lu
2022-10-16 20:51             ` [PATCH] Add user extension " Richard Stallman
2022-10-16 21:13               ` Alan Mackenzie
2022-10-18 11:58                 ` Richard Stallman
2022-10-17  5:31               ` Eli Zaretskii
2022-10-17  8:28                 ` Jean Louis
2022-10-19 17:04                   ` Richard Stallman
2022-10-19 19:06                     ` Eli Zaretskii
2022-10-20 19:46                 ` Richard Stallman
2022-10-21  5:51                   ` Eli Zaretskii
2022-10-21  6:02                     ` Po Lu
2022-10-23 19:14                     ` Richard Stallman
  -- strict thread matches above, loose matches on Subject: below --
2020-08-28  2:25 [PATCH] Add user content " Qiantan Hong
2020-08-28 14:37 ` Lars Ingebrigtsen
2020-08-28 15:41   ` Qiantan Hong
2020-08-30 13:43     ` Lars Ingebrigtsen
2020-08-29  4:07   ` Richard Stallman
2020-08-29  4:10 ` Richard Stallman
2020-08-29  4:45   ` Qiantan Hong

Code repositories for project(s) associated with this public inbox

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

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