socket args
[emacs.git] / lisp / xwidget.el
blob22d80405869c4ec036e4b8f2053ed9a5300d1aa5
1 ;;; xwidget.el --- api functions for xwidgets
2 ;; see xwidget.c for more api functions
5 ;;; Commentary:
6 ;;
8 (require 'xwidget-internal)
10 ;;TODO model after make-text-button instead!
11 ;;; Code:
13 (defun xwidget-insert (pos type title width height)
14 "Insert an xwidget at POS, given ID, TYPE, TITLE WIDTH and HEIGHT.
15 Return ID
17 see xwidget.c for types suitable for TYPE."
18 (goto-char pos)
19 (let ((id (make-xwidget (point) (point) type title width height nil)))
20 (put-text-property (point)
21 (+ 1 (point)) 'display (list 'xwidget ':xwidget id))
23 id))
26 (defun xwidget-at (pos)
27 "Return xwidget at POS."
28 ;;TODO this function is a bit tedious because the C layer isnt well protected yet and
29 ;;xwidgetp aparently doesnt work yet
30 (let* ((disp (get-text-property pos 'display))
31 (xw (car (cdr (cdr disp)))))
32 ;;(if ( xwidgetp xw) xw nil)
33 (if (equal 'xwidget (car disp)) xw)
39 ;; (defun xwidget-socket-handler ()
40 ;; "Create plug for socket. TODO."
41 ;; (interactive)
42 ;; (message "socket handler xwidget %S" last-input-event)
43 ;; (let*
44 ;; ((xwidget-event-type (nth 2 last-input-event))
45 ;; (xwidget-id (nth 1 last-input-event)))
46 ;; (cond ( (eq xwidget-event-type 'xembed-ready)
47 ;; (let*
48 ;; ((xembed-id (nth 3 last-input-event)))
49 ;; (message "xembed ready event: %S xw-id:%s" xembed-id xwidget-id)
50 ;; ;;TODO fetch process data from the xwidget. create it, store process info
51 ;; ;;will start emacs/uzbl in a xembed socket when its ready
52 ;; ;; (cond
53 ;; ;; ((eq 3 xwidget-id)
54 ;; ;; (start-process "xembed" "*xembed*" (format "%ssrc/emacs" default-directory) "-q" "--parent-id" (number-to-string xembed-id) ) )
55 ;; ;; ((eq 5 xwidget-id)
56 ;; ;; (start-process "xembed2" "*xembed2*" "uzbl-core" "-s" (number-to-string xembed-id) "http://www.fsf.org" ) )
57 ;; )))))
62 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
63 ;;; webkit support
64 (require 'browse-url)
65 (require 'image-mode);;for some image-mode alike functinoality
66 (require 'cl);;for flet
68 ;;;###autoload
69 (defun xwidget-webkit-browse-url (url &optional new-session)
70 "Ask xwidget-webkit to browse URL.
71 NEW-SESSION specifies whether to create a new xwidget-webkit session. URL
72 defaults to the string looking like a url around the cursor position."
73 (interactive (progn
74 (require 'browse-url)
75 (browse-url-interactive-arg "xwidget-webkit URL: ")))
76 (when (stringp url)
77 (if new-session
78 (xwidget-webkit-new-session url)
79 (xwidget-webkit-goto-url url))))
82 ;;shims for adapting image mode code to the webkit browser window
83 (defun xwidget-image-display-size (spec &optional pixels frame)
84 "Image code adaptor. SPEC PIXELS FRAME like the corresponding `image-mode' fn."
85 (let ((xwi (xwidget-info (xwidget-at 1))))
86 (cons (aref xwi 2)
87 (aref xwi 3))))
89 (defmacro xwidget-image-mode-navigation-adaptor (fn)
90 "Image code adaptor. `image-mode' FN is called."
91 `(lambda () (interactive)
92 (flet ((image-display-size (spec) (xwidget-image-display-size spec)))
93 (funcall ,fn ))))
95 (defmacro xwidget-image-mode-navigation-adaptor-p (fn)
96 "Image code adaptor. `image-mode' FN is called with interactive arg."
97 `(lambda (n) (interactive "p")
98 (flet ((image-display-size (spec) (xwidget-image-display-size spec)))
99 (funcall ,fn n))))
102 ;;todo.
103 ;; - check that the webkit support is compiled in
104 (defvar xwidget-webkit-mode-map
105 (let ((map (make-sparse-keymap)))
106 (define-key map "g" 'xwidget-webkit-browse-url)
107 (define-key map "a" 'xwidget-webkit-adjust-size-to-content)
108 (define-key map "b" 'xwidget-webkit-back )
109 (define-key map "r" 'xwidget-webkit-reload )
110 (define-key map "t" (lambda () (interactive) (message "o")) )
111 (define-key map "\C-m" 'xwidget-webkit-insert-string)
112 (define-key map "w" 'xwidget-webkit-current-url)
114 ;;similar to image mode bindings
115 (define-key map (kbd "SPC") (xwidget-image-mode-navigation-adaptor 'image-scroll-up))
116 (define-key map (kbd "DEL") (xwidget-image-mode-navigation-adaptor 'image-scroll-down))
118 (define-key map [remap scroll-up] (xwidget-image-mode-navigation-adaptor 'image-scroll-up))
119 (define-key map [remap scroll-up-command] (xwidget-image-mode-navigation-adaptor 'image-scroll-up))
121 (define-key map [remap scroll-down] (xwidget-image-mode-navigation-adaptor 'image-scroll-down))
122 (define-key map [remap scroll-down-command] (xwidget-image-mode-navigation-adaptor 'image-scroll-down))
124 (define-key map [remap forward-char] (xwidget-image-mode-navigation-adaptor-p 'image-forward-hscroll))
125 (define-key map [remap backward-char] (xwidget-image-mode-navigation-adaptor-p 'image-backward-hscroll))
126 (define-key map [remap right-char] (xwidget-image-mode-navigation-adaptor-p 'image-forward-hscroll))
127 (define-key map [remap left-char] (xwidget-image-mode-navigation-adaptor-p 'image-backward-hscroll))
128 (define-key map [remap previous-line] (xwidget-image-mode-navigation-adaptor-p 'image-previous-line))
129 (define-key map [remap next-line] (xwidget-image-mode-navigation-adaptor-p 'image-next-line))
131 (define-key map [remap move-beginning-of-line] (xwidget-image-mode-navigation-adaptor 'image-bol))
132 (define-key map [remap move-end-of-line] (xwidget-image-mode-navigation-adaptor 'image-eol))
133 (define-key map [remap beginning-of-buffer] (xwidget-image-mode-navigation-adaptor 'image-bob))
134 (define-key map [remap end-of-buffer] (xwidget-image-mode-navigation-adaptor 'image-eob))
135 map)
136 "Keymap for `xwidget-webkit-mode'.")
138 ;;the xwidget event needs to go into a higher level handler
139 ;;since the xwidget can generate an event even if its offscreen
140 ;;TODO this needs to use callbacks and consider different xw ev types
141 (define-key (current-global-map) [xwidget-event] 'xwidget-event-handler)
143 (defun xwidget-event-handler ()
144 "Receive xwidget event."
145 (interactive)
146 (message "stuff happened to xwidget %S" last-input-event)
147 (let*
148 ((xwidget-event-type (nth 1 last-input-event))
149 (xwidget (nth 2 last-input-event))
150 (xwidget-callback (xwidget-get xwidget 'callback)))
151 (funcall xwidget-callback xwidget xwidget-event-type)))
153 (defun xwidget-webkit-callback (xwidget xwidget-event-type)
154 (save-excursion
155 (set-buffer (xwidget-buffer xwidget))
156 (cond ((eq xwidget-event-type 'document-load-finished)
157 (message "webkit finished loading: '%s'" (xwidget-webkit-get-title xwidget))
158 (xwidget-adjust-size-to-content xwidget)
159 (rename-buffer (format "*xwidget webkit: %s *" (xwidget-webkit-get-title xwidget)))
163 (define-derived-mode xwidget-webkit-mode
164 special-mode "xwidget-webkit" "xwidget webkit view mode"
165 (setq buffer-read-only t)
166 ;; Keep track of [vh]scroll when switching buffers
167 (image-mode-setup-winprops)
171 (defvar xwidget-webkit-last-session-buffer nil)
173 (defun xwidget-webkit-last-session ()
174 "Last active webkit, or a new one."
175 (if (buffer-live-p xwidget-webkit-last-session-buffer)
176 (save-excursion
177 (set-buffer xwidget-webkit-last-session-buffer)
178 (xwidget-at 1))
179 nil))
181 (defun xwidget-webkit-current-session ()
182 "Either the webkit in the current buffer, or the last one used, which might be nil."
183 (if (xwidget-at 1)
184 (xwidget-at 1)
185 (xwidget-webkit-last-session)))
187 (defun xwidget-adjust-size-to-content (xw)
188 "Resize XW to content."
189 ;;xwidgets doesnt support widgets that have their own opinions about size well yet
190 ;;this reads the desired size and resizes the emacs allocated area accordingly
191 (let ((size (xwidget-size-request xw)))
192 (xwidget-resize xw (car size) (cadr size))))
195 (defvar xwidget-webkit-activeelement-js
197 function findactiveelement(myframes){
198 if(document.activeElement.value != undefined)
199 return document.activeElement;
200 for(i=0;i<myframes.length;i++){
201 if(myframes[i].document.activeElement.value != undefined)
202 return myframes[i].document.activeElement;
203 else{
204 if(myframes[i].frames.length > 0)
205 findactiveelement(myframes[i].frames);
206 else
207 return;
214 "javascript that finds the active element."
215 ;;yes its ugly. because:
216 ;; - there is aparently no way to find the active frame other than recursion
217 ;; - the js "for each" construct missbehaved on the "frames" collection
218 ;; - a window with no frameset still has frames.length == 1, but frames[0].document.activeElement != document.activeElement
222 (defun xwidget-webkit-insert-string (xw str)
223 "Insert string in the active field in the webkit.
224 Argument XW webkit.
225 Argument STR string."
226 ;;read out the string in the field first and provide for edit
227 (interactive
228 (let* ((xww (xwidget-webkit-current-session))
229 (field-value
230 (progn
231 (xwidget-webkit-execute-script xww xwidget-webkit-activeelement-js)
232 (xwidget-webkit-execute-script xww "document.title=findactiveelement(frames).value")
233 (xwidget-webkit-get-title xww))))
234 (list xww
235 (read-string "string:" field-value))))
236 (xwidget-webkit-execute-script xw (format "findactiveelement(frames).value='%s'" str)))
241 (defun xwidget-webkit-adjust-size-to-content ()
242 "Adjust webkit to content size."
243 (interactive)
244 ( xwidget-adjust-size-to-content ( xwidget-webkit-current-session)))
246 (defun xwidget-webkit-adjust-size (w h)
247 "Manualy set webkit size.
248 Argument W width.
249 Argument H height."
250 ;;TODO shouldnt be tied to the webkit xwidget
251 (interactive "nWidth:\nnHeight:\n")
252 ( xwidget-resize ( xwidget-webkit-current-session) w h))
255 (defun xwidget-webkit-new-session (url)
256 "Create a new webkit session buffer with URL."
257 (let*
258 ((bufname (generate-new-buffer-name "*xwidget-webkit*"))
260 (setq xwidget-webkit-last-session-buffer (switch-to-buffer (get-buffer-create bufname)))
261 (insert " ")
262 (setq xw (xwidget-insert 1 'webkit-osr bufname 1000 1000))
263 (xwidget-put xw 'callback 'xwidget-webkit-callback)
264 (xwidget-webkit-mode)
265 (xwidget-webkit-goto-uri ( xwidget-webkit-last-session) url )))
268 (defun xwidget-webkit-goto-url (url)
269 "Goto URL."
270 (if ( xwidget-webkit-current-session)
271 (progn
272 (xwidget-webkit-goto-uri ( xwidget-webkit-current-session) url))
273 ( xwidget-webkit-new-session url)))
275 (defun xwidget-webkit-back ()
276 "Back in history."
277 (interactive)
278 (xwidget-webkit-execute-script ( xwidget-webkit-current-session) "history.go(-1);"))
280 (defun xwidget-webkit-reload ()
281 "Reload current url."
282 (interactive)
283 (xwidget-webkit-execute-script ( xwidget-webkit-current-session) "history.go(0);"))
285 (defun xwidget-webkit-current-url ()
286 "Get the webkit url. place it on kill ring."
287 (interactive)
288 ;;notice the fugly "title" hack. it is needed because the webkit api doesnt support returning values.
289 ;;TODO make a wrapper for the title hack so its easy to remove should webkit someday support JS return values
290 ;;or we find some other way to access the DOM
291 (xwidget-webkit-execute-script (xwidget-webkit-current-session) "document.title=document.URL;")
292 (kill-new (xwidget-webkit-get-title (xwidget-webkit-current-session))))
296 ;; use declare here?
297 ;; (declare-function xwidget-resize-internal "xwidget.c" )
298 ;; check-declare-function?
300 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
301 ;; xwidget plist management(similar to the process plist functions)
303 (defun xwidget-get (xwidget propname)
304 "Return the value of XWIDGET' PROPNAME property.
305 This is the last value stored with `(xwidget-put XWIDGET PROPNAME VALUE)'."
306 (plist-get (xwidget-plist xwidget) propname))
308 (defun xwidget-put (xwidget propname value)
309 "Change XWIDGET' PROPNAME property to VALUE.
310 It can be retrieved with `(xwidget-get XWIDGET PROPNAME)'."
311 (set-xwidget-plist xwidget
312 (plist-put (xwidget-plist xwidget) propname value)))
315 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
316 (defun xwidget-cleanup ()
317 "Delete zombie xwidgets."
318 ;;its still pretty easy to trigger bugs with xwidgets.
319 ;;this function tries to implement a workaround
320 (interactive)
321 (xwidget-delete-zombies) ;;kill xviews who should have been deleted but stull linger
322 (redraw-display);;redraw display otherwise ghost of zombies will remain to haunt the screen
327 ;;this is a workaround because I cant find the right place to put it in C
328 ;;seems to work well in practice though
329 (add-hook 'window-configuration-change-hook 'xwidget-cleanup)
331 ;;killflash is sadly not reliable yet.
332 (defvar xwidget-webkit-kill-flash-oneshot t)
333 (defun xwidget-webkit-kill-flash ()
334 "Disable the flash plugin in webkit.
335 This is needed because Flash is non-free and doesnt work reliably
336 on 64 bit systems and offscreen rendering. Sadly not reliable
337 yet, so deinstall Flash instead for now."
338 ;;you can only call this once or webkit crashes and takes emacs with it. odd.
339 (unless xwidget-webkit-kill-flash-oneshot
340 (xwidget-disable-plugin-for-mime "application/x-shockwave-flash")
341 (setq xwidget-webkit-kill-flash-oneshot t)))
343 (xwidget-webkit-kill-flash)
345 (provide 'xwidget)
347 (provide 'xwidget)
349 ;;; xwidget.el ends here