(browse-url-netscape, browse-url-netscape-sentinel)
[bpt/emacs.git] / lisp / browse-url.el
1 ;;; browse-url.el --- ask a WWW browser to load a URL
2
3 ;; Copyright 1995, 1996 Free Software Foundation, Inc.
4
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/
10
11 ;; This file is part of GNU Emacs.
12
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.
17
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.
22
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.
27
28 ;;; Commentary:
29
30 ;; The latest version of this package should be available from
31 ;; <URL:http://wombat.doc.ic.ac.uk/emacs/browse-url.el>.
32
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:
40
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
49
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/>.
53
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.
57
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?
61
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>
65
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>
69
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.
74
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/>
79
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.
86
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>.
94
95 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
96 ;; Help!
97
98 ;; Can you write and test some code for the Macintrash and Windoze
99 ;; Netscape remote control APIs? (See the URL above).
100
101 ;; Do any other browsers have remote control?
102
103 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
104 ;; Usage
105
106 ;; To display the URL at or before point:
107 ;; M-x browse-url-at-point RET
108
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.)
114
115 ;; To display the current buffer in a web browser:
116 ;; M-x browse-url-of-buffer RET
117
118 ;; In Dired, to display the file named on the current line:
119 ;; M-x browse-url-of-dired-file RET
120
121 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
122 ;; Customisation (~/.emacs)
123
124 ;; To see what variables are available for customization, type
125 ;; `M-x set-variable browse-url TAB'.
126
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))))
136
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))))
140
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))
144
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))
148
149 ;; To always save modified buffers before displaying the file in a browser:
150 ;; (setq browse-url-save-file t)
151
152 ;; To get round the Netscape caching problem, you could EITHER have
153 ;; write-file in html-helper-mode make Netscape reload the document:
154 ;;
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
166 ;;
167 ;; OR have browse-url-of-file ask Netscape to load and then reload the
168 ;; file:
169 ;;
170 ;; (add-hook 'browse-url-of-file-hook 'browse-url-netscape-reload)
171
172 ;; You may also want to customise browse-url-netscape-arguments, e.g.
173 ;; (setq browse-url-netscape-arguments '("-install"))
174 ;;
175 ;; or similarly for the other browsers.
176
177 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
178 ;;; Change Log:
179
180 ;; 0.00 03 Apr 1995 Denis Howe <dbh@doc.ic.ac.uk>
181 ;; Created.
182
183 ;; 0.01 04 Apr 1995
184 ;; All names start with "browse-url-". Added provide.
185
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.
189
190 ;; 0.03 06 Apr 1995
191 ;; Add browse-url-netscape-reload, browse-url-netscape-send.
192 ;; browse-url-of-file save file option.
193
194 ;; 0.04 08 Apr 1995
195 ;; b-u-file-url separate function. Change b-u-filename-alist
196 ;; default.
197
198 ;; 0.05 09 Apr 1995
199 ;; Added b-u-of-file-hook.
200
201 ;; 0.06 11 Apr 1995
202 ;; Improved .emacs suggestions and documentation.
203
204 ;; 0.07 13 Apr 1995
205 ;; Added browse-url-interactive-arg optional prompt.
206
207 ;; 0.08 18 Apr 1995
208 ;; Exclude final "." from browse-url-regexp.
209
210 ;; 0.09 21 Apr 1995
211 ;; Added mouse-set-point to browse-url-interactive-arg.
212
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.
217
218 ;; 0.11 25 Apr 1995
219 ;; Fix reading of ~/.mosaicpid. Thanks Dag.H.Wanvik@kvatro.no.
220
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>.
226
227 ;; 0.13 28 Apr 1995
228 ;; Exclude final [,;] from browse-url-regexp.
229
230 ;; 0.14 02 May 1995
231 ;; Provide browser argument variables.
232
233 ;; 0.15 07 May 1995
234 ;; More Netscape options. Thanks Peter Arius
235 ;; <arius@immd2.informatik.uni-erlangen.de>.
236
237 ;; 0.16 17 May 1995
238 ;; Added browse-url-at-mouse.
239 ;; Thanks Wayne Mesard <wmesard@sgi.com>
240
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>.
245
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>.
249
250 ;; 0.19 24 Aug 1995
251 ;; Improved documentation.
252 ;; Thanks Kevin Rodgers <kevin.rodgers@ihs.com>.
253
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>.
258
259 ;; 0.21 09 Sep 1995
260 ;; XMosaic CCI functions.
261 ;; Thanks Marc Furrer <Marc.Furrer@di.epfl.ch>.
262
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>.
266
267 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
268 ;;; Code:
269
270 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
271 ;; Variables
272
273 (eval-when-compile (require 'dired))
274
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.")
279
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''.")
285
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.")
291
292 ;;;###autoload
293 (defgroup browse-url nil
294 "Use a web browser to look at a URL."
295 :group 'applications)
296
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)
306
307 (defcustom browse-url-netscape-program "netscape"
308 "*The name by which to invoke Netscape."
309 :type 'string
310 :group 'browse-url)
311
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)
316
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)
323
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)
331
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)
336
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.")
344
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.")
348
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.
352
353 Set this to `browse-url-netscape-reload' to force Netscape to load the
354 file rather than displaying a cached copy.")
355
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.")
364
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.")
369
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'.")
374
375 (defvar browse-url-temp-file-name nil)
376 (make-variable-buffer-local 'browse-url-temp-file-name)
377
378 (defvar browse-url-temp-file-list '())
379
380 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
381 ;; URL input
382
383 ;; thingatpt.el doesn't work for complex regexps
384
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 ""))
394
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.
398
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)))))
410
411 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
412 ;; Browse current buffer
413
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))
434
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)
461
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))))
485
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)))))))
499
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))))
506
507 (add-hook 'kill-buffer-hook 'browse-url-delete-temp-file)
508 (add-hook 'kill-emacs-hook 'browse-url-delete-temp-file-list)
509
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)))
515
516 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
517 ;; Browser-independant commands
518
519 ;; A generic command to call the current b-u-browser-function
520
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))
527
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)))
535
536 ;; Define these if not already defined (XEmacs compatibility)
537
538 (defun browse-url-event-buffer (event)
539 (window-buffer (posn-window (event-start event))))
540
541 (defun browse-url-event-point (event)
542 (posn-point (event-start event)))
543
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))))
559
560 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
561 ;; Browser-specific commands
562
563 ;; --- Netscape ---
564
565 ;; Put the correct DISPLAY value in the environment for Netscape
566 ;; launched from multi-display Emacs.
567
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)))
581
582
583 ;;;###autoload
584 (defun browse-url-netscape (url &optional new-window)
585 "Ask the Netscape WWW browser to load URL.
586
587 Default to the URL around or before point. The strings in variable
588 `browse-url-netscape-arguments' are also passed to Netscape.
589
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.
594
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)))))
614
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))))))
624
625 (defun browse-url-netscape-reload ()
626 "Ask Netscape to reload its current document."
627 (interactive)
628 (browse-url-netscape-send "reload"))
629
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)))))
637
638 ;; --- Mosaic ---
639
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")
667 )
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"))))
673
674 ;; --- Grail ---
675
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.")
681
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")))
695
696 ;; --- Mosaic using CCI ---
697
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.
701
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'.
705
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.
710
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"))
722
723 ;; --- IXI Mosaic ---
724
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))
733
734 ;; --- W3 ---
735
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))
743
744 ;; --- Lynx in an xterm ---
745
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))
754
755 ;; --- Lynx in an Emacs "term" window ---
756
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)))))
772
773 (provide 'browse-url)
774
775 ;;; browse-url.el ends here