From 7ea8c3184b5343ea177dc516d6fab0d98c9c57d9 Mon Sep 17 00:00:00 2001
From: Sungbin Jo <pcr910303@icloud.com>
Date: Fri, 26 Jul 2019 03:41:10 +0900
Subject: [PATCH 3/3] Add support for file downloading in macOS xwidget-webkit

Co-authored-by: Jaesup Kwak <veshboo@gmail.com>

* lisp/xwidget.el (xwidget-webkit-callback): Add case for
'response-callback' event.
(xwidget-webkit-download-dir): New variable.
(xwidget-webkit-save-as-file): New function.
* src/nsxwidget.m (XwWebView::decidePolicyForNavigationResponse):
Store download event.
* src/xwidget.c src/xwidget.h (store_xwidget_download_callback_event):
New function.
---
 etc/NEWS        |  4 ++++
 lisp/xwidget.el | 31 +++++++++++++++++++++++++++++++
 src/nsxwidget.m | 12 ++++++++++++
 src/xwidget.c   | 20 ++++++++++++++++++++
 src/xwidget.h   |  5 +++++
 5 files changed, 72 insertions(+)

diff --git a/etc/NEWS b/etc/NEWS
index f9a42f73be..c7f980f212 100644
--- a/etc/NEWS
+++ b/etc/NEWS
@@ -2469,6 +2469,10 @@ instances of xwidget webkit is not supported.
 
 *** New variable 'xwidget-webkit-enable-plugins'.
 
+** On macOS, downloading files from xwidget-webkit is supported.
+
+*** New variable 'xwidget-webkit-download-dir'.
+
 
 
 ----------------------------------------------------------------------
diff --git a/lisp/xwidget.el b/lisp/xwidget.el
index 584a894148..2e8bfa3a98 100644
--- a/lisp/xwidget.el
+++ b/lisp/xwidget.el
@@ -288,6 +288,12 @@ xwidget-webkit-callback
                    (xwidget-webkit-show-id-or-named-element
                     xwidget
                     (match-string 1 strarg)))))
+            ;; TODO: Response handling other than download.
+            ((eq xwidget-event-type 'download-callback)
+             (let ((url  (nth 3 last-input-event))
+                   (mime-type (nth 4 last-input-event))
+                   (file-name (nth 5 last-input-event)))
+               (xwidget-webkit-save-as-file url mime-type file-name)))
             ((eq xwidget-event-type 'javascript-callback)
              (let ((proc (nth 3 last-input-event))
                    (arg  (nth 4 last-input-event)))
@@ -308,6 +314,31 @@ xwidget-webkit-mode
   ;; Keep track of [vh]scroll when switching buffers
   (image-mode-setup-winprops))
 
+;;; Download, save as file.
+
+(defcustom xwidget-webkit-download-dir "~/Downloads/"
+  "Directory where download file saved."
+  :version "27.1"
+  :type 'file)
+
+(defun xwidget-webkit-save-as-file (url mime-type file-name)
+  "For XWIDGET webkit, save URL of MIME-TYPE to location specified by user.
+FILE-NAME combined with `xwidget-webkit-download-dir' is the default file name
+of the prompt when reading.  When the file name the user specified is a
+directory, URL is saved at the specified directory as FILE-NAME."
+  (let ((save-name (read-file-name
+                    (format "Save URL `%s' of type `%s' in file/directory: " url mime-type)
+                    xwidget-webkit-download-dir
+                    (when file-name
+                      (expand-file-name
+                       file-name
+                       xwidget-webkit-download-dir)))))
+    (if (file-directory-p save-name)
+        (setq save-name
+              (expand-file-name (file-name-nondirectory file-name) save-name)))
+    (setq xwidget-webkit-download-dir (file-name-directory save-name))
+    (url-copy-file url save-name t)))
+
 ;;; Bookmarks integration
 
 (defcustom xwidget-webkit-bookmark-jump-new-session nil
diff --git a/src/nsxwidget.m b/src/nsxwidget.m
index 87a10e34e0..8cac4b49ec 100644
--- a/src/nsxwidget.m
+++ b/src/nsxwidget.m
@@ -122,6 +122,18 @@ - (void)webView:(WKWebView *)webView
 decidePolicyForNavigationResponse:(WKNavigationResponse *)navigationResponse
 decisionHandler:(void (^)(WKNavigationResponsePolicy))decisionHandler
 {
+  if (!navigationResponse.canShowMIMEType)
+    {
+      NSString *url = navigationResponse.response.URL.absoluteString;
+      NSString *mimetype = navigationResponse.response.MIMEType;
+      NSString *filename = navigationResponse.response.suggestedFilename;
+      decisionHandler (WKNavigationResponsePolicyCancel);
+      store_xwidget_download_callback_event (self.xw,
+                                             url.UTF8String,
+                                             mimetype.UTF8String,
+                                             filename.UTF8String);
+      return;
+    }
   decisionHandler (WKNavigationResponsePolicyAllow);
 
   self.urlScriptBlocked[navigationResponse.response.URL] =
diff --git a/src/xwidget.c b/src/xwidget.c
index 15d909f51c..aa5470a419 100644
--- a/src/xwidget.c
+++ b/src/xwidget.c
@@ -268,6 +268,26 @@ store_xwidget_event_string (struct xwidget *xw, const char *eventname,
   kbd_buffer_store_event (&event);
 }
 
+void
+store_xwidget_download_callback_event (struct xwidget *xw,
+                                       const char *url,
+                                       const char *mimetype,
+                                       const char *filename)
+{
+  struct input_event event;
+  Lisp_Object xwl;
+  XSETXWIDGET (xwl, xw);
+  EVENT_INIT (event);
+  event.kind = XWIDGET_EVENT;
+  event.frame_or_window = Qnil;
+  event.arg = list5 (intern ("download-callback"),
+                     xwl,
+                     build_string (url),
+                     build_string (mimetype),
+                     build_string (filename));
+  kbd_buffer_store_event (&event);
+}
+
 void
 store_xwidget_js_callback_event (struct xwidget *xw,
                                  Lisp_Object proc,
diff --git a/src/xwidget.h b/src/xwidget.h
index 73d8bbd540..11260f98b1 100644
--- a/src/xwidget.h
+++ b/src/xwidget.h
@@ -155,6 +155,11 @@ #define XG_XWIDGET_VIEW "emacs_xwidget_view"
                                  const char *eventname,
                                  const char *eventstr);
 
+void store_xwidget_download_callback_event (struct xwidget *xw,
+                                            const char *url,
+                                            const char *mimetype,
+                                            const char *filename);
+
 void store_xwidget_js_callback_event (struct xwidget *xw,
                                       Lisp_Object proc,
                                       Lisp_Object argument);
-- 
2.17.2 (Apple Git-113)

