emacs-diffs
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

emacs-29 a137f71c67e: Improvements to xwidget on macOS (bug#60703)


From: Eli Zaretskii
Subject: emacs-29 a137f71c67e: Improvements to xwidget on macOS (bug#60703)
Date: Thu, 2 Mar 2023 05:55:47 -0500 (EST)

branch: emacs-29
commit a137f71c67e88204a32ebd747beb8fdd7db2fbe9
Author: Andrew De Angelis <bobodeangelis@gmail.com>
Commit: Eli Zaretskii <eliz@gnu.org>

    Improvements to xwidget on macOS (bug#60703)
    
    * src/nsxwidget.m ()
    ([XwWebView initWithFrame:configuration:xwidget:])
    (nsxwidget_init):  Fixed memory leaks: when sending an alloc
    message to an object, send an autorelease message to any objects
    we won't explictly release.
    ([XwWebView webView:didFinishNavigation:]): Second string to
    store in 'store_xwidget_event_string' is "load finished" rather
    than empty string.
    ([XwWebView webView:didStartProvisionalNavigation:])
    ([XwWebView webView:didReceiveServerRedirectForProvisionalNavigation:])
    ([XwWebView webView:didCommitNavigation:]): New functions.
    (nsxwidget_webkit_estimated_load_progress): New function.
    (nsxwidget_webkit_stop_loading): New function.
    * src/xwidget.c (Fxwidget_webkit_estimated_load_progress): Call
    'nsxwidget_webkit_estimated_load_progress' if we're on MacOS.
    (Fxwidget_webkit_stop_loading): Call 'nsxwidget_webkit_stop_loading'
    if we're on MacOS.
    (syms_of_xwidget): Define symbol for function.
    'xwidget_webkit_estimated_load_progress' if we're on MacOS.
    * src/nsxwidget.h: Signature for functions
    'nsxwidget_webkit_estimated_load_progress' and
    'nsxwidget_webkit_stop_loading'.
    * lisp/xwidget.el (xwidget-webkit-current-url): Message URL rather
    than return value of 'kill-new' (which is always nil).
---
 lisp/xwidget.el |   3 +-
 src/nsxwidget.h |   2 ++
 src/nsxwidget.m | 100 ++++++++++++++++++++++++++++++++++++++++----------------
 src/xwidget.c   |  63 +++++++++++++++++++++--------------
 4 files changed, 114 insertions(+), 54 deletions(-)

diff --git a/lisp/xwidget.el b/lisp/xwidget.el
index abbda29081e..7daca81f9f7 100644
--- a/lisp/xwidget.el
+++ b/lisp/xwidget.el
@@ -925,7 +925,8 @@ Return the buffer."
   "Display the current xwidget webkit URL and place it on the `kill-ring'."
   (interactive nil xwidget-webkit-mode)
   (let ((url (xwidget-webkit-uri (xwidget-webkit-current-session))))
-    (message "URL: %s" (kill-new (or url "")))))
+    (when url (kill-new url))
+    (message "URL: %s" url)))
 
 (defun xwidget-webkit-browse-history ()
   "Display a buffer containing the history of page loads."
diff --git a/src/nsxwidget.h b/src/nsxwidget.h
index 8d55fac5326..2b5596f905e 100644
--- a/src/nsxwidget.h
+++ b/src/nsxwidget.h
@@ -36,6 +36,8 @@ Lisp_Object nsxwidget_webkit_uri (struct xwidget *xw);
 Lisp_Object nsxwidget_webkit_title (struct xwidget *xw);
 void nsxwidget_webkit_goto_uri (struct xwidget *xw, const char *uri);
 void nsxwidget_webkit_goto_history (struct xwidget *xw, int rel_pos);
+double nsxwidget_webkit_estimated_load_progress(struct xwidget *xw);
+void nsxwidget_webkit_stop_loading (struct xwidget *xw);
 void nsxwidget_webkit_zoom (struct xwidget *xw, double zoom_change);
 void nsxwidget_webkit_execute_script (struct xwidget *xw, const char *script,
                                       Lisp_Object fun);
diff --git a/src/nsxwidget.m b/src/nsxwidget.m
index e1fbd749b62..0e00589bb7f 100644
--- a/src/nsxwidget.m
+++ b/src/nsxwidget.m
@@ -57,12 +57,13 @@ along with GNU Emacs.  If not, see 
<https://www.gnu.org/licenses/>.  */
 @end
 @implementation XwWebView : WKWebView
 
-- (id)initWithFrame:(CGRect)frame
+- (id) initWithFrame:(CGRect)frame
       configuration:(WKWebViewConfiguration *)configuration
             xwidget:(struct xwidget *)xw
 {
   /* Script controller to add script message handler and user script.  */
-  WKUserContentController *scriptor = [[WKUserContentController alloc] init];
+  WKUserContentController *scriptor = [[[WKUserContentController alloc] init]
+                                        autorelease];
   configuration.userContentController = scriptor;
 
   /* Enable inspect element context menu item for debugging.  */
@@ -81,7 +82,8 @@ along with GNU Emacs.  If not, see 
<https://www.gnu.org/licenses/>.  */
   if (self)
     {
       self.xw = xw;
-      self.urlScriptBlocked = [[NSMutableDictionary alloc] init];
+      self.urlScriptBlocked = [[[NSMutableDictionary alloc] init]
+                                autorelease];
       self.navigationDelegate = self;
       self.UIDelegate = self;
       self.customUserAgent =
@@ -89,23 +91,48 @@ along with GNU Emacs.  If not, see 
<https://www.gnu.org/licenses/>.  */
         @" AppleWebKit/603.3.8 (KHTML, like Gecko)"
         @" Version/11.0.1 Safari/603.3.8";
       [scriptor addScriptMessageHandler:self name:@"keyDown"];
-      [scriptor addUserScript:[[WKUserScript alloc]
-                                initWithSource:xwScript
-                                 injectionTime:
-                                  WKUserScriptInjectionTimeAtDocumentStart
-                                forMainFrameOnly:NO]];
+      WKUserScript *userScript = [[[WKUserScript alloc]
+                                    initWithSource:xwScript
+                                     injectionTime:
+                                      WKUserScriptInjectionTimeAtDocumentStart
+                                    forMainFrameOnly:NO] autorelease];
+      [scriptor addUserScript:userScript];
     }
   return self;
 }
 
-- (void)webView:(WKWebView *)webView
+/* These 4 functions emulate the behavior of webkit_view_load_changed_cb
+   in the GTK implementation*/
+- (void) webView:(WKWebView *)webView
 didFinishNavigation:(WKNavigation *)navigation
 {
   if (EQ (Fbuffer_live_p (self.xw->buffer), Qt))
-    store_xwidget_event_string (self.xw, "load-changed", "");
+    store_xwidget_event_string (self.xw, "load-changed", "load-finished");
 }
 
-- (void)webView:(WKWebView *)webView
+- (void) webView:(WKWebView *)webView
+didStartProvisionalNavigation:(WKNavigation *)navigation
+{
+  if (EQ (Fbuffer_live_p (self.xw->buffer), Qt))
+    store_xwidget_event_string (self.xw, "load-changed", "load-started");
+}
+
+- (void) webView:(WKWebView *)webView
+didReceiveServerRedirectForProvisionalNavigation:(WKNavigation *)navigation
+{
+  if (EQ (Fbuffer_live_p (self.xw->buffer), Qt))
+    store_xwidget_event_string (self.xw, "load-changed", "load-redirected");
+}
+
+/* Start loading WKWebView */
+- (void) webView:(WKWebView *)webView
+didCommitNavigation:(WKNavigation *)navigation
+{
+  if (EQ (Fbuffer_live_p (self.xw->buffer), Qt))
+    store_xwidget_event_string (self.xw, "load-changed", "load-committed");
+}
+
+- (void) webView:(WKWebView *)webView
 decidePolicyForNavigationAction:(WKNavigationAction *)navigationAction
 decisionHandler:(void (^)(WKNavigationActionPolicy))decisionHandler
 {
@@ -114,13 +141,13 @@ decisionHandler:(void 
(^)(WKNavigationActionPolicy))decisionHandler
     decisionHandler (WKNavigationActionPolicyAllow);
     break;
   default:
-    // decisionHandler (WKNavigationActionPolicyCancel);
+    /* decisionHandler (WKNavigationActionPolicyCancel); */
     decisionHandler (WKNavigationActionPolicyAllow);
     break;
   }
 }
 
