]> git.eshelyaron.com Git - emacs.git/commitdiff
Add utility functions and new xwidget commands
authorSungbin Jo <pcr910303@icloud.com>
Wed, 12 Aug 2020 10:34:29 +0000 (12:34 +0200)
committerLars Ingebrigtsen <larsi@gnus.org>
Wed, 12 Aug 2020 10:34:39 +0000 (12:34 +0200)
Co-authored-by: Jaesup Kwak <veshboo@gmail.com>
* etc/NEWS: Announce new functions and options.
* lisp/xwidget.el (xwidget): New defgroup.
(xwidget-webkit-mode-map): Add new keybindings.
(xwidget-webkit-scroll-up, xwidget-webkit-scroll-down)
(xwidget-webkit-scroll-forward, xwidget-webkit-scroll-backward):
Add optional argument to specify specific amounts to scroll down.
(xwidget-webkit-scroll-up-line, xwidget-webkit-scroll-down-line): New
functions.
(xwidget-webkit-scroll-bottom): Fix function to scroll to the bottom
of the document.
(xwidget-webkit-callback): Use new function to update buffer title
even when Javascript is disabled.
(xwidget-webkit-bookmark-jump-new-session): New variable.
(xwidget-webkit-bookmark-make-record): Modify to use xwidget-webkit to
open bookmark that is created in xwidget-webkit.
(xwidget-webkit-insert-string): Fix Javascript snippet to not throw
Javsscript exceptions.
(xwidget-webkit-inside-pixel-width)
(xwidget-window-inside-pixel-height): New functions.
(xwidget-webkit-adjust-size-to-window): Use new functions.
(xwidget-webkit-new-session): Insert invisible URL instead of an empty
string to achieve better default behavior.
(xwidget-webkit-back, xwidget-webkit-forward, xwidget-webkit-reload)
(xwidget-webkit-current-url): Use new functions to enable scrolling
even when Javascript is disabled.
(xwidget-webkit-copy-selection-as-kill): Remove unnecessary lambda.
* src/nsxwidget.h src/nsxwidget.m (nsxwidget_webkit_uri)
(nsxwidget_webkit_title, nsxwidget_webkit_goto_history): Add new
functions.
* src/xwidget.c (Fxwidget_webkit_uri, Fxwidget_webkit_title)
(Fxwidget_webkit_goto_history): Add new functions.
(syms_of_xwidget): Define new functions.

etc/NEWS
lisp/xwidget.el
src/nsxwidget.h
src/nsxwidget.m
src/xwidget.c

index 509333649745949243e924d1c880c600e5f2546d..cfe180ff68833ccc35b52b1565a4d56c8c0d8d1e 100644 (file)
--- a/etc/NEWS
+++ b/etc/NEWS
@@ -790,6 +790,29 @@ never be narrower than 19 characters.
 When the 'bookmark.el' library is loaded, a customize choice is added
 to 'tab-bar-new-tab-choice' for new tabs to show the bookmark list.
 
+
+** xwidget-webkit mode
+
+*** New xwidget functions
+'xwidget-webkit-uri' (return the current URL), 'xwidget-webkit-title'
+(return the current title), and 'xwidget-webkit-goto-history' (goto a
+point in history).
+
+*** Pixel-based scrolling
+The 'xwidget-webkit-scroll-up', 'xwidget-webkit-scroll-down' commands
+now supports scrolling arbitrary pixel values.  It now treats the
+optional 2nd argument as the pixel values to scroll.
+
+*** New commands for scrolling
+The new commands 'xwidget-webkit-scroll-up-line',
+'xwidget-webkit-scroll-down-line', 'xwidget-webkit-scroll-forward',
+'xwidget-webkit-scroll-backward' can be used to scroll webkit by the
+height of lines or width of chars.
+
+*** New user option 'xwidget-webkit-bookmark-jump-new-session'.
+When non-nil, use a new xwidget webkit session after bookmark jump.
+Otherwise, it will use 'xwidget-webkit-last-session'.
+
 \f
 * New Modes and Packages in Emacs 28.1
 
