new version
[emacs.git] / lisp / browse-url.el
blob5dce2608674c7ec7a4ee9ca94e67a6465d735d66
1 ;;; browse-url.el --- ask a WWW browser to load a URL
3 ;; Copyright 1995, 1996 Free Software Foundation, Inc.
5 ;; Author: Denis Howe <dbh@doc.ic.ac.uk>
6 ;; Maintainer: Denis Howe <dbh@doc.ic.ac.uk>
7 ;; Created: 03 Apr 1995
8 ;; Keywords: hypertext
9 ;; X-Home page: http://wombat.doc.ic.ac.uk/
11 ;; This file is part of GNU Emacs.
13 ;; GNU Emacs is free software; you can redistribute it and/or modify
14 ;; it under the terms of the GNU General Public License as published by
15 ;; the Free Software Foundation; either version 2, or (at your option)
16 ;; any later version.
18 ;; GNU Emacs is distributed in the hope that it will be useful,
19 ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
20 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 ;; GNU General Public License for more details.
23 ;; You should have received a copy of the GNU General Public License
24 ;; along with GNU Emacs; see the file COPYING. If not, write to the
25 ;; Free Software Foundation, Inc., 59 Temple Place - Suite 330,
26 ;; Boston, MA 02111-1307, USA.
28 ;;; Commentary:
30 ;; The latest version of this package should be available from
31 ;; <URL:http://wombat.doc.ic.ac.uk/emacs/browse-url.el>.
33 ;; This package provides functions which read a URL (Uniform Resource
34 ;; Locator) from the minibuffer, defaulting to the URL around point,
35 ;; and ask a World-Wide Web browser to load it. It can also load the
36 ;; URL associated with the current buffer. Different browsers use
37 ;; different methods of remote control so there is one function for
38 ;; each supported browser. If the chosen browser is not running, it
39 ;; is started. Currently there is support for:
41 ;; Function Browser Earliest version
42 ;; browse-url-netscape Netscape 1.1b1
43 ;; browse-url-mosaic XMosaic <= 2.4
44 ;; browse-url-cci XMosaic 2.5
45 ;; browse-url-w3 w3 0
46 ;; browse-url-iximosaic IXI Mosaic ?
47 ;; browse-url-lynx-* Lynx 0
48 ;; browse-url-grail Grail 0.3b1
50 ;; Note that versions of Netscape before 1.1b1 did not have remote
51 ;; control. <URL:http://www.netscape.com/newsref/std/x-remote.html>
52 ;; and <URL:http://www.netscape.com/info/APIs/>.
54 ;; Netscape can cache Web pages so it may be necessary to tell it to
55 ;; reload the current page if it has changed (e.g. if you have edited
56 ;; it). There is currently no perfect automatic solution to this.
58 ;; Netscape allows you to specify the id of the window you want to
59 ;; control but which window DO you want to control and how do you
60 ;; discover its id?
62 ;; If using XMosaic before version 2.5, check the definition of
63 ;; browse-url-usr1-signal below.
64 ;; <URL:http://www.ncsa.uiuc.edu/SDG/Software/XMosaic/remote-control.html>
66 ;; XMosaic version 2.5 introduced Common Client Interface allowing you
67 ;; to control mosaic through Unix sockets.
68 ;; <URL:http://www.ncsa.uiuc.edu/SDG/Software/XMosaic/CCI/cci-spec.html>
70 ;; William M. Perry's excellent "w3" WWW browser for
71 ;; Emacs <URL:ftp://cs.indiana.edu/pub/elisp/w3/>
72 ;; has a function w3-follow-url-at-point, but that
73 ;; doesn't let you edit the URL like browse-url.
75 ;; I recommend Nelson Minar <nelson@santafe.edu>'s excellent
76 ;; html-helper-mode.el for editing HTML and thank Nelson for
77 ;; his many useful comments on this code.
78 ;; <URL:http://www.santafe.edu/~nelson/hhm-beta/>
80 ;; This package generalises function html-previewer-process in Marc
81 ;; Andreessen <marca@ncsa.uiuc.edu>'s html-mode (LCD
82 ;; modes/html-mode.el.Z) and provides better versions of the URL
83 ;; functions in Michelangelo Grigni <mic@cs.ucsd.edu>'s ffap.el
84 ;; (find-file-at-point) <URL:ftp://cs.ucsd.edu:/pub/mic/>. The huge
85 ;; hyperbole package also contains similar functions.
87 ;; Grail is the freely available WWW browser implemented in Python, a
88 ;; cool object-oriented freely available interpreted language. Grail
89 ;; 0.3b1 was the first version to have remote control as distributed.
90 ;; For more information on Grail see
91 ;; <URL:http://monty.cnri.reston.va.us/> and for more information on
92 ;; Python see <url:http://www.python.org/>. Grail support in
93 ;; browse-url.el written by Barry Warsaw <bwarsaw@python.org>.
95 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
96 ;; Help!
98 ;; Can you write and test some code for the Macintrash and Windoze
99 ;; Netscape remote control APIs? (See the URL above).
101 ;; Do any other browsers have remote control?
103 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
104 ;; Usage
106 ;; To display the URL at or before point:
107 ;; M-x browse-url-at-point RET
109 ;; To display a URL by shift-clicking on it, put this in your ~/.emacs
110 ;; file:
111 ;; (global-set-key [S-mouse-2] 'browse-url-at-mouse)
112 ;; (Note that using Shift-mouse-1 is not desirable because
113 ;; that event has a standard meaning in Emacs.)
115 ;; To display the current buffer in a web browser:
116 ;; M-x browse-url-of-buffer RET
118 ;; In Dired, to display the file named on the current line:
119 ;; M-x browse-url-of-dired-file RET
121 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
122 ;; Customisation (~/.emacs)
124 ;; To see what variables are available for customization, type
125 ;; `M-x set-variable browse-url TAB'.
127 ;; Bind the browse-url commands to keys with the `C-c C-z' prefix
128 ;; (as used by html-helper-mode):
129 ;; (global-set-key "\C-c\C-z." 'browse-url-at-point)
130 ;; (global-set-key "\C-c\C-zb" 'browse-url-of-buffer)
131 ;; (global-set-key "\C-c\C-zu" 'browse-url)
132 ;; (global-set-key "\C-c\C-zv" 'browse-url-of-file)
133 ;; (add-hook 'dired-mode-hook
134 ;; (function (lambda ()
135 ;; (local-set-key "\C-c\C-zf" 'browse-url-of-dired-file))))
137 ;; Browse URLs in mail messages by clicking mouse-2:
138 ;; (add-hook 'rmail-mode-hook (function (lambda () ; rmail-mode startup
139 ;; (define-key rmail-mode-map [mouse-2] 'browse-url-at-mouse))))
141 ;; Browse URLs in Usenet messages by clicking mouse-2:
142 ;; (eval-after-load "gnus"
143 ;; '(define-key gnus-article-mode-map [mouse-2] 'browse-url-at-mouse))
145 ;; Use the Emacs w3 browser when not running under X11:
146 ;; (or (eq window-system 'x)
147 ;; (setq browse-url-browser-function 'browse-url-w3))
149 ;; To always save modified buffers before displaying the file in a browser:
150 ;; (setq browse-url-save-file t)
152 ;; To get round the Netscape caching problem, you could EITHER have
153 ;; write-file in html-helper-mode make Netscape reload the document:
155 ;; (autoload 'browse-url-netscape-reload "browse-url"
156 ;; "Ask a WWW browser to redisplay the current file." t)
157 ;; (add-hook 'html-helper-mode-hook
158 ;; (function (lambda ()
159 ;; (add-hook 'local-write-file-hooks
160 ;; (function (lambda ()
161 ;; (let ((local-write-file-hooks))
162 ;; (save-buffer))
163 ;; (browse-url-netscape-reload)
164 ;; t)) ; => file written by hook
165 ;; t)))) ; append to l-w-f-hooks
167 ;; OR have browse-url-of-file ask Netscape to load and then reload the
168 ;; file:
170 ;; (add-hook 'browse-url-of-file-hook 'browse-url-netscape-reload)
172 ;; You may also want to customise browse-url-netscape-arguments, e.g.
173 ;; (setq browse-url-netscape-arguments '("-install"))
175 ;; or similarly for the other browsers.
177 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
178 ;;; Change Log:
180 ;; 0.00 03 Apr 1995 Denis Howe <dbh@doc.ic.ac.uk>
181 ;; Created.
183 ;; 0.01 04 Apr 1995
184 ;; All names start with "browse-url-". Added provide.
186 ;; 0.02 05 Apr 1995
187 ;; Save file at start of browse-url-of-file.
188 ;; Use start-process instead of start-process-shell-command.
190 ;; 0.03 06 Apr 1995
191 ;; Add browse-url-netscape-reload, browse-url-netscape-send.
192 ;; browse-url-of-file save file option.
194 ;; 0.04 08 Apr 1995
195 ;; b-u-file-url separate function. Change b-u-filename-alist
196 ;; default.
198 ;; 0.05 09 Apr 1995
199 ;; Added b-u-of-file-hook.
201 ;; 0.06 11 Apr 1995
202 ;; Improved .emacs suggestions and documentation.
204 ;; 0.07 13 Apr 1995
205 ;; Added browse-url-interactive-arg optional prompt.
207 ;; 0.08 18 Apr 1995
208 ;; Exclude final "." from browse-url-regexp.
210 ;; 0.09 21 Apr 1995
211 ;; Added mouse-set-point to browse-url-interactive-arg.
213 ;; 0.10 24 Apr 1995
214 ;; Added Mosaic signal sending variations.
215 ;; Thanks Brian K Servis <servis@ecn.purdue.edu>.
216 ;; Don't use xprop for Netscape.
218 ;; 0.11 25 Apr 1995
219 ;; Fix reading of ~/.mosaicpid. Thanks Dag.H.Wanvik@kvatro.no.
221 ;; 0.12 27 Apr 1995
222 ;; Interactive prefix arg => URL *after* point.
223 ;; Thanks Michelangelo Grigni <mic@cs.ucsd.edu>.
224 ;; Added IXI Mosaic support.
225 ;; Thanks David Karr <dkarr@nmo.gtegsc.com>.
227 ;; 0.13 28 Apr 1995
228 ;; Exclude final [,;] from browse-url-regexp.
230 ;; 0.14 02 May 1995
231 ;; Provide browser argument variables.
233 ;; 0.15 07 May 1995
234 ;; More Netscape options. Thanks Peter Arius
235 ;; <arius@immd2.informatik.uni-erlangen.de>.
237 ;; 0.16 17 May 1995
238 ;; Added browse-url-at-mouse.
239 ;; Thanks Wayne Mesard <wmesard@sgi.com>
241 ;; 0.17 27 Jun 1995
242 ;; Renamed browse-url-at-point to browse-url-url-at-point.
243 ;; Added browse-url-at-point.
244 ;; Thanks Jonathan Cano <cano@patch.tandem.com>.
246 ;; 0.18 16 Aug 1995
247 ;; Fixed call to browse-url-url-at-point in browse-url-at-point.
248 ;; Thanks Eric Ding <ericding@San-Jose.ate.slb.com>.
250 ;; 0.19 24 Aug 1995
251 ;; Improved documentation.
252 ;; Thanks Kevin Rodgers <kevin.rodgers@ihs.com>.
254 ;; 0.20 31 Aug 1995
255 ;; browse-url-of-buffer to handle file-less buffers.
256 ;; browse-url-of-dired-file browses current file in dired.
257 ;; Thanks Kevin Rodgers <kevin.rodgers@ihs.com>.
259 ;; 0.21 09 Sep 1995
260 ;; XMosaic CCI functions.
261 ;; Thanks Marc Furrer <Marc.Furrer@di.epfl.ch>.
263 ;; 0.22 13 Sep 1995
264 ;; Fixed new-window documentation and added to browse-url-cci.
265 ;; Thanks Dilip Sequeira <djs@dcs.ed.ac.uk>.
267 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
268 ;;; Code:
270 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
271 ;; Variables
273 (eval-when-compile (require 'dired))
275 (defvar browse-url-path-regexp
276 "[^]\t\n \"'()<>[^`{}]*[^]\t\n \"'()<>[^`{}.,;]+"
277 "A regular expression probably matching the host, path or e-mail
278 part of a URL.")
280 (defvar browse-url-short-regexp
281 (concat "[-A-Za-z0-9.]+" browse-url-path-regexp)
282 "A regular expression probably matching a URL without an access scheme.
283 Hostname matching is stricter in this case than for
284 ``browse-url-regexp''.")
286 (defvar browse-url-regexp
287 (concat
288 "\\(https?://\\|ftp://\\|gopher://\\|telnet://\\|wais://\\|file:/\\|s?news:\\|mailto:\\)"
289 browse-url-path-regexp)
290 "A regular expression probably matching a complete URL.")
292 ;;;###autoload
293 (defgroup browse-url nil
294 "Use a web browser to look at a URL."
295 :group 'applications)
297 ;;;###autoload
298 (defcustom browse-url-browser-function
299 'browse-url-netscape
300 "*Function to display the current buffer in a WWW browser.
301 This is used by the `browse-url-at-point', `browse-url-at-mouse', and
302 `browse-url-of-file' commands.
303 The function should take one argument, an URL."
304 :type 'function
305 :group 'browse-url)
307 (defcustom browse-url-netscape-program "netscape"
308 "*The name by which to invoke Netscape."
309 :type 'string
310 :group 'browse-url)
312 (defcustom browse-url-netscape-arguments nil
313 "*A list of strings to pass to Netscape as arguments."
314 :type '(repeat (string :tag "Argument"))
315 :group 'browse-url)
317 (defcustom browse-url-netscape-startup-arguments browse-url-netscape-arguments
318 "*A list of strings to pass to Netscape when it starts up.
319 Defaults to the value of `browse-url-netscape-arguments' at the time
320 browse-url is loaded."
321 :type '(repeat (string :tag "Argument"))
322 :group 'browse-url)
324 (defcustom browse-url-new-window-p nil
325 "*If non-nil, always open a new browser window.
326 Passing an interactive argument to \\[browse-url-netscape] or
327 \\[browse-url-cci] reverses the effect of this variable. Requires
328 Netscape version 1.1N or later or XMosaic version 2.5 or later."
329 :type 'boolean
330 :group 'browse-url)
332 (defcustom browse-url-mosaic-arguments nil
333 "*A list of strings to pass to Mosaic as arguments."
334 :type '(repeat (string :tag "Argument"))
335 :group 'browse-url)
337 (defvar browse-url-filename-alist
338 '(("^/+" . "file:/"))
339 "An alist of (REGEXP . STRING) pairs.
340 Any substring of a filename matching one of the REGEXPs is replaced by
341 the corresponding STRING. All pairs are applied in the order given.
342 The default value prepends `file:' to any path beginning with `/'.
343 Used by the `browse-url-of-file' command.")
345 (defvar browse-url-save-file nil
346 "If non-nil, save the buffer before displaying its file.
347 Used by the `browse-url-of-file' command.")
349 (defvar browse-url-of-file-hook nil
350 "A hook to be run with run-hook after `browse-url-of-file' has asked
351 a browser to load a file.
353 Set this to `browse-url-netscape-reload' to force Netscape to load the
354 file rather than displaying a cached copy.")
356 (defvar browse-url-usr1-signal
357 (if (and (boundp 'emacs-major-version)
358 (or (> emacs-major-version 19) (>= emacs-minor-version 29)))
359 'SIGUSR1 ; Why did I think this was in lower case before?
360 30) ; Check /usr/include/signal.h.
361 "The argument to `signal-process' for sending SIGUSR1 to XMosaic.
362 Emacs 19.29 accepts 'SIGUSR1, earlier versions require an integer
363 which is 30 on SunOS and 16 on HP-UX and Solaris.")
365 (defvar browse-url-CCI-port 3003
366 "Port to access XMosaic via CCI.
367 This can be any number between 1024 and 65535 but must correspond to
368 the value set in the browser.")
370 (defvar browse-url-CCI-host "localhost"
371 "*Host to access XMosaic via CCI.
372 This should be the host name of the machine running XMosaic with CCI
373 enabled. The port number should be set in `browse-url-CCI-port'.")
375 (defvar browse-url-temp-file-name nil)
376 (make-variable-buffer-local 'browse-url-temp-file-name)
378 (defvar browse-url-temp-file-list '())
380 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
381 ;; URL input
383 ;; thingatpt.el doesn't work for complex regexps
385 (defun browse-url-url-at-point ()
386 "Return the URL around or before point.
387 Search backwards for the start of a URL ending at or after
388 point. If no URL found, return the empty string.
389 A file name is also acceptable, and `http://' will be prepended to it."
390 (or (thing-at-point 'url)
391 (let ((file (thing-at-point 'filename)))
392 (if file (concat "http://" file)))
393 ""))
395 ;; Having this as a separate function called by the browser-specific
396 ;; functions allows them to be stand-alone commands, making it easier
397 ;; to switch between browsers.
399 (defun browse-url-interactive-arg (prompt)
400 "Read a URL from the minibuffer, prompting with PROMPT.
401 Default to the URL at or before point. If invoke with a mouse button,
402 set point to the position clicked first. Return a list for use in
403 `interactive' containing the URL and browse-url-new-window-p or its
404 negation if a prefix argument was given."
405 (let ((event (elt (this-command-keys) 0)))
406 (and (listp event) (mouse-set-point event)))
407 (list (read-string prompt (browse-url-url-at-point))
408 (not (eq (null browse-url-new-window-p)
409 (null current-prefix-arg)))))
411 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
412 ;; Browse current buffer
414 ;;;###autoload
415 (defun browse-url-of-file (&optional file)
416 "Ask a WWW browser to display FILE.
417 Display the current buffer's file if FILE is nil or if called
418 interactively. Turn the filename into a URL with function
419 browse-url-file-url. Pass the URL to a browser using variable
420 `browse-url-browser-function' then run `browse-url-of-file-hook'."
421 (interactive)
422 (or file
423 (setq file (buffer-file-name))
424 (error "Current buffer has no file"))
425 (let ((buf (get-file-buffer file)))
426 (if buf
427 (save-excursion
428 (set-buffer buf)
429 (cond ((not (buffer-modified-p)))
430 (browse-url-save-file (save-buffer))
431 (t (message "%s modified since last save" file))))))
432 (funcall browse-url-browser-function (browse-url-file-url file))
433 (run-hooks 'browse-url-of-file-hook))
435 (defun browse-url-file-url (file)
436 "Return the URL corresponding to FILE.
437 Use variable `browse-url-filename-alist' to map filenames to URLs.
438 Convert EFS file names of the form /USER@HOST:PATH to ftp://HOST/PATH."
439 ;; URL-encode special chars, do % first
440 (let ((s 0))
441 (while (setq s (string-match "%" file s))
442 (setq file (replace-match "%25" t t file)
443 s (1+ s))))
444 (while (string-match "[*\"()',=;? ]" file)
445 (let ((enc (format "%%%x" (aref file (match-beginning 0)))))
446 (setq file (replace-match enc t t file))))
447 (let ((maps browse-url-filename-alist))
448 (while maps
449 (let* ((map (car maps))
450 (from-re (car map))
451 (to-string (cdr map)))
452 (setq maps (cdr maps))
453 (and (string-match from-re file)
454 (setq file (replace-match to-string t t file))))))
455 ;; Check for EFS path
456 (and (string-match "^/\\([^:@]+@\\)?\\([^:]+\\):/*" file)
457 (setq file (concat "ftp://"
458 (substring file (match-beginning 2) (match-end 2))
459 "/" (substring file (match-end 0)))))
460 file)
462 ;;;###autoload
463 (defun browse-url-of-buffer (&optional buffer)
464 "Ask a WWW browser to display BUFFER.
465 Display the current buffer if BUFFER is nil."
466 (interactive)
467 (save-excursion
468 (and buffer (set-buffer buffer))
469 (let ((file-name
470 (or buffer-file-name
471 (and (boundp 'dired-directory) dired-directory))))
472 (or file-name
473 (progn
474 (or browse-url-temp-file-name
475 (setq browse-url-temp-file-name
476 (make-temp-name
477 (expand-file-name (buffer-name)
478 (or (getenv "TMPDIR") "/tmp")))
479 browse-url-temp-file-list
480 (cons browse-url-temp-file-name
481 browse-url-temp-file-list)))
482 (setq file-name browse-url-temp-file-name)
483 (write-region (point-min) (point-max) file-name nil 'no-message)))
484 (browse-url-of-file file-name))))
486 (defun browse-url-delete-temp-file (&optional temp-file-name)
487 ;; Delete browse-url-temp-file-name from the file system and from
488 ;; browse-url-temp-file-list. If optional arg TEMP-FILE-NAME is
489 ;; non-nil, delete it instead, but only from the file system --
490 ;; browse-url-temp-file-list is not affected.
491 (let ((file-name (or temp-file-name browse-url-temp-file-name)))
492 (if (and file-name (file-exists-p file-name))
493 (progn
494 (delete-file file-name)
495 (if (null temp-file-name)
496 (setq browse-url-temp-file-list
497 (delete browse-url-temp-file-name
498 browse-url-temp-file-list)))))))
500 (defun browse-url-delete-temp-file-list ()
501 ;; Delete all elements of browse-url-temp-file-list.
502 (while browse-url-temp-file-list
503 (browse-url-delete-temp-file (car browse-url-temp-file-list))
504 (setq browse-url-temp-file-list
505 (cdr browse-url-temp-file-list))))
507 (add-hook 'kill-buffer-hook 'browse-url-delete-temp-file)
508 (add-hook 'kill-emacs-hook 'browse-url-delete-temp-file-list)
510 ;;;###autoload
511 (defun browse-url-of-dired-file ()
512 "In Dired, ask a WWW browser to display the file named on this line."
513 (interactive)
514 (browse-url-of-file (dired-get-filename)))
516 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
517 ;; Browser-independant commands
519 ;; A generic command to call the current b-u-browser-function
521 (defun browse-url (&rest args)
522 "Ask a WWW browser to load URL.
523 Prompts for a URL, defaulting to the URL at or before point. Variable
524 `browse-url-browser-function' says which browser to use."
525 (interactive (browse-url-interactive-arg "URL: "))
526 (apply browse-url-browser-function args))
528 ;;;###autoload
529 (defun browse-url-at-point ()
530 "Ask a WWW browser to load the URL at or before point.
531 Doesn't let you edit the URL like browse-url. Variable
532 `browse-url-browser-function' says which browser to use."
533 (interactive)
534 (funcall browse-url-browser-function (browse-url-url-at-point)))
536 ;; Define these if not already defined (XEmacs compatibility)
538 (defun browse-url-event-buffer (event)
539 (window-buffer (posn-window (event-start event))))
541 (defun browse-url-event-point (event)
542 (posn-point (event-start event)))
544 ;;;###autoload
545 (defun browse-url-at-mouse (event)
546 "Ask a WWW browser to load a URL clicked with the mouse.
547 The URL is the one around or before the position of the mouse click
548 but point is not changed. Doesn't let you edit the URL like
549 browse-url. Variable `browse-url-browser-function' says which browser
550 to use."
551 (interactive "e")
552 (save-excursion
553 (set-buffer (browse-url-event-buffer event))
554 (goto-char (browse-url-event-point event))
555 (let ((url (browse-url-url-at-point)))
556 (if (string-equal url "")
557 (error "No URL found"))
558 (funcall browse-url-browser-function url))))
560 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
561 ;; Browser-specific commands
563 ;; --- Netscape ---
565 ;; Put the correct DISPLAY value in the environment for Netscape
566 ;; launched from multi-display Emacs.
568 (defun browse-url-process-environment ()
569 (let* ((device (and (fboundp 'selected-device)
570 (fboundp 'device-connection)
571 (selected-device)))
572 (display (and device (fboundp 'device-type)
573 (eq (device-type device) 'x)
574 (not (equal (device-connection device)
575 (getenv "DISPLAY"))))))
576 (if display
577 ;; Attempt to run on the correct display
578 (cons (concat "DISPLAY=" (device-connection device))
579 process-environment)
580 process-environment)))
583 ;;;###autoload
584 (defun browse-url-netscape (url &optional new-window)
585 "Ask the Netscape WWW browser to load URL.
587 Default to the URL around or before point. The strings in variable
588 `browse-url-netscape-arguments' are also passed to Netscape.
590 When called interactively, if variable `browse-url-new-window-p' is
591 non-nil, load the document in a new Netscape window, otherwise use a
592 random existing one. A non-nil interactive prefix argument reverses
593 the effect of browse-url-new-window-p.
595 When called non-interactively, optional second argument NEW-WINDOW is
596 used instead of browse-url-new-window-p."
597 (interactive (browse-url-interactive-arg "Netscape URL: "))
598 ;; URL encode any commas in the URL
599 (while (string-match "," url)
600 (setq url (replace-match "%2C" t t url)))
601 (let* ((process-environment (browse-url-process-environment))
602 (process (apply 'start-process
603 (concat "netscape " url) nil
604 browse-url-netscape-program
605 (append browse-url-netscape-arguments
606 (if new-window '("-noraise"))
607 (list "-remote"
608 (concat "openURL(" url
609 (if new-window ",new-window")
610 ")"))))))
611 (set-process-sentinel process
612 (list 'lambda '(process change)
613 (list 'browse-url-netscape-sentinel 'process url)))))
615 (defun browse-url-netscape-sentinel (process url)
616 "Handle a change to the process communicating with Netscape."
617 (or (eq (process-exit-status process) 0)
618 (let* ((process-environment (browse-url-process-environment)))
619 ;; Netscape not running - start it
620 (message "Starting Netscape...")
621 (apply 'start-process (concat "netscape" url) nil
622 browse-url-netscape-program
623 (append browse-url-netscape-startup-arguments (list url))))))
625 (defun browse-url-netscape-reload ()
626 "Ask Netscape to reload its current document."
627 (interactive)
628 (browse-url-netscape-send "reload"))
630 (defun browse-url-netscape-send (command)
631 "Send a remote control command to Netscape."
632 (let* ((process-environment (browse-url-process-environment)))
633 (apply 'start-process "netscape" nil
634 browse-url-netscape-program
635 (append browse-url-netscape-arguments
636 (list "-remote" command)))))
638 ;; --- Mosaic ---
640 ;;;###autoload
641 (defun browse-url-mosaic (url &optional new-window)
642 ;; new-window ignored
643 "Ask the XMosaic WWW browser to load URL.
644 Default to the URL around or before point."
645 (interactive (browse-url-interactive-arg "Mosaic URL: "))
646 (let ((pidfile (expand-file-name "~/.mosaicpid"))
647 pid pidbuf)
648 (if (file-readable-p pidfile)
649 (save-excursion
650 (find-file pidfile)
651 (goto-char (point-min))
652 (setq pid (read (current-buffer)))
653 (kill-buffer nil)))
654 (if (and pid (zerop (signal-process pid 0))) ; Mosaic running
655 (save-excursion
656 (find-file (format "/tmp/Mosaic.%d" pid))
657 (erase-buffer)
658 (insert "goto\n" url "\n")
659 (save-buffer)
660 (kill-buffer nil)
661 ;; Send signal SIGUSR to Mosaic
662 (message "Signalling Mosaic...")
663 (signal-process pid browse-url-usr1-signal)
664 ;; Or you could try:
665 ;; (call-process "kill" nil 0 nil "-USR1" (int-to-string pid))
666 (message "Signalling Mosaic...done")
668 ;; Mosaic not running - start it
669 (message "Starting Mosaic...")
670 (apply 'start-process "xmosaic" nil "xmosaic"
671 (append browse-url-mosaic-arguments (list url)))
672 (message "Starting Mosaic...done"))))
674 ;; --- Grail ---
676 ;;;###autoload
677 (defvar browse-url-grail
678 (concat (or (getenv "GRAILDIR") "~/.grail") "/user/rcgrail.py")
679 "*Location of Grail remote control client script `rcgrail.py'.
680 Typically found in $GRAILDIR/rcgrail.py, or ~/.grail/user/rcgrail.py.")
682 ;;;###autoload
683 (defun browse-url-grail (url)
684 "Ask the Grail WWW browser to load URL.
685 Default to the URL around or before point. Runs the program in the
686 variable `browse-url-grail'."
687 (interactive (browse-url-interactive-arg "Grail URL: "))
688 (message "Sending URL to Grail...")
689 (save-excursion
690 (set-buffer (get-buffer-create " *Shell Command Output*"))
691 (erase-buffer)
692 ;; don't worry about this failing.
693 (call-process browse-url-grail nil 0 nil url)
694 (message "Sending URL to Grail... done")))
696 ;; --- Mosaic using CCI ---
698 (defun browse-url-cci (url &optional new-window)
699 "Ask the XMosaic WWW browser to load URL.
700 Default to the URL around or before point.
702 This function only works for XMosaic version 2.5 or later. You must
703 select `CCI' from XMosaic's File menu, set the CCI Port Address to the
704 value of variable `browse-url-CCI-port', and enable `Accept requests'.
706 When called interactively, if variable `browse-url-new-window-p' is
707 non-nil, load the document in a new browser window, otherwise use a
708 random existing one. A non-nil interactive prefix argument reverses
709 the effect of browse-url-new-window-p.
711 When called non-interactively, optional second argument NEW-WINDOW is
712 used instead of browse-url-new-window-p."
713 (interactive (browse-url-interactive-arg "Mosaic URL: "))
714 (open-network-stream "browse-url" " *browse-url*"
715 browse-url-CCI-host browse-url-CCI-port)
716 ;; Todo: start browser if fails
717 (process-send-string "browse-url"
718 (concat "get url (" url ") output "
719 (if new-window "new" "current") "\r\n"))
720 (process-send-string "browse-url" "disconnect\r\n")
721 (delete-process "browse-url"))
723 ;; --- IXI Mosaic ---
725 ;;;###autoload
726 (defun browse-url-iximosaic (url &optional new-window)
727 ;; new-window ignored
728 "Ask the IXIMosaic WWW browser to load URL.
729 Default to the URL around or before point."
730 (interactive (browse-url-interactive-arg "IXI Mosaic URL: "))
731 (start-process "tellw3b" nil "tellw3b"
732 "-service WWW_BROWSER ixi_showurl " url))
734 ;; --- W3 ---
736 ;;;###autoload
737 (defun browse-url-w3 (url &optional new-window)
738 ;; new-window ignored
739 "Ask the w3 WWW browser to load URL.
740 Default to the URL around or before point."
741 (interactive (browse-url-interactive-arg "W3 URL: "))
742 (w3-fetch url))
744 ;; --- Lynx in an xterm ---
746 ;;;###autoload
747 (defun browse-url-lynx-xterm (url &optional new-window)
748 ;; new-window ignored
749 "Ask the Lynx WWW browser to load URL.
750 Default to the URL around or before point. A new Lynx process is run
751 in an Xterm window."
752 (interactive (browse-url-interactive-arg "Lynx URL: "))
753 (start-process (concat "lynx" url) nil "xterm" "-e" "lynx" url))
755 ;; --- Lynx in an Emacs "term" window ---
757 ;;;###autoload
758 (defun browse-url-lynx-emacs (url &optional new-window)
759 ;; new-window ignored
760 "Ask the Lynx WWW browser to load URL.
761 Default to the URL around or before point. Run a new Lynx process in
762 an Emacs buffer."
763 (interactive (browse-url-interactive-arg "Lynx URL: "))
764 (let ((system-uses-terminfo t)) ; Lynx uses terminfo
765 (if (fboundp 'make-term)
766 (let ((term-term-name "vt100"))
767 (set-buffer (make-term "browse-url" "lynx" nil url))
768 (term-mode)
769 (term-char-mode)
770 (switch-to-buffer "*browse-url*"))
771 (terminal-emulator "*browse-url*" "lynx" (list url)))))
773 (provide 'browse-url)
775 ;;; browse-url.el ends here