summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--README.xwidget35
-rw-r--r--configure.ac43
-rw-r--r--lisp/net/browse-url.el13
-rw-r--r--lisp/xwidget.el592
-rw-r--r--src/Makefile.in10
-rw-r--r--src/buffer.c8
-rw-r--r--src/dispextern.h27
-rw-r--r--src/dispnew.c12
-rw-r--r--src/emacs.c6
-rw-r--r--src/emacsgtkfixed.c112
-rw-r--r--src/emacsgtkfixed.h28
-rw-r--r--src/keyboard.c25
-rw-r--r--src/lisp.h5
-rw-r--r--src/print.c16
-rw-r--r--src/termhooks.h4
-rw-r--r--src/window.c6
-rw-r--r--src/xdisp.c259
-rw-r--r--src/xterm.c15
-rw-r--r--src/xwidget.c2062
-rw-r--r--src/xwidget.h120
-rw-r--r--test/xwidget-test-manual.el212
21 files changed, 3589 insertions, 21 deletions
diff --git a/README.xwidget b/README.xwidget
new file mode 100644
index 00000000000..650be0dac9f
--- /dev/null
+++ b/README.xwidget
@@ -0,0 +1,35 @@
+-*-org-*-
+Please see https://github.com/jave/xwidget-aux for documentation.
+
+* NEWS
+** Xwidgets : A new feature for embedding native widgets
+inside Emacs buffers. If you have gtk3 and webkit-devel installed,
+you can try the embedded webkit browser with m-x xwidget-webkit-browse-url.
+
+
+* lisp/Changelog
+
+2015-02-01 Joakim Verona <joakim@verona.se>
+ Support for the new Xwidget feature.
+ * xwidget.el:
+* src/Changelog
+2015-02-01 Joakim Verona <joakim@verona.se>
+ Support for the new Xwidget feature.
+ * window.c, Makefile.in, buffer.c, dispextern.h, dispnew.c, emacs.c:
+ * emacsgtkfixed.c, emacsgtkfixed.h, keyboard.c, lisp.h, print.c:
+ * termhooks.h, window.c, xdisp.c, xterm.c
+ New files for xwidgets:
+ * xwidget.c, xwidget.h:
+ Support for testing xwidgets
+ * xwidget-test-manual.el:
+
+2015-02-01 Grégoire Jadi <daimrod@gmail.com>
+ Support for testing xwidgets
+ * parallell-remote.el, parallell-xwidget.el, parallell.el:
+ * xwidget-tests.el:
+ various improvements to xwidgets:
+ * xwidgets.c:
+* Changelog
+2015-02-01 Joakim Verona <joakim@verona.se>
+ Support for the new Xwidget feature.
+ * configure.ac:
diff --git a/configure.ac b/configure.ac
index 192634bdc45..3874cf1ee96 100644
--- a/configure.ac
+++ b/configure.ac
@@ -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 in Emacs buffers])
+
## For the times when you want to build Emacs but don't have
## a suitable makeinfo, and can live without the manuals.
dnl http://lists.gnu.org/archive/html/emacs-devel/2008-04/msg01844.html
@@ -2522,6 +2524,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
@@ -4801,7 +4838,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)
@@ -5122,6 +5159,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/net/browse-url.el b/lisp/net/browse-url.el
index 42fb9549255..57c7b61fc28 100644
--- a/lisp/net/browse-url.el
+++ b/lisp/net/browse-url.el
@@ -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
index 00000000000..a4e4a422df9
--- /dev/null
+++ b/lisp/xwidget.el
@@ -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 &optional args)
+ "Insert an xwidget at POS.
+given ID, TYPE, TITLE WIDTH and
+HEIGHT in the current buffer.
+
+Return ID
+
+see `make-xwidget' for types suitable for TYPE."
+ (goto-char pos)
+ (let ((id (make-xwidget (point) (point)
+ type title width height args)))
+ (put-text-property (point) (+ 1 (point))
+ 'display (list 'xwidget ':xwidget id))
+ id))
+
+(defun xwidget-at (pos)
+ "Return xwidget at POS."
+ ;;TODO this function is a bit tedious because the C layer isnt well protected yet and
+ ;;xwidgetp aparently doesnt work yet
+ (let* ((disp (get-text-property pos 'display))
+ (xw (car (cdr (cdr disp)))))
+ ;;(if ( xwidgetp xw) xw nil)
+ (if (equal 'xwidget (car disp)) xw)))
+
+
+;; (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
diff --git a/src/Makefile.in b/src/Makefile.in
index 32615c848a7..81977dbfec2 100644
--- a/src/Makefile.in
+++ b/src/Makefile.in
@@ -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) \
diff --git a/src/buffer.c b/src/buffer.c
index 67eda3ee89e..223683db6f3 100644
--- a/src/buffer.c
+++ b/src/buffer.c
@@ -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))
diff --git a/src/dispextern.h b/src/dispextern.h
index b0f2944da86..5ec1b373ac9 100644
--- a/src/dispextern.h
+++ b/src/dispextern.h
@@ -348,6 +348,10 @@ enum glyph_type
/* Glyph is a space of fractional width and/or height. */
STRETCH_GLYPH
+#ifdef HAVE_XWIDGETS
+ /* Glyph is an external widget drawn by the GUI toolkit. */
+ ,XWIDGET_GLYPH
+#endif
};
@@ -499,6 +503,9 @@ struct glyph
/* Image ID for image glyphs (type == IMAGE_GLYPH). */
int img_id;
+#ifdef HAVE_XWIDGETS
+ struct xwidget* xwidget;
+#endif
/* Sub-structure for type == STRETCH_GLYPH. */
struct
{
@@ -1350,6 +1357,9 @@ struct glyph_string
/* Image, if any. */
struct image *img;
+#ifdef HAVE_XWIDGETS
+ struct xwidget* xwidget;
+#endif
/* Slice */
struct glyph_slice slice;
@@ -2094,6 +2104,10 @@ enum display_element_type
/* Continuation glyphs. See the comment for IT_TRUNCATION. */
IT_CONTINUATION
+
+#ifdef HAVE_XWIDGETS
+ ,IT_XWIDGET
+#endif
};
@@ -2157,6 +2171,9 @@ enum it_method {
GET_FROM_C_STRING,
GET_FROM_IMAGE,
GET_FROM_STRETCH,
+#ifdef HAVE_XWIDGETS
+ GET_FROM_XWIDGET,
+#endif
NUM_IT_METHODS
};
@@ -2378,6 +2395,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. */
@@ -2502,6 +2525,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;
diff --git a/src/dispnew.c b/src/dispnew.c
index a1782913154..6ee4ccedf0b 100644
--- a/src/dispnew.c
+++ b/src/dispnew.c
@@ -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;
@@ -4115,6 +4122,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;
diff --git a/src/emacs.c b/src/emacs.c
index fdd17d1e062..87b1f11d59b 100644
--- a/src/emacs.c
+++ b/src/emacs.c
@@ -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 ();
diff --git a/src/emacsgtkfixed.c b/src/emacsgtkfixed.c
index abec78fb073..598c5c1a81e 100644
--- a/src/emacsgtkfixed.c
+++ b/src/emacsgtkfixed.c
@@ -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,9 +67,86 @@ 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)
{
@@ -76,9 +156,13 @@ emacs_fixed_class_init (EmacsFixedClass *klass)
widget_class->get_preferred_width = emacs_fixed_get_preferred_width;
widget_class->get_preferred_height = emacs_fixed_get_preferred_height;
+#ifdef HAVE_XWIDGETS
+ widget_class->size_allocate = emacs_fixed_gtk_widget_size_allocate;
+#endif
g_type_class_add_private (klass, sizeof (EmacsFixedPrivate));
}
+
static void
emacs_fixed_init (EmacsFixed *fixed)
{
diff --git a/src/emacsgtkfixed.h b/src/emacsgtkfixed.h
index bcf1cd9072e..7364d906cf6 100644
--- a/src/emacsgtkfixed.h
+++ b/src/emacsgtkfixed.h
@@ -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
diff --git a/src/keyboard.c b/src/keyboard.c
index 1176d701f2a..a9ff77d0473 100644
--- a/src/keyboard.c
+++ b/src/keyboard.c
@@ -4124,6 +4124,20 @@ kbd_buffer_get_event (KBOARD **kbp,
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)
{
obj = make_lispy_event (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 */
diff --git a/src/lisp.h b/src/lisp.h
index f5242ab84a1..87bc3efd198 100644
--- a/src/lisp.h
+++ b/src/lisp.h
@@ -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,
diff --git a/src/print.c b/src/print.c
index 1a0aebbeba7..75288bc6a3a 100644
--- a/src/print.c
+++ b/src/print.c
@@ -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;
diff --git a/src/termhooks.h b/src/termhooks.h
index 3cafc437e59..58ae2397d78 100644
--- a/src/termhooks.h
+++ b/src/termhooks.h
@@ -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
diff --git a/src/window.c b/src/window.c
index 293140041a9..5cbd58ddde9 100644
--- a/src/window.c
+++ b/src/window.c
@@ -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). */
diff --git a/src/xdisp.c b/src/xdisp.c
index ef9d72d5ab9..faec93fc6f9 100644
--- a/src/xdisp.c
+++ b/src/xdisp.c
@@ -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
@@ -17002,6 +17055,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
@@ -18596,6 +18656,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
}
@@ -24013,6 +24095,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))
{
@@ -24507,6 +24596,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,
@@ -24843,6 +24944,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
@@ -24964,7 +25079,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; \
@@ -24995,8 +25110,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); \
@@ -25015,6 +25137,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:
@@ -25653,6 +25787,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
@@ -26993,6 +27234,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
@@ -27362,6 +27607,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)
diff --git a/src/xterm.c b/src/xterm.c
index 6a63a454bac..555af2b536c 100644
--- a/src/xterm.c
+++ b/src/xterm.c
@@ -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;
@@ -8020,6 +8030,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
index 00000000000..b68d3cb70ff
--- /dev/null
+++ b/src/xwidget.c
@@ -0,0 +1,2062 @@
+#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"
+/* Convert STRING, a string constant, to a type acceptable as glib data.
+ Paul Eggert*/
+static char *
+gstr (char const *string)
+{
+ return (char *) string;
+}
+
+
+//TODO embryo of lisp allocators for xwidgets
+//TODO xwidget* should be Lisp_xwidget*
+static struct xwidget *
+allocate_xwidget (void)
+{
+ return ALLOCATE_PSEUDOVECTOR (struct xwidget, height, PVEC_XWIDGET);
+}
+
+//TODO xwidget_view* should be Lisp_xwidget_view*
+static struct xwidget_view *
+allocate_xwidget_view (void)
+{
+ return ALLOCATE_PSEUDOVECTOR (struct xwidget_view, redisplayed,
+ PVEC_XWIDGET_VIEW);
+}
+
+#define XSETXWIDGET(a, b) (XSETPSEUDOVECTOR (a, b, PVEC_XWIDGET))
+#define XSETXWIDGET_VIEW(a, b) (XSETPSEUDOVECTOR (a, b, PVEC_XWIDGET_VIEW))
+
+struct xwidget_view *xwidget_view_lookup (struct xwidget *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);
+
+static GtkWidget *xwgir_create (char *, char *, char *, Lisp_Object);
+
+
+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
+
+ ARGUMENTS are xwgir constructor args
+ */
+)(Lisp_Object beg, Lisp_Object end,
+ Lisp_Object type,
+ Lisp_Object title,
+ Lisp_Object width, Lisp_Object height,
+ Lisp_Object arguments, Lisp_Object buffer)
+{
+ //should work a bit like "make-button"(make-button BEG END &rest PROPERTIES)
+ // arg "type" and fwd should be keyword args eventually
+ //(make-xwidget 3 3 'button "oei" 31 31 nil)
+ //(xwidget-info (car xwidget-list))
+ struct xwidget *xw = allocate_xwidget ();
+ Lisp_Object val;
+ xw->type = type;
+ xw->title = title;
+ if (NILP (buffer))
+ buffer = Fcurrent_buffer (); // no need to gcpro because Fcurrent_buffer doesn't call Feval/eval_sub.
+ else
+ buffer = Fget_buffer_create (buffer);
+ xw->buffer = buffer;
+
+ xw->height = XFASTINT (height);
+ xw->width = XFASTINT (width);
+ xw->kill_without_query = 0;
+ XSETXWIDGET (val, xw); // set the vectorlike_header of VAL
+ // with the correct value
+ Vxwidget_list = Fcons (val, Vxwidget_list);
+ xw->widgetwindow_osr = NULL;
+ xw->widget_osr = NULL;
+ xw->plist = Qnil;
+
+
+
+
+#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 (SSDATA (Fcar (Fcdr (Fget (xw->type, QCxwgir_class)))), //class
+ SSDATA (Fcar (Fget (xw->type, QCxwgir_class))), //namespace
+ SSDATA (Fcar (Fcdr (Fcdr (Fget (xw->type, QCxwgir_class))))), //constructor
+ arguments
+ );
+
+ 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;
+}
+
+static 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));
+ 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);
+
+}
+
+static void
+xwidget_show_view (struct xwidget_view *xv)
+{
+ xv->hidden = 0;
+ gtk_widget_show (xv->widgetwindow);
+ gtk_fixed_move (GTK_FIXED (xv->emacswindow), xv->widgetwindow, xv->x + xv->clip_left, xv->y + xv->clip_top); //TODO refactor
+}
+
+
+/* hide an xvidget view */
+static 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);
+}
+
+
+static void
+xwidget_plug_added (GtkSocket * socket, gpointer user_data)
+{
+ //hmm this doesnt seem to get called for foreign windows
+ printf ("xwidget_plug_added\n");
+}
+
+static 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 */
+}
+
+
+static 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 xv_widget)
+{
+ // Queue a redraw of onscreen widget
+ // There is a guard against receiving an invalid widget,
+ // which should only happen if we failed to remove the
+ // the specific signal handler for the damage event
+ if (GTK_IS_WIDGET (xv_widget))
+ gtk_widget_queue_draw (GTK_WIDGET (xv_widget));
+ else
+ printf ("Warning, offscreen_damage_event received invalid xv pointer:%p\n",
+ (void *) xv_widget);
+
+
+ return FALSE;
+}
+
+static void
+store_xwidget_event_string (struct xwidget *xw, const char *eventname,
+ const char *eventstr)
+{
+ //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);
+
+ store_xwidget_event_string (xw, "document-load-finished", "");
+}
+
+gboolean
+webkit_osr_download_callback (WebKitWebView * webkitwebview,
+ WebKitDownload * arg1, gpointer 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);
+ store_xwidget_event_string (xw, "navigation-policy-decision-requested",
+ webkit_web_navigation_action_get_original_uri
+ (navigation_action));
+ return FALSE;
+}
+
+//for gtk3 offscreen rendered widgets
+static gboolean
+xwidget_osr_draw_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;
+}
+
+static gboolean
+xwidget_osr_event_forward (GtkWidget * widget,
+ GdkEvent * event, gpointer user_data)
+{
+ /* copy events that arrive at the outer widget to the offscreen widget */
+ struct xwidget *xw =
+ (struct xwidget *) g_object_get_data (G_OBJECT (widget), XG_XWIDGET);
+ GdkEvent *eventcopy = gdk_event_copy (event);
+ eventcopy->any.window = gtk_widget_get_window (xw->widget_osr); // works
+
+ 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)
+{
+ const gchar *namespace = SSDATA (lnamespace);
+ const gchar *namespace_version = SSDATA (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;
+}
+
+
+static int
+xwgir_convert_lisp_to_gir_arg (GIArgument * giarg,
+ GIArgInfo * arginfo, Lisp_Object lisparg)
+{
+
+ GITypeTag tag;
+ 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;
+}
+
+GtkWidget *
+xwgir_create (char *class, char *namespace, char *constructor,
+ Lisp_Object arguments)
+{
+ //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
+
+ GIArgument return_value;
+
+ GIObjectInfo *obj_info =
+ g_irepository_find_by_name (girepository, namespace, class);
+ //some constructors are like "new_with_label etc
+ GIFunctionInfo *f_info = g_object_info_find_method (obj_info, constructor);
+ g_function_info_invoke (f_info, NULL, 0, NULL, 0, &return_value, NULL);
+
+
+ //////////////////////////////////////////////////////////////////////////////
+ // refactorable
+
+ //loop over args, convert from lisp to primitive type, given arg
+ //introspection data TODO g_callable_info_get_n_args(f_info) should
+ //match
+ GError *error = NULL;
+ GIArgument in_args[20];
+
+ 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 NULL;
+ }
+ int i;
+ Lisp_Object n;
+ for (i = 0; i < argscount ; ++i)
+ {
+ XSETFASTINT (n, i);
+ xwgir_convert_lisp_to_gir_arg (&in_args[i],
+ g_callable_info_get_arg (f_info, i),
+ Fnth (n, arguments));
+ }
+
+ //in_args[0].v_pointer = widget;
+ //g_function_info_invoke (f_info, NULL, 0, NULL, 0, &return_value, NULL);
+ if (!g_function_info_invoke (f_info,
+ in_args, argscount,
+ NULL, 0, &return_value, &error))
+ {
+ //g_error("ERROR: %s\n", error->message);
+ printf ("invokation error\n");
+ return NULL;
+ }
+ ///////////////////////////////////////
+
+
+
+ return return_value.v_pointer;
+
+}
+
+
+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 = SSDATA (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 = SSDATA (Fcar (Fcdr (Fget (xw->type, QCxwgir_class))));
+ //////////////////////////////////////////////////////////////////////////////
+ // class, namespace, argumentss
+ GIObjectInfo *obj_info =
+ g_irepository_find_by_name (girepository, namespace, class);
+ GIFunctionInfo *f_info =
+ g_object_info_find_method (obj_info, SSDATA (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;
+}
+
+static 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));
+}
+
+static 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;
+}
+
+static 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;
+}
+
+static gboolean
+xwidget_osr_event_set_embedder (GtkWidget * widget,
+ GdkEvent * event, gpointer data)
+{
+ struct xwidget_view *xv = (struct xwidget_view *) data;
+ struct xwidget *xww = XXWIDGET (xv->model);
+ 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));
+ return FALSE;
+}
+
+
+/* initializes and does initial placement of an xwidget view on screen */
+static struct xwidget_view *
+xwidget_init_view (struct xwidget *xww, struct glyph_string *s, int x, int y)
+{
+ struct xwidget_view *xv = allocate_xwidget_view ();
+ Lisp_Object val;
+
+ XSETXWIDGET_VIEW (val, xv);
+ Vxwidget_view_list = Fcons (val, Vxwidget_view_list);
+
+ XSETWINDOW (xv->w, s->w);
+ XSETXWIDGET (xv->model, xww);
+
+ //widget creation
+ if (EQ (xww->type, Qbutton))
+ {
+ xv->widget = gtk_button_new_with_label (SSDATA (xww->title));
+ 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 (SSDATA (xww->title));
+ //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),
+ gstr ("plug added"));
+ g_signal_connect_after (xv->widget, "plug-removed",
+ G_CALLBACK (xwidget_plug_removed),
+ gstr ("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),
+ gstr ("slider changed"));
+ }
+ 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:%p socket id:%p %p\n",
+ (void *) xww,
+ (void *) gtk_socket_get_id (GTK_SOCKET (xv->widget)),
+ (void *) 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, Qsocket_osr) || (!NILP (Fget (xww->type, QCxwgir_class))))
+ {
+ 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.
+
+ */
+ 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.
+ */
+ 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), SSDATA (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),
+ SSDATA (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 (), SSDATA (mime));
+ if (wp == NULL)
+ return Qnil;
+ if (webkit_web_plugin_get_enabled (wp))
+ {
+ webkit_web_plugin_set_enabled (wp, FALSE);
+ return Qt;
+ }
+ return Qnil;
+}
+
+#ifdef HAVE_XLXW_DOMDUMP
+/* dom dumping is work in progress.
+ 2 of the methods used from webkit are deprecated nowm and replacements sought
+ */
+static void
+xwidget_webkit_dom_dump (WebKitDOMNode * parent)
+{
+ WebKitDOMNodeList *list;
+ 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_XLXW_DOMDUMP */
+
+#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);
+
+ xw->width = w;
+ xw->height = h;
+ //if theres a osr resize it 1st
+ if (xw->widget_osr)
+ {
+ gtk_widget_set_size_request (GTK_WIDGET (xw->widget_osr),
+ xw->width, xw->height); //minimum size
+ gtk_window_resize (GTK_WINDOW (xw->widgetwindow_osr), xw->width,
+ xw->height);
+ /* gtk_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_CONTAINER (xw->widgetwindow_osr));
+
+ }
+
+ for (Lisp_Object tail = Vxwidget_view_list; CONSP (tail); tail = XCDR (tail))
+ {
+ if (XWIDGET_VIEW_P (XCAR (tail)))
+ {
+ xv = XXWIDGET_VIEW (XCAR (tail));
+ if (XXWIDGET (xv->model) == xw)
+ {
+ /* gtk_layout_set_size (GTK_CONTAINER
+ (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;
+
+ adjustment =
+ gtk_scrolled_window_get_vadjustment (GTK_SCROLLED_WINDOW
+ (xw->widgetscrolledwindow_osr));
+ if (EQ (Qvertical, axis))
+ {
+ adjustment =
+ gtk_scrolled_window_get_vadjustment (GTK_SCROLLED_WINDOW
+ (xw->widgetscrolledwindow_osr));
+ }
+ if (EQ (Qhorizontal, axis))
+ {
+ adjustment =
+ gtk_scrolled_window_get_hadjustment (GTK_SCROLLED_WINDOW
+ (xw->widgetscrolledwindow_osr));
+ }
+
+ if (EQ (Qt, relative))
+ {
+ final_value = gtk_adjustment_get_value (adjustment) + XFASTINT (value);
+ }
+ else
+ {
+ final_value = 0.0 + XFASTINT (value);
+ }
+
+ gtk_adjustment_set_value (adjustment, final_value);
+
+ return Qnil;
+}
+
+
+DEFUN ("xwidget-size-request",
+ Fxwidget_size_request, Sxwidget_size_request,
+ 1, 1, 0, doc:
+ /* 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
+ 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);
+ // xv->model still has signals pointing to the view
+ // there can be several views. find the matchin signals and delete them
+ int i;
+ i = g_signal_handlers_disconnect_matched (XXWIDGET (xv->model)->widgetwindow_osr,
+ G_SIGNAL_MATCH_DATA,
+ 0, 0, 0, 0,
+ xv->widget);
+ printf ("delete view num signals %d\n",i);
+
+
+ return Qnil;
+}
+
+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)
+{
+
+ 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);
+#ifdef HAVE_XLXW_DOMDUMP
+ defsubr (&Sxwidget_webkit_dom_dump);
+#endif
+
+ 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");
+ DEFSYM (Qtoggle, "ToggleButton");
+ DEFSYM (Qslider, "slider");
+ DEFSYM (Qsocket, "socket");
+ DEFSYM (Qsocket_osr, "socket-osr");
+
+ 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);
+ Fdelete_xwidget_view (XCAR (tail));
+ }
+ }
+ }
+}
+
+struct xwidget_view *
+xwidget_view_lookup (struct xwidget *xw, struct window *w)
+{
+ Lisp_Object xwidget, window, ret;
+ XSETXWIDGET (xwidget, xw);
+ XSETWINDOW (window, w);
+
+ ret = Fxwidget_view_lookup (xwidget, window);
+
+ return EQ (ret, Qnil) ? NULL : XXWIDGET_VIEW (ret);
+}
+
+struct xwidget *
+lookup_xwidget (Lisp_Object spec)
+{
+ /* When a xwidget lisp spec is found initialize the C struct that is
+ used in the C code. This is done by redisplay so values change
+ if the spec changes. So, take special care of one-shot events
+
+ 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;
+ Lisp_Object value;
+ struct xwidget *xw;
+
+ value = xwidget_spec_value (spec, QCxwidget, &found);
+ xw = XXWIDGET (value);
+
+ return xw;
+}
+
+/*set up detection of touched xwidget*/
+void
+xwidget_start_redisplay (void)
+{
+ for (Lisp_Object tail = Vxwidget_view_list; CONSP (tail);
+ tail = XCDR (tail))
+ {
+ if (XWIDGET_VIEW_P (XCAR (tail)))
+ XXWIDGET_VIEW (XCAR (tail))->redisplayed = 0;
+ }
+}
+
+/* the xwidget was touched during redisplay, so it isnt a candidate for hiding*/
+void
+xwidget_touch (struct xwidget_view *xv)
+{
+ xv->redisplayed = 1;
+}
+
+static int
+xwidget_touched (struct xwidget_view *xv)
+{
+ return xv->redisplayed;
+}
+
+/* redisplay has ended, now we should hide untouched xwidgets
+*/
+void
+xwidget_end_redisplay (struct window *w, struct glyph_matrix *matrix)
+{
+
+ int i;
+ int area;
+
+
+ xwidget_start_redisplay ();
+ //iterate desired glyph matrix of window here, hide gtk widgets
+ //not in the desired matrix.
+
+ //this only takes care of xwidgets in active windows.
+ //if a window goes away from screen xwidget views wust be deleted
+
+ // dump_glyph_matrix(matrix, 2);
+ for (i = 0; i < matrix->nrows; ++i)
+ {
+ // dump_glyph_row (MATRIX_ROW (matrix, i), i, glyphs);
+ struct glyph_row *row;
+ row = MATRIX_ROW (matrix, i);
+ if (row->enabled_p != 0)
+ {
+ for (area = LEFT_MARGIN_AREA; area < LAST_AREA; ++area)
+ {
+ struct glyph *glyph = row->glyphs[area];
+ struct glyph *glyph_end = glyph + row->used[area];
+ for (; glyph < glyph_end; ++glyph)
+ {
+ if (glyph->type == XWIDGET_GLYPH)
+ {
+ /*
+ the only call to xwidget_end_redisplay is in dispnew
+ xwidget_end_redisplay(w->current_matrix);
+ */
+ xwidget_touch (xwidget_view_lookup (glyph->u.xwidget,
+ w));
+ }
+ }
+ }
+ }
+ }
+
+ for (Lisp_Object tail = Vxwidget_view_list; CONSP (tail);
+ tail = XCDR (tail))
+ {
+ if (XWIDGET_VIEW_P (XCAR (tail)))
+ {
+ struct xwidget_view *xv = XXWIDGET_VIEW (XCAR (tail));
+
+ //"touched" is only meaningful for the current window, so
+ //disregard other views
+ if (XWINDOW (xv->w) == w)
+ {
+ if (xwidget_touched (xv))
+ xwidget_show_view (xv);
+ else
+ xwidget_hide_view (xv);
+ }
+ }
+ }
+}
+
+/* Kill all xwidget in BUFFER. */
+void
+kill_buffer_xwidgets (Lisp_Object buffer)
+{
+ Lisp_Object tail, xwidget;
+ for (tail = Fget_buffer_xwidgets (buffer); CONSP (tail); tail = XCDR (tail))
+ {
+ xwidget = XCAR (tail);
+ Vxwidget_list = Fdelq (xwidget, Vxwidget_list);
+ /* TODO free the GTK things in xw */
+ {
+ CHECK_XWIDGET (xwidget);
+ struct xwidget *xw = XXWIDGET (xwidget);
+ if (xw->widget_osr && xw->widgetwindow_osr)
+ {
+ gtk_widget_destroy (xw->widget_osr);
+ gtk_widget_destroy (xw->widgetwindow_osr);
+ }
+ }
+ }
+}
+
+#endif /* HAVE_XWIDGETS */
diff --git a/src/xwidget.h b/src/xwidget.h
new file mode 100644
index 00000000000..dcce0ea40d8
--- /dev/null
+++ b/src/xwidget.h
@@ -0,0 +1,120 @@
+#ifndef XWIDGET_H_INCLUDED
+#define XWIDGET_H_INCLUDED
+
+void x_draw_xwidget_glyph_string (struct glyph_string *s);
+void syms_of_xwidget (void);
+
+//extern Lisp_Object Qxwidget;
+
+
+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;
+};
+
+
+struct xwidget *xwidget_from_id (int id);
+
+//extern int xwidget_owns_kbd;
+
+void xwidget_start_redisplay (void);
+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/xwidget-test-manual.el b/test/xwidget-test-manual.el
new file mode 100644
index 00000000000..1c9b181467a
--- /dev/null
+++ b/test/xwidget-test-manual.el
@@ -0,0 +1,212 @@
+;;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" "new"))
+ (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" "new"))
+
+ (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-button-constructor"
+ (xwgir-require-namespace "Gtk" "3.0")
+ (put 'xwgirButtonLabel :xwgir-class '("Gtk" "Button" "new_with_label"))
+
+ (xwidget-insert (point-min) 'xwgirButtonLabel "xwgir label didnt work..." 700 700 '("constructor 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" "new"))
+
+ (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-broken"
+ (xwgir-require-namespace "Gtk" "3.0")
+ (put 'xwgirHScale :xwgir-class '("Gtk" "HScale" "new_with_range" ))
+
+ (xwidget-insert (point-min) 'xwgirHScale "xwgir label didnt work..." 700 700 '(0.0 100.0 1.0))
+ (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)