-- (void)webView:(WKWebView *)webView
+- (void) webView:(WKWebView *)webView
 decidePolicyForNavigationResponse:(WKNavigationResponse *)navigationResponse
 decisionHandler:(void (^)(WKNavigationResponsePolicy))decisionHandler
 {
@@ -166,7 +193,7 @@ decisionHandler:(void 
(^)(WKNavigationResponsePolicy))decisionHandler
 
 /* No additional new webview or emacs window will be created
    for <a ... target="_blank">.  */
-- (WKWebView *)webView:(WKWebView *)webView
+- (WKWebView *) webView:(WKWebView *)webView
 createWebViewWithConfiguration:(WKWebViewConfiguration *)configuration
    forNavigationAction:(WKNavigationAction *)navigationAction
         windowFeatures:(WKWindowFeatures *)windowFeatures
@@ -177,7 +204,7 @@ createWebViewWithConfiguration:(WKWebViewConfiguration 
*)configuration
 }
 
 /* Open panel for file upload.  */
-- (void)webView:(WKWebView *)webView
+- (void) webView:(WKWebView *)webView
 runOpenPanelWithParameters:(WKOpenPanelParameters *)parameters
 initiatedByFrame:(WKFrameInfo *)frame
 completionHandler:(void (^)(NSArray<NSURL *> *URLs))completionHandler
