diff options
-rw-r--r-- | README.xwidget | 35 | ||||
-rw-r--r-- | configure.ac | 43 | ||||
-rw-r--r-- | lisp/net/browse-url.el | 13 | ||||
-rw-r--r-- | lisp/xwidget.el | 592 | ||||
-rw-r--r-- | src/Makefile.in | 10 | ||||
-rw-r--r-- | src/buffer.c | 8 | ||||
-rw-r--r-- | src/dispextern.h | 27 | ||||
-rw-r--r-- | src/dispnew.c | 12 | ||||
-rw-r--r-- | src/emacs.c | 6 | ||||
-rw-r--r-- | src/emacsgtkfixed.c | 112 | ||||
-rw-r--r-- | src/emacsgtkfixed.h | 28 | ||||
-rw-r--r-- | src/keyboard.c | 25 | ||||
-rw-r--r-- | src/lisp.h | 5 | ||||
-rw-r--r-- | src/print.c | 16 | ||||
-rw-r--r-- | src/termhooks.h | 4 | ||||
-rw-r--r-- | src/window.c | 6 | ||||
-rw-r--r-- | src/xdisp.c | 259 | ||||
-rw-r--r-- | src/xterm.c | 15 | ||||
-rw-r--r-- | src/xwidget.c | 2062 | ||||
-rw-r--r-- | src/xwidget.h | 120 | ||||
-rw-r--r-- | test/xwidget-test-manual.el | 212 |
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) |