]> code.delx.au - gnu-emacs/commitdiff
Merge branch 'master' into xwidget
authorJoakim Verona <joakim@verona.se>
Sat, 31 Jan 2015 23:37:46 +0000 (00:37 +0100)
committerJoakim Verona <joakim@verona.se>
Sat, 31 Jan 2015 23:37:46 +0000 (00:37 +0100)
26 files changed:
README.xwidget [new file with mode: 0644]
configure.ac
lisp/emacs-parallel/README.org [new file with mode: 0644]
lisp/emacs-parallel/parallel-remote.el [new file with mode: 0644]
lisp/emacs-parallel/parallel-xwidget.el [new file with mode: 0644]
lisp/emacs-parallel/parallel.el [new file with mode: 0644]
lisp/net/browse-url.el
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]
test/automated/xwidget-tests.el [new file with mode: 0644]
test/xwidget-test-manual.el [new file with mode: 0644]

diff --git a/README.xwidget b/README.xwidget
new file mode 100644 (file)
index 0000000..cfde411
--- /dev/null
@@ -0,0 +1,2 @@
+-*-org-*-
+Please see https://github.com/jave/xwidget-aux for documentation.
index 5776e4ef8ed9d5352bfc4b90d000e584941116bf..f4fcf529498c896c9d8ebebc7a371cf5f692aaf0 100644 (file)
@@ -374,6 +374,8 @@ otherwise for the first of `gfile' or `inotify' that is usable.])
  ],
  [with_file_notification=$with_features])
 
+OPTION_DEFAULT_OFF([xwidgets],[enable use of some gtk widgets it 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
@@ -2527,6 +2529,41 @@ if test "${HAVE_GTK}" = "yes"; then
  term_header=gtkutil.h
 fi
 
+
+HAVE_XWIDGETS=no
+HAVE_WEBKIT=no
+HAVE_GIR=no
+
+if test "${with_xwidgets}" != "no" && test "${USE_GTK_TOOLKIT}" = "GTK3"  && test "$window_system" != "none" ; then
+   echo "xwidgets enabled, checking webkit, and others"
+   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
+
+
+#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
+
+
+fi
+
 CFLAGS=$OLD_CFLAGS
 LIBS=$OLD_LIBS
 
@@ -4806,7 +4843,7 @@ TOOLKIT_LIBW=
 case "$USE_X_TOOLKIT" in
   MOTIF) TOOLKIT_LIBW="$MOTIF_LIBW" ;;
   LUCID) TOOLKIT_LIBW="$LUCID_LIBW" ;;
-  none) test "x$HAVE_GTK" = "xyes" && TOOLKIT_LIBW="$GTK_LIBS" ;;
+  none) test "x$HAVE_GTK" = "xyes" && TOOLKIT_LIBW="$GTK_LIBS -lXcomposite" ;;
 esac
 AC_SUBST(TOOLKIT_LIBW)
 
@@ -5127,6 +5164,10 @@ echo "  Does Emacs use -lxft?                                   ${HAVE_XFT}"
 echo "  Does Emacs directly use zlib?                           ${HAVE_ZLIB}"
 
 echo "  Does Emacs use toolkit scroll bars?                     ${USE_TOOLKIT_SCROLL_BARS}"
+
+echo "  Does Emacs support Xwidgets?                            ${HAVE_XWIDGETS}"
+echo "       Does xwidgets support webkit(requires gtk3)?       ${HAVE_WEBKIT}"
+echo "       Does xwidgets support gobject introspection?       ${HAVE_GIR}"
 echo
 
 if test -n "${EMACSDATA}"; then