index f0940a92031a4a4db175f579feeb3928fc603df0..e38bd1b32fb5feddf18cabcf47ca894c3105f51c 100644 (file)
 (declare-function xwidget-resize "xwidget.c" (xwidget new-width new-height))
 (declare-function xwidget-webkit-execute-script "xwidget.c"
                   (xwidget script &optional callback))
+(declare-function xwidget-webkit-uri "xwidget.c" (xwidget))
+(declare-function xwidget-webkit-title "xwidget.c" (xwidget))
 (declare-function xwidget-webkit-goto-uri "xwidget.c" (xwidget uri))
+(declare-function xwidget-webkit-goto-history "xwidget.c" (xwidget rel-pos))
 (declare-function xwidget-webkit-zoom "xwidget.c" (xwidget factor))
 (declare-function xwidget-plist "xwidget.c" (xwidget))
 (declare-function set-xwidget-plist "xwidget.c" (xwidget plist))
 (declare-function get-buffer-xwidgets "xwidget.c" (buffer))
 (declare-function xwidget-query-on-exit-flag "xwidget.c" (xwidget))
 
+(defgroup xwidget nil
+  "Displaying native widgets in Emacs buffers."
+  :group 'widgets)
+
 (defun xwidget-insert (pos type title width height &optional args)
   "Insert an xwidget at position POS.
 Supply the xwidget's TYPE, TITLE, WIDTH, and HEIGHT.
@@ -78,6 +85,8 @@ This returns the result of `make-xwidget'."
 ;;; webkit support
 (require 'browse-url)
 (require 'image-mode);;for some image-mode alike functionality
+(require 'seq)
+(require 'url-handlers)
 
 ;;;###autoload
 (defun xwidget-webkit-browse-url (url &optional new-session)
@@ -124,6 +133,7 @@ in `split-window-right' with a new xwidget webkit session."
     (define-key map "g" 'xwidget-webkit-browse-url)
     (define-key map "a" 'xwidget-webkit-adjust-size-dispatch)
     (define-key map "b" 'xwidget-webkit-back)
+    (define-key map "f" 'xwidget-webkit-forward)
     (define-key map "r" 'xwidget-webkit-reload)
     (define-key map "t" (lambda () (interactive) (message "o"))) ;FIXME: ?!?
     (define-key map "\C-m" 'xwidget-webkit-insert-string)
@@ -133,20 +143,21 @@ in `split-window-right' with a new xwidget webkit session."
 
     ;;similar to image mode bindings
     (define-key map (kbd "SPC")                 'xwidget-webkit-scroll-up)
+    (define-key map (kbd "S-SPC")               'xwidget-webkit-scroll-down)
     (define-key map (kbd "DEL")                 'xwidget-webkit-scroll-down)
 
-    (define-key map [remap scroll-up]           'xwidget-webkit-scroll-up)
+    (define-key map [remap scroll-up]           'xwidget-webkit-scroll-up-line)
     (define-key map [remap scroll-up-command]   'xwidget-webkit-scroll-up)
 
-    (define-key map [remap scroll-down]         'xwidget-webkit-scroll-down)
+    (define-key map [remap scroll-down]         'xwidget-webkit-scroll-down-line)
     (define-key map [remap scroll-down-command] 'xwidget-webkit-scroll-down)
 
     (define-key map [remap forward-char]        'xwidget-webkit-scroll-forward)
     (define-key map [remap backward-char]       'xwidget-webkit-scroll-backward)
     (define-key map [remap right-char]          'xwidget-webkit-scroll-forward)
     (define-key map [remap left-char]           'xwidget-webkit-scroll-backward)
-    (define-key map [remap previous-line]       'xwidget-webkit-scroll-down)
-    (define-key map [remap next-line]           'xwidget-webkit-scroll-up)
+    (define-key map [remap previous-line]       'xwidget-webkit-scroll-down-line)
+    (define-key map [remap next-line]           'xwidget-webkit-scroll-up-line)
 
     ;; (define-key map [remap move-beginning-of-line] 'image-bol)
     ;; (define-key map [remap move-end-of-line]       'image-eol)
@@ -165,33 +176,63 @@ in `split-window-right' with a new xwidget webkit session."
   (interactive)
   (xwidget-webkit-zoom (xwidget-webkit-current-session) -0.1))
 
-(defun xwidget-webkit-scroll-up ()
-  "Scroll webkit up."
-  (interactive)
+(defun xwidget-webkit-scroll-up (&optional arg)
+  "Scroll webkit up by ARG pixels; or full window height if no ARG.
+Stop if bottom of page is reached.
+Interactively, ARG is the prefix numeric argument.
+Negative ARG scrolls down."
+  (interactive "P")
   (xwidget-webkit-execute-script
    (xwidget-webkit-current-session)
-   "window.scrollBy(0, 50);"))
-
-(defun xwidget-webkit-scroll-down ()
-  "Scroll webkit down."
-  (interactive)
+   (format "window.scrollBy(0, %d);"
+           (or arg (xwidget-window-inside-pixel-height (selected-window))))))
+
+(defun xwidget-webkit-scroll-down (&optional arg)
+  "Scroll webkit down by ARG pixels; or full window height if no ARG.
+Stop if top of page is reached.
+Interactively, ARG is the prefix numeric argument.
+Negative ARG scrolls up."
+  (interactive "P")
   (xwidget-webkit-execute-script
    (xwidget-webkit-current-session)
-   "window.scrollBy(0, -50);"))
-
-(defun xwidget-webkit-scroll-forward ()
-  "Scroll webkit forwards."
-  (interactive)
+   (format "window.scrollBy(0, -%d);"
+           (or arg (xwidget-window-inside-pixel-height (selected-window))))))
+
+(defun xwidget-webkit-scroll-up-line (&optional n)
+  "Scroll webkit up by N lines.
+The height of line is calculated with `window-font-height'.
+Stop if the bottom edge of the page is reached.
+If N is omitted or nil, scroll up by one line."
+  (interactive "p")
+  (xwidget-webkit-scroll-up (* n (window-font-height))))
+
+(defun xwidget-webkit-scroll-down-line (&optional n)
+  "Scroll webkit down by N lines.
+The height of line is calculated with `window-font-height'.
+Stop if the top edge of the page is reached.
+If N is omitted or nil, scroll down by one line."
+  (interactive "p")
+  (xwidget-webkit-scroll-down (* n (window-font-height))))
+
+(defun xwidget-webkit-scroll-forward (&optional n)
+  "Scroll webkit horizontally by N chars.
+The width of char is calculated with `window-font-width'.
+If N is ommited or nil, scroll forwards by one char."
+  (interactive "p")
   (xwidget-webkit-execute-script
    (xwidget-webkit-current-session)
-   "window.scrollBy(50, 0);"))
-
-(defun xwidget-webkit-scroll-backward ()
-  "Scroll webkit backwards."
-  (interactive)
+   (format "window.scrollBy(%d, 0);"
+           (* n (window-font-width)))))
+
+(defun xwidget-webkit-scroll-backward (&optional n)
+  "Scroll webkit back by N chars.
+The width of char is calculated with `window-font-width'.
+If N is ommited or nil, scroll backwards by one char."
+  (interactive "p")
   (xwidget-webkit-execute-script
    (xwidget-webkit-current-session)
-   "window.scrollBy(-50, 0);"))
+   (format "window.scrollBy(-%d, 0);"
+           (* n (window-font-width)))))
 
 (defun xwidget-webkit-scroll-top ()
   "Scroll webkit to the very top."
@@ -205,7 +246,7 @@ in `split-window-right' with a new xwidget webkit session."
   (interactive)
   (xwidget-webkit-execute-script
    (xwidget-webkit-current-session)
-   "window.scrollTo(pageXOffset, window.document.body.clientHeight);"))
+   "window.scrollTo(pageXOffset, window.document.body.scrollHeight);"))
 
 ;; The xwidget event needs to go into a higher level handler
 ;; since the xwidget can generate an event even if it's offscreen.
@@ -236,15 +277,11 @@ XWIDGET instance, XWIDGET-EVENT-TYPE depends on the originating xwidget."
        "error: callback called for xwidget with dead buffer")
     (with-current-buffer (xwidget-buffer xwidget)
       (cond ((eq xwidget-event-type 'load-changed)
-             (xwidget-webkit-execute-script
-              xwidget "document.title"
-              (lambda (title)
-                (xwidget-log "webkit finished loading: '%s'" title)
-                ;; Do not adjust webkit size to window here, the
-                ;; selected window can be the mini-buffer window
-                ;; unwantedly.
-                (rename-buffer (format "*xwidget webkit: %s *" title))))
-             (pop-to-buffer (current-buffer)))
+             (let ((title (xwidget-webkit-title xwidget)))
+               (xwidget-log "webkit finished loading: %s" title)
+               ;; Do not adjust webkit size to window here, the selected window
+               ;; can be the mini-buffer window unwantedly.
+               (rename-buffer (format "*xwidget webkit: %s *" title) t)))
             ((eq xwidget-event-type 'decide-policy)
              (let ((strarg  (nth 3 last-input-event)))
                (if (string-match ".*#\\(.*\\)" strarg)
@@ -264,20 +301,34 @@ XWIDGET instance, XWIDGET-EVENT-TYPE depends on the originating xwidget."
 If non-nil, plugins are enabled.  Otherwise, disabled."))
 
 (define-derived-mode xwidget-webkit-mode
-    special-mode "xwidget-webkit" "Xwidget webkit view mode."
-    (setq buffer-read-only t)
-    (setq-local bookmark-make-record-function
-                #'xwidget-webkit-bookmark-make-record)
-    ;; Keep track of [vh]scroll when switching buffers
-    (image-mode-setup-winprops))
+  special-mode "xwidget-webkit" "Xwidget webkit view mode."
+  (setq buffer-read-only t)
+  (setq-local bookmark-make-record-function
+              #'xwidget-webkit-bookmark-make-record)
+  ;; Keep track of [vh]scroll when switching buffers
+  (image-mode-setup-winprops))
+
+;;; Bookmarks integration
+
+(defcustom xwidget-webkit-bookmark-jump-new-session nil
+  "Control bookmark jump to use new session or not.
+If non-nil, use a new xwidget webkit session after bookmark jump.
+Otherwise, it will use `xwidget-webkit-last-session'.
+When you set this variable to nil, consider further customization with
+`xwidget-webkit-last-session-buffer'."
+  :version "27.1"
+  :type 'boolean)
 
 (defun xwidget-webkit-bookmark-make-record ()
-  "Integrate Emacs bookmarks with the webkit xwidget."
+  "Create bookmark record in webkit xwidget."
   (nconc (bookmark-make-record-default t t)
-         `((page     . ,(xwidget-webkit-current-url))
-           (handler  . (lambda (bmk) (browse-url
-                                 (bookmark-prop-get bmk 'page)))))))
+         `((page . ,(xwidget-webkit-uri (xwidget-webkit-current-session)))
+           (handler  . (lambda (bmk)
+                         (xwidget-webkit-browse-url
+                          (bookmark-prop-get bmk 'page)
+                          xwidget-webkit-bookmark-jump-new-session))))))
 
+;;; xwidget webkit session
 
 (defvar xwidget-webkit-last-session-buffer nil)
 
@@ -325,7 +376,7 @@ function findactiveelement(doc){
 
 "
 
-  "javascript that finds the active element."
+  "Javascript that finds the active element."
   ;; Yes it's ugly, because:
   ;; - there is apparently no way to find the active frame other than recursion
   ;; - the js "for each" construct misbehaved on the "frames" collection
@@ -335,19 +386,22 @@ function findactiveelement(doc){
   )
 
 (defun xwidget-webkit-insert-string ()
-  "Prompt for a string and insert it in the active field in the
-current webkit widget."
+  "Insert string into the active field in the current webkit widget."
   ;; Read out the string in the field first and provide for edit.
   (interactive)
+  ;; As the prompt differs on JavaScript execution results,
+  ;; the function must handle the prompt itself.
   (let ((xww (xwidget-webkit-current-session)))
     (xwidget-webkit-execute-script
      xww
      (concat xwidget-webkit-activeelement-js "
 (function () {
   var res = findactiveelement(document);
-  return [res.value, res.type];
+  if (res)
+    return [res.value, res.type];
 })();")
      (lambda (field)
+       "Prompt a string for the FIELD and insert in the active input."
        (let ((str (pcase field
                     (`[,val "text"]
                      (read-string "Text: " val))
@@ -466,11 +520,23 @@ For example, use this to display an anchor."
   (ignore-errors
     (recenter-top-bottom)))
 
+;; Utility functions
+
+(defun xwidget-window-inside-pixel-width (window)
+  "Return Emacs WINDOW body width in pixel."
+  (let ((edges (window-inside-pixel-edges window)))
+    (- (nth 2 edges) (nth 0 edges))))
+
+(defun xwidget-window-inside-pixel-height (window)
+  "Return Emacs WINDOW body height in pixel."
+  (let ((edges (window-inside-pixel-edges window)))
+    (- (nth 3 edges) (nth 1 edges))))
+
 (defun xwidget-webkit-adjust-size-to-window (xwidget &optional window)
   "Adjust the size of the webkit XWIDGET to fit the WINDOW."
   (xwidget-resize xwidget
-                  (window-pixel-width window)
-                  (window-pixel-height window)))
+                  (xwidget-window-inside-pixel-width window)
+                  (xwidget-window-inside-pixel-height window)))
 
 (defun xwidget-webkit-adjust-size (w h)
   "Manually set webkit size to width W, height H."
@@ -510,42 +576,46 @@ For example, use this to display an anchor."
                                               (get-buffer-create bufname)))
     ;; The xwidget id is stored in a text property, so we need to have
     ;; at least character in this buffer.
-    (insert " ")
-    (setq xw (xwidget-insert 1 'webkit bufname
-                             (window-pixel-width)
-                             (window-pixel-height)))
+    ;; Insert invisible url, good default for next `g' to browse url.
+    (let ((start (point)))
+      (insert url)
+      (put-text-property start (+ start (length url)) 'invisible t)
+      (setq xw (xwidget-insert
+                start 'webkit bufname
+                (xwidget-window-inside-pixel-width (selected-window))
+                (xwidget-window-inside-pixel-height (selected-window)))))
     (xwidget-put xw 'callback callback)
     (xwidget-webkit-mode)
     (xwidget-webkit-goto-uri (xwidget-webkit-last-session) url)))
 
 
 (defun xwidget-webkit-goto-url (url)
-  "Goto URL."
+  "Goto URL with xwidget webkit."
   (if (xwidget-webkit-current-session)
       (progn
         (xwidget-webkit-goto-uri (xwidget-webkit-current-session) url))
     (xwidget-webkit-new-session url)))
 
 (defun xwidget-webkit-back ()
-  "Go back in history."
+  "Go back to previous URL in xwidget webkit buffer."
+  (interactive)
+  (xwidget-webkit-goto-history (xwidget-webkit-current-session) -1))
+
+(defun xwidget-webkit-forward ()
+  "Go forward in history."
   (interactive)
-  (xwidget-webkit-execute-script (xwidget-webkit-current-session)
-                                 "history.go(-1);"))
+  (xwidget-webkit-goto-history (xwidget-webkit-current-session) 1))
 
 (defun xwidget-webkit-reload ()
-  "Reload current url."
+  "Reload current URL."
   (interactive)
-  (xwidget-webkit-execute-script (xwidget-webkit-current-session)
-                                 "history.go(0);"))
+  (xwidget-webkit-goto-history (xwidget-webkit-current-session) 0))
 
 (defun xwidget-webkit-current-url ()
-  "Get the webkit url and place it on the kill-ring."
+  "Display the current xwidget webkit URL and place it on the `kill-ring'."
   (interactive)
-  (xwidget-webkit-execute-script
-   (xwidget-webkit-current-session)
-   "document.URL" (lambda (rv)
-                    (let ((url (kill-new (or rv ""))))
-                      (message "url: %s" url)))))
+  (let ((url (xwidget-webkit-uri (xwidget-webkit-current-session))))
+    (message "URL: %s" (kill-new (or url "")))))
 
 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 (defun xwidget-webkit-get-selection (proc)
@@ -556,10 +626,9 @@ For example, use this to display an anchor."
    proc))
 
 (defun xwidget-webkit-copy-selection-as-kill ()
-  "Get the webkit selection and put it on the kill-ring."
+  "Get the webkit selection and put it on the `kill-ring'."
   (interactive)
-  (xwidget-webkit-get-selection (lambda (selection) (kill-new selection))))
-
+  (xwidget-webkit-get-selection #'kill-new))
 
 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 ;; Xwidget plist management (similar to the process plist functions)
index 7e2a3e0c402243f6a78bb355f05eef462f95ef38..521601922f2dadcf952475c42328c7979105cbdb 100644 (file)
@@ -32,7 +32,10 @@ along with GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.  */
 /* Functions for xwidget webkit.  */
 
 bool nsxwidget_is_web_view (struct xwidget *xw);
+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);
 void nsxwidget_webkit_zoom (struct xwidget *xw, double zoom_change);
 void nsxwidget_webkit_execute_script (struct xwidget *xw, const char *script,
                                       Lisp_Object fun);
index c5376dd311cfff324421e1a845f952f77da6db4e..8643ba24d80cfd9823aba9b9e59c720d6d01e998 100644 (file)
@@ -292,6 +292,21 @@ nsxwidget_is_web_view (struct xwidget *xw)
   return xw->xwWidget != NULL &&
     [xw->xwWidget isKindOfClass:WKWebView.class];
 }
+
+Lisp_Object
+nsxwidget_webkit_uri (struct xwidget *xw)
+{
+  XwWebView *xwWebView = (XwWebView *) xw->xwWidget;
+  return build_string_with_nsstr (xwWebView.URL.absoluteString);
+}
+
+Lisp_Object
+nsxwidget_webkit_title (struct xwidget *xw)
+{
+  XwWebView *xwWebView = (XwWebView *) xw->xwWidget;
+  return build_string_with_nsstr (xwWebView.title);
+}
+
 /* @Note ATS - Need application transport security in 'Info.plist' or
    remote pages will not loaded.  */
 void
@@ -304,6 +319,17 @@ nsxwidget_webkit_goto_uri (struct xwidget *xw, const char *uri)
   [xwWebView loadRequest:urlRequest];
 }
 