@@ -197,13 +224,13 @@ completionHandler:(void (^)(NSArray<NSURL *> 
*URLs))completionHandler
    - Correct mouse hand/arrow/I-beam is displayed (TODO: not perfect yet).
 */
 
-- (void)mouseDown:(NSEvent *)event
+- (void) mouseDown:(NSEvent *)event
 {
   [self.xw->xv->emacswindow mouseDown:event];
   [super mouseDown:event];
 }
 
-- (void)mouseUp:(NSEvent *)event
+- (void) mouseUp:(NSEvent *)event
 {
   [self.xw->xv->emacswindow mouseUp:event];
   [super mouseUp:event];
@@ -214,7 +241,7 @@ completionHandler:(void (^)(NSArray<NSURL *> 
*URLs))completionHandler
    emacs as first responder to avoid focus held in an input element
    with matching text.  */
 
-- (void)keyDown:(NSEvent *)event
+- (void) keyDown:(NSEvent *)event
 {
   Lisp_Object var = Fintern (build_string ("isearch-mode"), Qnil);
   Lisp_Object val = buffer_local_value (var, Fcurrent_buffer ());
@@ -250,7 +277,7 @@ completionHandler:(void (^)(NSArray<NSURL *> 
*URLs))completionHandler
     }];
 }
 
-- (void)interpretKeyEvents:(NSArray<NSEvent *> *)eventArray
+- (void) interpretKeyEvents:(NSArray<NSEvent *> *)eventArray
 {
   /* We should do nothing and do not forward (default implementation
      if we not override here) to let emacs collect key events and ask
@@ -258,7 +285,7 @@ completionHandler:(void (^)(NSArray<NSURL *> 
*URLs))completionHandler
 }
 
 static NSString *xwScript;
-+ (void)initialize
++ (void) initialize
 {
   /* Find out if an input element has focus.
      Message to script message handler when 'C-g' key down.  */
@@ -284,7 +311,7 @@ static NSString *xwScript;
 
 /* Confirming to WKScriptMessageHandler, listens concerning keyDown in
    webkit. Currently 'C-g'.  */
-- (void)userContentController:(WKUserContentController *)userContentController
+- (void) userContentController:(WKUserContentController *)userContentController
       didReceiveScriptMessage:(WKScriptMessage *)message
 {
   if ([message.body isEqualToString:@"C-g"])
@@ -343,6 +370,20 @@ nsxwidget_webkit_goto_history (struct xwidget *xw, int 
rel_pos)
   }
 }
 
