]> git.eshelyaron.com Git - emacs.git/commitdiff
Support for the new Xwidget feature.
authorJoakim Verona <joakim@verona.se>
Tue, 19 Jan 2016 19:27:12 +0000 (20:27 +0100)
committerJoakim Verona <joakim@verona.se>
Tue, 19 Jan 2016 19:58:22 +0000 (20:58 +0100)
* configure.ac:
(HAVE_XWIDGETS, WIDGET_OBJ, EMACS_CONFIG_FEATURES):
* xterm.c (x_draw_glyph_string, x_draw_bar_cursor):
* xdisp.c:
(handle_display_spec, handle_single_display_spec, push_it)
(pop_it, set_iterator_to_next, dump_glyph)
(calc_pixel_width_or_height, fill_xwidget_glyph_string)
(BUILD_XWIDGET_GLYPH_STRING, BUILD_GLYPH_STRINGS)
(produce_xwidget_glyph, x_produce_glyphs)
(get_window_cursor_type):
* window.c (Fdelete_window_internal):
* termhooks.h (e):
* print.c (print_object):
* lisp.h (ptrdiff_t):
* keyboard.c (kbd_buffer_get_event, make_lispy_event)
(syms_of_keyboard):
* emacs.c (main):
* dispnew.c (update_window, scrolling_window):
* dispextern.h (g, i):
* Makefile.in (XWIDGETS_OBJ, WEBKIT_CFLAGS, WEBKIT_LIBS)
(GIR_LIBS, ALL_CFLAGS, base_obj, LIBES):
* keyboard.c (kbd_buffer_get_event):
* emacsgtkfixed.c (emacs_fixed_gtk_widget_size_allocate)
(emacs_fixed_class_init): Add case for an xwidget view.

* xwidget.c, xwidget.h, xwidget.el: New files for xwidgets

Co-authored-by: Grégoire Jadi <daimrod@gmail.com>
Various improvements to the Xwidget feature.
* xwidgets.c:
* emacsgtkfixed.c:
* xwidget.el:

19 files changed:
configure.ac
etc/NEWS
lisp/xwidget.el [new file with mode: 0644]
src/Makefile.in
src/buffer.c
src/dispextern.h
src/dispnew.c
src/emacs.c
src/emacsgtkfixed.c
src/emacsgtkfixed.h
src/keyboard.c
src/lisp.h
src/print.c
src/termhooks.h
src/window.c
src/xdisp.c
src/xterm.c
src/xwidget.c [new file with mode: 0644]
src/xwidget.h [new file with mode: 0644]

index 3aeba22ec47bf8cee13aeccdfd1197189cbc52ac..95f79ab8d4fa33db5c2cae125c394ecfda3930fc 100644 (file)
@@ -373,6 +373,9 @@ otherwise for the first of 'inotify' or 'gfile' that is usable.])
  ],
  [with_file_notification=$with_features])
 
+OPTION_DEFAULT_OFF([xwidgets],
+  [enable use of some gtk widgets in Emacs buffers])
+
 ## For the times when you want to build Emacs but don't have
 ## a suitable makeinfo, and can live without the manuals.
 dnl http://lists.gnu.org/archive/html/emacs-devel/2008-04/msg01844.html
@@ -2562,6 +2565,42 @@ if test "${HAVE_GTK}" = "yes"; then
  term_header=gtkutil.h
 fi
 
+
+HAVE_XWIDGETS=no
+HAVE_WEBKIT=no
+HAVE_GIR=no
+XWIDGETS_OBJ=
+if test "$with_xwidgets" != "no" && test "$USE_GTK_TOOLKIT" = "GTK3" &&
+   test "$window_system" != "none"
+then
+  HAVE_XWIDGETS=yes
+  AC_DEFINE([HAVE_XWIDGETS], 1, [Define to 1 if you have xwidgets support.])
+
+  dnl xwidgets
+  dnl - enable only if GTK3 is enabled, and we have a window system
+  dnl - check for webkit and gobject introspection
+  dnl webkit version for gtk3.
+  WEBKIT_REQUIRED=1.4.0
+  WEBKIT_MODULES="webkitgtk-3.0 >= $WEBKIT_REQUIRED"
+
+  if test "${with_gtk3}" = "yes"; then
+    PKG_CHECK_MODULES(WEBKIT, $WEBKIT_MODULES, HAVE_WEBKIT=yes, HAVE_WEBKIT=no)
+    if test $HAVE_WEBKIT = yes; then
+       AC_DEFINE([HAVE_WEBKIT_OSR], 1,
+         [Define to 1 if you have webkit_osr support.])
+    fi
+  fi
+
+  GIR_REQUIRED=1.32.1
+  GIR_MODULES="gobject-introspection-1.0 >= $GIR_REQUIRED"
+  PKG_CHECK_MODULES(GIR, $GIR_MODULES, HAVE_GIR=yes, HAVE_GIR=no)
+  if test $HAVE_GIR = yes; then
+     AC_DEFINE([HAVE_GIR], 1, [Define to 1 if you have GIR support.])
+  fi
+  XWIDGETS_OBJ=xwidget.o
+fi
+AC_SUBST(XWIDGETS_OBJ)
+
 CFLAGS=$OLD_CFLAGS
 LIBS=$OLD_LIBS
 
@@ -4925,6 +4964,9 @@ case "$USE_X_TOOLKIT" in
   LUCID) TOOLKIT_LIBW="$LUCID_LIBW" ;;
   none) test "x$HAVE_GTK" = "xyes" && TOOLKIT_LIBW="$GTK_LIBS" ;;
 esac
+if test "$HAVE_XWIDGETS" = "yes"; then
+  TOOLKIT_LIBW="$TOOLKIT_LIBW -lXcomposite"
+fi
 AC_SUBST(TOOLKIT_LIBW)
 
 if test "${opsys}" != "mingw32"; then