+void
+nsxwidget_webkit_goto_history (struct xwidget *xw, int rel_pos)
+{
+  XwWebView *xwWebView = (XwWebView *) xw->xwWidget;
+  switch (rel_pos) {
+  case -1: [xwWebView goBack]; break;
+  case 0: [xwWebView reload]; break;
+  case 1: [xwWebView goForward]; break;
+  }
+}
+
 void
 nsxwidget_webkit_zoom (struct xwidget *xw, double zoom_change)
 {
index a3a3cd8d5bc47393ed8d1643b3e7ba6f78ecb5bf..d5c229c2b19224a4ed420dd44312496f5ef71c47 100644 (file)
@@ -749,6 +749,36 @@ xwidget_is_web_view (struct xwidget *xw)
       return Qnil;                                                     \
     }
 
+DEFUN ("xwidget-webkit-uri",
+       Fxwidget_webkit_uri, Sxwidget_webkit_uri,
+       1, 1, 0,
+       doc: /* Get the current URL of XWIDGET webkit.  */)
+  (Lisp_Object xwidget)
+{
+  WEBKIT_FN_INIT ();
+#ifdef USE_GTK
+  WebKitWebView *wkwv = WEBKIT_WEB_VIEW (xw->widget_osr);
+  return build_string (webkit_web_view_get_uri (wkwv));
+#elif defined NS_IMPL_COCOA
+  return nsxwidget_webkit_uri (xw);
+#endif
+}
+
+DEFUN ("xwidget-webkit-title",
+       Fxwidget_webkit_title, Sxwidget_webkit_title,
+       1, 1, 0,
+       doc: /* Get the current title of XWIDGET webkit.  */)
+  (Lisp_Object xwidget)
+{
+  WEBKIT_FN_INIT ();
+#ifdef USE_GTK
+  WebKitWebView *wkwv = WEBKIT_WEB_VIEW (xw->widget_osr);
+  return build_string (webkit_web_view_get_title (wkwv));
+#elif defined NS_IMPL_COCOA
+  return nsxwidget_webkit_title (xw);
+#endif
+}
+
 DEFUN ("xwidget-webkit-goto-uri",
        Fxwidget_webkit_goto_uri, Sxwidget_webkit_goto_uri,
        2, 2, 0,
@@ -766,6 +796,31 @@ DEFUN ("xwidget-webkit-goto-uri",
   return Qnil;
 }
 
+DEFUN ("xwidget-webkit-goto-history",
+       Fxwidget_webkit_goto_history, Sxwidget_webkit_goto_history,
+       2, 2, 0,
+       doc: /* Make the XWIDGET webkit load REL-POS (-1, 0, 1) page in browse history.  */)
+  (Lisp_Object xwidget, Lisp_Object rel_pos)
+{
+  WEBKIT_FN_INIT ();
+  /* Should be one of -1, 0, 1 */
+  if (XFIXNUM (rel_pos) < -1 || XFIXNUM (rel_pos) > 1)
+    args_out_of_range_3 (rel_pos, make_fixnum (-1), make_fixnum (1));
+
+#ifdef USE_GTK
+  WebKitWebView *wkwv = WEBKIT_WEB_VIEW (xw->widget_osr);
+  switch (XFIXNAT (rel_pos))
+    {
+    case -1: webkit_web_view_go_back (wkwv); break;
+    case 0: webkit_web_view_reload (wkwv); break;
+    case 1: webkit_web_view_go_forward (wkwv); break;
+    }
+#elif defined NS_IMPL_COCOA
+  nsxwidget_webkit_goto_history (xw, XFIXNAT (rel_pos));
+#endif
+  return Qnil;
+}
+
 DEFUN ("xwidget-webkit-zoom",
        Fxwidget_webkit_zoom, Sxwidget_webkit_zoom,
        2, 2, 0,
@@ -1106,7 +1161,10 @@ syms_of_xwidget (void)
   defsubr (&Sxwidget_query_on_exit_flag);
   defsubr (&Sset_xwidget_query_on_exit_flag);
 
+  defsubr (&Sxwidget_webkit_uri);
+  defsubr (&Sxwidget_webkit_title);
   defsubr (&Sxwidget_webkit_goto_uri);
+  defsubr (&Sxwidget_webkit_goto_history);
   defsubr (&Sxwidget_webkit_zoom);
   defsubr (&Sxwidget_webkit_execute_script);
   DEFSYM (Qwebkit, "webkit");