+double
+nsxwidget_webkit_estimated_load_progress (struct xwidget *xw)
+{
+  XwWebView *xwWebView = (XwWebView *) xw->xwWidget;
+  return xwWebView.estimatedProgress;
+}
+
+void
+nsxwidget_webkit_stop_loading (struct xwidget *xw)
+{
+  XwWebView *xwWebView = (XwWebView *) xw->xwWidget;
+  [xwWebView stopLoading];
+}
+
 void
 nsxwidget_webkit_zoom (struct xwidget *xw, double zoom_change)
 {
@@ -430,7 +471,7 @@ nsxwidget_webkit_execute_script (struct xwidget *xw, const 
char *script,
         }
       else if (result && FUNCTIONP (fun))
         {
-          // NSLog (@"result=%@, type=%@", result, [result class]);
+          /* NSLog (@"result=%@, type=%@", result, [result class]); */
           Lisp_Object lisp_value = js_to_lisp (result);
           store_xwidget_js_callback_event (xw, fun, lisp_value);
         }
@@ -440,19 +481,20 @@ nsxwidget_webkit_execute_script (struct xwidget *xw, 
const char *script,
 /* Window containing an xwidget.  */
 
 @implementation XwWindow
-- (BOOL)isFlipped { return YES; }
+- (BOOL) isFlipped { return YES; }
 @end
 
 /* Xwidget model, macOS Cocoa part.  */
 
 void
-nsxwidget_init(struct xwidget *xw)
+nsxwidget_init (struct xwidget *xw)
 {
   block_input ();
   NSRect rect = NSMakeRect (0, 0, xw->width, xw->height);
   xw->xwWidget = [[XwWebView alloc]
                    initWithFrame:rect
-                   configuration:[[WKWebViewConfiguration alloc] init]
+                   configuration:[[[WKWebViewConfiguration alloc] init]
+                                   autorelease]
                          xwidget:xw];
   xw->xwWindow = [[XwWindow alloc]
                    initWithFrame:rect];
@@ -470,16 +512,18 @@ nsxwidget_kill (struct xwidget *xw)
         ((XwWebView *) xw->xwWidget).configuration.userContentController;
       [scriptor removeAllUserScripts];
       [scriptor removeScriptMessageHandlerForName:@"keyDown"];
-      [scriptor release];
+
       if (xw->xv)
         xw->xv->model = Qnil; /* Make sure related view stale.  */
 
       /* This stops playing audio when a xwidget-webkit buffer is
-         killed.  I could not find other solution.  */
+         killed.  I could not find other solution.
+         TODO: improve this */
       nsxwidget_webkit_goto_uri (xw, "about:blank");
 
       [((XwWebView *) xw->xwWidget).urlScriptBlocked release];
       [xw->xwWidget removeFromSuperviewWithoutNeedingDisplay];
+
       [xw->xwWidget release];
       [xw->xwWindow removeFromSuperviewWithoutNeedingDisplay];
       [xw->xwWindow release];
@@ -507,7 +551,7 @@ nsxwidget_get_size (struct xwidget *xw)
 /* Xwidget view, macOS Cocoa part.  */
 
 @implementation XvWindow : NSView
-- (BOOL)isFlipped { return YES; }
+- (BOOL) isFlipped { return YES; }
 @end
 
 void
diff --git a/src/xwidget.c b/src/xwidget.c
index efe27055629..7f30e48c954 100644
--- a/src/xwidget.c
+++ b/src/xwidget.c
@@ -3063,6 +3063,36 @@ DEFUN ("xwidget-webkit-title",
 #endif
 }
 
+DEFUN ("xwidget-webkit-estimated-load-progress",
+       Fxwidget_webkit_estimated_load_progress, 
Sxwidget_webkit_estimated_load_progress,
+       1, 1, 0, doc: /* Get the estimated load progress of XWIDGET, a WebKit 
widget.
+Return a value ranging from 0.0 to 1.0, based on how close XWIDGET
+is to completely loading its page.  */)
+  (Lisp_Object xwidget)
+{
+  struct xwidget *xw;
+#ifdef USE_GTK
+  WebKitWebView *webview;
+#endif
+  double value;
+
+  CHECK_LIVE_XWIDGET (xwidget);
+  xw = XXWIDGET (xwidget);
+  CHECK_WEBKIT_WIDGET (xw);
+
+  block_input ();
+#ifdef USE_GTK
+  webview = WEBKIT_WEB_VIEW (xw->widget_osr);
+  value = webkit_web_view_get_estimated_load_progress (webview);
+#elif defined NS_IMPL_COCOA
+  value = nsxwidget_webkit_estimated_load_progress (xw);
+#endif
+
+  unblock_input ();
+
+  return make_float (value);
+}
+
 DEFUN ("xwidget-webkit-goto-uri",
        Fxwidget_webkit_goto_uri, Sxwidget_webkit_goto_uri,
        2, 2, 0,
@@ -3810,28 +3840,6 @@ LIMIT is not specified or nil, it is treated as `50'.  
*/)
   return list3 (back, here, forward);
 }
 
-DEFUN ("xwidget-webkit-estimated-load-progress",
-       Fxwidget_webkit_estimated_load_progress, 
Sxwidget_webkit_estimated_load_progress,
-       1, 1, 0, doc: /* Get the estimated load progress of XWIDGET, a WebKit 
widget.
-Return a value ranging from 0.0 to 1.0, based on how close XWIDGET
-is to completely loading its page.  */)
-  (Lisp_Object xwidget)
-{
-  struct xwidget *xw;
-  WebKitWebView *webview;
-  double value;
-
-  CHECK_LIVE_XWIDGET (xwidget);
-  xw = XXWIDGET (xwidget);
-  CHECK_WEBKIT_WIDGET (xw);
-
-  block_input ();
-  webview = WEBKIT_WEB_VIEW (xw->widget_osr);
-  value = webkit_web_view_get_estimated_load_progress (webview);
-  unblock_input ();
-
-  return make_float (value);
-}
 #endif
 
 DEFUN ("xwidget-webkit-set-cookie-storage-file",
@@ -3874,19 +3882,23 @@ This will stop any data transfer that may still be in 
progress inside
 XWIDGET as part of loading a page.  */)
   (Lisp_Object xwidget)
 {
-#ifdef USE_GTK
   struct xwidget *xw;
+#ifdef USE_GTK
   WebKitWebView *webview;
+#endif
 
   CHECK_LIVE_XWIDGET (xwidget);
   xw = XXWIDGET (xwidget);
   CHECK_WEBKIT_WIDGET (xw);
 
   block_input ();
+#ifdef USE_GTK
   webview = WEBKIT_WEB_VIEW (xw->widget_osr);
   webkit_web_view_stop_loading (webview);
-  unblock_input ();
+#elif defined NS_IMPL_COCOA
+  nsxwidget_webkit_stop_loading (xw);
 #endif
+  unblock_input ();
 
   return Qnil;
 }
@@ -3936,8 +3948,9 @@ syms_of_xwidget (void)
 #ifdef USE_GTK
   defsubr (&Sxwidget_webkit_load_html);
   defsubr (&Sxwidget_webkit_back_forward_list);
-  defsubr (&Sxwidget_webkit_estimated_load_progress);
 #endif
+
+  defsubr (&Sxwidget_webkit_estimated_load_progress);
   defsubr (&Skill_xwidget);
 
   DEFSYM (QCxwidget, ":xwidget");



reply via email to

[Prev in Thread] Current Thread [Next in Thread]