@@ -5264,6 +5306,9 @@ AS_ECHO(["  Does Emacs use -lXaw3d?                                 ${HAVE_XAW3D
   Does Emacs directly use zlib?                           ${HAVE_ZLIB}
   Does Emacs have dynamic modules support?                ${HAVE_MODULES}
   Does Emacs use toolkit scroll bars?                     ${USE_TOOLKIT_SCROLL_BARS}
+  Does Emacs support Xwidgets?                            ${HAVE_XWIDGETS}
+      Does xwidgets support webkit(requires gtk3)?        ${HAVE_WEBKIT}
+      Does xwidgets support gobject introspection?        ${HAVE_GIR}
 "])
 
 if test -n "${EMACSDATA}"; then
index 4e415a1039a701df57ac17820a8d7f8783eb03c7..db6e51dfd45d1e79b29013ac49ab22ebf6caa562 100644 (file)
--- a/etc/NEWS
+++ b/etc/NEWS
@@ -120,6 +120,21 @@ and can contain escape sequences for command keys, quotes, and the like.
 \f
 * Changes in Emacs 25.1
 
++++
+** Xwidgets : A new feature for embedding native widgets
+inside Emacs buffers. If you have gtk3 and webkit-devel installed, you
+can access the embedded webkit browser with m-x
+xwidget-webkit-browse-url. This will open a new buffer with the
+embedded browser. The buffer will have a new mode, xwidget-webkit
+mode which is similar to image mode, which supports the webkit widget.
+
+*** New functions for xwidget-webkit mode `xwidget-webkit-insert-string',
+`xwidget-webkit-adjust-size-dispatch', `xwidget-webkit-back',
+`xwidget-webkit-browse-url', `xwidget-webkit-reload',
+`xwidget-webkit-current-url', `xwidget-webkit-scroll-backward',
+`xwidget-webkit-scroll-forward', `xwidget-webkit-scroll-down',
+`xwidget-webkit-scroll-up',
+
 +++
 ** Emacs can now load shared/dynamic libraries (modules).
 A dynamic Emacs module is a shared library that provides additional
diff --git a/lisp/xwidget.el b/lisp/xwidget.el
new file mode 100644 (file)
index 0000000..ce6d939
--- /dev/null
@@ -0,0 +1,608 @@
+;;; xwidget.el --- api functions for xwidgets  -*- lexical-binding: t -*-
+;;
+;; Copyright (C) 2011-2015 Free Software Foundation, Inc.
+;;
+;; Author: Joakim Verona (joakim@verona.se)
+;;
+;; This file is part of GNU Emacs.
+;;
+;; GNU Emacs is free software: you can redistribute it and/or modify
+;; it under the terms of the GNU General Public License as published by
+;; the Free Software Foundation, either version 3 of the License, or
+;; (at your option) any later version.
+
+;; GNU Emacs is distributed in the hope that it will be useful,
+;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+;; GNU General Public License for more details.
+
+;; You should have received a copy of the GNU General Public License
+;; along with GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.
+;;
+;; --------------------------------------------------------------------
+
+;;; Commentary:
+;;
+;; See xwidget.c for more api functions
+
+;;TODO this breaks compilation when we dont have xwidgets
+;;(require 'xwidget-internal)
+
+;;; Code:
+
+(require 'cl-lib)
+(require 'reporter)
+(require 'bookmark)
+
+(defcustom xwidget-webkit-scroll-behaviour 'native
+  "Scroll behaviour of the webkit instance.
+'native or 'image."
+  :group 'xwidgets)
+
+(defun xwidget-insert (pos type title width height &optional args)
+  "Insert an xwidget at POS.
+given ID, TYPE, TITLE WIDTH and
+HEIGHT in the current buffer.
+
+Return ID
+
+see `make-xwidget' for types suitable for TYPE.
+Optional argument ARGS usage depends on the xwidget."
+  (goto-char pos)
+  (let ((id (make-xwidget (point) (point)
+                          type title width height args)))
+    (put-text-property (point) (+ 1 (point))
+                       'display (list 'xwidget ':xwidget id))
+    id))
+
+(defun xwidget-at (pos)
+  "Return xwidget at POS."
+  ;;TODO this function is a bit tedious because the C layer isnt well
+  ;;protected yet and xwidgetp aparently doesnt work yet
+  (let* ((disp (get-text-property pos 'display))
+         (xw (car (cdr (cdr  disp)))))
+    ;;(if ( xwidgetp  xw) xw nil)
+    (if (equal 'xwidget (car disp)) xw)))
+
+
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;;; webkit support
+(require 'browse-url)
+(require 'image-mode);;for some image-mode alike functionality
+
+;;;###autoload
+(defun xwidget-webkit-browse-url (url &optional new-session)
+  "Ask xwidget-webkit to browse URL.
+NEW-SESSION specifies whether to create a new xwidget-webkit session.  URL
+defaults to the string looking like a url around the cursor position."
+  (interactive (progn
+                 (require 'browse-url)
+                 (browse-url-interactive-arg "xwidget-webkit URL: "
+                                             ;;( xwidget-webkit-current-url)
+                                             )))
+  (when (stringp url)
+    (if new-session
+        (xwidget-webkit-new-session url)
+      (xwidget-webkit-goto-url url))))
+
+
+;;shims for adapting image mode code to the webkit browser window
+(defun xwidget-image-display-size  (spec &optional pixels frame)
+  "Image code adaptor.  SPEC PIXELS FRAME like the corresponding
+`image-mode' fn."
+  (let ((xwi (xwidget-info  (xwidget-at 1))))
+    (cons (aref xwi 2)
+          (aref xwi 3))))
+
+(defadvice image-display-size (around image-display-size-for-xwidget
+                                      (spec &optional pixels frame)
+                                      activate)
+  "Advice for re-using image mode for xwidget."
+  (if (eq (car spec) 'xwidget)
+      (setq ad-return-value (xwidget-image-display-size spec pixels frame))
+    ad-do-it))
+
+;;todo.
+;; - check that the webkit support is compiled in
+(defvar xwidget-webkit-mode-map
+  (let ((map (make-sparse-keymap)))
+    (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 "r" 'xwidget-webkit-reload )
+    (define-key map "t" (lambda () (interactive) (message "o")) )
+    (define-key map "\C-m" 'xwidget-webkit-insert-string)
+    (define-key map "w" 'xwidget-webkit-current-url)
+
+    ;;similar to image mode bindings
+    (define-key map (kbd "SPC")                 'xwidget-webkit-scroll-up)
+    (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-command]   'xwidget-webkit-scroll-up)
+
+    (define-key map [remap scroll-down]         'xwidget-webkit-scroll-down)
+    (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]          'image-previous-line)
+    ;; (define-key map [remap next-line]              'image-next-line)
+
+    ;; (define-key map [remap move-beginning-of-line] 'image-bol)
+    ;; (define-key map [remap move-end-of-line]       'image-eol)
+    ;; (define-key map [remap beginning-of-buffer]    'image-bob)
+    ;; (define-key map [remap end-of-buffer]          'image-eob)
+    map)
+  "Keymap for `xwidget-webkit-mode'.")
+
+(defun xwidget-webkit-scroll-up ()
+  "Scroll webkit up,either native or like image mode."
+  (interactive)
+  (if (eq xwidget-webkit-scroll-behaviour 'native)
+      (xwidget-set-adjustment (xwidget-webkit-last-session) 'vertical t 50)
+    (image-scroll-up)))
+
+(defun xwidget-webkit-scroll-down ()
+  "Scroll webkit down,either native or like image mode."
+  (interactive)
+  (if (eq xwidget-webkit-scroll-behaviour 'native)
+      (xwidget-set-adjustment (xwidget-webkit-last-session) 'vertical t -50)
+    (image-scroll-down)))
+
+(defun xwidget-webkit-scroll-forward ()
+  "Scroll webkit forward,either native or like image mode."
+  (interactive)
+  (if (eq xwidget-webkit-scroll-behaviour 'native)
+      (xwidget-set-adjustment (xwidget-webkit-last-session) 'horizontal t 50)
+    (xwidget-webkit-scroll-forward)))
+
+(defun xwidget-webkit-scroll-backward ()
+  "Scroll webkit backward,either native or like image mode."
+  (interactive)
+  (if (eq xwidget-webkit-scroll-behaviour 'native)
+      (xwidget-set-adjustment (xwidget-webkit-last-session) 'horizontal t -50)
+    (xwidget-webkit-scroll-backward)))
+
+
+;;the xwidget event needs to go into a higher level handler
+;;since the xwidget can generate an event even if its offscreen
+;;TODO this needs to use callbacks and consider different xw ev types
+(define-key (current-global-map) [xwidget-event] 'xwidget-event-handler)
+(defun xwidget-log ( &rest msg)
+  "Log MSG to a buffer."
+  (let ( (buf  (get-buffer-create "*xwidget-log*")))
+    (save-excursion
+      (buffer-disable-undo buf)
+      (set-buffer buf)
+      (insert (apply  'format msg))
+      (insert "\n"))))
+
+(defun xwidget-event-handler ()
+  "Receive xwidget event."
+  (interactive)
+  (xwidget-log "stuff happened to xwidget %S" last-input-event)
+  (let*
+      ((xwidget-event-type (nth 1 last-input-event))
+       (xwidget (nth 2 last-input-event))
+       ;;(xwidget-callback (xwidget-get xwidget 'callback))
+       ;;TODO stopped working for some reason
+       )
+    ;;(funcall  xwidget-callback xwidget xwidget-event-type)
+    (message "xw callback %s" xwidget)
+    (funcall  'xwidget-webkit-callback xwidget xwidget-event-type)))
+
+(defun xwidget-webkit-callback (xwidget xwidget-event-type)
+  "Callback for xwidgets.
+XWIDGET instance, XWIDGET-EVENT-TYPE depends on the originating xwidget."
+  (save-excursion
+    (cond ((buffer-live-p (xwidget-buffer xwidget))
+           (set-buffer (xwidget-buffer xwidget))
+           (let* ((strarg  (nth 3 last-input-event)))
+             (cond ((eq xwidget-event-type 'document-load-finished)
+                    (xwidget-log "webkit finished loading: '%s'"
+                                 (xwidget-webkit-get-title xwidget))
+                    ;;TODO - check the native/internal scroll
+                    ;;(xwidget-adjust-size-to-content xwidget)
+                    (xwidget-webkit-adjust-size-dispatch) ;;TODO xwidget arg
+                    (rename-buffer (format "*xwidget webkit: %s *"
+                                           (xwidget-webkit-get-title xwidget)))
+                    (pop-to-buffer (current-buffer)))
+                   ((eq xwidget-event-type
+                        'navigation-policy-decision-requested)
+                    (if (string-match ".*#\\(.*\\)" strarg)
+                        (xwidget-webkit-show-id-or-named-element
+                         xwidget
+                         (match-string 1 strarg))))
+                   (t (xwidget-log "unhandled event:%s" xwidget-event-type)))))
+          (t (xwidget-log
+              "error: callback called for xwidget with dead buffer")))))
+
+(defvar bookmark-make-record-function)
+(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))
+
+(defun xwidget-webkit-bookmark-make-record ()
+"Integrate Emacs bookmarks with the webkit xwidget."
+  (nconc (bookmark-make-record-default t t)
+         `((page     . ,(xwidget-webkit-current-url))
+           (handler  . (lambda (bmk) (browse-url
+                                      (bookmark-prop-get bmk 'page)))))))
+
+
+(defvar xwidget-webkit-last-session-buffer nil)
+
+(defun  xwidget-webkit-last-session ()
+  "Last active webkit, or nil."
+  (if (buffer-live-p xwidget-webkit-last-session-buffer)
+      (with-current-buffer xwidget-webkit-last-session-buffer
+        (xwidget-at 1))
+    nil))
+
+(defun xwidget-webkit-current-session ()
+  "Either the webkit in the current buffer, or the last one used,
+which might be nil."
+  (if (xwidget-at 1)
+      (xwidget-at 1)
+    (xwidget-webkit-last-session)))
+
+(defun xwidget-adjust-size-to-content (xw)
+  "Resize XW to content."
+  ;;xwidgets doesnt support widgets that have their own opinions about
+  ;;size well yet this reads the desired size and resizes the emacs
+  ;;allocated area accordingly
+  (let ((size (xwidget-size-request xw)))
+    (xwidget-resize xw (car size) (cadr size))))
+
+
+(defvar xwidget-webkit-activeelement-js"
+function findactiveelement(doc){
+//alert(doc.activeElement.value);
+   if(doc.activeElement.value != undefined){
+      return doc.activeElement;
+   }else{
+        // recurse over the child documents:
+        var frames = doc.getElementsByTagName('frame');
+        for (var i = 0; i < frames.length; i++)
+        {
+                var d = frames[i].contentDocument;
+                 var rv = findactiveelement(d);
+                 if(rv != undefined){
+                    return rv;
+                 }
+        }
+    }
+    return undefined;
+};
+
+
+"
+
+  "javascript that finds the active element."
+  ;;yes its ugly. because:
+  ;; - there is aparently no way to find the active frame other than recursion
+  ;; - the js "for each" construct missbehaved on the "frames" collection
+  ;; - a window with no frameset still has frames.length == 1, but
+  ;; frames[0].document.activeElement != document.activeElement
+  ;;TODO the activeelement type needs to be examined, for iframe, etc.
+  )
+
+(defun xwidget-webkit-insert-string (xw str)
+  "Insert string in the active field in the webkit.
+Argument XW webkit.
+Argument STR string."
+  ;;read out the string in the field first and provide for edit
+  (interactive
+   (let* ((xww (xwidget-webkit-current-session))
+
+          (field-value
+           (progn
+             (xwidget-webkit-execute-script xww xwidget-webkit-activeelement-js)
+             (xwidget-webkit-execute-script-rv
+              xww
+              "findactiveelement(document).value;" )))
+          (field-type (xwidget-webkit-execute-script-rv
+                       xww
+                       "findactiveelement(document).type;" )))
+     (list xww
+           (cond ((equal "text" field-type)
+                  (read-string "text:" field-value))
+                 ((equal "password" field-type)
+                  (read-passwd "password:" nil field-value))
+                 ((equal "textarea" field-type)
+                  (xwidget-webkit-begin-edit-textarea xww field-value))))))
+  (xwidget-webkit-execute-script
+   xw
+   (format "findactiveelement(document).value='%s'" str)))
+
+(defvar xwidget-xwbl)
+(defun xwidget-webkit-begin-edit-textarea (xw text)
+  "Start editing of a webkit text area.
+XW is the xwidget identifier, TEXT is retrieved from the webkit."
+  (switch-to-buffer
+   (generate-new-buffer "textarea"))
+
+  (set (make-local-variable 'xwidget-xwbl) xw)
+  (insert text))
+
+(defun xwidget-webkit-end-edit-textarea ()
+    "End editing of a webkit text area."
+  (interactive)
+  (goto-char (point-min))
+  (while (search-forward "\n" nil t)
+    (replace-match "\\n" nil t))
+  (xwidget-webkit-execute-script
+   xwidget-xwbl
+   (format "findactiveelement(document).value='%s'"
+           (buffer-substring (point-min) (point-max))))
+  ;;TODO convert linefeed to \n
+  )
+
+(defun xwidget-webkit-show-named-element (xw element-name)
+  "Make named-element show.  for instance an anchor.
+Argument XW is the xwidget.
+Argument ELEMENT-NAME is the element name to display in the webkit xwidget."
+  (interactive (list (xwidget-webkit-current-session)
+                     (read-string "element name:")))
+  ;;TODO since an xwidget is an Emacs object, it is not trivial to do
+  ;; some things that are taken for granted in a normal browser.
+  ;; scrolling an anchor/named-element into view is one such thing.
+  ;; This function implements a proof-of-concept for this.  Problems
+  ;; remaining: - The selected window is scrolled but this is not
+  ;; always correct - This needs to be interfaced into browse-url
+  ;; somehow. the tricky part is that we need to do this in two steps:
+  ;; A: load the base url, wait for load signal to arrive B: navigate
+  ;; to the anchor when the base url is finished rendering
+
+  ;; This part figures out the Y coordinate of the element
+  (let ((y (string-to-number
+            (xwidget-webkit-execute-script-rv
+             xw
+             (format
+              "document.getElementsByName('%s')[0].getBoundingClientRect().top"
+              element-name)
+             0))))
+    ;; Now we need to tell emacs to scroll the element into view.
+    (xwidget-log "scroll: %d" y)
+    (set-window-vscroll (selected-window) y t)))
+
+(defun xwidget-webkit-show-id-element (xw element-id)
+  "Make id-element show.  for instance an anchor.
+Argument XW is the webkit xwidget.
+Argument ELEMENT-ID is the id of the element to show."
+  (interactive (list (xwidget-webkit-current-session)
+                     (read-string "element id:")))
+  (let ((y (string-to-number
+            (xwidget-webkit-execute-script-rv
+             xw
+             (format "document.getElementById('%s').getBoundingClientRect().top"
+                     element-id)
+             0))))
+    ;; Now we need to tell emacs to scroll the element into view.
+    (xwidget-log "scroll: %d" y)
+    (set-window-vscroll (selected-window) y t)))
+
+(defun xwidget-webkit-show-id-or-named-element (xw element-id)
+  "Make id-element show.  for instance an anchor.
+Argument XW is the webkit xwidget.
+Argument ELEMENT-ID is either a name or an element id."
+  (interactive (list (xwidget-webkit-current-session)
+                     (read-string "element id:")))
+  (let* ((y1 (string-to-number
+              (xwidget-webkit-execute-script-rv
+               xw
+               (format "document.getElementsByName('%s')[0].getBoundingClientRect().top" element-id)
+               "0")))
+         (y2 (string-to-number
+              (xwidget-webkit-execute-script-rv
+               xw
+               (format "document.getElementById('%s').getBoundingClientRect().top" element-id)
+                                                "0")))
+         (y3 (max y1 y2)))
+    ;; Now we need to tell emacs to scroll the element into view.
+    (xwidget-log "scroll: %d" y3)
+    (set-window-vscroll (selected-window) y3 t)))
+
+(defun xwidget-webkit-adjust-size-to-content ()
+  "Adjust webkit to content size."
+  (interactive)
+  (xwidget-adjust-size-to-content (xwidget-webkit-current-session)))
+
+(defun xwidget-webkit-adjust-size-dispatch ()
+  "Adjust size according to mode."
+  (interactive)
+  (if (eq xwidget-webkit-scroll-behaviour 'native)
+      (xwidget-webkit-adjust-size-to-window)
+    (xwidget-webkit-adjust-size-to-content))
+  ;; The recenter is intended to correct a visual glitch.
+  ;; It errors out if the buffer isn't visible, but then we dont get the glitch,
+  ;; so silence errors
+  (ignore-errors
+    (recenter-top-bottom))
+  )
+
+(defun xwidget-webkit-adjust-size-to-window ()
+  "Adjust webkit to window."
+  (interactive)
+  (xwidget-resize ( xwidget-webkit-current-session) (window-pixel-width)
+                  (window-pixel-height)))
+
+(defun xwidget-webkit-adjust-size (w h)
+  "Manualy set webkit size.
+Argument W width.
+Argument H height."
+  ;; TODO shouldn't be tied to the webkit xwidget
+  (interactive "nWidth:\nnHeight:\n")
+  (xwidget-resize ( xwidget-webkit-current-session) w h))
+
+(defun xwidget-webkit-fit-width ()
+  "Adjust width of webkit to window width."
+  (interactive)
+  (xwidget-webkit-adjust-size (- (nth 2 (window-inside-pixel-edges))
+                                 (car (window-inside-pixel-edges)))
+                              1000))
+
+(defun xwidget-webkit-new-session (url)
+  "Create a new webkit session buffer with URL."
+  (let*
+      ((bufname (generate-new-buffer-name "*xwidget-webkit*"))
+       xw)
+    (setq xwidget-webkit-last-session-buffer (switch-to-buffer
+                                              (get-buffer-create bufname)))
+    (insert " 'a' adjusts the xwidget size.")
+    (setq xw (xwidget-insert 1 'webkit-osr  bufname 1000 1000))
+    (xwidget-put xw 'callback 'xwidget-webkit-callback)
+    (xwidget-webkit-mode)
+    (xwidget-webkit-goto-uri (xwidget-webkit-last-session) url )))
+
+
+(defun xwidget-webkit-goto-url (url)
+  "Goto URL."
+  (if (xwidget-webkit-current-session)
+      (progn
+        (xwidget-webkit-goto-uri (xwidget-webkit-current-session) url))
+    (xwidget-webkit-new-session url)))
+
+(defun xwidget-webkit-back ()
+  "Back in history."
+  (interactive)
+  (xwidget-webkit-execute-script (xwidget-webkit-current-session)
+                                 "history.go(-1);"))
+
+(defun xwidget-webkit-reload ()
+  "Reload current url."
+  (interactive)
+  (xwidget-webkit-execute-script (xwidget-webkit-current-session)
+                                 "history.go(0);"))
+
+(defun xwidget-webkit-current-url ()
+  "Get the webkit url.  place it on kill ring."
+  (interactive)
+  (let* ((rv (xwidget-webkit-execute-script-rv (xwidget-webkit-current-session)
+                                               "document.URL"))
+         (url (kill-new (or rv ""))))
+    (message "url: %s" url )
+    url))
+
+(defun xwidget-webkit-execute-script-rv (xw script &optional default)
+  "Same as 'xwidget-webkit-execute-script' but but with return value.
+XW is the webkit instance.  SCRIPT is the script to execut.
+DEFAULT is the defaultreturn value."
+  ;; Notice the ugly "title" hack.  It is needed because the Webkit
+  ;; API at the time of writing didn't support returning values.  This
+  ;; is a wrapper for the title hack so its easy to remove should
+  ;; Webkit someday support JS return values or we find some other way
+  ;; to access the DOM.
+
+  ;; Reset webkit title. Not very nice.
+  (let* ((emptytag "titlecantbewhitespaceohthehorror")
+         title)
+    (xwidget-webkit-execute-script xw (format "document.title=\"%s\";"
+                                              (or default emptytag)))
+    (xwidget-webkit-execute-script xw (format "document.title=%s;" script))
+    (setq title (xwidget-webkit-get-title xw))
+    (if (equal emptytag title)
+        (setq title ""))
+    (unless title
+      (setq title default))
+    title))
+
+
+;; Use declare here?
+;; (declare-function xwidget-resize-internal "xwidget.c" )
+;; check-declare-function?
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+(defun xwidget-webkit-get-selection ()
+  "Get the webkit selection."
+  (xwidget-webkit-execute-script-rv (xwidget-webkit-current-session)
+                                    "window.getSelection().toString();"))
+
+(defun xwidget-webkit-copy-selection-as-kill ()
+  "Get the webkit selection and put it on the kill ring."
+  (interactive)
+  (kill-new (xwidget-webkit-get-selection)))
+
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; Xwidget plist management(similar to the process plist functions)
+
+(defun xwidget-get (xwidget propname)
+  "Return the value of XWIDGET' PROPNAME property.
+This is the last value stored with `(xwidget-put XWIDGET PROPNAME VALUE)'."
+  (plist-get (xwidget-plist xwidget) propname))
+
+(defun xwidget-put (xwidget propname value)
+  "Change XWIDGET' PROPNAME property to VALUE.
+It can be retrieved with `(xwidget-get XWIDGET PROPNAME)'."
+  (set-xwidget-plist xwidget
+                     (plist-put (xwidget-plist xwidget) propname value)))
+
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+(defun xwidget-delete-zombies ()
+  "Helper for `xwidget-cleanup'."
+  (dolist (xwidget-view xwidget-view-list)
+    (when (or (not (window-live-p (xwidget-view-window xwidget-view)))
+              (not (memq (xwidget-view-model xwidget-view)
+                         xwidget-list)))
+      (delete-xwidget-view xwidget-view))))
+
+(defun xwidget-cleanup ()
+  "Delete zombie xwidgets."
+  ;; During development it was sometimes easy to wind up with zombie
+  ;; xwidget instances.
+  ;; This function tries to implement a workaround should it occur again.
+  (interactive)
+  ;; Kill xviews who should have been deleted but stull linger.
+  (xwidget-delete-zombies)
+  ;; Redraw display otherwise ghost of zombies will remain to haunt the screen
+  (redraw-display))
+
+;; This would have felt better in C, but this seems to work well in
+;; practice though.
+(add-hook 'window-configuration-change-hook 'xwidget-delete-zombies)
+
+(defun xwidget-kill-buffer-query-function ()
+  "Ask beforek illing a buffer that has xwidgets."
+  (let ((xwidgets (get-buffer-xwidgets (current-buffer))))
+    (or (not xwidgets)
+        (not (memq t (mapcar 'xwidget-query-on-exit-flag xwidgets)))
+        (yes-or-no-p
+         (format "Buffer %S has xwidgets; kill it? "
+                 (buffer-name (current-buffer)))))))
+
+(add-hook 'kill-buffer-query-functions 'xwidget-kill-buffer-query-function)
+
+(defun report-xwidget-bug ()
+  "Report a bug in GNU Emacs about the XWidget branch.
+Prompts for bug subject.  Leaves you in a mail buffer."
+  (interactive)
+  (let ((reporter-prompt-for-summary-p t))
+    (reporter-submit-bug-report "submit@debbugs.gnu.org" nil nil nil nil
+                                (format "Package: emacs-xwidgets
+
+Please describe exactly what actions triggered the bug, and the
+precise symptoms of the bug.  If you can, give a recipe starting
+from `emacs -Q'.
+
+If Emacs crashed, and you have the Emacs process in the gdb
+deubbger, please include the output from the following gdb
+commands:
+    `bt full' and `xbacktrace'.
+
+For information about debugging Emacs, please read the file
+%s" (expand-file-name "DEBUG" data-directory)))))
+
+(provide 'xwidget)
+
+;;; xwidget.el ends here
index 74c0e4eeda5953e9f6577cc72a003de76a43de13..2b5ae30a70441a0da35fbb08d77ec721b89cf9d0 100644 (file)
@@ -152,6 +152,9 @@ DBUS_LIBS = @DBUS_LIBS@
 ## dbusbind.o if HAVE_DBUS, else empty.
 DBUS_OBJ = @DBUS_OBJ@
 
+## xwidgets.o if HAVE_XWIDGETS, else empty.
+XWIDGETS_OBJ = @XWIDGETS_OBJ@
+
 LIB_EXECINFO=@LIB_EXECINFO@
 
 SETTINGS_CFLAGS = @SETTINGS_CFLAGS@
@@ -219,6 +222,11 @@ CFLAGS_SOUND= @CFLAGS_SOUND@
 RSVG_LIBS= @RSVG_LIBS@
 RSVG_CFLAGS= @RSVG_CFLAGS@
 
+WEBKIT_LIBS= @WEBKIT_LIBS@
+WEBKIT_CFLAGS= @WEBKIT_CFLAGS@
+
+GIR_LIBS= @GIR_LIBS@
+GIR_CFLAGS= @GIR_CFLAGS@
 CAIRO_LIBS= @CAIRO_LIBS@
 CAIRO_CFLAGS= @CAIRO_CFLAGS@
 
@@ -358,6 +366,7 @@ ALL_CFLAGS=-Demacs $(MYCPPFLAGS) -I. -I$(srcdir) \
   $(GNUSTEP_CFLAGS) $(CFLAGS_SOUND) $(RSVG_CFLAGS) $(IMAGEMAGICK_CFLAGS) \
   $(PNG_CFLAGS) $(LIBXML2_CFLAGS) $(DBUS_CFLAGS) \
   $(XRANDR_CFLAGS) $(XINERAMA_CFLAGS) $(XFIXES_CFLAGS) \
+  $(WEBKIT_CFLAGS) $(GIR_CFLAGS) \
   $(SETTINGS_CFLAGS) $(FREETYPE_CFLAGS) $(FONTCONFIG_CFLAGS) \
   $(LIBOTF_CFLAGS) $(M17N_FLT_CFLAGS) $(DEPFLAGS) \
   $(LIBGNUTLS_CFLAGS) $(GFILENOTIFY_CFLAGS) $(CAIRO_CFLAGS) \
@@ -387,6 +396,7 @@ base_obj = dispnew.o frame.o scroll.o xdisp.o menu.o $(XMENU_OBJ) window.o \
        process.o gnutls.o callproc.o \
        region-cache.o sound.o atimer.o \
        doprnt.o intervals.o textprop.o composite.o xml.o $(NOTIFY_OBJ) \
+       $(XWIDGETS_OBJ) \
        profiler.o decompress.o \
        $(MSDOS_OBJ) $(MSDOS_X_OBJ) $(NS_OBJ) $(CYGWIN_OBJ) $(FONT_OBJ) \
        $(W32_OBJ) $(WINDOW_SYSTEM_OBJ) $(XGSELOBJ)
@@ -467,6 +477,7 @@ lisp = $(addprefix ${lispsource}/,${shortlisp})
 LIBES = $(LIBS) $(W32_LIBS) $(LIBS_GNUSTEP) $(LIBX_BASE) $(LIBIMAGE) \
    $(LIBX_OTHER) $(LIBSOUND) \
    $(RSVG_LIBS) $(IMAGEMAGICK_LIBS) $(LIB_ACL) $(LIB_CLOCK_GETTIME) \
+   $(WEBKIT_LIBS) $(GIR_LIBS) \
    $(LIB_EACCESS) $(LIB_FDATASYNC) $(LIB_TIMER_TIME) $(DBUS_LIBS) \
    $(LIB_EXECINFO) $(XRANDR_LIBS) $(XINERAMA_LIBS) $(XFIXES_LIBS) \
    $(LIBXML2_LIBS) $(LIBGPM) $(LIBRESOLV) $(LIBS_SYSTEM) $(CAIRO_LIBS) \
index b02135cef874de7805ba6f1e3b0413eda176efff..a2981c90f661e8fa0356ee5bfe00f8565d721de8 100644 (file)
@@ -43,6 +43,9 @@ along with GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.  */
 #include "keymap.h"
 #include "frame.h"
 
+#ifdef HAVE_XWIDGETS
+# include "xwidget.h"
+#endif
 #ifdef WINDOWSNT
 #include "w32heap.h"           /* for mmap_* */
 #endif
@@ -1747,6 +1750,9 @@ cleaning up all windows currently displaying the buffer to be killed. */)
 
   kill_buffer_processes (buffer);
 
+#ifdef HAVE_XWIDGETS
+  kill_buffer_xwidgets (buffer);
+#endif
   /* Killing buffer processes may run sentinels which may have killed
      our buffer.  */
   if (!BUFFER_LIVE_P (b))
index bb876f5af70ca963fb0c5909ffbbd44c659c6d11..fad5bfd6f2faed79bdf762a0180639cd82b6186e 100644 (file)
@@ -348,6 +348,10 @@ enum glyph_type
 
   /* Glyph is a space of fractional width and/or height.  */
   STRETCH_GLYPH
+#ifdef HAVE_XWIDGETS
+  /* Glyph is an external widget drawn by the GUI toolkit.   */
+  ,XWIDGET_GLYPH
+#endif
 };
 
 
@@ -499,6 +503,9 @@ struct glyph
     /* Image ID for image glyphs (type == IMAGE_GLYPH).  */
     int img_id;
 
+#ifdef HAVE_XWIDGETS
+    struct xwidget *xwidget;
+#endif
     /* Sub-structure for type == STRETCH_GLYPH.  */
     struct
     {
@@ -1350,6 +1357,9 @@ struct glyph_string
   /* Image, if any.  */
   struct image *img;
 
+#ifdef HAVE_XWIDGETS
+  struct xwidget *xwidget;
+#endif
   /* Slice */
   struct glyph_slice slice;
 
@@ -2102,6 +2112,10 @@ enum display_element_type
 
   /* Continuation glyphs.  See the comment for IT_TRUNCATION.  */
   IT_CONTINUATION
+
+#ifdef HAVE_XWIDGETS
+  ,IT_XWIDGET
+#endif
 };
 
 
@@ -2165,6 +2179,9 @@ enum it_method {
   GET_FROM_C_STRING,
   GET_FROM_IMAGE,
   GET_FROM_STRETCH,
+#ifdef HAVE_XWIDGETS
+  GET_FROM_XWIDGET,
+#endif
   NUM_IT_METHODS
 };
 
@@ -2382,6 +2399,12 @@ struct it
       struct {
        Lisp_Object object;
       } stretch;
+#ifdef HAVE_XWIDGETS
+      /* method == GET_FROM_XWIDGET */
+      struct {
+       Lisp_Object object;
+      } xwidget;
+#endif
     } u;
 
     /* Current text and display positions.  */
@@ -2506,6 +2529,11 @@ struct it
   /* If what == IT_IMAGE, the id of the image to display.  */
   ptrdiff_t image_id;
 
+#ifdef HAVE_XWIDGETS
+  /* If what == IT_XWIDGET.  */
+  struct xwidget *xwidget;
+#endif
+
   /* Values from `slice' property.  */
   struct it_slice slice;
 
index 3e1557fa3b947bbc6a752e680deaf0fdc4e7686f..571ed5f851f601c1b28f8557afe9ee5753c3640e 100644 (file)
@@ -44,6 +44,10 @@ along with GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.  */
 #include TERM_HEADER
 #endif /* HAVE_WINDOW_SYSTEM */
 
+#ifdef HAVE_XWIDGETS
+# include "xwidget.h"
+#endif
+
 #include <errno.h>
 
 #include <fpending.h>
@@ -3545,6 +3549,9 @@ update_window (struct window *w, bool force_p)
   add_window_display_history (w, w->current_matrix->method, paused_p);
 #endif
 
+#ifdef HAVE_XWIDGETS
+  xwidget_end_redisplay (w, w->current_matrix);
+#endif
   clear_glyph_matrix (desired_matrix);
 
   return paused_p;
@@ -4118,6 +4125,11 @@ scrolling_window (struct window *w, bool header_line_p)
        break;
     }
 
+#ifdef HAVE_XWIDGETS
+  /* Currently this seems needed to detect xwidget movement reliably. */
+    return 0;
+#endif
+
   /* Give up if some rows in the desired matrix are not enabled.  */
   if (! MATRIX_ROW_ENABLED_P (desired_matrix, i))
     return -1;
index b1b2170a02823dd577d810880e4a0ec4eb96293d..6de0fffb9045f25166fd4b733060717deda78303 100644 (file)
@@ -66,6 +66,9 @@ along with GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.  */
 #include "buffer.h"
 #include "window.h"
 
+#ifdef HAVE_XWIDGETS
+# include "xwidget.h"
+#endif
 #include "atimer.h"
 #include "blockinput.h"
 #include "syssignal.h"
@@ -1485,6 +1488,9 @@ Using an Emacs configured with --with-x-toolkit=lucid does not have this problem
       syms_of_xfns ();
       syms_of_xmenu ();
       syms_of_fontset ();
+#ifdef HAVE_XWIDGETS
+      syms_of_xwidget ();
+#endif
       syms_of_xsettings ();
 #ifdef HAVE_X_SM
       syms_of_xsmfns ();
index cdcaf803ba5d72fffafd69726b97c12e423bc213..da1017df2ae45e46b558e2e2aef387119e2e8369 100644 (file)
@@ -23,6 +23,9 @@ along with GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.  */
 #include "lisp.h"
 #include "frame.h"
 #include "xterm.h"
+#ifdef HAVE_XWIDGETS
+# include "xwidget.h"
+#endif
 #include "emacsgtkfixed.h"
 
 /* Silence a bogus diagnostic; see GNOME bug 683906.  */
@@ -31,27 +34,10 @@ along with GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.  */
 # pragma GCC diagnostic ignored "-Wunused-local-typedefs"
 #endif
 
-#define EMACS_TYPE_FIXED emacs_fixed_get_type ()
-#define EMACS_FIXED(obj) \
-  G_TYPE_CHECK_INSTANCE_CAST (obj, EMACS_TYPE_FIXED, EmacsFixed)
-
 typedef struct _EmacsFixed EmacsFixed;
 typedef struct _EmacsFixedPrivate EmacsFixedPrivate;
 typedef struct _EmacsFixedClass EmacsFixedClass;
 
-struct _EmacsFixed
-{
-  GtkFixed container;
-
-  /*< private >*/
-  EmacsFixedPrivate *priv;
-};
-
-struct _EmacsFixedClass
-{
-  GtkFixedClass parent_class;
-};
-
 struct _EmacsFixedPrivate
 {
   struct frame *f;
@@ -64,9 +50,87 @@ static void emacs_fixed_get_preferred_width  (GtkWidget *widget,
 static void emacs_fixed_get_preferred_height (GtkWidget *widget,
                                               gint      *minimum,
                                               gint      *natural);
-static GType emacs_fixed_get_type (void);
 G_DEFINE_TYPE (EmacsFixed, emacs_fixed, GTK_TYPE_FIXED)
 
+#ifdef HAVE_XWIDGETS
+
+struct GtkFixedPrivateL
+{
+  GList *children;
+};
+
+static void emacs_fixed_gtk_widget_size_allocate (GtkWidget *widget,
+                                                  GtkAllocation *allocation)
+{
+  // For xwidgets.
+
+  // This basically re-implements the base class method and adds an
+  // additional case for an xwidget view.
+
+  // It would be nicer if the bse class method could be called first,
+  // and the the xview modification only would remain here. It wasn't
+  // possible to solve it that way yet.
+  EmacsFixedClass *klass;
+  GtkWidgetClass *parent_class;
+  struct GtkFixedPrivateL* priv;
+
+  klass = EMACS_FIXED_GET_CLASS (widget);
+  parent_class = g_type_class_peek_parent (klass);
+  parent_class->size_allocate (widget, allocation);
+
+  priv = G_TYPE_INSTANCE_GET_PRIVATE (widget,
+                               GTK_TYPE_FIXED,
+                               struct GtkFixedPrivateL);
+
+  gtk_widget_set_allocation (widget, allocation);
+
+  if (gtk_widget_get_has_window (widget))
+    {
+      if (gtk_widget_get_realized (widget))
+        gdk_window_move_resize (gtk_widget_get_window (widget),
+                                allocation->x,
+                                allocation->y,
+                                allocation->width,
+                                allocation->height);
+    }
+
+  for (GList *children = priv->children; children; children = children->next)
+    {
+      GtkFixedChild *child = children->data;
+
+      if (!gtk_widget_get_visible (child->widget))
+        continue;
+
+      GtkRequisition child_requisition;
+      gtk_widget_get_preferred_size (child->widget, &child_requisition, NULL);
+
+      GtkAllocation child_allocation;
+      child_allocation.x = child->x;
+      child_allocation.y = child->y;
+
+      if (!gtk_widget_get_has_window (widget))
+        {
+          child_allocation.x += allocation->x;
+          child_allocation.y += allocation->y;
+        }
+
+      child_allocation.width = child_requisition.width;
+      child_allocation.height = child_requisition.height;
+
+      struct xwidget_view *xv
+        = g_object_get_data (G_OBJECT (child->widget), XG_XWIDGET_VIEW);
+      if (xv)
+        {
+          child_allocation.width = xv->clip_right;
+          child_allocation.height = xv->clip_bottom - xv->clip_top;
+        }
+
+      gtk_widget_size_allocate (child->widget, &child_allocation);
+    }
+}
+
+#endif  /* HAVE_XWIDGETS */
+
 static void
 emacs_fixed_class_init (EmacsFixedClass *klass)
 {
@@ -74,11 +138,16 @@ emacs_fixed_class_init (EmacsFixedClass *klass)
 
   widget_class = (GtkWidgetClass*) klass;
 
+
   widget_class->get_preferred_width = emacs_fixed_get_preferred_width;
   widget_class->get_preferred_height = emacs_fixed_get_preferred_height;
+#ifdef HAVE_XWIDGETS
+  widget_class->size_allocate = emacs_fixed_gtk_widget_size_allocate;
+#endif
   g_type_class_add_private (klass, sizeof (EmacsFixedPrivate));
 }
 
+
 static void
 emacs_fixed_init (EmacsFixed *fixed)
 {
index 73280b83e57b6a7642d0d05d258b37b3f8b64f2a..5b2fa566785182de83fb9af564cffc1c393628e0 100644 (file)
@@ -27,7 +27,35 @@ struct frame;
 
 G_BEGIN_DECLS
 
+struct frame;
+
+#define EMACS_TYPE_FIXED                  (emacs_fixed_get_type ())
+#define EMACS_FIXED(obj)                  (G_TYPE_CHECK_INSTANCE_CAST ((obj), EMACS_TYPE_FIXED, EmacsFixed))
+#define EMACS_FIXED_CLASS(klass)          (G_TYPE_CHECK_CLASS_CAST ((klass), EMACS_TYPE_FIXED, EmacsFixedClass))
+#define EMACS_IS_FIXED(obj)               (G_TYPE_CHECK_INSTANCE_TYPE ((obj), EMACS_TYPE_FIXED))
+#define EMACS_IS_FIXED_CLASS(klass)       (G_TYPE_CHECK_CLASS_TYPE ((klass), EMACS_TYPE_FIXED))
+#define EMACS_FIXED_GET_CLASS(obj)        (G_TYPE_INSTANCE_GET_CLASS ((obj), EMACS_TYPE_FIXED, EmacsFixedClass))
+
+//typedef struct _EmacsFixed              EmacsFixed;
+typedef struct _EmacsFixedPrivate       EmacsFixedPrivate;
+typedef struct _EmacsFixedClass         EmacsFixedClass;
+
+struct _EmacsFixed
+{
+  GtkFixed container;
+
+  /*< private >*/
+  EmacsFixedPrivate *priv;
+};
+
+
+struct _EmacsFixedClass
+{
+  GtkFixedClass parent_class;
+};
+
 extern GtkWidget *emacs_fixed_new (struct frame *f);
+extern GType emacs_fixed_get_type (void);
 
 G_END_DECLS
 
index 6bdfc1aa084811dd7e3512ded2d4beca1d6590af..58831f548cad0091070ccc75b260ae3b9d0e8440 100644 (file)
@@ -4013,6 +4013,13 @@ kbd_buffer_get_event (KBOARD **kbp,
          obj = make_lispy_event (&event->ie);
          kbd_fetch_ptr = event + 1;
        }
+#endif
+#ifdef HAVE_XWIDGETS
+      else if (event->kind == XWIDGET_EVENT)
+       {
+         obj = make_lispy_event (&event->ie);
+         kbd_fetch_ptr = event + 1;
+       }
 #endif
       else if (event->kind == CONFIG_CHANGED_EVENT)
        {
@@ -5950,6 +5957,14 @@ make_lispy_event (struct input_event *event)
       }
 #endif /* HAVE_DBUS */
 
+#ifdef HAVE_XWIDGETS
+    case XWIDGET_EVENT:
+      {
+        return Fcons (Qxwidget_event,event->arg);
+      }
+#endif
+
+
 #if defined HAVE_GFILENOTIFY || defined HAVE_INOTIFY
     case FILE_NOTIFY_EVENT:
       {
@@ -10956,6 +10971,10 @@ syms_of_keyboard (void)
   DEFSYM (Qdbus_event, "dbus-event");
 #endif
 
+#ifdef HAVE_XWIDGETS
+  DEFSYM (Qxwidget_event,"xwidget-event");
+#endif
+
 #ifdef USE_FILE_NOTIFY
   DEFSYM (Qfile_notify, "file-notify");
 #endif /* USE_FILE_NOTIFY */
index f33a8f2494e688e52f9cbd8693ec7816550ed43f..b0a8d75c43907edb8b4195c0e4b61d96cbb9d0a6 100644 (file)
@@ -799,6 +799,12 @@ enum pvec_type
   PVEC_WINDOW_CONFIGURATION,
   PVEC_SUBR,
   PVEC_OTHER,
+
+#ifdef HAVE_XWIDGETS
+  PVEC_XWIDGET,
+  PVEC_XWIDGET_VIEW,
+#endif
+
   /* These should be last, check internal_equal to see why.  */
   PVEC_COMPILED,
   PVEC_CHAR_TABLE,
index 269d8f250e2d69ef5f8fa2458a2bddb707bd0091..4dd4e963093133849d69c4fb2000268d1514de82 100644 (file)
@@ -33,6 +33,10 @@ along with GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.  */
 #include "intervals.h"
 #include "blockinput.h"
 
+#ifdef HAVE_XWIDGETS
+# include "xwidget.h"
+#endif
+
 #include <c-ctype.h>
 #include <float.h>
 #include <ftoastr.h>
@@ -1736,6 +1740,18 @@ print_object (Lisp_Object obj, Lisp_Object printcharfun, bool escapeflag)
          print_c_string (XSUBR (obj)->symbol_name, printcharfun);
          printchar ('>', printcharfun);
        }
+#ifdef HAVE_XWIDGETS
+      else if (XWIDGETP (obj))
+       {
+         print_c_string ("#<xwidget ", printcharfun);
+         printchar ('>', printcharfun);
+       }
+      else if (XWIDGET_VIEW_P (obj))
+       {
+         print_c_string ("#<xwidget ", printcharfun);
+         printchar ('>', printcharfun);
+       }
+#endif
       else if (WINDOWP (obj))
        {
          int len = sprintf (buf, "#<window %"pI"d",
index 29223757621ca10ca3c3d86a7093adfb308b54a6..c183528ee84320a03cc74d4b647b7f5fe2726f10 100644 (file)
@@ -239,6 +239,11 @@ enum event_kind
   , NS_NONKEY_EVENT
 #endif
 
+#ifdef HAVE_XWIDGETS
+  /* events generated by xwidgets*/
+   , XWIDGET_EVENT
+#endif
+
 #ifdef USE_FILE_NOTIFY
   /* File or directory was changed.  */
   , FILE_NOTIFY_EVENT
index 2eacc3a2647fe585a2e4a4ae8faa88edc6906861..880ca4a46bb34f65156a87104b741f5eb839cd05 100644 (file)
@@ -41,6 +41,9 @@ along with GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.  */
 #ifdef MSDOS
 #include "msdos.h"
 #endif
+#ifdef HAVE_XWIDGETS
+# include "xwidget.h"
+#endif
 
 static ptrdiff_t count_windows (struct window *);
 static ptrdiff_t get_leaf_windows (struct window *, struct window **,
@@ -4370,6 +4373,9 @@ Signal an error when WINDOW is the only window on its frame.  */)
 
       /* Block input.  */
       block_input ();
+#ifdef HAVE_XWIDGETS
+      xwidget_view_delete_all_in_window (w);
+#endif
       window_resize_apply (p, horflag);
       /* If this window is referred to by the dpyinfo's mouse
         highlight, invalidate that slot to be safe (Bug#9904).  */
index d730a0bf1b6875373fcccc5c08ad7c5c7c41885b..89385c0e17267f5c2cb64da807d3f482d0d8dbff 100644 (file)
@@ -318,6 +318,9 @@ along with GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.  */
 #include TERM_HEADER
 #endif /* HAVE_WINDOW_SYSTEM */
 
+#ifdef HAVE_XWIDGETS
+# include "xwidget.h"
+#endif
 #ifndef FRAME_X_OUTPUT
 #define FRAME_X_OUTPUT(f) ((f)->output_data.x)
 #endif
@@ -854,6 +857,9 @@ static bool next_element_from_buffer (struct it *);
 static bool next_element_from_composition (struct it *);
 static bool next_element_from_image (struct it *);
 static bool next_element_from_stretch (struct it *);
+#ifdef HAVE_XWIDGETS
+static bool next_element_from_xwidget (struct it *);
+#endif
 static void load_overlay_strings (struct it *, ptrdiff_t);
 static bool get_next_display_element (struct it *);
 static enum move_it_result
@@ -4690,6 +4696,9 @@ handle_display_spec (struct it *it, Lisp_Object spec, Lisp_Object object,
   if (CONSP (spec)
       /* Simple specifications.  */
       && !EQ (XCAR (spec), Qimage)
+#ifdef HAVE_XWIDGETS
+      && !EQ (XCAR (spec), Qxwidget)
+#endif
       && !EQ (XCAR (spec), Qspace)
       && !EQ (XCAR (spec), Qwhen)
       && !EQ (XCAR (spec), Qslice)
@@ -5137,7 +5146,12 @@ handle_single_display_spec (struct it *it, Lisp_Object spec, Lisp_Object object,
                  || ((it ? FRAME_WINDOW_P (it->f) : frame_window_p)
                      && valid_image_p (value))
 #endif /* not HAVE_WINDOW_SYSTEM */
-                 || (CONSP (value) && EQ (XCAR (value), Qspace)));
+             || (CONSP (value) && EQ (XCAR (value), Qspace))
+#ifdef HAVE_XWIDGETS
+             || ((it ? FRAME_WINDOW_P (it->f) : frame_window_p)
+                && valid_xwidget_spec_p (value))
+#endif
+             );
 
   if (valid_p && display_replaced == 0)
     {
@@ -5212,6 +5226,17 @@ handle_single_display_spec (struct it *it, Lisp_Object spec, Lisp_Object object,
          *position = it->position = start_pos;
          retval = 1 + (it->area == TEXT_AREA);
        }
+#ifdef HAVE_XWIDGETS
+      else if (valid_xwidget_spec_p(value))
+       {
+          it->what = IT_XWIDGET;
+          it->method = GET_FROM_XWIDGET;
+          it->position = start_pos;
+         it->object = NILP (object) ? it->w->contents : object;
+         *position = start_pos;
+          it->xwidget = lookup_xwidget(value);
+       }
+#endif
 #ifdef HAVE_WINDOW_SYSTEM
       else
        {
@@ -5964,6 +5989,11 @@ push_it (struct it *it, struct text_pos *position)
     case GET_FROM_STRETCH:
       p->u.stretch.object = it->object;
       break;
+#ifdef HAVE_XWIDGETS
+    case GET_FROM_XWIDGET:
+      p->u.xwidget.object = it->object;
+      break;
+#endif
     case GET_FROM_BUFFER:
     case GET_FROM_DISPLAY_VECTOR:
     case GET_FROM_STRING:
@@ -6065,6 +6095,11 @@ pop_it (struct it *it)
       it->object = p->u.image.object;
       it->slice = p->u.image.slice;
       break;
+#ifdef HAVE_XWIDGETS
+    case GET_FROM_XWIDGET:
+      it->object = p->u.xwidget.object;
+      break;
+#endif
     case GET_FROM_STRETCH:
       it->object = p->u.stretch.object;
       break;
@@ -6739,7 +6774,10 @@ static next_element_function const get_next_element[NUM_IT_METHODS] =
   next_element_from_string,
   next_element_from_c_string,
   next_element_from_image,
-  next_element_from_stretch
+  next_element_from_stretch,
+#ifdef HAVE_XWIDGETS
+  next_element_from_xwidget,
+#endif
 };
 
 #define GET_NEXT_DISPLAY_ELEMENT(it) (*get_next_element[(it)->method]) (it)
@@ -7600,6 +7638,10 @@ set_iterator_to_next (struct it *it, bool reseat_p)
 
     case GET_FROM_IMAGE:
     case GET_FROM_STRETCH:
+#ifdef HAVE_XWIDGETS
+    case GET_FROM_XWIDGET:
+#endif
+
       /* The position etc with which we have to proceed are on
         the stack.  The position may be at the end of a string,
          if the `display' property takes up the whole string.  */
@@ -8061,6 +8103,15 @@ next_element_from_image (struct it *it)
   return true;
 }
 
+#ifdef HAVE_XWIDGETS
+static bool
+next_element_from_xwidget (struct it *it)
+{
+  it->what = IT_XWIDGET;
+  return true;
+}
+#endif
+
 
 /* Fill iterator IT with next display element from a stretch glyph
    property.  IT->object is the value of the text property.  Value is
@@ -18793,6 +18844,28 @@ dump_glyph (struct glyph_row *row, struct glyph *glyph, int area)
               glyph->left_box_line_p,
               glyph->right_box_line_p);
     }
+#ifdef HAVE_XWIDGETS
+  else if (glyph->type == XWIDGET_GLYPH)
+    {
+      fprintf (stderr,
+              "  %5d %4c %6d %c %3d 0x%05x %c %4d %1.1d%1.1d\n",
+              glyph - row->glyphs[TEXT_AREA],
+              'X',
+              glyph->charpos,
+              (BUFFERP (glyph->object)
+               ? 'B'
+               : (STRINGP (glyph->object)
+                  ? 'S'
+                  : '-')),
+              glyph->pixel_width,
+              glyph->u.xwidget,
+              '.',
+              glyph->face_id,
+              glyph->left_box_line_p,
+              glyph->right_box_line_p);
+
+    }
+#endif
 }
 
 
@@ -24291,6 +24364,13 @@ calc_pixel_width_or_height (double *res, struct it *it, Lisp_Object prop,
 
              return OK_PIXELS (width_p ? img->width : img->height);
            }
+# ifdef HAVE_XWIDGETS
+         if (FRAME_WINDOW_P (it->f) && valid_xwidget_spec_p (prop))
+           {
+              // TODO: Don't return dummy size.
+              return OK_PIXELS (100);
+            }
+# endif
 #endif
          if (EQ (car, Qplus) || EQ (car, Qminus))
            {
@@ -24796,6 +24876,18 @@ fill_image_glyph_string (struct glyph_string *s)
 }
 
 
+#ifdef HAVE_XWIDGETS
+static void
+fill_xwidget_glyph_string (struct glyph_string *s)
+{
+  eassert (s->first_glyph->type == XWIDGET_GLYPH);
+  s->face = FACE_FROM_ID (s->f, s->first_glyph->face_id);
+  s->font = s->face->font;
+  s->width = s->first_glyph->pixel_width;
+  s->ybase += s->first_glyph->voffset;
+  s->xwidget = s->first_glyph->u.xwidget;
+}
+#endif
 /* Fill glyph string S from a sequence of stretch glyphs.
 
    START is the index of the first glyph to consider,
@@ -25181,6 +25273,20 @@ compute_overhangs_and_x (struct glyph_string *s, int x, bool backward_p)
        }                                                               \
      while (false)
 
+#ifdef HAVE_XWIDGETS
+#define BUILD_XWIDGET_GLYPH_STRING(START, END, HEAD, TAIL, HL, X, LAST_X) \
+     do                                                                        \
+       {                                                               \
+        s = alloca (sizeof *s);                                        \
+        INIT_GLYPH_STRING (s, NULL, w, row, area, START, HL);          \
+        fill_xwidget_glyph_string (s);                                 \
+        append_glyph_string (&(HEAD), &(TAIL), s);                     \
+        ++(START);                                                     \
+         s->x = (X);                                                   \
+       }                                                               \
+     while (false)
+#endif
+
 
 /* Add a glyph string for a sequence of character glyphs to the list
    of strings between HEAD and TAIL.  START is the index of the first
@@ -25302,7 +25408,7 @@ compute_overhangs_and_x (struct glyph_string *s, int x, bool backward_p)
    to allocate glyph strings (because draw_glyphs can be called
    asynchronously).  */
 
-#define BUILD_GLYPH_STRINGS(START, END, HEAD, TAIL, HL, X, LAST_X)     \
+#define BUILD_GLYPH_STRINGS_1(START, END, HEAD, TAIL, HL, X, LAST_X)   \
   do                                                                   \
     {                                                                  \
       HEAD = TAIL = NULL;                                              \
@@ -25333,8 +25439,17 @@ compute_overhangs_and_x (struct glyph_string *s, int x, bool backward_p)
            case IMAGE_GLYPH:                                           \
              BUILD_IMAGE_GLYPH_STRING (START, END, HEAD, TAIL,         \
                                        HL, X, LAST_X);                 \
-             break;                                                    \
-                                                                       \
+             break;
+
+#ifdef HAVE_XWIDGETS
+# define BUILD_GLYPH_STRINGS_XW(START, END, HEAD, TAIL, HL, X, LAST_X) \
+            case XWIDGET_GLYPH:                                         \
+              BUILD_XWIDGET_GLYPH_STRING (START, END, HEAD, TAIL,       \
+                                          HL, X, LAST_X);               \
+              break;
+#endif
+
+#define BUILD_GLYPH_STRINGS_2(START, END, HEAD, TAIL, HL, X, LAST_X)   \
            case GLYPHLESS_GLYPH:                                       \
              BUILD_GLYPHLESS_GLYPH_STRING (START, END, HEAD, TAIL,     \
                                            HL, X, LAST_X);             \
@@ -25353,6 +25468,18 @@ compute_overhangs_and_x (struct glyph_string *s, int x, bool backward_p)
     } while (false)
 
 
+#ifdef HAVE_XWIDGETS
+# define BUILD_GLYPH_STRINGS(START, END, HEAD, TAIL, HL, X, LAST_X)    \
+    BUILD_GLYPH_STRINGS_1(START, END, HEAD, TAIL, HL, X, LAST_X)       \
+    BUILD_GLYPH_STRINGS_XW(START, END, HEAD, TAIL, HL, X, LAST_X)      \
+    BUILD_GLYPH_STRINGS_2(START, END, HEAD, TAIL, HL, X, LAST_X)
+#else
+# define BUILD_GLYPH_STRINGS(START, END, HEAD, TAIL, HL, X, LAST_X)    \
+    BUILD_GLYPH_STRINGS_1(START, END, HEAD, TAIL, HL, X, LAST_X)       \
+    BUILD_GLYPH_STRINGS_2(START, END, HEAD, TAIL, HL, X, LAST_X)
+#endif
+
+
 /* Draw glyphs between START and END in AREA of ROW on window W,
    starting at x-position X.  X is relative to AREA in W.  HL is a
    face-override with the following meaning:
@@ -25991,6 +26118,109 @@ produce_image_glyph (struct it *it)
     }
 }
 
+#ifdef HAVE_XWIDGETS
+static void
+produce_xwidget_glyph (struct it *it)
+{
+  struct xwidget *xw;
+  int glyph_ascent, crop;
+  eassert (it->what == IT_XWIDGET);
+
+  struct face *face = FACE_FROM_ID (it->f, it->face_id);
+  eassert (face);
+  /* Make sure X resources of the face is loaded.  */
+  prepare_face_for_display (it->f, face);
+
+  xw = it->xwidget;
+  it->ascent = it->phys_ascent = glyph_ascent = xw->height/2;
+  it->descent = xw->height/2;
+  it->phys_descent = it->descent;
+  it->pixel_width = xw->width;
+  /* It's quite possible for images to have an ascent greater than
+     their height, so don't get confused in that case.  */
+  if (it->descent < 0)
+    it->descent = 0;
+
+  it->nglyphs = 1;
+
+  if (face->box != FACE_NO_BOX)
+    {
+      if (face->box_line_width > 0)
+       {
+         it->ascent += face->box_line_width;
+         it->descent += face->box_line_width;
+       }
+
+      if (it->start_of_box_run_p)
+       it->pixel_width += eabs (face->box_line_width);
+      it->pixel_width += eabs (face->box_line_width);
+    }
+
+  take_vertical_position_into_account (it);
+
+  /* Automatically crop wide image glyphs at right edge so we can
+     draw the cursor on same display row.  */
+  crop = it->pixel_width - (it->last_visible_x - it->current_x);
+  if (crop > 0 && (it->hpos == 0 || it->pixel_width > it->last_visible_x / 4))
+    it->pixel_width -= crop;
+
+  if (it->glyph_row)
+    {
+      enum glyph_row_area area = it->area;
+      struct glyph *glyph
+       = it->glyph_row->glyphs[area] + it->glyph_row->used[area];
+
+      if (it->glyph_row->reversed_p)
+       {
+         struct glyph *g;
+
+         /* Make room for the new glyph.  */
+         for (g = glyph - 1; g >= it->glyph_row->glyphs[it->area]; g--)
+           g[1] = *g;
+         glyph = it->glyph_row->glyphs[it->area];
+       }
+      if (glyph < it->glyph_row->glyphs[area + 1])
+       {
+         glyph->charpos = CHARPOS (it->position);
+         glyph->object = it->object;
+         glyph->pixel_width = it->pixel_width;
+         glyph->ascent = glyph_ascent;
+         glyph->descent = it->descent;
+         glyph->voffset = it->voffset;
+         glyph->type = XWIDGET_GLYPH;
+         glyph->avoid_cursor_p = it->avoid_cursor_p;
+         glyph->multibyte_p = it->multibyte_p;
+         if (it->glyph_row->reversed_p && area == TEXT_AREA)
+           {
+             /* In R2L rows, the left and the right box edges need to be
+                drawn in reverse direction.  */
+             glyph->right_box_line_p = it->start_of_box_run_p;
+             glyph->left_box_line_p = it->end_of_box_run_p;
+           }
+         else
+           {
+             glyph->left_box_line_p = it->start_of_box_run_p;
+             glyph->right_box_line_p = it->end_of_box_run_p;
+           }
+          glyph->overlaps_vertically_p = 0;
+          glyph->padding_p = 0;
+         glyph->glyph_not_available_p = 0;
+         glyph->face_id = it->face_id;
+          glyph->u.xwidget = it->xwidget;
+         glyph->font_type = FONT_TYPE_UNKNOWN;
+         if (it->bidi_p)
+           {
+             glyph->resolved_level = it->bidi_it.resolved_level;
+             eassert ((it->bidi_it.type & 7) == it->bidi_it.type);
+             glyph->bidi_type = it->bidi_it.type;
+           }
+         ++it->glyph_row->used[area];
+       }
+      else
+       IT_EXPAND_MATRIX_WIDTH (it, area);
+    }
+}
+#endif
 
 /* Append a stretch glyph to IT->glyph_row.  OBJECT is the source
    of the glyph, WIDTH and HEIGHT are the width and height of the
@@ -27401,6 +27631,10 @@ x_produce_glyphs (struct it *it)
     produce_image_glyph (it);
   else if (it->what == IT_STRETCH)
     produce_stretch_glyph (it);
+#ifdef HAVE_XWIDGETS
+  else if (it->what == IT_XWIDGET)
+    produce_xwidget_glyph (it);
+#endif
 
  done:
   /* Accumulate dimensions.  Note: can't assume that it->descent > 0
@@ -27770,6 +28004,10 @@ get_window_cursor_type (struct window *w, struct glyph *glyph, int *width,
   /* Use normal cursor if not blinked off.  */
   if (!w->cursor_off_p)
     {
+#ifdef HAVE_XWIDGETS
+      if (glyph != NULL && glyph->type == XWIDGET_GLYPH)
+        return NO_CURSOR;
+#endif
       if (glyph != NULL && glyph->type == IMAGE_GLYPH)
        {
          if (cursor_type == FILLED_BOX_CURSOR)
index 5a6d643bad4fac705ff05d96e99d697ce6491b31..44eed22d2ec0e56e9e82e0921b6ead199c896311 100644 (file)
@@ -62,6 +62,9 @@ along with GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.  */
 #include "composite.h"
 #include "frame.h"
 #include "dispextern.h"
+#ifdef HAVE_XWIDGETS
+# include "xwidget.h"
+#endif
 #include "fontset.h"
 #include "termhooks.h"
 #include "termopts.h"
@@ -3511,6 +3514,12 @@ x_draw_glyph_string (struct glyph_string *s)
       x_draw_image_glyph_string (s);
       break;
 
+#ifdef HAVE_XWIDGETS
+    case XWIDGET_GLYPH:
+      x_draw_xwidget_glyph_string (s);
+      break;
+#endif
+
     case STRETCH_GLYPH:
       x_draw_stretch_glyph_string (s);
       break;
@@ -8920,6 +8929,11 @@ x_draw_bar_cursor (struct window *w, struct glyph_row *row, int width, enum text
   if (cursor_glyph == NULL)
     return;
 
+#ifdef HAVE_XWIDGETS
+  if (cursor_glyph->type == XWIDGET_GLYPH)
+    return; // Experimental avoidance of cursor on xwidget.
+#endif
+
   /* If on an image, draw like a normal cursor.  That's usually better
      visible than drawing a bar, esp. if the image is large so that
      the bar might not be in the window.  */
diff --git a/src/xwidget.c b/src/xwidget.c
new file mode 100644 (file)
index 0000000..74319e1
--- /dev/null
@@ -0,0 +1,1332 @@
+/* Support for embedding graphical components in a buffer.
+
+Copyright (C) 2011-2015 Free Software Foundation, Inc.
+
+This file is part of GNU Emacs.
+
+GNU Emacs is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+GNU Emacs is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.  */
+
+#include <config.h>
+
+
+#include <signal.h>
+
+#include <stdio.h>
+#include <setjmp.h>
+#ifdef HAVE_X_WINDOWS
+
+#include "lisp.h"
+#include "blockinput.h"
+#include "syssignal.h"
+
+#include "xterm.h"
+#include <X11/cursorfont.h>
+
+#ifndef makedev
+# include <sys/types.h>
+#endif
+
+#ifdef BSD_SYSTEM
+# include <sys/ioctl.h>
+#endif
+
+#include "systime.h"
+
+#ifndef INCLUDED_FCNTL
+# include <fcntl.h>
+#endif
+#include <ctype.h>
+#include <errno.h>
+#include <setjmp.h>
+#include <sys/stat.h>
+
+#include "charset.h"
+#include "character.h"
+#include "coding.h"
+#include "ccl.h"
+#include "frame.h"
+#include "dispextern.h"
+#include "fontset.h"
+#include "termhooks.h"
+#include "termopts.h"
+#include "termchar.h"
+#include "disptab.h"
+#include "buffer.h"
+#include "window.h"
+#include "keyboard.h"
+#include "intervals.h"
+#include "process.h"
+#include "atimer.h"
+#include "keymap.h"
+
+
+#ifdef USE_X_TOOLKIT
+#include <X11/Shell.h>
+#endif
+#include <X11/extensions/Xcomposite.h>
+#include <X11/extensions/Xrender.h>
+#include <cairo.h>
+#ifdef HAVE_SYS_TIME_H
+#include <sys/time.h>
+#endif
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+
+#include "gtkutil.h"
+#include "font.h"
+#endif /* HAVE_X_WINDOWS */
+
+#include <gtk/gtk.h>
+#include <gdk/gdk.h>
+
+#include <gtk/gtkx.h>
+
+#include "emacsgtkfixed.h"
+
+#include <wchar.h>
+
+#include <webkit/webkitwebview.h>
+#include <webkit/webkitwebplugindatabase.h>
+#include <webkit/webkitwebplugin.h>
+#include <webkit/webkitglobals.h>
+#include <webkit/webkitwebnavigationaction.h>
+#include <webkit/webkitdownload.h>
+#include <webkit/webkitwebpolicydecision.h>
+
+#include "xwidget.h"
+
+static struct xwidget *
+allocate_xwidget (void)
+{
+  return ALLOCATE_PSEUDOVECTOR (struct xwidget, height, PVEC_XWIDGET);
+}
+
+static struct xwidget_view *
+allocate_xwidget_view (void)
+{
+  return ALLOCATE_PSEUDOVECTOR (struct xwidget_view, redisplayed,
+                                PVEC_XWIDGET_VIEW);
+}
+
+#define XSETXWIDGET(a, b) (XSETPSEUDOVECTOR (a, b, PVEC_XWIDGET))
+#define XSETXWIDGET_VIEW(a, b) (XSETPSEUDOVECTOR (a, b, PVEC_XWIDGET_VIEW))
+
+struct xwidget_view *xwidget_view_lookup (struct xwidget *, struct window *);
+Lisp_Object xwidget_spec_value (Lisp_Object , Lisp_Object , int *);
+gboolean offscreen_damage_event (GtkWidget * , GdkEvent * , gpointer );
+void webkit_document_load_finished_cb (WebKitWebView *, WebKitWebFrame *,
+                                       gpointer );
+gboolean webkit_download_cb (WebKitWebView *, WebKitDownload *, gpointer);
+
+gboolean
+webkit_mime_type_policy_typedecision_requested_cb (WebKitWebView *,
+                                                   WebKitWebFrame *,
+                                                   WebKitNetworkRequest *,
+                                                   gchar *,
+                                                   WebKitWebPolicyDecision *,
+                                                   gpointer);
+
+gboolean
+webkit_new_window_policy_decision_requested_cb (WebKitWebView *,
+                                                WebKitWebFrame *,
+                                                WebKitNetworkRequest *,
+                                                WebKitWebNavigationAction *,
+                                                WebKitWebPolicyDecision *,
+                                                gpointer);
+
+gboolean
+webkit_navigation_policy_decision_requested_cb (WebKitWebView *,
+                                                WebKitWebFrame *,
+                                                WebKitNetworkRequest *,
+                                                WebKitWebNavigationAction *,
+                                                WebKitWebPolicyDecision *,
+                                                gpointer);
+
+
+
+DEFUN ("make-xwidget",
+       Fmake_xwidget, Smake_xwidget,
+       7, 8, 0,
+       doc: /* Make an xwidget from BEG to END of TYPE.
+
+If BUFFER is nil it uses the current
+buffer. If BUFFER is a string and no such
+buffer exists, it is created.
+
+TYPE is a symbol which can take one of the
+following values:
+
+- webkit_osr
+
+Returns the newly constructed xwidget, or nil if construction
+fails.  */)
+  (Lisp_Object beg, Lisp_Object end,
+  Lisp_Object type,
+  Lisp_Object title,
+  Lisp_Object width, Lisp_Object height,
+  Lisp_Object arguments, Lisp_Object buffer)
+{
+  //should work a bit like "make-button"(make-button BEG END &rest PROPERTIES)
+  // arg "type" and fwd should be keyword args eventually
+  //(make-xwidget 3 3 'button "oei" 31 31 nil)
+  //(xwidget-info (car xwidget-list))
+  struct xwidget *xw = allocate_xwidget ();
+  Lisp_Object val;
+  xw->type = type;
+  xw->title = title;
+  if (NILP (buffer))
+    buffer = Fcurrent_buffer ();       // no need to gcpro because
+                                        // Fcurrent_buffer doesn't
+                                        // call Feval/eval_sub.
+  else
+    buffer = Fget_buffer_create (buffer);
+  xw->buffer = buffer;
+
+  xw->height = XFASTINT (height);
+  xw->width = XFASTINT (width);
+  xw->kill_without_query = 0;
+  XSETXWIDGET (val, xw);       // set the vectorlike_header of VAL
+                                // with the correct value
+  Vxwidget_list = Fcons (val, Vxwidget_list);
+  xw->widgetwindow_osr = NULL;
+  xw->widget_osr = NULL;
+  xw->plist = Qnil;
+
+
+  if (EQ (xw->type, Qwebkit_osr))
+    {
+      block_input ();
+      xw->widgetwindow_osr = gtk_offscreen_window_new ();
+      gtk_window_resize (GTK_WINDOW (xw->widgetwindow_osr), xw->width,
+                         xw->height);
+      xw->widgetscrolledwindow_osr = NULL;     //webkit osr is the
+                                                //only scrolled
+                                                //component atm
+
+      if (EQ (xw->type, Qwebkit_osr))
+        {
+          xw->widgetscrolledwindow_osr = gtk_scrolled_window_new (NULL, NULL);
+          gtk_scrolled_window_set_min_content_height (GTK_SCROLLED_WINDOW
+                                                      (xw->
+                                                       widgetscrolledwindow_osr),
+                                                      xw->height);
+          gtk_scrolled_window_set_min_content_width (GTK_SCROLLED_WINDOW
+                                                     (xw->
+                                                      widgetscrolledwindow_osr),
+                                                     xw->width);
+          gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW
+                                          (xw->widgetscrolledwindow_osr),
+                                          GTK_POLICY_ALWAYS,
+                                          GTK_POLICY_ALWAYS);
+
+          xw->widget_osr = webkit_web_view_new ();
+          gtk_container_add (GTK_CONTAINER (xw->widgetscrolledwindow_osr),
+                             GTK_WIDGET (WEBKIT_WEB_VIEW (xw->widget_osr)));
+        }
+
+      gtk_widget_set_size_request (GTK_WIDGET (xw->widget_osr), xw->width,
+                                   xw->height);
+
+      if (EQ (xw->type, Qwebkit_osr))
+        {
+          gtk_container_add (GTK_CONTAINER (xw->widgetwindow_osr),
+                             xw->widgetscrolledwindow_osr);
+        }
+      else
+        {
+          gtk_container_add (GTK_CONTAINER (xw->widgetwindow_osr),
+                             xw->widget_osr);
+        }
+
+      gtk_widget_show (xw->widget_osr);
+      gtk_widget_show (xw->widgetwindow_osr);
+      gtk_widget_show (xw->widgetscrolledwindow_osr);
+
+      /* store some xwidget data in the gtk widgets for convenient
+         retrieval in the event handlers. */
+      g_object_set_data (G_OBJECT (xw->widget_osr), XG_XWIDGET,
+                         (gpointer) (xw));
+      g_object_set_data (G_OBJECT (xw->widgetwindow_osr), XG_XWIDGET,
+                         (gpointer) (xw));
+
+      /* signals */
+      if (EQ (xw->type, Qwebkit_osr))
+        {
+          g_signal_connect (G_OBJECT (xw->widget_osr),
+                            "document-load-finished",
+                            G_CALLBACK
+                            (webkit_document_load_finished_cb), xw);
+
+          g_signal_connect (G_OBJECT (xw->widget_osr),
+                            "download-requested",
+                            G_CALLBACK (webkit_download_cb), xw);
+
+          g_signal_connect (G_OBJECT (xw->widget_osr),
+                            "mime-type-policy-decision-requested",
+                            G_CALLBACK
+                            (webkit_mime_type_policy_typedecision_requested_cb),
+                            xw);
+
+          g_signal_connect (G_OBJECT (xw->widget_osr),
+                            "new-window-policy-decision-requested",
+                            G_CALLBACK
+                            (webkit_new_window_policy_decision_requested_cb),
+                            xw);
+
+          g_signal_connect (G_OBJECT (xw->widget_osr),
+                            "navigation-policy-decision-requested",
+                            G_CALLBACK
+                            (webkit_navigation_policy_decision_requested_cb),
+                            xw);
+        }
+
+      unblock_input ();
+
+    }
+
+  return val;
+}
+
+DEFUN ("get-buffer-xwidgets", Fget_buffer_xwidgets, Sget_buffer_xwidgets,
+       1, 1, 0,
+       doc: /* Return a list of xwidgets associated with BUFFER.
+BUFFER  may be a buffer or the name of one.  */)
+  (Lisp_Object buffer)
+{
+  Lisp_Object xw, tail, xw_list;
+
+  if (NILP (buffer))
+    return Qnil;
+  buffer = Fget_buffer (buffer);
+  if (NILP (buffer))
+    return Qnil;
+
+  xw_list = Qnil;
+
+  for (tail = Vxwidget_list; CONSP (tail); tail = XCDR (tail))
+    {
+      xw = XCAR (tail);
+      if (XWIDGETP (xw) && EQ (Fxwidget_buffer (xw), buffer))
+        xw_list = Fcons (xw, xw_list);
+    }
+  return xw_list;
+}
+
+static int
+xwidget_hidden (struct xwidget_view *xv)
+{
+  return xv->hidden;
+}
+
+
+
+static void
+xwidget_show_view (struct xwidget_view *xv)
+{
+  xv->hidden = 0;
+  gtk_widget_show (xv->widgetwindow);
+  gtk_fixed_move (GTK_FIXED (xv->emacswindow),
+                  xv->widgetwindow,
+                  xv->x + xv->clip_left,
+                  xv->y + xv->clip_top);
+}
+
+
+/* Hide an xvidget view.  */
+static void
+xwidget_hide_view (struct xwidget_view *xv)
+{
+  xv->hidden = 1;
+  gtk_fixed_move (GTK_FIXED (xv->emacswindow), xv->widgetwindow,
+                  10000, 10000);
+}
+
+
+
+/* When the off-screen webkit master view changes this signal is called.
+   It copies the bitmap from the off-screen instance.  */
+gboolean
+offscreen_damage_event (GtkWidget * widget, GdkEvent * event,
+                        gpointer xv_widget)
+{
+  // Queue a redraw of onscreen widget.
+  // There is a guard against receiving an invalid widget,
+  // which should only happen if we failed to remove the
+  // specific signal handler for the damage event.
+  if (GTK_IS_WIDGET (xv_widget))
+    gtk_widget_queue_draw (GTK_WIDGET (xv_widget));
+  else
+    printf ("Warning, offscreen_damage_event received invalid xv pointer:%p\n",
+            (void *) xv_widget);
+
+  return FALSE;
+}
+
+static void
+store_xwidget_event_string (struct xwidget *xw, const char *eventname,
+                            const char *eventstr)
+{
+  struct input_event event;
+  Lisp_Object xwl;
+  XSETXWIDGET (xwl, xw);
+  EVENT_INIT (event);
+  event.kind = XWIDGET_EVENT;
+  event.frame_or_window = Qnil;
+
+  event.arg = Qnil;
+  event.arg = Fcons (build_string (eventstr), event.arg);
+  event.arg = Fcons (xwl, event.arg);
+  event.arg = Fcons (intern (eventname), event.arg);
+  kbd_buffer_store_event (&event);
+
+}
+
+//TODO deprecated, use load-status
+void
+webkit_document_load_finished_cb (WebKitWebView * webkitwebview,
+                                  WebKitWebFrame * arg1,
+                                  gpointer data)
+{
+  struct xwidget *xw =
+    (struct xwidget *) g_object_get_data (G_OBJECT (webkitwebview),
+                                          XG_XWIDGET);
+
+  store_xwidget_event_string (xw, "document-load-finished", "");
+}
+
+gboolean
+webkit_download_cb (WebKitWebView * webkitwebview,
+                    WebKitDownload * arg1,
+                    gpointer data)
+{
+  struct xwidget *xw =
+    (struct xwidget *) g_object_get_data (G_OBJECT (webkitwebview),
+                                          XG_XWIDGET);
+  store_xwidget_event_string (xw, "download-requested",
+                              webkit_download_get_uri (arg1));
+
+  return FALSE;
+}
+
+gboolean
+webkit_mime_type_policy_typedecision_requested_cb (WebKitWebView *webView,
+                                                   WebKitWebFrame *frame,
+                                                   WebKitNetworkRequest * request,
+                                                   gchar * mimetype,
+                                                   WebKitWebPolicyDecision *policy_decision,
+                                                   gpointer user_data)
+{
+  // This function makes webkit send a download signal for all unknown
+  // mime types. TODO Defer the decision to lisp, so that its possible
+  // to make Emacs handle teext mime for instance.xs
+  if (!webkit_web_view_can_show_mime_type (webView, mimetype))
+    {
+      webkit_web_policy_decision_download (policy_decision);
+      return TRUE;
+    }
+  else
+    {
+      return FALSE;
+    }
+}
+
+
+gboolean
+webkit_new_window_policy_decision_requested_cb (WebKitWebView *webView,
+                                                WebKitWebFrame *frame,
+                                                WebKitNetworkRequest *request,
+                                                WebKitWebNavigationAction *navigation_action,
+                                                WebKitWebPolicyDecision *policy_decision,
+                                                gpointer user_data)
+{
+  struct xwidget *xw =
+    (struct xwidget *) g_object_get_data (G_OBJECT (webView), XG_XWIDGET);
+  webkit_web_navigation_action_get_original_uri (navigation_action);
+
+  store_xwidget_event_string (xw, "new-window-policy-decision-requested",
+                              webkit_web_navigation_action_get_original_uri
+                              (navigation_action));
+  return FALSE;
+}
+
+gboolean
+webkit_navigation_policy_decision_requested_cb (WebKitWebView *webView,
+                                                WebKitWebFrame *frame,
+                                                WebKitNetworkRequest *request,
+                                                WebKitWebNavigationAction *navigation_action,
+                                                WebKitWebPolicyDecision * policy_decision,
+                                                gpointer user_data)
+{
+  struct xwidget *xw =
+    (struct xwidget *) g_object_get_data (G_OBJECT (webView), XG_XWIDGET);
+  store_xwidget_event_string (xw, "navigation-policy-decision-requested",
+                              webkit_web_navigation_action_get_original_uri
+                              (navigation_action));
+  return FALSE;
+}
+
+// For gtk3 offscreen rendered widgets.
+static gboolean
+xwidget_osr_draw_cb (GtkWidget * widget, cairo_t * cr, gpointer data)
+{
+  struct xwidget *xw =
+    (struct xwidget *) g_object_get_data (G_OBJECT (widget), XG_XWIDGET);
+  struct xwidget_view *xv =
+    (struct xwidget_view *) g_object_get_data (G_OBJECT (widget),
+                                               XG_XWIDGET_VIEW);
+
+  cairo_rectangle (cr, 0, 0, xv->clip_right, xv->clip_bottom);
+  cairo_clip (cr);
+
+  if (xw->widgetscrolledwindow_osr != NULL)
+    gtk_widget_draw (xw->widgetscrolledwindow_osr, cr);
+  else
+    gtk_widget_draw (xw->widget_osr, cr);
+  return FALSE;
+}
+
+static gboolean
+xwidget_osr_event_forward (GtkWidget * widget,
+                           GdkEvent * event,
+                           gpointer user_data)
+{
+  /* Copy events that arrive at the outer widget to the offscreen widget. */
+  struct xwidget *xw =
+    (struct xwidget *) g_object_get_data (G_OBJECT (widget), XG_XWIDGET);
+  GdkEvent *eventcopy = gdk_event_copy (event);
+  eventcopy->any.window = gtk_widget_get_window (xw->widget_osr);
+
+  //TODO This might leak events. They should be deallocated later,
+  //perhaps in xwgir_event_cb
+  gtk_main_do_event (eventcopy);
+  return TRUE;                 //dont propagate this event furter
+}
+
+
+static gboolean
+xwidget_osr_event_set_embedder (GtkWidget * widget,
+                                GdkEvent * event, gpointer data)
+{
+  struct xwidget_view *xv = (struct xwidget_view *) data;
+  struct xwidget *xww = XXWIDGET (xv->model);
+  gdk_offscreen_window_set_embedder (gtk_widget_get_window
+                                     (xww->widgetwindow_osr),
+                                     gtk_widget_get_window (xv->widget));
+  return FALSE;
+}
+
+
+/* Initializes and does initial placement of an xwidget view on screen. */
+static struct xwidget_view *
+xwidget_init_view (struct xwidget *xww,
+                   struct glyph_string *s,
+                   int x, int y)
+{
+  struct xwidget_view *xv = allocate_xwidget_view ();
+  Lisp_Object val;
+
+  XSETXWIDGET_VIEW (val, xv);
+  Vxwidget_view_list = Fcons (val, Vxwidget_view_list);
+
+  XSETWINDOW (xv->w, s->w);
+  XSETXWIDGET (xv->model, xww);
+
+  if (EQ (xww->type, Qwebkit_osr))
+    {
+      xv->widget = gtk_drawing_area_new ();
+      // Expose event handling.
+      gtk_widget_set_app_paintable (xv->widget, TRUE);
+      gtk_widget_add_events (xv->widget, GDK_ALL_EVENTS_MASK);
+
+      /* Draw the view on damage-event */
+      g_signal_connect (G_OBJECT (xww->widgetwindow_osr), "damage-event",
+                        G_CALLBACK (offscreen_damage_event), xv->widget);
+
+      if (EQ (xww->type, Qwebkit_osr))
+        {
+          g_signal_connect (G_OBJECT (xv->widget), "button-press-event",
+                            G_CALLBACK (xwidget_osr_event_forward), NULL);
+          g_signal_connect (G_OBJECT (xv->widget), "button-release-event",
+                            G_CALLBACK (xwidget_osr_event_forward), NULL);
+          g_signal_connect (G_OBJECT (xv->widget), "motion-notify-event",
+                            G_CALLBACK (xwidget_osr_event_forward), NULL);
+        }
+      else
+        {
+          // xwgir debug , orthogonal to forwarding
+          g_signal_connect (G_OBJECT (xv->widget), "enter-notify-event",
+                            G_CALLBACK (xwidget_osr_event_set_embedder), xv);
+        }
+      g_signal_connect (G_OBJECT (xv->widget), "draw",
+                        G_CALLBACK (xwidget_osr_draw_cb), NULL);
+    }
+  // Widget realization.
+
+  // Make container widget 1st, and put the actual widget inside the
+  // container later.  Drawing should crop container window if necessary
+  // to handle case where xwidget is partially obscured by other Emacs
+  // windows.  Other containers than gtk_fixed where explored, but
+  // gtk_fixed had the most predictable behaviour so far.
+  xv->emacswindow = FRAME_GTK_WIDGET (s->f);
+  xv->widgetwindow = gtk_fixed_new ();
+  gtk_widget_set_has_window (xv->widgetwindow, TRUE);
+  gtk_container_add (GTK_CONTAINER (xv->widgetwindow), xv->widget);
+
+  // Store some xwidget data in the gtk widgets.
+  // The emacs frame.
+  g_object_set_data (G_OBJECT (xv->widget), XG_FRAME_DATA, (gpointer) (s->f));
+  // The xwidget.
+  g_object_set_data (G_OBJECT (xv->widget), XG_XWIDGET, (gpointer) (xww));
+  // The xwidget.
+  g_object_set_data (G_OBJECT (xv->widget), XG_XWIDGET_VIEW, (gpointer) (xv));
+  // The xwidget window.
+  g_object_set_data (G_OBJECT (xv->widgetwindow), XG_XWIDGET, (gpointer) (xww));
+  // the xwidget view.
+  g_object_set_data (G_OBJECT (xv->widgetwindow), XG_XWIDGET_VIEW,
+                     (gpointer) (xv));
+
+
+  gtk_widget_set_size_request (GTK_WIDGET (xv->widget), xww->width,
+                               xww->height);
+  gtk_widget_set_size_request (xv->widgetwindow, xww->width, xww->height);
+  gtk_fixed_put (GTK_FIXED (FRAME_GTK_WIDGET (s->f)), xv->widgetwindow, x, y);
+  xv->x = x;
+  xv->y = y;
+  gtk_widget_show_all (xv->widgetwindow);
+
+
+  return xv;
+}
+
+
+void
+x_draw_xwidget_glyph_string (struct glyph_string *s)
+{
+  /* This method is called by the redisplay engine and places the
+     xwidget on screen.  Moving and clipping is done here.  Also view
+     initialization.
+   */
+  struct xwidget *xww = s->xwidget;
+  struct xwidget_view *xv = xwidget_view_lookup (xww, s->w);
+  int clip_right;
+  int clip_bottom;
+  int clip_top;
+  int clip_left;
+
+  int x = s->x;
+  int y = s->y + (s->height / 2) - (xww->height / 2);
+  int moved = 0;
+
+  /* We do initialization here in the display loop because there is no
+     other time to know things like window placement etc.
+   */
+  xv = xwidget_init_view (xww, s, x, y);
+
+  // Calculate clipping, which is used for all manner of onscreen
+  // xwidget views.  Each widget border can get clipped by other emacs
+  // objects so there are four clipping variables.
+  clip_right =
+    min (xww->width,
+         WINDOW_RIGHT_EDGE_X (s->w) - x -
+         WINDOW_RIGHT_SCROLL_BAR_AREA_WIDTH (s->w) -
+         WINDOW_RIGHT_FRINGE_WIDTH (s->w));
+  clip_left =
+    max (0,
+         WINDOW_LEFT_EDGE_X (s->w) - x +
+         WINDOW_LEFT_SCROLL_BAR_AREA_WIDTH (s->w) +
+         WINDOW_LEFT_FRINGE_WIDTH (s->w));
+
+  clip_bottom =
+    min (xww->height,
+         WINDOW_BOTTOM_EDGE_Y (s->w) - WINDOW_MODE_LINE_HEIGHT (s->w) - y);
+  clip_top = max (0, WINDOW_TOP_EDGE_Y (s->w) - y);
+
+  // We are conserned with movement of the onscreen area. The area
+  // might sit still when the widget actually moves.  This happens
+  // when an Emacs window border moves across a widget window. So, if
+  // any corner of the outer widget clipping window moves, that counts
+  // as movement here, even if it looks like no movement happens
+  // because the widget sits still inside the clipping area.  The
+  // widget can also move inside the clipping area, which happens
+  // later
+  moved = (xv->x + xv->clip_left != x + clip_left)
+    || ((xv->y + xv->clip_top) != (y + clip_top));
+  xv->x = x;
+  xv->y = y;
+  if (moved) // Has it moved?
+    {
+          gtk_fixed_move (GTK_FIXED (FRAME_GTK_WIDGET (s->f)),
+                          xv->widgetwindow, x + clip_left, y + clip_top);
+    }
+  // Clip the widget window if some parts happen to be outside
+  // drawable area. An Emacs window is not a gtk window. A gtk window
+  // covers the entire frame. Clipping might have changed even if we
+  // havent actualy moved, we try figure out when we need to reclip
+  // for real.
+  if ((xv->clip_right != clip_right)
+      || (xv->clip_bottom != clip_bottom)
+      || (xv->clip_top != clip_top) || (xv->clip_left != clip_left))
+    {
+      gtk_widget_set_size_request (xv->widgetwindow, clip_right + clip_left,
+                                   clip_bottom + clip_top);
+      gtk_fixed_move (GTK_FIXED (xv->widgetwindow), xv->widget, -clip_left,
+                      -clip_top);
+
+      xv->clip_right = clip_right;
+      xv->clip_bottom = clip_bottom;
+      xv->clip_top = clip_top;
+      xv->clip_left = clip_left;
+    }
+  // If emacs wants to repaint the area where the widget lives, queue
+  // a redraw. It seems its possible to get out of sync with emacs
+  // redraws so emacs background sometimes shows up instead of the
+  // xwidgets background. It's just a visual glitch though.
+  if (!xwidget_hidden (xv))
+    {
+      gtk_widget_queue_draw (xv->widgetwindow);
+      gtk_widget_queue_draw (xv->widget);
+    }
+}
+
+
+// Macro that checks WEBKIT_IS_WEB_VIEW(xw->widget_osr) first
+#define WEBKIT_FN_INIT()                        \
+  struct xwidget* xw; \
+  CHECK_XWIDGET (xwidget); \
+ if (NILP (xwidget)) {printf("ERROR xwidget nil\n"); return Qnil;};    \
+  xw = XXWIDGET (xwidget);                                                    \
+  if (NULL == xw) printf("ERROR xw is 0\n");                               \
+  if ((NULL == xw->widget_osr) || !WEBKIT_IS_WEB_VIEW(xw->widget_osr)){  \
+    printf ("ERROR xw->widget_osr does not hold a webkit instance\n");\
+    return Qnil;\
+  };
+
+
+DEFUN ("xwidget-webkit-goto-uri",
+       Fxwidget_webkit_goto_uri, Sxwidget_webkit_goto_uri,
+       2, 2, 0,
+       doc: /* Make the xwidget webkit instance referenced by XWIDGET
+browse URI. */)
+  (Lisp_Object xwidget, Lisp_Object uri)
+{
+  WEBKIT_FN_INIT ();
+  CHECK_STRING (uri);
+  webkit_web_view_load_uri (WEBKIT_WEB_VIEW (xw->widget_osr), SSDATA (uri));
+  return Qnil;
+}
+
+
+DEFUN ("xwidget-webkit-execute-script",
+       Fxwidget_webkit_execute_script, Sxwidget_webkit_execute_script,
+       2, 2, 0,
+       doc: /* Make the Webkit XWIDGET execute javascript SCRIPT.  */)
+  (Lisp_Object xwidget, Lisp_Object script)
+{
+  WEBKIT_FN_INIT ();
+  CHECK_STRING (script);
+  webkit_web_view_execute_script (WEBKIT_WEB_VIEW (xw->widget_osr),
+                                  SSDATA (script));
+  return Qnil;
+}
+
+DEFUN ("xwidget-webkit-get-title",
+       Fxwidget_webkit_get_title, Sxwidget_webkit_get_title,
+       1, 1, 0,
+       doc: /* Returns the title from the Webkit instance in XWIDGET.
+This can be used to work around the lack of a return value from the
+exec method.  */ )
+  (Lisp_Object xwidget)
+{
+  // TODO support multibyte strings
+  WEBKIT_FN_INIT ();
+  const gchar *str =
+    webkit_web_view_get_title (WEBKIT_WEB_VIEW (xw->widget_osr));
+  if (str == 0)
+    {
+      // TODO maybe return Qnil instead. I suppose webkit returns
+      // nullpointer when doc is not properly loaded or something
+      return build_string ("");
+    }
+  return build_string (str);
+}
+
+DEFUN ("xwidget-resize", Fxwidget_resize, Sxwidget_resize, 3, 3, 0,
+       doc: /* Resize XWIDGET.  NEW_WIDTH NEW_HEIGHT defines the new
+size. */ )
+  (Lisp_Object xwidget, Lisp_Object new_width, Lisp_Object new_height)
+{
+  CHECK_XWIDGET (xwidget);
+  struct xwidget *xw = XXWIDGET (xwidget);
+  struct xwidget_view *xv;
+  int w, h;
+
+  CHECK_NUMBER (new_width);
+  CHECK_NUMBER (new_height);
+  w = XFASTINT (new_width);
+  h = XFASTINT (new_height);
+
+  xw->width = w;
+  xw->height = h;
+  // If there is a offscreen widget resize it 1st.
+  if (xw->widget_osr)
+    {
+      gtk_widget_set_size_request (GTK_WIDGET (xw->widget_osr),
+                                   xw->width, xw->height);     //minimum size
+      gtk_window_resize (GTK_WINDOW (xw->widgetwindow_osr), xw->width,
+                         xw->height);
+      gtk_scrolled_window_set_min_content_height (GTK_SCROLLED_WINDOW
+                                                  (xw->
+                                                   widgetscrolledwindow_osr),
+                                                  xw->height);
+      gtk_scrolled_window_set_min_content_width (GTK_SCROLLED_WINDOW
+                                                 (xw->
+                                                  widgetscrolledwindow_osr),
+                                                 xw->width);
+
+      gtk_container_resize_children (GTK_CONTAINER (xw->widgetwindow_osr));
+
+    }
+
+  for (Lisp_Object tail = Vxwidget_view_list; CONSP (tail); tail = XCDR (tail))
+    {
+      if (XWIDGET_VIEW_P (XCAR (tail)))
+        {
+          xv = XXWIDGET_VIEW (XCAR (tail));
+          if (XXWIDGET (xv->model) == xw)
+              gtk_widget_set_size_request (GTK_WIDGET (xv->widget), xw->width,
+                                           xw->height);
+        }
+    }
+
+  return Qnil;
+}
+
+
+
+DEFUN ("xwidget-set-adjustment",
+       Fxwidget_set_adjustment, Sxwidget_set_adjustment, 4, 4, 0,
+       doc: /* Set native scrolling for XWIDGET. AXIS can be 'vertical or
+'horizontal. If RELATIVE is t, scroll relative, otherwise absolutely.
+VALUE is the amount to scroll, either relatively or absolutely.  */)
+  (Lisp_Object xwidget, Lisp_Object axis, Lisp_Object relative,
+   Lisp_Object value)
+{
+  CHECK_XWIDGET (xwidget);
+  struct xwidget *xw = XXWIDGET (xwidget);
+  GtkAdjustment *adjustment;
+  float final_value = 0.0;
+
+  adjustment =
+    gtk_scrolled_window_get_vadjustment (GTK_SCROLLED_WINDOW
+                                         (xw->widgetscrolledwindow_osr));
+  if (EQ (Qvertical, axis))
+    {
+      adjustment =
+        gtk_scrolled_window_get_vadjustment (GTK_SCROLLED_WINDOW
+                                             (xw->widgetscrolledwindow_osr));
+    }
+  if (EQ (Qhorizontal, axis))
+    {
+      adjustment =
+        gtk_scrolled_window_get_hadjustment (GTK_SCROLLED_WINDOW
+                                             (xw->widgetscrolledwindow_osr));
+    }
+
+  if (EQ (Qt, relative))
+    {
+      final_value = gtk_adjustment_get_value (adjustment) + XFASTINT (value);
+    }
+  else
+    {
+      final_value = 0.0 + XFASTINT (value);
+    }
+
+  gtk_adjustment_set_value (adjustment, final_value);
+
+  return Qnil;
+}
+
+
+DEFUN ("xwidget-size-request",
+       Fxwidget_size_request, Sxwidget_size_request,
+       1, 1, 0,
+       doc: /* Return the desired size of the XWIDGET.
+
+This can be used to read the xwidget desired size, and resizes the
+Emacs allocated area accordingly.  */)
+  (Lisp_Object xwidget)
+{
+  CHECK_XWIDGET (xwidget);
+  GtkRequisition requisition;
+  Lisp_Object rv;
+  gtk_widget_size_request (XXWIDGET (xwidget)->widget_osr, &requisition);
+  rv = Qnil;
+  rv = Fcons (make_number (requisition.height), rv);
+  rv = Fcons (make_number (requisition.width), rv);
+  return rv;
+
+}
+
+DEFUN ("xwidgetp",
+       Fxwidgetp, Sxwidgetp,
+       1, 1, 0,
+       doc: /* Return t if OBJECT is a xwidget.  */)
+  (Lisp_Object object)
+{
+  return XWIDGETP (object) ? Qt : Qnil;
+}
+
+DEFUN ("xwidget-view-p",
+       Fxwidget_view_p, Sxwidget_view_p,
+       1, 1, 0,
+       doc: /* Return t if OBJECT is a xwidget-view.  */)
+  (Lisp_Object object)
+{
+  return XWIDGET_VIEW_P (object) ? Qt : Qnil;
+}
+
+DEFUN ("xwidget-info",
+       Fxwidget_info, Sxwidget_info,
+       1, 1, 0,
+       doc: /* Return XWIDGET properties in a vector.  Currently [TYPE
+TITLE WIDTH HEIGHT]. */)
+  (Lisp_Object xwidget)
+{
+  CHECK_XWIDGET (xwidget);
+  Lisp_Object info, n;
+  struct xwidget *xw = XXWIDGET (xwidget);
+
+  info = Fmake_vector (make_number (4), Qnil);
+  ASET (info, 0, xw->type);
+  ASET (info, 1, xw->title);
+  XSETFASTINT (n, xw->width);
+  ASET (info, 2, n);
+  XSETFASTINT (n, xw->height);
+  ASET (info, 3, n);
+
+  return info;
+}
+
+DEFUN ("xwidget-view-info",
+       Fxwidget_view_info, Sxwidget_view_info,
+       1, 1, 0,
+       doc: /* Return properties of XWIDGET-VIEW in a vector.
+Currently [X Y CLIP_RIGHT CLIP_BOTTOM CLIP_TOP CLIP_LEFT] */)
+  (Lisp_Object xwidget_view)
+{
+  CHECK_XWIDGET_VIEW (xwidget_view);
+  struct xwidget_view *xv = XXWIDGET_VIEW (xwidget_view);
+  Lisp_Object info;
+
+  info = Fmake_vector (make_number (6), Qnil);
+  ASET (info, 0, make_number (xv->x));
+  ASET (info, 1, make_number (xv->y));
+  ASET (info, 2, make_number (xv->clip_right));
+  ASET (info, 3, make_number (xv->clip_bottom));
+  ASET (info, 4, make_number (xv->clip_top));
+  ASET (info, 5, make_number (xv->clip_left));
+
+  return info;
+}
+
+DEFUN ("xwidget-view-model",
+       Fxwidget_view_model, Sxwidget_view_model,
+       1, 1, 0,
+       doc:  /* Return the model associated with XWIDGET-VIEW. */)
+  (Lisp_Object xwidget_view)
+{
+  CHECK_XWIDGET_VIEW (xwidget_view);
+  return XXWIDGET_VIEW (xwidget_view)->model;
+}
+
+DEFUN ("xwidget-view-window",
+       Fxwidget_view_window, Sxwidget_view_window,
+       1, 1, 0,
+       doc:  /* Return the window of XWIDGET-VIEW. */)
+  (Lisp_Object xwidget_view)
+{
+  CHECK_XWIDGET_VIEW (xwidget_view);
+  return XXWIDGET_VIEW (xwidget_view)->w;
+}
+
+
+DEFUN ("delete-xwidget-view",
+       Fdelete_xwidget_view, Sdelete_xwidget_view,
+       1, 1, 0,
+       doc:  /* Delete the XWIDGET-VIEW. */)
+  (Lisp_Object xwidget_view)
+{
+  CHECK_XWIDGET_VIEW (xwidget_view);
+  struct xwidget_view *xv = XXWIDGET_VIEW (xwidget_view);
+  gtk_widget_destroy (xv->widgetwindow);
+  Vxwidget_view_list = Fdelq (xwidget_view, Vxwidget_view_list);
+  // xv->model still has signals pointing to the view. There can be
+  // several views. Find the matching signals and delete them all.
+  g_signal_handlers_disconnect_matched  (XXWIDGET (xv->model)->widgetwindow_osr,
+                                         G_SIGNAL_MATCH_DATA,
+                                         0, 0, 0, 0,
+                                         xv->widget);
+  return Qnil;
+}
+
+DEFUN ("xwidget-view-lookup",
+       Fxwidget_view_lookup, Sxwidget_view_lookup,
+       1, 2, 0,
+       doc: /* Return the xwidget-view associated with XWIDGET in
+WINDOW if specified, otherwise it uses the selected window. Return nil
+if no association is found.  */)
+  (Lisp_Object xwidget, Lisp_Object window)
+{
+  CHECK_XWIDGET (xwidget);
+
+  if (NILP (window))
+    window = Fselected_window ();
+  CHECK_WINDOW (window);
+
+  for (Lisp_Object tail = Vxwidget_view_list; CONSP (tail);
+       tail = XCDR (tail))
+    {
+      Lisp_Object xwidget_view = XCAR (tail);
+      if (EQ (Fxwidget_view_model (xwidget_view), xwidget)
+          && EQ (Fxwidget_view_window (xwidget_view), window))
+        return xwidget_view;
+    }
+
+  return Qnil;
+}
+
+DEFUN ("xwidget-plist",
+       Fxwidget_plist, Sxwidget_plist,
+       1, 1, 0,
+       doc: /* Return the plist of XWIDGET.  */)
+  (register Lisp_Object xwidget)
+{
+  CHECK_XWIDGET (xwidget);
+  return XXWIDGET (xwidget)->plist;
+}
+
+DEFUN ("xwidget-buffer",
+       Fxwidget_buffer, Sxwidget_buffer,
+       1, 1, 0,
+       doc: /* Return the buffer of XWIDGET.  */)
+  (register Lisp_Object xwidget)
+{
+  CHECK_XWIDGET (xwidget);
+  return XXWIDGET (xwidget)->buffer;
+}
+
+DEFUN ("set-xwidget-plist",
+       Fset_xwidget_plist, Sset_xwidget_plist,
+       2, 2, 0,
+       doc: /* Replace the plist of XWIDGET with PLIST.
+Returns PLIST.  */)
+  (register Lisp_Object xwidget, Lisp_Object plist)
+{
+  CHECK_XWIDGET (xwidget);
+  CHECK_LIST (plist);
+
+  XXWIDGET (xwidget)->plist = plist;
+  return plist;
+}
+
+DEFUN ("set-xwidget-query-on-exit-flag",
+       Fset_xwidget_query_on_exit_flag, Sset_xwidget_query_on_exit_flag,
+       2, 2, 0,
+       doc: /* Specify if query is needed for XWIDGET when
+Emacs is exited.  If the second argument FLAG is non-nil, Emacs will
+queries the user before exiting or killing a buffer if XWIDGET is
+running.  This function returns FLAG. */)
+  (Lisp_Object xwidget, Lisp_Object flag)
+{
+  CHECK_XWIDGET (xwidget);
+  XXWIDGET (xwidget)->kill_without_query = NILP (flag);
+  return flag;
+}
+
+DEFUN ("xwidget-query-on-exit-flag",
+       Fxwidget_query_on_exit_flag, Sxwidget_query_on_exit_flag,
+       1, 1, 0,
+       doc: /* Return the current value of query-on-exit
+flag for XWIDGET. */)
+  (Lisp_Object xwidget)
+{
+  CHECK_XWIDGET (xwidget);
+  return (XXWIDGET (xwidget)->kill_without_query ? Qnil : Qt);
+}
+
+void
+syms_of_xwidget (void)
+{
+
+  defsubr (&Smake_xwidget);
+  defsubr (&Sxwidgetp);
+  DEFSYM (Qxwidgetp, "xwidgetp");
+  defsubr (&Sxwidget_view_p);
+  DEFSYM (Qxwidget_view_p, "xwidget-view-p");
+  defsubr (&Sxwidget_info);
+  defsubr (&Sxwidget_view_info);
+  defsubr (&Sxwidget_resize);
+  defsubr (&Sget_buffer_xwidgets);
+  defsubr (&Sxwidget_view_model);
+  defsubr (&Sxwidget_view_window);
+  defsubr (&Sxwidget_view_lookup);
+  defsubr (&Sxwidget_query_on_exit_flag);
+  defsubr (&Sset_xwidget_query_on_exit_flag);
+
+#ifdef HAVE_WEBKIT_OSR
+  defsubr (&Sxwidget_webkit_goto_uri);
+  defsubr (&Sxwidget_webkit_execute_script);
+  defsubr (&Sxwidget_webkit_get_title);
+  DEFSYM (Qwebkit_osr, "webkit-osr");
+#endif
+
+  defsubr (&Sxwidget_size_request);
+  defsubr (&Sdelete_xwidget_view);
+
+  defsubr (&Sxwidget_plist);
+  defsubr (&Sxwidget_buffer);
+  defsubr (&Sset_xwidget_plist);
+
+  defsubr (&Sxwidget_set_adjustment);
+
+  DEFSYM (Qxwidget, "xwidget");
+
+  DEFSYM (QCxwidget, ":xwidget");
+  DEFSYM (QCtitle, ":title");
+
+  /* Do not forget to update the docstring of make-xwidget if you add
+     new types. */
+
+  DEFSYM (Qvertical, "vertical");
+  DEFSYM (Qhorizontal, "horizontal");
+
+  DEFSYM (QCplist, ":plist");
+
+  DEFVAR_LISP ("xwidget-list", Vxwidget_list,
+               doc:    /* xwidgets list.  */);
+  Vxwidget_list = Qnil;
+
+  DEFVAR_LISP ("xwidget-view-list", Vxwidget_view_list,
+             doc:      /* xwidget views list.  */);
+  Vxwidget_view_list = Qnil;
+
+  Fprovide (intern ("xwidget-internal"), Qnil);
+
+}
+
+
+/* Value is non-zero if OBJECT is a valid Lisp xwidget specification.  A
+   valid xwidget specification is a list whose car is the symbol
+   `xwidget', and whose rest is a property list.  The property list must
+   contain a value for key `:type'.  That value must be the name of a
+   supported xwidget type.  The rest of the property list depends on the
+   xwidget type.  */
+
+bool
+valid_xwidget_spec_p (Lisp_Object object)
+{
+  int valid_p = false;
+
+  if (CONSP (object) && EQ (XCAR (object), Qxwidget))
+      valid_p = true;
+
+  return valid_p;
+}
+
+
+
+/* Find a value associated with key in spec.  */
+Lisp_Object
+xwidget_spec_value (Lisp_Object spec, Lisp_Object key, int *found)
+{
+  Lisp_Object tail;
+
+  eassert (valid_xwidget_spec_p (spec));
+
+  for (tail = XCDR (spec);
+       CONSP (tail) && CONSP (XCDR (tail)); tail = XCDR (XCDR (tail)))
+    {
+      if (EQ (XCAR (tail), key))
+        {
+          if (found)
+            *found = 1;
+          return XCAR (XCDR (tail));
+        }
+    }
+
+  if (found)
+    *found = 0;
+  return Qnil;
+}
+
+
+void
+xwidget_view_delete_all_in_window (struct window *w)
+{
+  struct xwidget_view *xv = NULL;
+  for (Lisp_Object tail = Vxwidget_view_list; CONSP (tail);
+       tail = XCDR (tail))
+    {
+      if (XWIDGET_VIEW_P (XCAR (tail)))
+        {
+          xv = XXWIDGET_VIEW (XCAR (tail));
+          if (XWINDOW (xv->w) == w)
+            {
+              Fdelete_xwidget_view (XCAR (tail));
+            }
+        }
+    }
+}
+
+struct xwidget_view *
+xwidget_view_lookup (struct xwidget *xw, struct window *w)
+{
+  Lisp_Object xwidget, window, ret;
+  XSETXWIDGET (xwidget, xw);
+  XSETWINDOW (window, w);
+
+  ret = Fxwidget_view_lookup (xwidget, window);
+
+  return EQ (ret, Qnil) ? NULL : XXWIDGET_VIEW (ret);
+}
+
+struct xwidget *
+lookup_xwidget (Lisp_Object spec)
+{
+  /* When a xwidget lisp spec is found initialize the C struct that is
+     used in the C code.  This is done by redisplay so values change
+     if the spec changes.  So, take special care of one-shot events.
+   */
+  int found = 0;
+  Lisp_Object value;
+  struct xwidget *xw;
+
+  value = xwidget_spec_value (spec, QCxwidget, &found);
+  xw = XXWIDGET (value);
+
+  return xw;
+}
+
+/* Set up detection of touched xwidget*/
+void
+xwidget_start_redisplay (void)
+{
+  for (Lisp_Object tail = Vxwidget_view_list; CONSP (tail);
+       tail = XCDR (tail))
+    {
+      if (XWIDGET_VIEW_P (XCAR (tail)))
+        XXWIDGET_VIEW (XCAR (tail))->redisplayed = 0;
+    }
+}
+
+/* The xwidget was touched during redisplay, so it isn't a candidate
+   for hiding.  */
+void
+xwidget_touch (struct xwidget_view *xv)
+{
+  xv->redisplayed = 1;
+}
+
+static int
+xwidget_touched (struct xwidget_view *xv)
+{
+  return xv->redisplayed;
+}
+
+/* Redisplay has ended, now we should hide untouched xwidgets
+*/
+void
+xwidget_end_redisplay (struct window *w, struct glyph_matrix *matrix)
+{
+
+  int i;
+  int area;
+
+  xwidget_start_redisplay ();
+  // Iterate desired glyph matrix of window here, hide gtk widgets
+  // not in the desired matrix.
+
+  // This only takes care of xwidgets in active windows.  if a window
+  // goes away from screen xwidget views wust be deleted
+
+  //  dump_glyph_matrix (matrix, 2);
+  for (i = 0; i < matrix->nrows; ++i)
+    {
+      //    dump_glyph_row (MATRIX_ROW (matrix, i), i, glyphs);
+      struct glyph_row *row;
+      row = MATRIX_ROW (matrix, i);
+      if (row->enabled_p != 0)
+        {
+          for (area = LEFT_MARGIN_AREA; area < LAST_AREA; ++area)
+            {
+              struct glyph *glyph = row->glyphs[area];
+              struct glyph *glyph_end = glyph + row->used[area];
+              for (; glyph < glyph_end; ++glyph)
+                {
+                  if (glyph->type == XWIDGET_GLYPH)
+                    {
+                      /*
+                        The only call to xwidget_end_redisplay is in dispnew
+                         xwidget_end_redisplay (w->current_matrix);
+                       */
+                      xwidget_touch (xwidget_view_lookup (glyph->u.xwidget,
+                                                          w));
+                    }
+                }
+            }
+        }
+    }
+
+  for (Lisp_Object tail = Vxwidget_view_list; CONSP (tail);
+       tail = XCDR (tail))
+    {
+      if (XWIDGET_VIEW_P (XCAR (tail)))
+        {
+          struct xwidget_view *xv = XXWIDGET_VIEW (XCAR (tail));
+
+          // "touched" is only meaningful for the current window, so
+          // disregard other views.
+          if (XWINDOW (xv->w) == w)
+            {
+              if (xwidget_touched (xv))
+                xwidget_show_view (xv);
+              else
+                xwidget_hide_view (xv);
+            }
+        }
+    }
+}
+
+/* Kill all xwidget in BUFFER. */
+void
+kill_buffer_xwidgets (Lisp_Object buffer)
+{
+  Lisp_Object tail, xwidget;
+  for (tail = Fget_buffer_xwidgets (buffer); CONSP (tail); tail = XCDR (tail))
+    {
+      xwidget = XCAR (tail);
+      Vxwidget_list = Fdelq (xwidget, Vxwidget_list);
+      /* TODO free the GTK things in xw */
+      {
+        CHECK_XWIDGET (xwidget);
+        struct xwidget *xw = XXWIDGET (xwidget);
+        if (xw->widget_osr && xw->widgetwindow_osr)
+          {
+            gtk_widget_destroy (xw->widget_osr);
+            gtk_widget_destroy (xw->widgetwindow_osr);
+          }
+      }
+    }
+}
diff --git a/src/xwidget.h b/src/xwidget.h
new file mode 100644 (file)
index 0000000..493000c
--- /dev/null
@@ -0,0 +1,135 @@
+/* Support for embedding graphical components in a buffer.
+
+Copyright (C) 2011-2015 Free Software Foundation, Inc.
+
+This file is part of GNU Emacs.
+
+GNU Emacs is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+GNU Emacs is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.  */
+
+#ifndef XWIDGET_H_INCLUDED
+#define XWIDGET_H_INCLUDED
+
+void x_draw_xwidget_glyph_string (struct glyph_string *s);
+void syms_of_xwidget (void);
+
+//extern Lisp_Object Qxwidget;
+
+
+bool valid_xwidget_spec_p (Lisp_Object object);
+
+#include <gtk/gtk.h>
+
+
+/*
+each xwidget instance/model is described by this struct.
+
+lisp pseudovector.
+
+
+ */
+struct xwidget
+{
+  struct vectorlike_header header;
+  Lisp_Object plist;           //auxilliary data
+  Lisp_Object type;            //the widget type
+  Lisp_Object buffer;          //buffer where xwidget lives
+  Lisp_Object title;           //a title that is used for button labels for instance
+
+  //here ends the lisp part.
+  //"height" is the marker field
+  int height;
+  int width;
+
+  //for offscreen widgets, unused if not osr
+  GtkWidget *widget_osr;
+  GtkWidget *widgetwindow_osr;
+  //this is used if the widget (webkit) is to be wrapped in a scrolled window,
+  GtkWidget *widgetscrolledwindow_osr;
+  /* Non-nil means kill silently if Emacs is exited. */
+  unsigned int kill_without_query:1;
+
+};
+
+
+//struct for each xwidget view
+struct xwidget_view
+{
+  struct vectorlike_header header;
+  Lisp_Object model;
+  Lisp_Object w;
+
+  //here ends the lisp part.
+  //"redisplayed" is the marker field
+  int redisplayed;             //if touched by redisplay
+
+  int hidden;                  //if the "live" instance isnt drawn
+
+  GtkWidget *widget;
+  GtkWidget *widgetwindow;
+  GtkWidget *emacswindow;
+  int x;
+  int y;
+  int clip_right;
+  int clip_bottom;
+  int clip_top;
+  int clip_left;
+
+
+  long handler_id;
+};
+
+/* Test for xwidget pseudovector*/
+#define XWIDGETP(x) PSEUDOVECTORP (x, PVEC_XWIDGET)
+#define XXWIDGET(a) (eassert (XWIDGETP(a)), \
+                     (struct xwidget *) XUNTAG(a, Lisp_Vectorlike))
+
+#define CHECK_XWIDGET(x) \
+  CHECK_TYPE (XWIDGETP (x), Qxwidgetp, x)
+
+/* Test for xwidget_view pseudovector */
+#define XWIDGET_VIEW_P(x) PSEUDOVECTORP (x, PVEC_XWIDGET_VIEW)
+#define XXWIDGET_VIEW(a) (eassert (XWIDGET_VIEW_P(a)), \
+                          (struct xwidget_view *) XUNTAG(a, Lisp_Vectorlike))
+
+#define CHECK_XWIDGET_VIEW(x) \
+  CHECK_TYPE (XWIDGET_VIEW_P (x), Qxwidget_view_p, x)
+
+struct xwidget_type
+{
+  /* A symbol uniquely identifying the xwidget type, */
+  Lisp_Object *type;
+
+  /* Check that SPEC is a valid image specification for the given
+     image type.  Value is non-zero if SPEC is valid.  */
+  int (*valid_p) (Lisp_Object spec);
+
+  /* Next in list of all supported image types.  */
+  struct xwidget_type *next;
+};
+
+
+struct xwidget *xwidget_from_id (int id);
+
+void xwidget_start_redisplay (void);
+void xwidget_end_redisplay (struct window *w, struct glyph_matrix *matrix);
+
+void xwidget_touch (struct xwidget_view *xw);
+
+struct xwidget *lookup_xwidget (Lisp_Object spec);
+#define XG_XWIDGET "emacs_xwidget"
+#define XG_XWIDGET_VIEW "emacs_xwidget_view"
+void xwidget_view_delete_all_in_window (struct window *w);
+
+void kill_buffer_xwidgets (Lisp_Object buffer);
+#endif /* XWIDGET_H_INCLUDED */