diff --git a/lisp/emacs-parallel/README.org b/lisp/emacs-parallel/README.org
new file mode 100644 (file)
index 0000000..7430505
--- /dev/null
@@ -0,0 +1,147 @@
+* Emacs Parallel
+
+  Emacs Parallel is yet another library to simulate parallel
+  computations in Emacs (because it lacks threads support in Elisp).
+
+* STARTED HowTo
+
+  You can execute a simple function a retrive the result like this:
+  #+BEGIN_SRC emacs-lisp
+    (parallel-get-result (parallel-start (lambda () (* 42 42))))
+    ⇒ 1764
+  #+END_SRC
+
+  Though you won't benefit from the parallelism because
+  ~parallel-get-result~ is blocking, that is it waits for the function
+  to be executed.
+
+  So you can use define a callback to be called when the function is
+  finished:
+  #+BEGIN_SRC emacs-lisp
+    (parallel-start (lambda () (sleep-for 4.2) "Hello World")
+                    :post-exec (lambda (results _status)
+                                 (message (first results))))
+    ⊣ Hello World
+  #+END_SRC
+
+  Here, why ~(first results)~ and not ~result~? Because you can send
+  data from the remote instance while it's running with
+  ~parallel-remote-send~:
+  #+BEGIN_SRC emacs-lisp
+    (parallel-start (lambda ()
+                      (parallel-remote-send "Hello")
+                      (sleep-for 4.2)
+                      "World")
+                    :post-exec (lambda (results _status)
+                                 (message "%s"
+                                          (mapconcat #'identity (reverse results) " "))))
+    ⊣ Hello World
+  #+END_SRC
+  As you may have noticed the results are pushed in a list, so the
+  first element is the result returned by the function called, the
+  second is the last piece of data send, and so on...
+
+  And of course you can execute some code when you receive data from
+  the remote instance:
+  #+BEGIN_SRC emacs-lisp
+    (parallel-start (lambda ()
+                      (parallel-remote-send 42)
+                      (sleep-for 4.2)         ; heavy computation to compute PI
+                      pi)
+                    :on-event (lambda (data)
+                                (message "Received %S" data)))
+    ⊣ Received 42
+    ⊣ Received 3.141592653589793
+  #+END_SRC
+
+  Because the function is executed in another Emacs instance (in Batch
+  Mode by default), the environment isn't the same. However you can
+  send some data with the ~env~ parameter:
+  #+BEGIN_SRC emacs-lisp
+    (let ((a 42)
+          (b 12))
+      (parallel-get-result (parallel-start (lambda (a b) (+ a b))
+                                           :env (list a b))))
+    ⇒ 54
+  #+END_SRC
+
+  By default, the remote Emacs instance is exited when the function is
+  executed, but you can keep it running with the
+  ~:continue-when-executed~ option and send new code to be executed
+  with ~parellel-send~.
+  #+BEGIN_SRC emacs-lisp
+    (let ((task (parallel-start (lambda () 42)
+                                :continue-when-executed t)))
+      (sleep-for 4.2)
+      (parallel-send task (lambda () (setq parallel-continue-when-executed nil) 12))
+      (parallel-get-results task))
+    ⇒ (12 42)
+  #+END_SRC
+
+  As you can see, to stop the remote instance you have to set the
+  variable ~parallel-continue-when-executed~ to nil.
+
+* Modules
+  
+** Parallel XWidget
+
+   [[http://www.emacswiki.org/emacs/EmacsXWidgets][Emacs XWidget]] is an experimental branch which permits to embed GTK+
+   widget inside Emacs buffers. For instance, it is possible to use it
+   to render an HTML page using the webkit engine within an Emacs
+   buffer.
+
+   With this module, you can configure your "main" Emacs to use
+   another one to render web pages.
+
+   Let's assume that you've cloned [[https://github.com/jave/xwidget-emacs][the Emacs XWidget repository]] in
+   ~$HOME/src/emacs-xwidget/~. Once you've compiled it, an Emacs
+   executable is available ~$HOME/src/emacs-xwidget/src/emacs~.
+
+   Configure ~parallel-xwidget~ to use it:
+   #+BEGIN_SRC emacs-lisp
+     (setq parallel-xwidget-config (list :emacs-path
+                                         (concat (getenv "HOME")
+                                                 "/src/emacs-xwidget/src/emacs")))
+   #+END_SRC
+
+   Then configure your current Emacs to use it:
+   #+BEGIN_SRC emacs-lisp
+     (setq browse-url-browser-function 'parallel-xwidget-browse-url)
+   #+END_SRC
+
+   You can check it out with M-x browse-url RET google.com RET.
+   
+* Tips & Tricks
+
+  If your windows manager is smart enough (like StumpwWM) you can use
+  it to move graphical windows (Emacs frames) in another desktop.
+
+  For example, I use this to move Emacs frames (with the title
+  "emacs-debug") to the group (aka desktop) 9:
+  #+BEGIN_SRC lisp
+    (define-frame-preference "9"
+      (0 nil t :title "emacs-debug"))  
+  #+END_SRC
+
+  And this to specify the title of the frame:
+  #+BEGIN_SRC emacs-lisp
+    (parallel-start (lambda () 42)
+                    :no-batch t
+                    :emacs-args '("-T" "emacs-debug"))
+  #+END_SRC
+  
+* TODO How does it work?
+
+* Known limitations
+
+  You can only send data to the remote (with the ~env~ parameter) or
+  from the remote (with ~parallel-send~ and ~parallel-remote-send~)
+  that have a printed representation (see [[info:elisp#Printed%20Representation][info:elisp#Printed
+  Representation]]).
+
+  So you can pass around numbers, symbols, strings, lists, vectors,
+  hash-table but you can't pass buffers, windows, frames...
+
+
+  It lacks documentation, tests and probably a clean API, but I'm
+  working on it!
diff --git a/lisp/emacs-parallel/parallel-remote.el b/lisp/emacs-parallel/parallel-remote.el
new file mode 100644 (file)
index 0000000..54626af
--- /dev/null
@@ -0,0 +1,81 @@
+;; -*- mode: emacs-lisp; lexical-binding: t; -*-
+;;; parallel-remote.el ---
+
+;; Copyright (C) 2013 Grégoire Jadi
+
+;; Author: Grégoire Jadi <gregoire.jadi@gmail.com>
+
+;; This program 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.
+
+;; This program 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 this program.  If not, see <http://www.gnu.org/licenses/>.
+
+;;; Commentary:
+
+;;; Code:
+
+(require 'cl)
+
+(defvar parallel-service nil)
+(defvar parallel-task-id nil)
+(defvar parallel-client nil)
+(defvar parallel--executed nil)
+(defvar parallel-continue-when-executed nil)
+
+(defun parallel-remote-send (data)
+  (process-send-string parallel-client
+                       (format "%S " (cons parallel-task-id data))))
+
+(defun parallel-remote--init ()
+  (setq parallel-client (make-network-process :name "emacs-parallel"
+                                              :buffer nil
+                                              :server nil
+                                              :service parallel-service
+                                              :host "localhost"
+                                              :family 'ipv4))
+  (set-process-filter parallel-client #'parallel-remote--filter)
+  (parallel-remote-send 'code)
+  (when noninteractive                  ; Batch Mode
+    ;; The evaluation is done in the `parallel--filter' but in Batch
+    ;; Mode, Emacs doesn't wait for the input, it stops as soon as
+    ;; `parallel--init' has been executed.
+    (while (null parallel--executed)
+      (sleep-for 10))))                 ; arbitrary chosen
+
+(defun parallel-remote--filter (_proc output)
+  (dolist (code (parallel--read-output output))
+    (parallel-remote-send
+     (if (or noninteractive
+             (not debug-on-error))
+         (condition-case err
+             (eval code)
+           (error err))
+       (eval code))))
+  (unless parallel-continue-when-executed
+    (setq parallel--executed t)
+    (kill-emacs)))
+
+(defun parallel--read-output (output)
+  "Read lisp forms from output and return them as a list."
+  (loop with output = (replace-regexp-in-string
+                       "\\`[ \t\n]*" ""
+                       (replace-regexp-in-string "[ \t\n]*\\'" "" output)) ; trim string
+        with start = 0
+        with end = (length output)
+        for ret = (read-from-string output start end)
+        for data = (first ret)
+        do (setq start (rest ret))
+        collect data
+        until (= start end)))
+
+(provide 'parallel-remote)
+
+;;; parallel-remote.el ends here
diff --git a/lisp/emacs-parallel/parallel-xwidget.el b/lisp/emacs-parallel/parallel-xwidget.el
new file mode 100644 (file)
index 0000000..7e23863
--- /dev/null
@@ -0,0 +1,59 @@
+;;; parallel-xwidget.el ---
+
+;; Copyright (C) 2013 Grégoire Jadi
+
+;; Author: Grégoire Jadi <gregoire.jadi@gmail.com>
+
+;; This program 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.
+
+;; This program 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 this program.  If not, see <http://www.gnu.org/licenses/>.
+
+;;; Commentary:
+
+;;; Code:
+
+(require 'parallel)
+(require 'browse-url)
+
+(defgroup parallel-xwidget nil
+  "Browse the web in another emacs instance with XWidget."
+  :group 'emacs)
+
+(defvar parallel-xwidget--task nil)
+
+(defcustom parallel-xwidget-config nil
+  "Parallel configuration."
+  :type 'alist
+  :group 'parallel-xwidget)
+
+(defun parallel-xwidget--init ()
+  (setq parallel-xwidget--task
+        (parallel-start (lambda ()
+                          (require 'xwidget))
+                        :graphical t
+                        :continue-when-executed t
+                        :config parallel-xwidget-config)))
+
+(defun parallel-xwidget-browse-url (url &optional new-session)
+  "Browse URL in another Emacs instance."
+  (interactive (browse-url-interactive-arg "xwidget-webkit URL: "))
+  (unless (and parallel-xwidget--task
+               (eq 'run (parallel-status parallel-xwidget--task)))
+    (parallel-xwidget--init))
+  (parallel-send parallel-xwidget--task
+                 (lambda (url new-session)
+                   (xwidget-webkit-browse-url url new-session))
+                 (url-tidy url) new-session))
+
+(provide 'parallel-xwidget)
+
+;;; parallel-xwidget.el ends here
diff --git a/lisp/emacs-parallel/parallel.el b/lisp/emacs-parallel/parallel.el
new file mode 100644 (file)
index 0000000..3e5eccf
--- /dev/null
@@ -0,0 +1,310 @@
+;; -*- lexical-binding: t; -*-
+;;; parallel.el ---
+
+;; Copyright (C) 2013 Grégoire Jadi
+
+;; Author: Grégoire Jadi <gregoire.jadi@gmail.com>
+
+;; This program 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.
+
+;; This program 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 this program.  If not, see <http://www.gnu.org/licenses/>.
+
+;;; Commentary:
+
+;;; Code:
+
+(require 'cl)
+(require 'parallel-remote)
+
+(defgroup parallel nil
+  "Execute stuff in parallel"
+  :group 'emacs)
+
+(defcustom parallel-sleep 0.05
+  "How many sec should we wait while polling."
+  :type 'number
+  :group 'parallel)
+
+(defcustom parallel-config nil
+  "Global config setting to use."
+  :type 'plist
+  :group 'parallel)
+
+(defvar parallel--server nil)
+(defvar parallel--tasks nil)
+(defvar parallel--tunnels nil)
+
+;; Declare external function
+(declare-function parallel-send "parallel-remote")
+
+(defun parallel-make-tunnel (username hostname)
+  (parallel--init-server)
+  (let ((tunnel (find-if (lambda (tun)
+                           (and (string= username
+                                         (process-get tun 'username))
+                                (string= hostname
+                                         (process-get tun 'hostname))))
+                         parallel--tunnels)))
+    (unless tunnel
+      (setq tunnel (start-process "parallel-ssh" nil "ssh"
+                                  "-N" "-R" (format "0:localhost:%s"
+                                                    (process-contact parallel--server :service))
+                                  (format "%s@%s" username hostname)))
+      (process-put tunnel 'username username)
+      (process-put tunnel 'hostname hostname)
+      (set-process-filter tunnel #'parallel--tunnel-filter)
+      (while (null (process-get tunnel 'service))
+        (sleep-for 0.01))
+      (push tunnel parallel--tunnels))
+    tunnel))
+
+(defun parallel-stop-tunnel (tunnel)
+  (setq parallel--tunnels (delq tunnel parallel--tunnels))
+  (delete-process tunnel))
+
+(defun parallel--tunnel-filter (proc output)
+  (if (string-match "\\([0-9]+\\)" output)
+      (process-put proc 'service (match-string 1 output))))
+
+(defmacro parallel--set-option (place config)
+  `(setf ,place (or ,place
+                    (plist-get ,config ,(intern (format ":%s" (symbol-name place))))
+                    (plist-get parallel-config ,(intern (format ":%s" (symbol-name place)))))))
+
+(defmacro parallel--set-options (config &rest options)
+  `(progn
+     ,@(loop for option in options
+             collect `(parallel--set-option ,option ,config))))
+
+(defun* parallel-start (exec-fun &key post-exec env timeout
+                                 emacs-path library-path emacs-args
+                                 graphical debug on-event continue-when-executed
+                                 username hostname hostport
+                                 config)
+  (parallel--init-server)
+
+  ;; Initialize parameters
+  (parallel--set-options config
+                         post-exec
+                         env
+                         timeout
+                         emacs-args
+                         graphical
+                         debug
+                         on-event
+                         continue-when-executed
+                         username
+                         hostname
+                         hostport)
+  
+  (setq emacs-path (or emacs-path
+                       (plist-get config :emacs-path)
+                       (plist-get parallel-config :emacs-path)
+                       (expand-file-name invocation-name
+                                         invocation-directory))
+        library-path (or library-path
+                         (plist-get config :library-path)
+                         (plist-get parallel-config :library-path)
+                         (locate-library "parallel-remote")))
+
+  (let ((task (parallel--new-task))
+        proc tunnel ssh-args)
+    (push task parallel--tasks)
+    (put task 'initialized nil)
+    (put task 'exec-fun exec-fun)
+    (put task 'env env)
+    (when (functionp post-exec)
+      (put task 'post-exec post-exec))
+    (when (functionp on-event)
+      (put task 'on-event on-event))
+    (put task 'results nil)
+    (put task 'status 'run)
+    (put task 'queue nil)
+
+    ;; We need to get the tunnel if it exists so we can send the right
+    ;; `service' to the remote.
+    (when (and username hostname)
+      (if hostport
+          (setq ssh-args (list "-R" (format "%s:localhost:%s" hostport
+                                            (process-contact parallel--server :service)))
+                tunnel t)
+        (setq tunnel (parallel-make-tunnel username hostname)
+              hostport (process-get tunnel 'service)))
+      (setq ssh-args (append
+                      ssh-args
+                      (if graphical (list "-X"))
+                      (list (format "%s@%s" username hostname)))))
+    (setq emacs-args (remq nil
+                           (list* "-Q" "-l" library-path
+                                  (if graphical nil "-batch")
+                                  "--eval" (format "(setq parallel-service '%S)"
+                                                   (if tunnel
+                                                       hostport
+                                                     (process-contact parallel--server :service)))
+                                  "--eval" (format "(setq parallel-task-id '%S)" task)
+                                  "--eval" (format "(setq debug-on-error '%S)" debug)
+                                  "--eval" (format "(setq parallel-continue-when-executed '%S)" continue-when-executed)
+                                  "-f" "parallel-remote--init"
+                                  emacs-args)))
+
+    ;; Reformat emacs-args if we use a tunnel (escape string)
+    (when tunnel
+      (setq emacs-args (list (mapconcat (lambda (string)
+                                          (if (find ?' string)
+                                              (prin1-to-string string)
+                                            string))
+                                        emacs-args " "))))
+    (setq proc (apply #'start-process "parallel" nil
+                      `(,@(when tunnel
+                            (list* "ssh" ssh-args))
+                        ,emacs-path
+                        ,@emacs-args)))
+    (put task 'proc proc)
+    (set-process-sentinel (get task 'proc) #'parallel--sentinel)
+    (when timeout
+      (run-at-time timeout nil (lambda ()
+                                 (when (memq (parallel-status task)
+                                             '(run stop))
+                                   (parallel-stop task)))))
+    task))
+
+(defun parallel--new-task ()
+  "Generate a new task by enforcing a unique name."
+  (let ((symbol-name (make-temp-name "parallel-task-")))
+    (while (intern-soft symbol-name)
+      (setq symbol-name (make-temp-name "parallel-task-")))
+    (intern symbol-name)))
+
+(defun parallel--init-server ()
+  "Initialize `parallel--server'."
+  (when (or (null parallel--server)
+            (not (eq (process-status parallel--server)
+                     'listen)))
+    (setq parallel--server
+          (make-network-process :name "parallel-server"
+                                :buffer nil
+                                :server t
+                                :host "localhost"
+                                :service t
+                                :family 'ipv4
+                                :filter #'parallel--filter
+                                :filter-multibyte t))))
+
+(defun parallel--get-task-process (proc)
+  "Return the task running the given PROC."
+  (find-if (lambda (task)
+             (eq (get task 'proc) proc))
+           parallel--tasks))
+
+(defun parallel--sentinel (proc _event)
+  "Sentinel to watch over the remote process.
+
+This function do the necessary cleanup when the remote process is
+finished."
+  (when (memq (process-status proc) '(exit signal))
+    (let* ((task (parallel--get-task-process proc))
+           (results (get task 'results))
+           (status (process-status proc)))
+      ;; 0 means that the remote process has terminated normally (no
+      ;; SIGNUM 0).
+      (if (zerop (process-exit-status proc))
+          (setq status 'success)
+        ;; on failure, push the exit-code or signal number on the
+        ;; results stack.
+        (push (process-exit-status proc) results))
+      (put task 'results results)
+      (put task 'status status)
+
+      (when (functionp (get task 'post-exec))
+        (funcall (get task 'post-exec)
+                 results status))
+      (setq parallel--tasks (delq task parallel--tasks)))))
+
+(defun parallel--call-with-env (fun env)
+  "Return a string which can be READ/EVAL by the remote process
+to `funcall' FUN with ENV as arguments."
+  (format "(funcall (read %S) %s)"
+          (prin1-to-string fun)
+          (mapconcat (lambda (obj)
+                       ;; We need to quote it because the remote
+                       ;; process will READ/EVAL it.
+                       (format "'%S" obj)) env " ")))
+
+(defun parallel--filter (connection output)
+  "Server filter used to retrieve the results send by the remote
+process and send the code to be executed by it."
+  (dolist (data (parallel--read-output output))
+    (parallel--process-output connection (first data) (rest data))))
+
+(defun parallel--process-output (connection task result)
+  (put task 'connection connection)
+  (cond ((and (not (get task 'initialized))
+              (eq result 'code))
+         (apply #'parallel-send
+                task
+                (get task 'exec-fun)
+                (get task 'env))
+         (let ((code nil))
+           (while (setq code (pop (get task 'queue)))
+             (apply #'parallel-send task (car code) (cdr code))))
+         (put task 'initialized t))
+        (t
+         (push result (get task 'results))
+         (if (functionp (get task 'on-event))
+             (funcall (get task 'on-event) result)))))
+
+(defun parallel-ready-p (task)
+  "Determine whether TASK is finished and if the results are
+available."
+  (memq (parallel-status task) '(success exit signal)))
+
+(defun parallel-get-result (task)
+  "Return the last result send by the remote call, that is the
+result returned by exec-fun."
+  (first (parallel-get-results task)))
+
+(defun parallel-get-results (task)
+  "Return all results send during the call of exec-fun."
+  (parallel-wait task)
+  (get task 'results))
+
+(defun parallel-success-p (task)
+  "Determine whether TASK has ended successfully."
+  (parallel-wait task)
+  (eq (parallel-status task) 'success))
+
+(defun parallel-status (task)
+  "Return TASK status."
+  (get task 'status))
+
+(defun parallel-wait (task)
+  "Wait for TASK."
+  (while (not (parallel-ready-p task))
+    (sleep-for parallel-sleep))
+  t)                                    ; for REPL
+
+(defun parallel-stop (task)
+  "Stop TASK."
+  (delete-process (get task 'proc)))
+
+(defun parallel-send (task fun &rest env)
+  "Send FUN to be evaluated by TASK in ENV."
+  (let ((connection (get task 'connection)))
+    (if connection
+        (process-send-string
+         connection
+         (parallel--call-with-env fun env))
+      (push (cons fun env) (get task 'queue)))))
+
+(provide 'parallel)
+
+;;; parallel.el ends here
index 42fb954925547f9b99952bfd79ff2b0cf9793025..57c7b61fc284dd8eb9d9608857de800b28948f26 100644 (file)
@@ -668,7 +668,7 @@ regarding its parameter treatment."
 ;; functions allows them to be stand-alone commands, making it easier
 ;; to switch between browsers.
 
-(defun browse-url-interactive-arg (prompt)
+(defun browse-url-interactive-arg (prompt &optional default-url)
   "Read a URL from the minibuffer, prompting with PROMPT.
 If `transient-mark-mode' is non-nil and the mark is active,
 it defaults to the current region, else to the URL at or before
@@ -685,7 +685,8 @@ for use in `interactive'."
                                      "[\t\r\f\n ]+" ""
                                      (buffer-substring-no-properties
                                       (region-beginning) (region-end))))
-                               (browse-url-url-at-point)))
+                               (browse-url-url-at-point)
+                                default-url))
        (not (eq (null browse-url-new-window-flag)
                 (null current-prefix-arg)))))
 
@@ -795,6 +796,13 @@ narrowed."
 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 ;; Browser-independent commands
 
+(defun url-tidy (url)
+  "Tidy up URL as much as possible."
+  (if (equal 0 (string-match ".*://" url))
+      url
+    (concat "http://" url) ;;TODO guess more url forms, like mailto
+    ))
+
 ;; A generic command to call the current browse-url-browser-function
 
 ;;;###autoload
@@ -807,6 +815,7 @@ first, if that exists."
   (interactive (browse-url-interactive-arg "URL: "))
   (unless (called-interactively-p 'interactive)
     (setq args (or args (list browse-url-new-window-flag))))
+  (setq url (url-tidy url))
   (when (and url-handler-mode (not (file-name-absolute-p url)))
     (setq url (expand-file-name url)))
   (let ((process-environment (copy-sequence process-environment))
diff --git a/lisp/xwidget.el b/lisp/xwidget.el
new file mode 100644 (file)
index 0000000..de3235d
--- /dev/null
@@ -0,0 +1,592 @@
+;;; xwidget.el --- api functions for xwidgets  -*- lexical-binding: t -*-
+;;  see xwidget.c for more api functions
+
+
+;;; Commentary:
+;;
+
+;;TODO this breaks compilation when we dont have xwidgets
+;;(require 'xwidget-internal)
+
+;;TODO model after make-text-button instead!
+;;; Code:
+
+(eval-when-compile (require 'cl))
+(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)
+  "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."
+  (goto-char pos)
+  (let ((id (make-xwidget (point) (point)
+                          type title width height nil)))
+    (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)))
+
+
+;; (defun xwidget-socket-handler ()
+;;   "Create plug for socket.  TODO."
+;;   (interactive)
+;;   (message "socket handler xwidget %S" last-input-event)
+;;   (let*
+;;       ((xwidget-event-type (nth 2 last-input-event))
+;;        (xwidget-id (nth 1 last-input-event)))
+;;     (cond ( (eq xwidget-event-type 'xembed-ready)
+;;             (let*
+;;                 ((xembed-id (nth 3 last-input-event)))
+;;               (message "xembed ready  event: %S xw-id:%s" xembed-id xwidget-id)
+;;               ;;TODO fetch process data from the xwidget. create it, store process info
+;;               ;;will start emacs/uzbl in a xembed socket when its ready
+;;               ;; (cond
+;;               ;;  ((eq 3 xwidget-id)
+;;               ;;   (start-process "xembed" "*xembed*" (format "%ssrc/emacs" default-directory) "-q" "--parent-id" (number-to-string xembed-id) ) )
+;;               ;;  ((eq 5 xwidget-id)
+;;               ;;   (start-process "xembed2" "*xembed2*" "uzbl-core"  "-s" (number-to-string xembed-id)  "http://www.fsf.org" )  )
+;;               )))))
+
+(defun xwidget-display (xwidget)
+  "Force XWIDGET to be displayed to create a xwidget_view.
+Return the window displaying XWIDGET."
+  (let* ((buffer (xwidget-buffer xwidget))
+         (window (display-buffer buffer))
+         (frame (window-frame window)))
+    (set-frame-visible frame t)
+    (redisplay t)
+    window))
+
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;;; webkit support
+(require 'browse-url)
+(require 'image-mode);;for some image-mode alike functionality
+(require 'cl-macs);;for flet
+
+;;;###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)
+    (setq url (url-tidy 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 send xwidget here
+                    (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 ()
+  (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. sucks.
+  )
+
+(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."
+  (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."
+  (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."
+  (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 isnt 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 shouldnt 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 (- (caddr (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 fugly "title" hack. it is needed because the webkit api
+  ;;doesnt 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. fugly.
+  (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."
+  ;;its still pretty easy to trigger bugs with xwidgets.
+  ;;this function tries to implement a workaround
+  (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 is a workaround because I cant find the right place to put it in C
+;;seems to work well in practice though
+;;(add-hook 'window-configuration-change-hook 'xwidget-cleanup)
+(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)
+
+;;killflash is sadly not reliable yet.
+(defvar xwidget-webkit-kill-flash-oneshot t)
+(defun xwidget-webkit-kill-flash ()
+  "Disable the flash plugin in webkit.
+This is needed because Flash is non-free and doesnt work reliably
+on 64 bit systems and offscreen rendering.  Sadly not reliable
+yet, so deinstall Flash instead for now."
+  ;;you can only call this once or webkit crashes and takes emacs with it. odd.
+  (unless xwidget-webkit-kill-flash-oneshot
+    (xwidget-disable-plugin-for-mime "application/x-shockwave-flash")
+    (setq xwidget-webkit-kill-flash-oneshot t)))
+
+(xwidget-webkit-kill-flash)
+
+(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 describee xactly whata ctions 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 32615c848a73ecc01157ac87aef489ad5ee9c317..81977dbfec2a5764f70f22c96b39c35015e432e2 100644 (file)
@@ -218,6 +218,12 @@ 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@
+
 IMAGEMAGICK_LIBS= @IMAGEMAGICK_LIBS@
 IMAGEMAGICK_CFLAGS= @IMAGEMAGICK_CFLAGS@
 
@@ -343,6 +349,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) \
@@ -372,11 +379,13 @@ 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) \
+       xwidget.o \
        profiler.o decompress.o \
        $(MSDOS_OBJ) $(MSDOS_X_OBJ) $(NS_OBJ) $(CYGWIN_OBJ) $(FONT_OBJ) \
        $(W32_OBJ) $(WINDOW_SYSTEM_OBJ) $(XGSELOBJ)
 obj = $(base_obj) $(NS_OBJC_OBJ)
 
+xwidget.o: xwidget.c xwidget.h
 ## Object files used on some machine or other.
 ## These go in the DOC file on all machines in case they are needed.
 ## Some of them have no DOC entries, but it does no harm to have them
@@ -421,6 +430,7 @@ ALLOBJS = $(FIRSTFILE_OBJ) $(VMLIMIT_OBJ) $(obj) $(otherobj)
 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) \
index 67eda3ee89ee1bd4bf7ad52d0bf6b616010e55e3..223683db6f32c60f6d3bacf7b29562696dffec96 100644 (file)
@@ -42,6 +42,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  /* HAVE_XWIDGETS */
 #ifdef WINDOWSNT
 #include "w32heap.h"           /* for mmap_* */
 #endif
@@ -1755,6 +1758,11 @@ cleaning up all windows currently displaying the buffer to be killed. */)
   kill_buffer_processes (buffer);
   UNGCPRO;
 
+#ifdef HAVE_XWIDGETS
+  GCPRO1 (buffer);
+  kill_buffer_xwidgets (buffer);
+  UNGCPRO;
+#endif  /* HAVE_XWIDGETS */
   /* Killing buffer processes may run sentinels which may have killed
      our buffer.  */
   if (!BUFFER_LIVE_P (b))
index 413947991ec689eb42c66024cea965d3bcc844bb..fbf0c74454d9e2264f360fa9a6608992f631bbba 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
     {
@@ -1353,6 +1360,9 @@ struct glyph_string
   /* Image, if any.  */
   struct image *img;
 
+#ifdef HAVE_XWIDGETS
+  struct xwidget* xwidget;
+#endif
   /* Slice */
   struct glyph_slice slice;
 
@@ -2097,6 +2107,10 @@ enum display_element_type
 
   /* Continuation glyphs.  See the comment for IT_TRUNCATION.  */
   IT_CONTINUATION
+
+#ifdef HAVE_XWIDGETS
+  ,IT_XWIDGET
+#endif
 };
 
 
@@ -2160,6 +2174,9 @@ enum it_method {
   GET_FROM_C_STRING,
   GET_FROM_IMAGE,
   GET_FROM_STRETCH,
+#ifdef HAVE_XWIDGETS
+  GET_FROM_XWIDGET,
+#endif
   NUM_IT_METHODS
 };
 
@@ -2381,6 +2398,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.  */
@@ -2505,6 +2528,10 @@ 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 3c8117e6b65981b0e0f9060803de053e4c5a7505..e614ceef12283ae24f7c4147c616c1609554cc6c 100644 (file)
@@ -48,6 +48,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>
@@ -3542,6 +3546,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;
@@ -4125,6 +4132,11 @@ scrolling_window (struct window *w, bool header_line_p)
        break;
     }
 
+#ifdef HAVE_XWIDGETS
+ //currently this is needed to detect xwidget movement reliably. or probably not.
+    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 fdd17d1e062c511bf97862954cb2f70babee6a08..87b1f11d59b059079b4becf01b890fa749acf45d 100644 (file)
@@ -65,6 +65,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 "systty.h"
 #include "atimer.h"
 #include "blockinput.h"
@@ -1434,6 +1437,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 abec78fb07300d615be540e82bcbaf896de22147..d52a1399bac6cedb3c35c50c4cc2d9006ed4f490 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,26 +34,26 @@ 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)
+//#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;
+/* struct _EmacsFixed */
+/* { */
+/*   GtkFixed container; */
 
-  /*< private >*/
-  EmacsFixedPrivate *priv;
-};
+/*   /\*< private >*\/ */
+/*   EmacsFixedPrivate *priv; */
+/* }; */
 
-struct _EmacsFixedClass
-{
-  GtkFixedClass parent_class;
-};
+/* struct _EmacsFixedClass */
+/* { */
+/*   GtkFixedClass parent_class; */
+/* }; */
 
 struct _EmacsFixedPrivate
 {
@@ -64,21 +67,109 @@ 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
+
+  //TODO 1st call base class method
+  EmacsFixedClass *klass;
+  GtkWidgetClass *parent_class;
+  struct GtkFixedPrivateL* priv;
+  GtkFixedChild *child;
+  GtkAllocation child_allocation;
+  GtkRequisition child_requisition;
+  GList *children;
+  struct xwidget_view* xv;
+  
+  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 (children = priv->children;
+       children;
+       children = children->next)
+    {
+      child = children->data;
+
+      if (!gtk_widget_get_visible (child->widget))
+        continue;
+
+      gtk_widget_get_preferred_size (child->widget, &child_requisition, NULL);
+      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;
+
+
+
+      xv = (struct xwidget_view*) 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)
 {
   GtkWidgetClass *widget_class;
+  GtkFixedClass *fixed_class;
 
   widget_class = (GtkWidgetClass*) klass;
+  fixed_class = (GtkFixedClass*) 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 GType
+emacs_fixed_child_type (GtkFixed *container)
+{
+  return GTK_TYPE_WIDGET;
+}
+
 static void
 emacs_fixed_init (EmacsFixed *fixed)
 {
index bcf1cd9072ee5c6dad80a7fc6aef358173d22e07..7364d906cf6f49b9f96edff0b2aa864cfdad9163 100644 (file)
@@ -25,7 +25,35 @@ along with GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.  */
 
 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 1176d701f2a16032481d20b0a1c50d6de37c3cd0..a9ff77d047346145dd0fb671c80c6dde8eb34db1 100644 (file)
@@ -4123,6 +4123,20 @@ kbd_buffer_get_event (KBOARD **kbp,
          obj = make_lispy_event (event);
          kbd_fetch_ptr = event + 1;
        }
+#endif
+#ifdef HAVE_XWIDGETS
+      else if (event->kind == XWIDGET_EVENT)
+       {
+         obj = make_lispy_event (event);
+         kbd_fetch_ptr = event + 1;
+       }
+#endif
+#ifdef HAVE_INOTIFY
+      else if (event->kind == FILE_NOTIFY_EVENT)
+        {
+          obj = make_lispy_event (event);
+          kbd_fetch_ptr = event + 1;
+        }
 #endif
       else if (event->kind == CONFIG_CHANGED_EVENT)
        {
@@ -6070,6 +6084,14 @@ make_lispy_event (struct input_event *event)
       }
 #endif /* HAVE_DBUS */
 
+#ifdef HAVE_XWIDGETS
+    case XWIDGET_EVENT:
+      {
+        return  Fcons (Qxwidget_event,event->arg);
+      }
+#endif /* HAVE_XWIDGETS */
+
+
 #if defined HAVE_GFILENOTIFY || defined HAVE_INOTIFY
     case FILE_NOTIFY_EVENT:
       {
@@ -11087,6 +11109,9 @@ syms_of_keyboard (void)
   DEFSYM (Qdbus_event, "dbus-event");
 #endif
 
+#ifdef HAVE_XWIDGETS
+  DEFSYM (Qxwidget_event,"xwidget-event");
+#endif /* HAVE_XWIDGETS */
 #ifdef USE_FILE_NOTIFY
   DEFSYM (Qfile_notify, "file-notify");
 #endif /* USE_FILE_NOTIFY */
index f5242ab84a1bcbf03204137897e958b0a0707e70..87bc3efd1980130b560ed65f26bb7f3e83ef050e 100644 (file)
@@ -781,6 +781,11 @@ 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 1a0aebbeba7f05a74656cdbfd6829245acf50e74..75288bc6a3a3aa28437d002d4f1be1d514491d50 100644 (file)
@@ -37,6 +37,10 @@ along with GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.  */
 #include "termhooks.h"         /* For struct terminal.  */
 #include "font.h"
 
+#ifdef HAVE_XWIDGETS
+#include "xwidget.h"
+#endif
+
 #include <float.h>
 #include <ftoastr.h>
 
@@ -1772,6 +1776,18 @@ print_object (Lisp_Object obj, Lisp_Object printcharfun, bool escapeflag)
          strout (XSUBR (obj)->symbol_name, -1, -1, printcharfun);
          PRINTCHAR ('>');
        }
+#ifdef HAVE_XWIDGETS
+      else if (XWIDGETP (obj))
+       {
+         strout ("#<xwidget ", -1, -1, printcharfun);
+         PRINTCHAR ('>');
+       }
+      else if (XWIDGET_VIEW_P (obj))
+       {
+         strout ("#<xwidget-view ", -1, -1, printcharfun);
+         PRINTCHAR ('>');
+       }
+#endif
       else if (WINDOWP (obj))
        {
          int len;
index 3cafc437e59954e6486fe1ac16d2ecb6d2a891f6..58ae2397d78104933f346803cea730acf53a22ad 100644 (file)
@@ -236,6 +236,10 @@ 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 2f44bf78304b5da98cf7f0dad1bf2021ea425ce9..b4230100150af067984f30f1ffcfdd7c467742b7 100644 (file)
@@ -44,6 +44,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 int displayed_window_lines (struct window *);
 static int count_windows (struct window *);
@@ -4559,6 +4562,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 68c0fa545724974aa22dafd535317d3f6cdd17e9..01d598fe2c2d2f5281b192cd8d652bacedf93cfb 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
@@ -842,6 +845,9 @@ static int next_element_from_c_string (struct it *);
 static int next_element_from_buffer (struct it *);
 static int next_element_from_composition (struct it *);
 static int next_element_from_image (struct it *);
+#ifdef HAVE_XWIDGETS
+static int next_element_from_xwidget(struct it *);
+#endif
 static int next_element_from_stretch (struct it *);
 static void load_overlay_strings (struct it *, ptrdiff_t);
 static int init_from_display_pos (struct it *, struct window *,
@@ -4678,6 +4684,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)
@@ -5124,7 +5133,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_p)
     {
@@ -5199,6 +5213,18 @@ 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
        {
@@ -5935,6 +5961,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
     }
   p->position = position ? *position : it->position;
   p->current = it->current;
@@ -6028,6 +6059,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;
@@ -6690,6 +6726,9 @@ static int (* get_next_element[NUM_IT_METHODS]) (struct it *it) =
   next_element_from_c_string,
   next_element_from_image,
   next_element_from_stretch
+#ifdef HAVE_XWIDGETS
+  ,next_element_from_xwidget
+#endif
 };
 
 #define GET_NEXT_DISPLAY_ELEMENT(it) (*get_next_element[(it)->method]) (it)
@@ -7535,6 +7574,10 @@ set_iterator_to_next (struct it *it, int 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.  */
@@ -7997,6 +8040,16 @@ next_element_from_image (struct it *it)
   return 1;
 }
 
+#ifdef HAVE_XWIDGETS
+/* im not sure about this FIXME JAVE*/
+static int
+next_element_from_xwidget (struct it *it)
+{
+  it->what = IT_XWIDGET;
+  return 1;
+}
+#endif
+
 
 /* Fill iterator IT with next display element from a stretch glyph
    property.  IT->object is the value of the text property.  Value is
@@ -17003,6 +17056,13 @@ try_window_reusing_current_matrix (struct window *w)
     return 0;
 #endif
 
+#ifdef HAVE_XWIDGETS_xxx
+ //currently this is needed to detect xwidget movement reliably. or probably not.
+  printf("try_window_reusing_current_matrix\n");
+    return 0;
+#endif
+
+
   if (/* This function doesn't handle terminal frames.  */
       !FRAME_WINDOW_P (f)
       /* Don't try to reuse the display if windows have been split
@@ -18597,6 +18657,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
 }
 
 
@@ -24014,6 +24096,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 dont return dummy size
+              return OK_PIXELS (width_p ? 100 : 100);
+            }
+#endif
 #endif
          if (EQ (car, Qplus) || EQ (car, Qminus))
            {
@@ -24518,6 +24607,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,
@@ -24853,6 +24954,20 @@ compute_overhangs_and_x (struct glyph_string *s, int x, int backward_p)
        }                                                               \
      while (0)
 
+#ifdef HAVE_XWIDGETS
+#define BUILD_XWIDGET_GLYPH_STRING(START, END, HEAD, TAIL, HL, X, LAST_X) \
+     do                                                                        \
+       { \
+        s = (struct glyph_string *) 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 (0)
+#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
@@ -24974,7 +25089,7 @@ compute_overhangs_and_x (struct glyph_string *s, int x, int 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;                                              \
@@ -25005,8 +25120,15 @@ compute_overhangs_and_x (struct glyph_string *s, int x, int backward_p)
            case IMAGE_GLYPH:                                           \
              BUILD_IMAGE_GLYPH_STRING (START, END, HEAD, TAIL,         \
                                        HL, X, LAST_X);                 \
-             break;                                                    \
-                                                                       \
+             break;
+
+#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;
+
+#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);             \
@@ -25025,6 +25147,18 @@ compute_overhangs_and_x (struct glyph_string *s, int x, int backward_p)
     } while (0)
 
 
+#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:
@@ -25663,6 +25797,113 @@ produce_image_glyph (struct it *it)
     }
 }
 
+#ifdef HAVE_XWIDGETS
+static void
+produce_xwidget_glyph (struct it *it)
+{
+  struct xwidget* xw;
+  struct face *face;
+  int glyph_ascent, crop;
+  eassert (it->what == IT_XWIDGET);
+
+  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.  */
+  if ((crop = it->pixel_width - (it->last_visible_x - it->current_x), crop > 0)
+      && (it->hpos == 0 || it->pixel_width > it->last_visible_x / 4))
+    {
+      it->pixel_width -= crop;
+    }
+
+  if (it->glyph_row)
+    {
+      struct glyph *glyph;
+      enum glyph_row_area area = it->area;
+
+      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;
+          //assert_valid_xwidget_id(glyph->u.xwidget_id,"produce_xwidget_glyph");
+         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
@@ -27003,6 +27244,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
@@ -27372,6 +27617,12 @@ 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 3955d027a528c832ab8375659ce47452c7248dcb..abceefb1b0e887667071e146c909f4e399719e23 100644 (file)
@@ -63,6 +63,9 @@ along with GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.  */
 #include "coding.h"
 #include "frame.h"
 #include "dispextern.h"
+#ifdef HAVE_XWIDGETS
+#include "xwidget.h"
+#endif
 #include "fontset.h"
 #include "termhooks.h"
 #include "termopts.h"
@@ -2676,6 +2679,13 @@ x_draw_glyph_string (struct glyph_string *s)
       x_draw_image_glyph_string (s);
       break;
 
+#ifdef HAVE_XWIDGETS
+    case XWIDGET_GLYPH:
+      //erase xwidget background
+      //x_draw_glyph_string_background (s, 0);
+      x_draw_xwidget_glyph_string (s);
+      break;
+#endif
     case STRETCH_GLYPH:
       x_draw_stretch_glyph_string (s);
       break;
@@ -8016,6 +8026,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..747e803
--- /dev/null
@@ -0,0 +1,1853 @@
+#include <config.h>
+#ifdef HAVE_XWIDGETS
+
+#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 /* makedev */
+
+#ifdef BSD_SYSTEM
+#include <sys/ioctl.h>
+#endif /* ! defined (BSD_SYSTEM) */
+
+#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 "emacs-icon.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>
+
+#ifdef HAVE_GTK3
+//for gtk3; sockets and plugs
+#include <gtk/gtkx.h>
+#include <gtk/gtkscrolledwindow.h>
+#include "emacsgtkfixed.h"
+#endif
+
+#include <wchar.h>
+
+#ifdef HAVE_WEBKIT_OSR
+#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>
+#endif
+
+//for GIR
+#include <girepository.h>
+
+#include "xwidget.h"
+
+//TODO embryo of lisp allocators for xwidgets
+//TODO xwidget* should be Lisp_xwidget*
+struct xwidget*
+allocate_xwidget (void)
+{
+  return ALLOCATE_PSEUDOVECTOR (struct xwidget, height, PVEC_XWIDGET);
+}
+
+//TODO xwidget_view* should be Lisp_xwidget_view*
+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* xw,     struct window *w);
+Lisp_Object xwidget_spec_value ( Lisp_Object spec, Lisp_Object  key,  int *found);
+gboolean offscreen_damage_event (GtkWidget *widget, GdkEvent *event, gpointer data);
+void     webkit_osr_document_load_finished_callback (WebKitWebView  *webkitwebview,
+                                                     WebKitWebFrame *arg1,
+                                                     gpointer        user_data);
+gboolean     webkit_osr_download_callback (WebKitWebView  *webkitwebview,
+                                       WebKitDownload *arg1,
+                                       gpointer        data);
+
+gboolean  webkit_osr_mime_type_policy_typedecision_requested_callback(WebKitWebView           *webView,
+                                                                      WebKitWebFrame          *frame,
+                                                                      WebKitNetworkRequest    *request,
+                                                                      gchar                   *mimetype,
+                                                                      WebKitWebPolicyDecision *policy_decision,
+                                                                      gpointer                 user_data);
+
+gboolean webkit_osr_new_window_policy_decision_requested_callback(WebKitWebView             *webView,
+                                                                  WebKitWebFrame            *frame,
+                                                                  WebKitNetworkRequest      *request,
+                                                                  WebKitWebNavigationAction *navigation_action,
+                                                                  WebKitWebPolicyDecision   *policy_decision,
+                                                                  gpointer                   user_data);
+
+
+gboolean webkit_osr_navigation_policy_decision_requested_callback(WebKitWebView             *webView,
+                                                        WebKitWebFrame            *frame,
+                                                        WebKitNetworkRequest      *request,
+                                                        WebKitWebNavigationAction *navigation_action,
+                                                        WebKitWebPolicyDecision   *policy_decision,
+                                                                  gpointer                   user_data);
+
+GtkWidget* xwgir_create(char* class, char* namespace);
+
+
+
+static void
+send_xembed_ready_event (struct xwidget* xw, int xembedid);
+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:
+- Button
+- ToggleButton
+- slider
+- socket
+- socket-osr
+- cairo
+*/
+         )
+  (Lisp_Object beg, Lisp_Object end,
+   Lisp_Object type,
+   Lisp_Object title,
+   Lisp_Object width, Lisp_Object height,
+   Lisp_Object data,
+   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;
+
+
+
+
+#ifdef HAVE_WEBKIT_OSR
+  /* DIY mvc. widget is rendered offscreen,
+     later bitmap copied to the views.
+   */
+  if (EQ(xw->type, Qwebkit_osr)||
+      EQ(xw->type, Qsocket_osr)||
+      (!NILP (Fget(xw->type, QCxwgir_class)))) {
+      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)));
+      }
+      if(EQ(xw->type, Qsocket_osr))
+          xw->widget_osr = gtk_socket_new();
+      if(!NILP (Fget(xw->type, QCxwgir_class)))
+          xw->widget_osr = xwgir_create(SDATA(Fcar(Fcdr(Fget(xw->type, QCxwgir_class)))),
+                                        SDATA(Fcar(Fget(xw->type, QCxwgir_class))));
+
+      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_osr_document_load_finished_callback),
+                            xw);
+
+          g_signal_connect (G_OBJECT (xw->widget_osr),
+                            "download-requested",
+                            G_CALLBACK (webkit_osr_download_callback),
+                            xw);
+
+          g_signal_connect (G_OBJECT (xw->widget_osr),
+                            "mime-type-policy-decision-requested",
+                            G_CALLBACK (webkit_osr_mime_type_policy_typedecision_requested_callback),
+                            xw);
+
+          g_signal_connect (G_OBJECT (xw->widget_osr),
+                            "new-window-policy-decision-requested",
+                            G_CALLBACK (webkit_osr_new_window_policy_decision_requested_callback),
+                            xw);
+
+          g_signal_connect (G_OBJECT (xw->widget_osr),
+                            "navigation-policy-decision-requested",
+                            G_CALLBACK (webkit_osr_navigation_policy_decision_requested_callback),
+                            xw);
+      }
+
+      if (EQ(xw->type, Qsocket_osr)) {
+          send_xembed_ready_event (xw, gtk_socket_get_id (GTK_SOCKET (xw->widget_osr)));
+          //gtk_widget_realize(xw->widget);
+      }
+
+
+      unblock_input();
+
+  }
+#endif  /* HAVE_WEBKIT_OSR */
+
+  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;
+}
+
+int
+xwidget_hidden(struct xwidget_view *xv)
+{
+  return  xv->hidden;
+}
+
+
+static void
+buttonclick_handler (GtkWidget * widget, gpointer data)
+{
+  Lisp_Object xwidget_view, xwidget;
+  XSETXWIDGET_VIEW (xwidget_view, (struct xwidget_view *) data);
+  xwidget = Fxwidget_view_model (xwidget_view);
+
+  struct input_event event;
+  Lisp_Object frame = Fwindow_frame (Fxwidget_view_window (xwidget_view));
+  struct frame *f = XFRAME (frame);
+  printf ("button clicked xw:%d '%s'\n", XXWIDGET (xwidget), XXWIDGET (xwidget)->title);
+
+  EVENT_INIT (event);
+  event.kind = XWIDGET_EVENT;
+
+  event.frame_or_window = frame;
+
+  event.arg = Qnil;
+  event.arg = Fcons (xwidget, event.arg);
+  event.arg = Fcons (intern ("buttonclick"), event.arg);
+
+  kbd_buffer_store_event (&event);
+}
+
+
+static void
+send_xembed_ready_event (struct xwidget* xw, int xembedid)
+{
+  Lisp_Object xw_lo;
+  XSETXWIDGET(xw_lo, xw);
+  struct input_event event;
+  EVENT_INIT (event);
+  event.kind = XWIDGET_EVENT;
+  event.frame_or_window = Qnil;        //frame; //how to get the frame here? //TODO i store it in the xwidget now
+
+  event.arg = Qnil;
+  event.arg = Fcons (make_number (xembedid), event.arg);
+  event.arg = Fcons (xw_lo, event.arg);
+  event.arg = Fcons (intern ("xembed-ready"), event.arg);
+
+
+  kbd_buffer_store_event (&event);
+
+}
+
+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); //TODO refactor
+}
+
+
+/* hide an xvidget view */
+void
+xwidget_hide_view (struct xwidget_view *xv)
+{
+  xv->hidden = 1;
+  //gtk_widget_hide(xw->widgetwindow);
+  gtk_fixed_move (GTK_FIXED (xv->emacswindow), xv->widgetwindow,
+                  10000, 10000);
+}
+
+
+void
+xwidget_plug_added(GtkSocket *socket,
+                   gpointer   user_data)
+{
+  //hmm this doesnt seem to get called for foreign windows
+  printf("xwidget_plug_added\n");
+}
+
+gboolean
+xwidget_plug_removed(GtkSocket *socket,
+                     gpointer   user_data)
+{
+  printf("xwidget_plug_removed\n");
+  return TRUE; /* dont run the default handler because that kills the socket and we want to reuse it*/
+}
+
+
+void
+xwidget_slider_changed (GtkRange *range,
+                        gpointer  user_data)
+{
+  //slider value changed. change value of siblings
+  //correspondingly. but remember that changing value will again
+  //trigger signal
+
+  //TODO MVC view storage wont be an array futureish so the loop needs to change eventually
+  //TODO MVC it would be nice if this code could be reusable but, alas, C is not a functional language
+  //issues are:
+  // - the type of the controllers value (double, boolean etc)
+  // - the getter and setter (but they can be func pointers)
+  // a behemoth macro is always an option.
+  double v=gtk_range_get_value(range);
+  struct xwidget_view* xvp = g_object_get_data (G_OBJECT (range), XG_XWIDGET_VIEW);
+  struct xwidget_view* xv;
+
+  printf("slider changed val:%f\n", v);
+
+  for (Lisp_Object tail = Vxwidget_view_list; CONSP (tail); tail = XCDR (tail))
+    {
+      if (XWIDGET_VIEW_P (XCAR (tail))) {
+        xv = XXWIDGET_VIEW (XCAR (tail));
+        if (EQ (xvp->model, xv->model)) {
+          //block sibling views signal handlers
+          g_signal_handler_block(xv->widget, xv->handler_id);
+
+          //set values of sibling views and unblock
+          gtk_range_set_value(GTK_RANGE(xv->widget), v);
+          g_signal_handler_unblock(xv->widget,xv->handler_id);
+        }
+      }
+    }
+}
+
+
+/* when the off-screen webkit master view changes this signal is called.
+   it copies the bitmap from the off-screen webkit instance */
+gboolean
+offscreen_damage_event (GtkWidget *widget, GdkEvent *event, gpointer data)
+{
+  //TODO this is wrong! should just queu a redraw of onscreen widget
+  gtk_widget_queue_draw (GTK_WIDGET (data));
+  return FALSE;
+}
+
+void
+store_xwidget_event_string(struct xwidget* xw, char* eventname, const char* eventstr)
+{
+  //refactor attempt
+  struct input_event event;
+  Lisp_Object xwl;
+  XSETXWIDGET(xwl,xw);
+  EVENT_INIT (event);
+  event.kind = XWIDGET_EVENT;
+  event.frame_or_window = Qnil;        //frame; //how to get the frame here? //TODO i store it in the xwidget now
+
+  event.arg = Qnil;
+  event.arg = Fcons (build_string(eventstr), event.arg);  //string so dont intern
+  event.arg = Fcons (xwl, event.arg); //TODO
+  event.arg = Fcons (intern (eventname), event.arg);//interning should be ok
+  kbd_buffer_store_event (&event);
+
+}
+
+//TODO deprecated, use load-status
+void
+webkit_osr_document_load_finished_callback (WebKitWebView  *webkitwebview,
+                                                     WebKitWebFrame *arg1,
+                                                     gpointer        data)
+{
+  //TODO this event sending code should be refactored
+  //  struct xwidget *xw = (struct xwidget *) data;
+  struct xwidget* xw = (struct xwidget*) g_object_get_data (G_OBJECT (webkitwebview), XG_XWIDGET);
+  printf("webkit finished loading\n");
+
+  store_xwidget_event_string(xw,
+                             "document-load-finished", "");
+}
+
+gboolean
+webkit_osr_download_callback (WebKitWebView  *webkitwebview,
+                                       WebKitDownload *arg1,
+                                       gpointer        data)
+{
+  //TODO this event sending code should be refactored
+  struct input_event event;
+  //  struct xwidget *xw = (struct xwidget *) data;
+  struct xwidget* xw = (struct xwidget*) g_object_get_data (G_OBJECT (webkitwebview), XG_XWIDGET);
+  printf("download requested %s\n", webkit_download_get_uri (arg1));
+
+
+  printf("webkit finished loading\n");
+
+  store_xwidget_event_string(xw, "download-requested", webkit_download_get_uri (arg1));
+
+  return FALSE;
+}
+
+gboolean
+webkit_osr_mime_type_policy_typedecision_requested_callback(WebKitWebView           *webView,
+                                                            WebKitWebFrame          *frame,
+                                                            WebKitNetworkRequest    *request,
+                                                            gchar                   *mimetype,
+                                                            WebKitWebPolicyDecision *policy_decision,
+                                                            gpointer                 user_data)
+{
+  printf("mime policy requested\n");
+  // 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 text mime for instance
+  if(!webkit_web_view_can_show_mime_type(webView, mimetype)){
+    webkit_web_policy_decision_download (policy_decision);
+    return TRUE;
+  }else{
+    return FALSE;
+  }
+}
+
+
+gboolean
+webkit_osr_new_window_policy_decision_requested_callback(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);
+  printf("webkit_osr_new_window_policy_decision_requested_callback %s\n",
+         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_osr_navigation_policy_decision_requested_callback(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);
+  printf("webkit_osr_navigation_policy_decision_requested_callback %s\n",
+         webkit_web_navigation_action_get_original_uri (navigation_action));
+  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
+gboolean
+xwidget_osr_draw_callback (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);//xw->width, xw->height);
+  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;
+}
+
+GtkWidget* xwgir_create_debug;
+
+
+
+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);// works
+
+  /* printf("xwidget_osr_event_forward redirect event to window:%d\n",   ((GdkEventAny*)eventcopy)->window); */
+  /* printf("A type:%d x:%f y:%f \n",   event->type, event->button.x, event->button.y); */
+  /* printf("B type:%d x:%f y:%f \n",   eventcopy->type, eventcopy->button.x, eventcopy->button.y); */
+    //gtk_button_get_event_window(xwgir_create_debug);
+  gtk_main_do_event(eventcopy); //TODO this will leak events. they should be deallocated later, perhaps in xwgir_event_callback
+  return TRUE; //dont propagate this event furter
+}
+
+GIRepository *girepository ;
+
+DEFUN ("xwgir-require-namespace", Fxwgir_require_namespace, Sxwgir_require_namespace, 2,2,0,
+       doc: /* Require a GObject Introspection namespace.
+               This must be done for all namespaces we want to use, before using other xwgir functions.*/)
+  (Lisp_Object lnamespace, Lisp_Object lnamespace_version)
+{
+  char* namespace = SDATA(lnamespace);
+  char* namespace_version = SDATA(lnamespace_version);
+  GError *error = NULL;
+
+  girepository = g_irepository_get_default();
+  g_irepository_require(girepository, namespace, namespace_version, 0, &error);
+  if (error) {
+    g_error("ERROR: %s\n", error->message);
+    return Qnil;
+  }
+  return Qt;
+}
+
+GtkWidget* xwgir_create(char* class, char* namespace){
+  //TODO this is more or less the same as xwgir-call-method, so should be refactored
+  //create a gtk widget, given its name
+  //find the constructor
+  //call it
+  //also figure out how to pass args
+
+  GError *error = NULL;
+  GIArgument return_value;
+
+  GIObjectInfo* obj_info = g_irepository_find_by_name(girepository, namespace, class);
+  GIFunctionInfo* f_info = g_object_info_find_method (obj_info, "new");
+  g_function_info_invoke(f_info,
+                         NULL, 0,
+                         NULL, 0,
+                         &return_value,
+                         NULL);
+  xwgir_create_debug = return_value.v_pointer;
+  return return_value.v_pointer;
+
+}
+
+int
+xwgir_convert_lisp_to_gir_arg(GIArgument* giarg,
+                              GIArgInfo* arginfo,
+                              Lisp_Object lisparg )
+{
+
+  GITypeTag   tag;
+  gboolean    is_pointer;
+  gboolean    is_enum;
+  tag =  g_type_info_get_tag (g_arg_info_get_type (arginfo));
+
+  switch (tag)
+    {
+    case GI_TYPE_TAG_BOOLEAN:
+      giarg->v_boolean = XFASTINT(lisparg);
+      break;
+    case GI_TYPE_TAG_INT8:
+      giarg->v_int8 = XFASTINT(lisparg);
+      break;
+    case GI_TYPE_TAG_UINT8:
+      giarg->v_uint8 = XFASTINT(lisparg);
+      break;
+    case GI_TYPE_TAG_INT16:
+      giarg->v_int16 = XFASTINT(lisparg);
+      break;
+    case GI_TYPE_TAG_UINT16:
+      giarg->v_uint16 = XFASTINT(lisparg);
+      break;
+    case GI_TYPE_TAG_INT32:
+      giarg->v_int32 = XFASTINT(lisparg);
+      break;
+    case GI_TYPE_TAG_UINT32:
+      giarg->v_uint32 = XFASTINT(lisparg);
+      break;
+
+    case GI_TYPE_TAG_INT64:
+      giarg->v_int64 = XFASTINT(lisparg);
+      break;
+    case GI_TYPE_TAG_UINT64:
+      giarg->v_uint64 = XFASTINT(lisparg);
+      break;
+
+
+    case GI_TYPE_TAG_FLOAT:
+      giarg->v_float = XFLOAT_DATA(lisparg);
+      break;
+
+    case GI_TYPE_TAG_DOUBLE:
+      giarg->v_double = XFLOAT_DATA(lisparg);
+      break;
+
+    case GI_TYPE_TAG_UTF8:
+    case GI_TYPE_TAG_FILENAME:
+      //giarg->v_string = SDATA(lisparg);
+      giarg->v_pointer = SDATA(lisparg);
+      break;
+
+    case GI_TYPE_TAG_ARRAY:
+    case GI_TYPE_TAG_GLIST:
+    case GI_TYPE_TAG_GSLIST:
+    case GI_TYPE_TAG_GHASH:
+    case GI_TYPE_TAG_ERROR:
+    case GI_TYPE_TAG_INTERFACE:
+    case GI_TYPE_TAG_VOID:
+    case GI_TYPE_TAG_UNICHAR:
+    case GI_TYPE_TAG_GTYPE:
+      //?? i dont know how to handle these yet TODO
+      printf("failed in my lisp to gir arg conversion duties. sob!\n");
+      return -1;
+      break;
+    }
+  return 0;
+}
+
+#if 0
+void
+refactor_attempt(){
+  //this methhod should be called from xwgir-xwidget-call-method and from xwgir xwidget construction
+  char* class = SDATA(Fcar(Fcdr(Fget(xw->type, QCxwgir_class))));
+
+  GIObjectInfo* obj_info = g_irepository_find_by_name(girepository, namespace, class);
+  GIFunctionInfo* f_info = g_object_info_find_method (obj_info, SDATA(method));
+
+  //loop over args, convert from lisp to primitive type, given arg introspection data
+  //TODO g_callable_info_get_n_args(f_info) should match
+  int argscount = XFASTINT(Flength(arguments));
+  if(argscount !=  g_callable_info_get_n_args(f_info)){
+    printf("xwgir call method arg count doesn match! \n");
+    return Qnil;
+  }
+  int i;
+  for (i = 1; i < argscount + 1; ++i)
+    {
+      xwgir_convert_lisp_to_gir_arg(&in_args[i], g_callable_info_get_arg(f_info, i - 1), Fnth(i - 1, arguments));
+    }
+
+  in_args[0].v_pointer = widget;
+  if(g_function_info_invoke(f_info,
+                            in_args, argscount + 1,
+                            NULL, 0,
+                            &return_value,
+                            &error)) {
+    //g_error("ERROR: %s\n", error->message);
+    printf("invokation error\n");
+     return Qnil;
+   }
+  return Qt;
+}
+#endif  /* 0 */
+
+DEFUN ("xwgir-xwidget-call-method", Fxwgir_xwidget_call_method,  Sxwgir_xwidget_call_method,       3, 3, 0,
+       doc:    /* Call Xwidget object method using GObject Introspection.
+                   XWIDGET is the xwidget instance to act upon.
+                    METHOD is the Gobject intrsopsection method name.
+                    ARGUMENTS is a list of arguments for the call. They will be converted to GObject types from Lisp types.
+                 */)
+  (Lisp_Object xwidget, Lisp_Object method, Lisp_Object arguments)
+{
+  CHECK_XWIDGET (xwidget);
+  GError *error = NULL;
+  GIArgument return_value;
+  GIArgument in_args[20];
+
+
+  struct xwidget* xw;
+  if (NILP (xwidget)) { printf("ERROR xwidget nil\n"); return Qnil; };
+  xw = XXWIDGET(xwidget);
+  if(NULL == xw) printf("ERROR xw is 0\n");
+  char* namespace = SDATA(Fcar(Fget(xw->type, QCxwgir_class)));
+  //we need the concrete widget, which happens in 2 ways depending on OSR or not TODO
+  GtkWidget* widget = NULL;
+  if(NULL == xw->widget_osr) {
+    widget = xwidget_view_lookup (xw, XWINDOW(FRAME_SELECTED_WINDOW (SELECTED_FRAME ()))) -> widget;
+  } else {
+    widget = xw->widget_osr;
+  }
+
+  //char* class = SDATA(SYMBOL_NAME(xw->type)); //this works but is unflexible
+  //figure out the class from the widget instead
+  /* printf("type class: %s %s\n", G_OBJECT_TYPE_NAME(widget), G_OBJECT_CLASS_NAME(G_OBJECT_GET_CLASS(widget))); */
+  /* char* class = G_OBJECT_TYPE_NAME(widget); //gives "GtkButton"(I want "Button") */
+  /* class += strlen(namespace);  //TODO check for corresponding api method. but this seems to work. */
+
+  char* class = SDATA(Fcar(Fcdr(Fget(xw->type, QCxwgir_class))));
+
+  GIObjectInfo* obj_info = g_irepository_find_by_name(girepository, namespace, class);
+  GIFunctionInfo* f_info = g_object_info_find_method (obj_info, SDATA(method));
+
+  //loop over args, convert from lisp to primitive type, given arg introspection data
+  //TODO g_callable_info_get_n_args(f_info) should match
+  int argscount = XFASTINT(Flength(arguments));
+  if(argscount !=  g_callable_info_get_n_args(f_info)){
+    printf("xwgir call method arg count doesn match! \n");
+    return Qnil;
+  }
+  int i;
+  Lisp_Object n;
+  for (i = 1; i < argscount + 1; ++i)
+    {
+        XSETFASTINT (n, i - 1);
+        xwgir_convert_lisp_to_gir_arg(&in_args[i], g_callable_info_get_arg(f_info, i - 1), Fnth(n, arguments));
+    }
+
+  in_args[0].v_pointer = widget;
+  if(g_function_info_invoke(f_info,
+                            in_args, argscount + 1,
+                            NULL, 0,
+                            &return_value,
+                            &error)) {
+    //g_error("ERROR: %s\n", error->message);
+    printf("invokation error\n");
+     return Qnil;
+   }
+  return Qt;
+}
+
+ void
+to_child (GtkWidget *bin,
+          double         widget_x,
+          double         widget_y,
+          double        *x_out,
+          double        *y_out)
+{
+  *x_out = widget_x;
+  *y_out = widget_y;
+}
+
+
+GdkWindow *
+offscreen_pick_embedded_child (GdkWindow *window,
+                               double x,
+                               double y,
+                               gpointer *data)
+{
+  //in this simple case we assume the window contains a single widget. easy.
+  //but then we get the problem that the widget cant be embedded in several windows
+  return gtk_widget_get_window (GTK_WIDGET (data));
+}
+
+void
+offscreen_to_embedder (GdkWindow *window,
+                       gdouble offscreen_x,
+                       gdouble offscreen_y,
+                       gpointer embedder_x,
+                       gpointer embedder_y,
+                       gpointer data)
+{
+  * (gdouble *) embedder_x = offscreen_x;
+  * (gdouble *) embedder_y = offscreen_y;
+}
+
+void
+offscreen_from_embedder (GdkWindow *window,
+                         gdouble embedder_x,
+                         gdouble embedder_y,
+                         gpointer offscreen_x,
+                         gpointer offscreen_y,
+                         gpointer user_data)
+{
+  * (gdouble *) offscreen_x = embedder_x;
+  * (gdouble *) offscreen_y = embedder_y;
+}
+
+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);
+  printf("gdk_offscreen_window_set_embedder %d %d\n",
+         GDK_IS_WINDOW(gtk_widget_get_window (xww->widget_osr)),
+         GDK_IS_WINDOW(gtk_widget_get_window (GTK_WIDGET (xv->widget))));
+  gdk_offscreen_window_set_embedder (gtk_widget_get_window (xww->widgetwindow_osr),
+                                     gtk_widget_get_window (xv->widget));
+}
+
+
+/* initializes and does initial placement of an xwidget view on screen */
+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;
+  GdkColor color;
+
+  XSETXWIDGET_VIEW (val, xv)  ;
+  Vxwidget_view_list = Fcons (val, Vxwidget_view_list);
+
+  XSETWINDOW(xv->w, s->w);
+  XSETXWIDGET(xv->model, xww);
+
+  //widget creation
+  if(EQ(xww->type, Qbutton))
+    {
+      xv->widget = gtk_button_new_with_label (XSTRING(xww->title)->data);
+      g_signal_connect (G_OBJECT (xv->widget), "clicked",
+                        G_CALLBACK (buttonclick_handler), xv); // the view rather than the model
+    } else if (EQ(xww->type, Qtoggle)) {
+    xv->widget = gtk_toggle_button_new_with_label (XSTRING(xww->title)->data);
+    //xv->widget = gtk_entry_new ();//temp hack to experiment with key propagation TODO entry widget is useful for testing
+  } else if (EQ(xww->type, Qsocket)) {
+    xv->widget = gtk_socket_new ();
+    g_signal_connect_after(xv->widget, "plug-added", G_CALLBACK(xwidget_plug_added), "plug added");
+    g_signal_connect_after(xv->widget, "plug-removed", G_CALLBACK(xwidget_plug_removed), "plug removed");
+    //TODO these doesnt help
+    gtk_widget_add_events(xv->widget, GDK_KEY_PRESS);
+    gtk_widget_add_events(xv->widget, GDK_KEY_RELEASE);
+  } else if (EQ(xww->type, Qslider)) {
+    xv->widget =
+      //gtk_hscale_new (GTK_ADJUSTMENT(gtk_adjustment_new (0.0, 0.0, 100.0, 1.0, 10.0, 10.0)));
+      gtk_hscale_new_with_range ( 0.0, 100.0, 10.0);
+    gtk_scale_set_draw_value (GTK_SCALE (xv->widget), FALSE);  //i think its emacs role to show text and stuff, so disable the widgets own text
+    xv->handler_id = g_signal_connect_after(xv->widget, "value-changed", G_CALLBACK(xwidget_slider_changed), "slider changed");
+  } else if (EQ(xww->type, Qcairo)) {
+    //Cairo view
+    //uhm cairo is differentish in gtk 3.
+    //gdk_cairo_create (gtk_widget_get_window (FRAME_GTK_WIDGET (s->f)));
+    xv->widget = gtk_drawing_area_new();
+    g_signal_connect (G_OBJECT (    xv->widget), "draw",
+                      G_CALLBACK (xwidget_osr_draw_callback), NULL);
+
+  } else if (EQ(xww->type, Qwebkit_osr)||
+             EQ(xww->type, Qsocket_osr)||
+             (!NILP (Fget(xww->type, QCxwgir_class))))//xwgir widgets are OSR
+  {
+    printf("osr init:%s\n",SDATA(SYMBOL_NAME(xww->type)));
+    xv->widget = gtk_drawing_area_new();
+    gtk_widget_set_app_paintable ( xv->widget, TRUE); //because expose event handling
+    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)){
+      /* ///xwgir debug */
+      /* //forward events. this isnt compatible with the set_embedded strategy */
+      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);
+    }
+
+    //draw
+    g_signal_connect (G_OBJECT (xv->widget), "draw",
+                      G_CALLBACK (xwidget_osr_draw_callback), NULL);
+
+  }
+  //else return 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
+  g_object_set_data (G_OBJECT (xv->widget), XG_FRAME_DATA, (gpointer) (s->f)); //the emacs frame
+  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
+  g_object_set_data (G_OBJECT (xv->widgetwindow), XG_XWIDGET, (gpointer) (xww)); //the xwidget window
+  g_object_set_data (G_OBJECT (xv->widgetwindow), XG_XWIDGET_VIEW, (gpointer) (xv)); //the xwidget window
+
+
+  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);
+
+
+
+  //widgettype specific initialization only possible after realization
+  if (EQ(xww->type, Qsocket)) {
+    printf ("xwid:%d socket id:%x %d\n",
+            xww,
+            gtk_socket_get_id (GTK_SOCKET (xv->widget)),
+            gtk_socket_get_id (GTK_SOCKET (xv->widget)));
+    send_xembed_ready_event (xww,
+                             gtk_socket_get_id (GTK_SOCKET (xv->widget)));
+    //gtk_widget_realize(xw->widget);
+  }
+
+  //////////////////////////////////////////////////////////////
+  // xwgir debug
+  if (//EQ(xww->type, Qwebkit_osr)|| //TODO should be able to choose compile time which method to use with webkit
+      EQ(xww->type, Qsocket_osr)||
+      (!NILP (Fget(xww->type, QCxwgir_class))))//xwgir widgets are OSR
+    {
+      printf("gdk_offscreen_window_set_embedder %d %d\n",
+             GDK_IS_WINDOW(gtk_widget_get_window (xww->widget_osr)),
+             GDK_IS_WINDOW(gtk_widget_get_window (GTK_WIDGET (xv->widget))));
+      // set_embedder needs to be called after xv->widget realization
+      gdk_offscreen_window_set_embedder (gtk_widget_get_window (xww->widgetwindow_osr),
+                                         gtk_widget_get_window (xv->widget));
+      g_signal_connect (gtk_widget_get_window (xv->widget), "pick-embedded-child",
+                        G_CALLBACK (offscreen_pick_embedded_child), xww->widgetwindow_osr);
+
+      g_signal_connect (gtk_widget_get_window (xww->widgetwindow_osr), "from-embedder",
+                        G_CALLBACK (offscreen_from_embedder), NULL);
+      g_signal_connect (gtk_widget_get_window (xww->widgetwindow_osr), "to-embedder",
+                        G_CALLBACK (offscreen_to_embedder), NULL);
+    }
+  ////////////////////////////////////////
+
+  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 init.
+
+  */
+  int box_line_hwidth = eabs (s->face->box_line_width);
+  int box_line_vwidth = max (s->face->box_line_width, 0);
+  int height = s->height;
+  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 it here in the display loop because there is no other
+     time to know things like window placement etc.
+  */
+  printf ("xv init for xw %d\n", xww);
+  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 clippng 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?
+    {
+      if (1)//!xwidget_hidden(xv))     //hidden equals not being seen during redisplay
+        {
+          //TODO should be possible to use xwidget_show_view here
+          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
+  //cliping 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
+  //TODO it seems its possible to get out of sync with emacs redraws so emacs bg sometimes shows up instead of xwidget
+  //its just a visual glitch though
+  if (!xwidget_hidden(xv)){
+    gtk_widget_queue_draw (xv->widgetwindow);
+    gtk_widget_queue_draw (xv->widget);
+  }
+}
+
+
+#ifdef HAVE_WEBKIT_OSR
+
+//FUGLY 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 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), SDATA(uri));
+  return Qnil;
+}
+
+
+DEFUN ("xwidget-webkit-execute-script", Fxwidget_webkit_execute_script,  Sxwidget_webkit_execute_script,
+       2, 2, 0,
+       doc:    /* webkit exec js.*/)
+  (Lisp_Object xwidget, Lisp_Object script)
+{
+  WEBKIT_FN_INIT();
+  CHECK_STRING(script);
+  webkit_web_view_execute_script( WEBKIT_WEB_VIEW(xw->widget_osr), SDATA(script));
+  return Qnil;
+}
+
+DEFUN ("xwidget-webkit-get-title", Fxwidget_webkit_get_title,  Sxwidget_webkit_get_title,
+       1, 1, 0,
+       doc:    /* Get 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));
+  //return make_string_from_bytes(str, wcslen((const wchar_t *)str), strlen(str));
+  if(str == 0){
+    //TODO maybe return Qnil instead. I suppose webkit returns nullpointer when doc is not properly loaded or something
+    printf("xwidget-webkit-get-title null webkit title\n");
+    return build_string("");
+  }
+  return build_string(str);
+}
+
+//TODO missnamed
+DEFUN ("xwidget-disable-plugin-for-mime", Fxwidget_disable_plugin_for_mime , Sxwidget_disable_plugin_for_mime,
+      1,1,0, doc: /* */)
+  (Lisp_Object mime)
+{
+  WebKitWebPlugin *wp = webkit_web_plugin_database_get_plugin_for_mimetype
+    (webkit_get_web_plugin_database(),  SDATA(mime));
+  if(wp == NULL) return Qnil;
+  if(webkit_web_plugin_get_enabled (wp)){
+    webkit_web_plugin_set_enabled  (wp, FALSE);
+    return Qt;
+  }
+  return Qnil;
+}
+
+
+void
+xwidget_webkit_dom_dump(WebKitDOMNode* parent)
+{
+  WebKitDOMNodeList* list;
+  int i;
+  int length;
+  WebKitDOMNode* attribute;
+  WebKitDOMNamedNodeMap* attrs;
+  WebKitDOMNode* child;
+  printf("node:%d type:%d name:%s content:%s\n",
+         parent,
+         webkit_dom_node_get_node_type(parent),//1 element 3 text 8 comment 2 attribute
+         webkit_dom_node_get_local_name(parent),
+         webkit_dom_node_get_text_content(parent));
+
+  if(webkit_dom_node_has_attributes(parent)){
+    attrs = webkit_dom_node_get_attributes(parent);
+
+    length = webkit_dom_named_node_map_get_length(attrs);
+    for (int i = 0; i < length; i++) {
+      attribute = webkit_dom_named_node_map_item(attrs,i);
+      printf(" attr node:%d type:%d name:%s content:%s\n",
+             attribute,
+             webkit_dom_node_get_node_type(attribute),//1 element 3 text 8 comment
+             webkit_dom_node_get_local_name(attribute),
+             webkit_dom_node_get_text_content(attribute));
+    }
+  }
+  list = webkit_dom_node_get_child_nodes(parent);
+  length = webkit_dom_node_list_get_length(list);
+
+  for (int i = 0; i < length; i++) {
+    child = webkit_dom_node_list_item(list, i);
+    //if(webkit_dom_node_has_child_nodes(child))
+    xwidget_webkit_dom_dump(child);
+  }
+}
+
+
+DEFUN ("xwidget-webkit-dom-dump", Fxwidget_webkit_dom_dump,  Sxwidget_webkit_dom_dump,
+       1, 1, 0,
+       doc:    /*Dump the DOM contained in the webkit instance in XWIDGET.*/)
+  (Lisp_Object xwidget)
+{
+  WEBKIT_FN_INIT();
+  xwidget_webkit_dom_dump(WEBKIT_DOM_NODE(webkit_web_view_get_dom_document( WEBKIT_WEB_VIEW(xw->widget_osr))));
+  return Qnil;
+}
+
+
+
+#endif  /* HAVE_WEBKIT_OSR */
+
+
+
+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);
+
+
+  printf("resize xwidget %d (%d,%d)->(%d,%d)\n",xw, xw->width,xw->height,w,h);
+  xw->width=w;
+  xw->height=h;
+  //if theres a osr resize it 1st
+  if(xw->widget_osr){
+    printf("resize xwidget_osr\n");
+    //gtk_container_set_resize_mode ( GTK_WINDOW(xw->widgetwindow_osr), GTK_RESIZE_QUEUE);
+    //gtk_container_set_resize_mode ( GTK_WINDOW(xw->widget_osr), GTK_RESIZE_QUEUE);
+
+
+    //gtk_layout_set_size (GTK_LAYOUT (xw->widgetwindow_osr), xw->width, xw->height);
+    gtk_widget_set_size_request (GTK_WIDGET (xw->widget_osr), xw->width, xw->height); //minimum size
+    //gtk_window_resize(    GTK_WINDOW(xw->widget_osr), xw->width, xw->height);
+    gtk_window_resize(    GTK_WINDOW(xw->widgetwindow_osr), xw->width, xw->height);
+    gtk_window_resize(    GTK_WINDOW(xw->widgetscrolledwindow_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_WINDOW(xw->widgetwindow_osr));
+    gtk_container_resize_children (GTK_CONTAINER(xw->widgetwindow_osr));
+
+  }
+
+  for (Lisp_Object tail = Vxwidget_view_list; CONSP (tail); tail = XCDR (tail)) //TODO MVC refactor lazy linear search
+    {
+      if (XWIDGET_VIEW_P (XCAR (tail))) {
+        xv = XXWIDGET_VIEW (XCAR (tail));
+        if(XXWIDGET (xv->model) == xw) {
+          gtk_layout_set_size (GTK_LAYOUT (xv->widgetwindow), xw->width, xw->height);
+          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 scrolling  */)
+  (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;
+
+  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:
+       /* Desired size of the XWIDGET.
+
+  This can be used to read the xwidget desired size,  and resizes the Emacs allocated area accordingly.
+
+(TODO crashes if arg not osr widget)*/)
+  (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: /* Get XWIDGET properties.
+             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:
+       /* Get XWIDGET-VIEW properties.
+        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: /* Get XWIDGET-VIEW model. */)
+  (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: /* Get XWIDGET-VIEW window. */)
+  (Lisp_Object xwidget_view)
+{
+  CHECK_XWIDGET_VIEW (xwidget_view);
+  return XXWIDGET_VIEW (xwidget_view)->w;
+}
+
+DEFUN ("xwidget-send-keyboard-event", Fxwidget_send_keyboard_event, Sxwidget_send_keyboard_event, 2, 2, 0,
+       doc:/* Synthesize a kbd event for  XWIDGET. TODO crashes atm.. */
+       )
+  (Lisp_Object  xwidget, Lisp_Object keydescriptor)
+{
+  //TODO this code crashes for offscreen widgets and ive tried many different strategies
+  //int keyval = 0x058; //X
+  int keyval = XFASTINT(keydescriptor); //X
+  char *keystring = "";
+  GdkKeymapKey* keys;
+  gint n_keys;
+  GdkDeviceManager* manager;
+  struct xwidget *xw;
+  GtkWidget* widget;
+  GdkEventKey* ev;
+  Lisp_Object window;
+  //popup_activated_flag = 1; //TODO just a hack
+  gdk_keymap_get_entries_for_keyval(gdk_keymap_get_default(), keyval, &keys, &n_keys);
+
+  xw = XXWIDGET(xwidget);
+
+  ev = (GdkEventKey*)gdk_event_new(GDK_KEY_PRESS);
+
+
+  //todo what about windowless widgets?
+
+  window = FRAME_SELECTED_WINDOW (SELECTED_FRAME ());
+
+
+  //TODO maybe we also need to special case sockets by picking up the plug rather than the socket
+  if(xw->widget_osr)
+    widget = xw->widget_osr;
+  else
+    widget = xwidget_view_lookup(xw, XWINDOW(window))->widget;
+
+  ev->window = gtk_widget_get_window(widget);
+  gtk_widget_grab_focus(widget);
+  ev->send_event = FALSE;
+
+  ev->hardware_keycode = keys[0].keycode;
+  ev->group = keys[0].group;
+
+  ev->keyval = keyval;
+  ev->time = GDK_CURRENT_TIME;
+
+  //ev->device = gdk_device_get_core_pointer();
+  manager = gdk_display_get_device_manager(gdk_window_get_display(ev->window));
+  gdk_event_set_device ((GdkEvent*)ev,   gdk_device_manager_get_client_pointer(manager));
+  gdk_event_put((GdkEvent*)ev);
+  //g_signal_emit_by_name(ev->window,"key-press-event", ev);
+
+  ev->type = GDK_KEY_RELEASE;
+  gdk_event_put((GdkEvent*)ev);
+  //g_signal_emit_by_name(ev->window,"key-release-event", ev);
+  //gtk_main_do_event(ev);
+
+  //TODO
+  //if I delete the event the receiving component eventually crashes.
+  //it ough TDTRT since event_put is supposed to copy the event
+  //so probably this leaks events now
+  //gdk_event_free((GdkEvent*)ev);
+
+  return Qnil;
+}
+
+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);
+}
+
+DEFUN ("xwidget-view-lookup", Fxwidget_view_lookup, Sxwidget_view_lookup,
+       1, 2, 0,
+       doc: /* Return the xwidget-view associated to XWIDGET in
+WINDOW if specified, otherwise it uses the selected window. */)
+  (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 ("set-frame-visible", Fset_frame_visible, Sset_frame_visible,
+       2, 2, 0,
+       doc: /* HACKY */)
+  (Lisp_Object frame, Lisp_Object flag)
+{
+  CHECK_FRAME (frame);
+  struct frame *f = XFRAME (frame);
+  SET_FRAME_VISIBLE (f, !NILP (flag));
+  return flag;
+}
+
+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 query 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)
+{
+  int i;
+
+  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);
+  defsubr (&Sset_frame_visible);
+
+  #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 (&Sxwgir_xwidget_call_method  );
+  defsubr (&Sxwgir_require_namespace);
+  defsubr (&Sxwidget_size_request  );
+  defsubr (&Sdelete_xwidget_view);
+  defsubr (&Sxwidget_disable_plugin_for_mime);
+
+  defsubr (&Sxwidget_send_keyboard_event);
+  defsubr (&Sxwidget_webkit_dom_dump);
+  defsubr (&Sxwidget_plist);
+  defsubr (&Sxwidget_buffer);
+  defsubr (&Sset_xwidget_plist);
+
+  defsubr (&Sxwidget_set_adjustment);
+
+  DEFSYM (Qxwidget, "xwidget");
+
+  DEFSYM (QCxwidget, ":xwidget");
+  DEFSYM (QCxwgir_class, ":xwgir-class");
+  DEFSYM (QCtitle, ":title");
+
+  /* Do not forget to update the docstring of make-xwidget if you add
+     new types. */
+  DEFSYM (Qbutton, "Button"); //changed to match the gtk class because xwgir(experimental and not really needed)
+  DEFSYM (Qtoggle, "ToggleButton");
+  DEFSYM (Qslider, "slider");
+  DEFSYM (Qsocket, "socket");
+  DEFSYM (Qsocket_osr, "socket-osr");
+  DEFSYM (Qcairo, "cairo");
+
+  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.  */
+
+int
+valid_xwidget_spec_p (Lisp_Object object)
+{
+  int valid_p = 0;
+
+  if (CONSP (object) && EQ (XCAR (object), Qxwidget))
+    {
+      /* Lisp_Object tem; */
+
+      /* for (tem = XCDR (object); CONSP (tem); tem = XCDR (tem)) */
+      /*   if (EQ (XCAR (tem), QCtype)) */
+      /*     { */
+      /*       tem = XCDR (tem); */
+      /*       if (CONSP (tem) && SYMBOLP (XCAR (tem))) */
+      /*         { */
+      /*        struct xwidget_type *type; */
+      /*        type = lookup_xwidget_type (XCAR (tem)); */
+      /*        if (type) */
+      /*          valid_p = type->valid_p (object); */
+      /*         } */
+
+      /*       break; */
+      /*     } */
+      //never mind type support for now
+      valid_p = 1;
+    }
+
+  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) {
+          gtk_widget_destroy(xv->widgetwindow);
+          Vxwidget_view_list = Fdelq (XCAR (tail), Vxwidget_view_list);
+        }
+      }
+    }
+}
+
+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
+
+     TODO remove xwidget init from display spec. simply store an xwidget reference only and set
+     size etc when creating the xwidget, which should happen before insertion into buffer
+  */
+  int found = 0, found1 = 0, found2 = 0;
+  Lisp_Object value;
+  struct xwidget *xw;
+
+  value = xwidget_spec_value (spec, QCxwidget, &found1);
+  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 isnt a candidate for hiding*/
+void
+xwidget_touch (struct xwidget_view *xv)
+{
+  xv->redisplayed = 1;
+}
+
+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;
+  struct xwidget *xw;
+  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);
+          }
+      }
+    }
+}
+
+#endif  /* HAVE_XWIDGETS */
diff --git a/src/xwidget.h b/src/xwidget.h
new file mode 100644 (file)
index 0000000..cbaddf6
--- /dev/null
@@ -0,0 +1,115 @@
+#ifndef XWIDGET_H_INCLUDED
+#define XWIDGET_H_INCLUDED
+
+void x_draw_xwidget_glyph_string (struct glyph_string *s);
+void syms_of_xwidget ();
+
+//extern Lisp_Object Qxwidget;
+
+
+int 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;
+};
+
+static struct xwidget_type *lookup_xwidget_type (Lisp_Object symbol);
+
+struct xwidget* xwidget_from_id(int id);
+
+//extern int xwidget_owns_kbd;
+
+void xwidget_start_redisplay();
+void xwidget_end_redisplay (struct window *w, struct glyph_matrix *matrix);
+
+void xwidget_touch (struct xwidget_view *xw);
+
+//void assert_valid_xwidget_id(int id,char *str);
+
+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 */
diff --git a/test/automated/xwidget-tests.el b/test/automated/xwidget-tests.el
new file mode 100644 (file)
index 0000000..7f79c94
--- /dev/null
@@ -0,0 +1,121 @@
+;; -*- lexical-binding: t; -*-
+
+(require 'cl)
+(require 'xwidget)
+(require 'xwidget-test)
+(require 'parallel)
+
+(defvar xwidget-parallel-config (list :emacs-path (expand-file-name
+                                                   "~/packages/xwidget-build/src/emacs")))
+
+(defmacro xwidget-deftest (name types &rest body)
+  (declare (indent defun))
+  (if (null types)
+      `(ert-deftest ,(intern (format "%s" name)) ()
+         (let ((parallel-config xwidget-parallel-config))
+           ,@body))
+    `(progn
+       ,@(loop for type in types
+               collect
+               `(ert-deftest ,(intern (format "%s-%s" name type)) ()
+                  (let ((parallel-config xwidget-parallel-config)
+                        (type ',type)
+                        (title ,(symbol-name type)))
+                    ,@body))))))
+
+(xwidget-deftest xwidget-make-xwidget (Button ToggleButton slider socket cairo)
+  (let* ((beg 1)
+         (end 1)
+         (width 100)
+         (height 100)
+         (data nil)
+         (proc (parallel-start
+                (lambda (beg end type title width height data)
+                  (require 'xwidget)
+                  (require 'cl)
+                  (with-temp-buffer
+                    (insert ?\0)
+                    (let* ((buffer (current-buffer))
+                           (xwidget (make-xwidget beg end type title width height data buffer)))
+                      (set-xwidget-query-on-exit-flag xwidget nil)
+                      (parallel-remote-send (coerce (xwidget-info xwidget) 'list))
+                      (parallel-remote-send (buffer-name buffer))
+                      (buffer-name (xwidget-buffer xwidget)))))
+                :env (list beg end type title width height data)))
+         (results (parallel-get-results proc)))
+    (should (parallel-success-p proc))
+    (when (parallel-success-p proc)
+      (destructuring-bind (xwidget-buffer temp-buffer xwidget-info)
+          results
+        (should (equal (list type title width height)
+                       xwidget-info))
+        (should (equal temp-buffer xwidget-buffer))))))
+
+(xwidget-deftest xwidget-query-on-exit-flag ()
+  (should (equal '(nil t)
+                 (parallel-get-results
+                  (parallel-start (lambda ()
+                                    (require 'xwidget)
+                                    (let ((xwidget (make-xwidget 1 1 'Button "Button" 100 100 nil)))
+                                      (parallel-remote-send (xwidget-query-on-exit-flag xwidget))
+                                      (set-xwidget-query-on-exit-flag xwidget nil)
+                                      (xwidget-query-on-exit-flag xwidget))))))))
+
+(xwidget-deftest xwidget-query-on-exit-flag (Button ToggleButton slider socket cairo)
+  (should (parallel-get-result
+           (parallel-start (lambda (type title)
+                             (require 'xwidget)
+                             (with-temp-buffer
+                               (let ((xwidget (make-xwidget 1 1 type title 10 10 nil)))
+                                 (set-xwidget-query-on-exit-flag xwidget nil)
+                                 (xwidgetp xwidget))))
+                           :env (list type title)))))
+
+(xwidget-deftest xwidget-CHECK_XWIDGET ()
+  (should (equal (parallel-get-result
+                  (parallel-start (lambda ()
+                                    (require 'xwidget)
+                                    (xwidget-info nil))))
+                 '(wrong-type-argument xwidgetp nil)))
+  (should (equal (parallel-get-result
+                  (parallel-start (lambda ()
+                                    (require 'xwidget)
+                                    (xwidget-view-info nil))))
+                 '(wrong-type-argument xwidget-view-p nil))))
+
+(xwidget-deftest xwidget-view-p (Button ToggleButton slider socket cairo)
+  (should (parallel-get-result
+           (parallel-start (lambda (type title)
+                             (require 'xwidget)
+                             (with-temp-buffer
+                               (insert ?\0)
+                               (let* ((xwidget (xwidget-insert 1 type title 100 100))
+                                      (window (xwidget-display xwidget)))
+                                 (set-xwidget-query-on-exit-flag xwidget nil)
+                                 (xwidget-view-p
+                                  (xwidget-view-lookup xwidget window)))))
+                           :env (list type title)
+                           :graphical t
+                           :emacs-args '("-T" "emacs-debug")))))
+
+(defun xwidget-interactive-tests ()
+  "Interactively test Button ToggleButton and slider.
+
+Start Emacs instances and try to insert the xwidget."
+  (interactive)
+  (flet ((test-xwidget (type)
+                       (parallel-get-result
+                        (parallel-start (lambda ()
+                                          (require 'xwidget)
+                                          (with-temp-buffer
+                                            (insert ?\0)
+                                            (set-xwidget-query-on-exit-flag
+                                             (xwidget-insert 1 type (format "%s" type) 100 100) nil)
+                                            (display-buffer (current-buffer))
+                                            (cons type (or (y-or-n-p (format "Do you see a %s?" type)) 'failed))))
+                                        :graphical t
+                                        :debug t
+                                        :config xwidget-parallel-config))))
+    (message "%S" (mapcar #'test-xwidget '(Button ToggleButton slider)))))
+
+(provide 'xwidget-tests)
diff --git a/test/xwidget-test-manual.el b/test/xwidget-test-manual.el
new file mode 100644 (file)
index 0000000..3732dca
--- /dev/null
@@ -0,0 +1,204 @@
+;;test like:
+;; cd /path/to/xwidgets-emacs-dir
+;; make   all&&  src/emacs -q --eval "(progn (load \"`pwd`/lisp/xwidget-test.el\") (xwidget-demo-basic))"
+
+
+;; you should see:
+;; - a gtk button
+;; - a gtk toggle button
+;; - a gtk slider button
+;; - an xembed window(using gtk_socket) showing another emacs instance
+;; - an xembed window(using gtk_socket) showing an uzbl web browser if its installed
+
+;;the widgets will move when you type in the buffer. good!
+
+;;there will be redrawing issues when widgets change rows, etc. bad!
+
+;;its currently difficult to give kbd focus to the xembedded emacs,
+;;but try evaling the following:
+
+;; (xwidget-set-keyboard-grab 3 1)
+
+
+
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; demo/test functions
+(require 'xwidget)
+
+(defmacro xwidget-demo (name &rest body)
+  `(defun ,(intern (concat "xwidget-demo-" name)) ()
+     (interactive)
+     (switch-to-buffer ,(format "*xwidget-demo-%s*" name))
+     (text-mode);;otherwise no local keymap
+     (insert "Some random text for xwidgets to be inserted in for demo purposes.\n")
+     ,@body))
+
+(xwidget-demo "a-button"
+              (xwidget-insert (point-min) 'Button  "button" 60  50)
+              (define-key (current-local-map) [xwidget-event] 'xwidget-handler-demo-basic))
+
+(xwidget-demo "a-button-bidi"
+              (xwidget-insert (+ 5 (point-min)) 'Button  "button" 60  50)
+              (set (make-local-variable 'bidi-paragraph-direction) 'right-to-left)
+              (define-key (current-local-map) [xwidget-event] 'xwidget-handler-demo-basic))
+
+
+(xwidget-demo "a-toggle-button"
+              (xwidget-insert (point-min) 'ToggleButton  "toggle" 60  50)
+              (define-key (current-local-map) [xwidget-event] 'xwidget-handler-demo-basic))
+
+(xwidget-demo "a-big-button"
+              (xwidget-insert (point-min)  'Button "button" 400  500)
+              (define-key (current-local-map) [xwidget-event] 'xwidget-handler-demo-basic))
+
+(xwidget-demo "a-socket"
+              (xwidget-insert (point-min)  'socket "socket" 500  500)
+              (define-key (current-local-map) [xwidget-event] 'xwidget-handler-demo-basic))
+
+(xwidget-demo "a-socket-osr-broken"
+              (xwidget-insert (point-min)  'socket-osr "socket-osr" 500  500)
+              (define-key (current-local-map) [xwidget-event] 'xwidget-handler-demo-basic))
+
+
+(xwidget-demo "a-slider"
+              (xwidget-insert (point-min)  'slider "slider" 500  100)
+              (define-key (current-local-map) [xwidget-event] 'xwidget-handler-demo-basic))
+
+(xwidget-demo "a-canvas"
+              (xwidget-insert (point-min)  'cairo "canvas" 1000  1000)
+              (define-key (current-local-map) [xwidget-event] 'xwidget-handler-demo-basic))
+
+(xwidget-demo "a-webkit-broken"
+              (xwidget-insert (point-min)  'webkit "webkit" 1000  1000)
+              (define-key (current-local-map) [xwidget-event] 'xwidget-handler-demo-basic))
+
+(xwidget-demo "a-webkit-osr"
+              (xwidget-insert (point-min)  'webkit-osr "webkit-osr" 1000  1000)
+              (define-key (current-local-map) [xwidget-event] 'xwidget-handler-demo-basic)
+              (xwidget-webkit-goto-uri (xwidget-at 1) "http://www.fsf.org"))
+
+(xwidget-demo "a-xwgir"
+              (xwidget-insert (point-min)  'xwgir "xwgir" 1000  1000)
+              (define-key (current-local-map) [xwidget-event] 'xwidget-handler-demo-basic))
+
+(xwidget-demo "a-xwgir-color-button"
+              (xwgir-require-namespace "Gtk" "3.0")
+              (put 'ColorButton :xwgir-class '("Gtk" "ColorSelection"))
+              (xwidget-insert (point-min)  'ColorButton "xwgir-color-button" 1000  1000)
+              (define-key (current-local-map) [xwidget-event] 'xwidget-handler-demo-basic))
+
+(xwidget-demo "a-xwgir-button"
+              (xwgir-require-namespace "Gtk" "3.0")
+              (put 'xwgirButton :xwgir-class '("Gtk" "Button"))
+
+              (xwidget-insert (point-min)  'xwgirButton "xwgir label didnt work..." 700  700)
+              (xwgir-xwidget-call-method (xwidget-at 1) "set_label" '( "xwgir label worked!"))
+              (define-key (current-local-map) [xwidget-event] 'xwidget-handler-demo-basic))
+
+(xwidget-demo "a-xwgir-check-button"
+              (xwgir-require-namespace "Gtk" "3.0")
+              (put 'xwgirCheckButton :xwgir-class '("Gtk" "CheckButton"))
+
+              (xwidget-insert (point-min)  'xwgirCheckButton "xwgir label didnt work..." 700  700)
+              (define-key (current-local-map) [xwidget-event] 'xwidget-handler-demo-basic))
+
+(xwidget-demo "a-xwgir-hscale"
+              (xwgir-require-namespace "Gtk" "3.0")
+              (put 'xwgirHScale :xwgir-class '("Gtk" "HScale"))
+
+              (xwidget-insert (point-min)  'xwgirHScale "xwgir label didnt work..." 700  700)
+              (define-key (current-local-map) [xwidget-event] 'xwidget-handler-demo-basic))
+
+(xwidget-demo "a-xwgir-webkit"
+              (xwgir-require-namespace "WebKit" "3.0")
+              (put 'xwgirWebkit :xwgir-class '("WebKit" "WebView"))
+
+              (xwidget-insert (point-min)  'xwgirWebkit "xwgir webkit..." 700  700)
+              (define-key (current-local-map) [xwidget-event] 'xwidget-handler-demo-basic))
+
+
+
+;; tentative testcase:
+;; (xwgir-require-namespace "WebKit" "3.0")
+
+;; (put 'webkit-osr :xwgir-class '("WebKit" "WebView"))
+;; (xwgir-call-method (xwidget-at 1) "set_zoom_level" '(3.0))
+
+;; (xwgir-require-namespace "Gtk" "3.0")
+;; (put 'color-selection :xwgir-class '("Gtk" "ColorSelection"))
+
+
+(xwidget-demo "basic"
+  (xwidget-insert (point-min)  'button "button" 40  50 )
+  (xwidget-insert          15  'toggle "toggle" 60  30  )
+  (xwidget-insert          30  'socket "emacs"  400 200 )
+  (xwidget-insert          20  'slider "slider" 100 50  )
+  (xwidget-insert          40  'socket "uzbl-core"   400 400 )
+  (define-key (current-local-map) [xwidget-event] 'xwidget-handler-demo-basic)
+)
+
+
+;it doesnt seem gtk_socket_steal works very well. its deprecated.
+; xwininfo -int
+; then (xwidget-embed-steal 3 <winid>)
+(defun xwidget-demo-grab ()
+  (interactive)
+  (insert "0 <<< grabbed appp will appear here\n")
+  (xwidget-insert          1 1 3 "1" 1000 )
+  (define-key (current-local-map) [xwidget-event] 'xwidget-handler-demo-grab)
+  )
+
+;ive basically found these xembeddable things:
+;openvrml
+;emacs
+;mplayer
+;surf
+;uzbl
+
+;try the openvrml:
+;/usr/libexec/openvrml-xembed 0 ~/Desktop/HelloWorld.wrl
+
+(defun xwidget-handler-demo-basic ()
+  (interactive)
+  (message "stuff happened to xwidget %S" last-input-event)
+  (let*
+      ((xwidget-event-type (nth 1 last-input-event))
+       (xwidget (nth 2 last-input-event)))
+    (cond ( (eq xwidget-event-type 'xembed-ready)
+            (let*
+                ((xembed-id (nth 3 last-input-event)))
+              (message "xembed ready  event: %S xw-id:%s" xembed-id xwidget)
+              ;;will start emacs/uzbl in a xembed socket when its ready
+              (cond
+               (t;;(eq 3 xwidget)
+                (start-process "xembed" "*xembed*" "/var/lib/jenkins/jobs/emacs-xwidgets-automerge/workspace/src/emacs" "-q" "--parent-id" (number-to-string xembed-id) ) )
+;;               ((eq 5 xwidget-id)
+;;                (start-process "xembed2" "*xembed2*" "uzbl-core"  "-s" (number-to-string xembed-id)  "http://www.fsf.org" )
+               )
+
+               )
+            ))))
+
+
+
+(defun xwidget-handler-demo-grab ()
+  (interactive)
+  (message "stuff happened to xwidget %S" last-input-event)
+  (let*
+      ((xwidget-event-type (nth 2 last-input-event)))
+    (cond ( (eq xwidget-event-type 'xembed-ready)
+            (let*
+                ((xembed-id (nth 3 last-input-event)))
+              (message "xembed ready  %S" xembed-id)
+              )
+            ))))
+(defun xwidget-dummy-hook ()
+  (message "xwidget dummy hook called"))
+
+;  (xwidget-resize-hack 1 200 200)
+
+;(xwidget-demo-basic)
+
+(provide 'xwidget-test-manual)