]> code.delx.au - gnu-emacs/blob - lisp/net/browse-url.el
Merge from origin/emacs-24
[gnu-emacs] / lisp / net / browse-url.el
1 ;;; browse-url.el --- pass a URL to a WWW browser
2
3 ;; Copyright (C) 1995-2015 Free Software Foundation, Inc.
4
5 ;; Author: Denis Howe <dbh@doc.ic.ac.uk>
6 ;; Maintainer: emacs-devel@gnu.org
7 ;; Created: 03 Apr 1995
8 ;; Keywords: hypertext, hypermedia, mouse
9
10 ;; This file is part of GNU Emacs.
11
12 ;; GNU Emacs is free software: you can redistribute it and/or modify
13 ;; it under the terms of the GNU General Public License as published by
14 ;; the Free Software Foundation, either version 3 of the License, or
15 ;; (at your option) any later version.
16
17 ;; GNU Emacs is distributed in the hope that it will be useful,
18 ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
19 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 ;; GNU General Public License for more details.
21
22 ;; You should have received a copy of the GNU General Public License
23 ;; along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>.
24
25 ;;; Commentary:
26
27 ;; This package provides functions which read a URL (Uniform Resource
28 ;; Locator) from the minibuffer, defaulting to the URL around point,
29 ;; and ask a World-Wide Web browser to load it. It can also load the
30 ;; URL associated with the current buffer. Different browsers use
31 ;; different methods of remote control so there is one function for
32 ;; each supported browser. If the chosen browser is not running, it
33 ;; is started. Currently there is support for the following browsers,
34 ;; some of them probably now obsolete:
35
36 ;; Function Browser Earliest version
37 ;; browse-url-mozilla Mozilla Don't know
38 ;; browse-url-firefox Firefox Don't know (tried with 1.0.1)
39 ;; browse-url-chromium Chromium 3.0
40 ;; browse-url-galeon Galeon Don't know
41 ;; browse-url-epiphany Epiphany Don't know
42 ;; browse-url-netscape Netscape 1.1b1
43 ;; browse-url-mosaic XMosaic/mMosaic <= 2.4
44 ;; browse-url-cci XMosaic 2.5
45 ;; browse-url-w3 w3 0
46 ;; browse-url-w3-gnudoit w3 remotely
47 ;; browse-url-text-* Any text browser 0
48 ;; browse-url-generic arbitrary
49 ;; browse-url-default-windows-browser MS-Windows browser
50 ;; browse-url-default-macosx-browser Mac OS X browser
51 ;; browse-url-xdg-open Free Desktop xdg-open on Gnome, KDE, Xfce4, LXDE
52 ;; browse-url-gnome-moz GNOME interface to Mozilla
53 ;; browse-url-kde KDE konqueror (kfm)
54 ;; browse-url-elinks Elinks Don't know (tried with 0.12.GIT)
55
56 ;; [A version of the Netscape browser is now free software
57 ;; <URL:http://www.mozilla.org/>, albeit not GPLed, so it is
58 ;; reasonable to have that as the default.]
59
60 ;; Note that versions of Netscape before 1.1b1 did not have remote
61 ;; control. <URL:http://www.netscape.com/newsref/std/x-remote.html>.
62
63 ;; Browsers can cache Web pages so it may be necessary to tell them to
64 ;; reload the current page if it has changed (e.g. if you have edited
65 ;; it). There is currently no perfect automatic solution to this.
66
67 ;; Netscape allows you to specify the id of the window you want to
68 ;; control but which window DO you want to control and how do you
69 ;; discover its id?
70
71 ;; William M. Perry's excellent "w3" WWW browser for
72 ;; Emacs <URL:ftp://cs.indiana.edu/pub/elisp/w3/>
73 ;; has a function w3-follow-url-at-point, but that
74 ;; doesn't let you edit the URL like browse-url.
75 ;; The `gnuserv' package that can be used to control it in another
76 ;; Emacs process is available from
77 ;; <URL:ftp://ftp.splode.com/pub/users/friedman/packages/>.
78
79 ;; Lynx is now distributed by the FSF. See also
80 ;; <URL:http://lynx.browser.org/>.
81
82 ;; Free graphical browsers that could be used by `browse-url-generic'
83 ;; include Chimera <URL:ftp://ftp.cs.unlv.edu/pub/chimera> and
84 ;; <URL:http://www.unlv.edu/chimera/>, Arena
85 ;; <URL:ftp://ftp.yggdrasil.com/pub/dist/web/arena> and Amaya
86 ;; <URL:ftp://ftp.w3.org/pub/amaya>. mMosaic
87 ;; <URL:ftp://ftp.enst.fr/pub/mbone/mMosaic/>,
88 ;; <URL:http://www.enst.fr/~dauphin/mMosaic/> (with development
89 ;; support for Java applets and multicast) can be used like Mosaic by
90 ;; setting `browse-url-mosaic-program' appropriately.
91
92 ;; I [Denis Howe, not Dave Love] recommend Nelson Minar
93 ;; <nelson@santafe.edu>'s excellent html-helper-mode.el for editing
94 ;; HTML and thank Nelson for his many useful comments on this code.
95 ;; <URL:http://www.santafe.edu/%7Enelson/hhm-beta/>
96
97 ;; See also hm--html-menus <URL:http://www.tnt.uni-hannover.de/%7Emuenkel/
98 ;; software/own/hm--html-menus/>. For composing correct HTML see also
99 ;; PSGML the general SGML structure editor package
100 ;; <URL:ftp://ftp.lysator.liu.se/pub/sgml>; hm--html-menus can be used
101 ;; with this.
102
103 ;; This package generalizes function html-previewer-process in Marc
104 ;; Andreessen's html-mode (LCD modes/html-mode.el.Z). See also the
105 ;; ffap.el package. The huge hyperbole package also contains similar
106 ;; functions.
107
108 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
109 ;; Help!
110
111 ;; Can you write and test some code for the Macintrash and Windoze
112 ;; Netscape remote control APIs? (See the URL above).
113
114 ;; Do any other browsers have remote control?
115
116 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
117 ;; Usage
118
119 ;; To display the URL at or before point:
120 ;; M-x browse-url-at-point RET
121 ;; or, similarly but with the opportunity to edit the URL extracted from
122 ;; the buffer, use:
123 ;; M-x browse-url
124
125 ;; To display a URL by shift-clicking on it, put this in your init file:
126 ;; (global-set-key [S-mouse-2] 'browse-url-at-mouse)
127 ;; (Note that using Shift-mouse-1 is not desirable because
128 ;; that event has a standard meaning in Emacs.)
129
130 ;; To display the current buffer in a web browser:
131 ;; M-x browse-url-of-buffer RET
132
133 ;; To display the current region in a web browser:
134 ;; M-x browse-url-of-region RET
135
136 ;; In Dired, to display the file named on the current line:
137 ;; M-x browse-url-of-dired-file RET
138
139 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
140 ;; Customization (~/.emacs)
141
142 ;; To see what variables are available for customization, type
143 ;; `M-x set-variable browse-url TAB'. Better, use
144 ;; `M-x customize-group browse-url'.
145
146 ;; Bind the browse-url commands to keys with the `C-c C-z' prefix
147 ;; (as used by html-helper-mode):
148 ;; (global-set-key "\C-c\C-z." 'browse-url-at-point)
149 ;; (global-set-key "\C-c\C-zb" 'browse-url-of-buffer)
150 ;; (global-set-key "\C-c\C-zr" 'browse-url-of-region)
151 ;; (global-set-key "\C-c\C-zu" 'browse-url)
152 ;; (global-set-key "\C-c\C-zv" 'browse-url-of-file)
153 ;; (add-hook 'dired-mode-hook
154 ;; (lambda ()
155 ;; (local-set-key "\C-c\C-zf" 'browse-url-of-dired-file)))
156
157 ;; Browse URLs in mail messages under RMAIL by clicking mouse-2:
158 ;; (add-hook 'rmail-mode-hook (lambda () ; rmail-mode startup
159 ;; (define-key rmail-mode-map [mouse-2] 'browse-url-at-mouse)))
160 ;; Alternatively, add `goto-address' to `rmail-show-message-hook'.
161
162 ;; Gnus provides a standard feature to activate URLs in article
163 ;; buffers for invocation of browse-url.
164
165 ;; Use the Emacs w3 browser when not running under X11:
166 ;; (or (eq window-system 'x)
167 ;; (setq browse-url-browser-function 'browse-url-w3))
168
169 ;; To always save modified buffers before displaying the file in a browser:
170 ;; (setq browse-url-save-file t)
171
172 ;; To get round the Netscape caching problem, you could EITHER have
173 ;; write-file in html-helper-mode make Netscape reload the document:
174 ;;
175 ;; (autoload 'browse-url-netscape-reload "browse-url"
176 ;; "Ask a WWW browser to redisplay the current file." t)
177 ;; (add-hook 'html-helper-mode-hook
178 ;; (lambda ()
179 ;; (add-hook 'local-write-file-hooks
180 ;; (lambda ()
181 ;; (let ((local-write-file-hooks))
182 ;; (save-buffer))
183 ;; (browse-url-netscape-reload)
184 ;; t) ; => file written by hook
185 ;; t))) ; append to l-w-f-hooks
186 ;;
187 ;; OR have browse-url-of-file ask Netscape to load and then reload the
188 ;; file:
189 ;;
190 ;; (add-hook 'browse-url-of-file-hook 'browse-url-netscape-reload)
191
192 ;; You may also want to customize browse-url-netscape-arguments, e.g.
193 ;; (setq browse-url-netscape-arguments '("-install"))
194 ;;
195 ;; or similarly for the other browsers.
196
197 ;; To invoke different browsers for different URLs:
198 ;; (setq browse-url-browser-function '(("^mailto:" . browse-url-mail)
199 ;; ("." . browse-url-netscape)))
200
201 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
202 ;;; Code:
203
204 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
205 ;; Variables
206
207 (defgroup browse-url nil
208 "Use a web browser to look at a URL."
209 :prefix "browse-url-"
210 :link '(emacs-commentary-link "browse-url")
211 :group 'external
212 :group 'comm)
213
214 ;;;###autoload
215 (defcustom browse-url-browser-function
216 'browse-url-default-browser
217 "Function to display the current buffer in a WWW browser.
218 This is used by the `browse-url-at-point', `browse-url-at-mouse', and
219 `browse-url-of-file' commands.
220
221 If the value is not a function it should be a list of pairs
222 \(REGEXP . FUNCTION). In this case the function called will be the one
223 associated with the first REGEXP which matches the current URL. The
224 function is passed the URL and any other args of `browse-url'. The last
225 regexp should probably be \".\" to specify a default browser."
226 :type '(choice
227 (function-item :tag "Emacs W3" :value browse-url-w3)
228 (function-item :tag "W3 in another Emacs via `gnudoit'"
229 :value browse-url-w3-gnudoit)
230 (function-item :tag "eww" :value eww-browse-url)
231 (function-item :tag "Mozilla" :value browse-url-mozilla)
232 (function-item :tag "Firefox" :value browse-url-firefox)
233 (function-item :tag "Chromium" :value browse-url-chromium)
234 (function-item :tag "Galeon" :value browse-url-galeon)
235 (function-item :tag "Epiphany" :value browse-url-epiphany)
236 (function-item :tag "Netscape" :value browse-url-netscape)
237 (function-item :tag "Mosaic" :value browse-url-mosaic)
238 (function-item :tag "Mosaic using CCI" :value browse-url-cci)
239 (function-item :tag "Text browser in an xterm window"
240 :value browse-url-text-xterm)
241 (function-item :tag "Text browser in an Emacs window"
242 :value browse-url-text-emacs)
243 (function-item :tag "KDE" :value browse-url-kde)
244 (function-item :tag "Elinks" :value browse-url-elinks)
245 (function-item :tag "Specified by `Browse Url Generic Program'"
246 :value browse-url-generic)
247 (function-item :tag "Default Windows browser"
248 :value browse-url-default-windows-browser)
249 (function-item :tag "Default Mac OS X browser"
250 :value browse-url-default-macosx-browser)
251 (function-item :tag "GNOME invoking Mozilla"
252 :value browse-url-gnome-moz)
253 (function-item :tag "Default browser"
254 :value browse-url-default-browser)
255 (function :tag "Your own function")
256 (alist :tag "Regexp/function association list"
257 :key-type regexp :value-type function))
258 :version "24.1"
259 :group 'browse-url)
260
261 (defcustom browse-url-mailto-function 'browse-url-mail
262 "Function to display mailto: links.
263 This variable uses the same syntax as the
264 `browse-url-browser-function' variable. If the
265 `browse-url-mailto-function' variable is nil, that variable will
266 be used instead."
267 :type '(choice
268 (function-item :tag "Emacs Mail" :value browse-url-mail)
269 (function-item :tag "None" nil))
270 :version "24.1"
271 :group 'browse-url)
272
273 (defcustom browse-url-netscape-program "netscape"
274 ;; Info about netscape-remote from Karl Berry.
275 "The name by which to invoke Netscape.
276
277 The free program `netscape-remote' from
278 <URL:http://home.netscape.com/newsref/std/remote.c> is said to start
279 up very much quicker than `netscape'. Reported to compile on a GNU
280 system, given vroot.h from the same directory, with cc flags
281 -DSTANDALONE -L/usr/X11R6/lib -lXmu -lX11."
282 :type 'string
283 :group 'browse-url)
284
285 (defcustom browse-url-netscape-arguments nil
286 "A list of strings to pass to Netscape as arguments."
287 :type '(repeat (string :tag "Argument"))
288 :group 'browse-url)
289
290 (defcustom browse-url-netscape-startup-arguments browse-url-netscape-arguments
291 "A list of strings to pass to Netscape when it starts up.
292 Defaults to the value of `browse-url-netscape-arguments' at the time
293 `browse-url' is loaded."
294 :type '(repeat (string :tag "Argument"))
295 :group 'browse-url)
296
297 (defcustom browse-url-browser-display nil
298 "The X display for running the browser, if not same as Emacs's."
299 :type '(choice string (const :tag "Default" nil))
300 :group 'browse-url)
301
302 (defcustom browse-url-mozilla-program "mozilla"
303 "The name by which to invoke Mozilla."
304 :type 'string
305 :group 'browse-url)
306
307 (defcustom browse-url-mozilla-arguments nil
308 "A list of strings to pass to Mozilla as arguments."
309 :type '(repeat (string :tag "Argument"))
310 :group 'browse-url)
311
312 (defcustom browse-url-mozilla-startup-arguments browse-url-mozilla-arguments
313 "A list of strings to pass to Mozilla when it starts up.
314 Defaults to the value of `browse-url-mozilla-arguments' at the time
315 `browse-url' is loaded."
316 :type '(repeat (string :tag "Argument"))
317 :group 'browse-url)
318
319 (defcustom browse-url-firefox-program
320 (let ((candidates '("firefox" "iceweasel" "icecat")))
321 (while (and candidates (not (executable-find (car candidates))))
322 (setq candidates (cdr candidates)))
323 (or (car candidates) "firefox"))
324 "The name by which to invoke Firefox."
325 :type 'string
326 :group 'browse-url)
327
328 (defcustom browse-url-firefox-arguments nil
329 "A list of strings to pass to Firefox as arguments."
330 :type '(repeat (string :tag "Argument"))
331 :group 'browse-url)
332
333 (defcustom browse-url-firefox-startup-arguments browse-url-firefox-arguments
334 "A list of strings to pass to Firefox when it starts up.
335 Defaults to the value of `browse-url-firefox-arguments' at the time
336 `browse-url' is loaded."
337 :type '(repeat (string :tag "Argument"))
338 :group 'browse-url)
339
340 (make-obsolete-variable 'browse-url-firefox-startup-arguments
341 "it no longer has any effect." "24.5")
342
343 (defcustom browse-url-chromium-program
344 (let ((candidates '("chromium" "chromium-browser")))
345 (while (and candidates (not (executable-find (car candidates))))
346 (setq candidates (cdr candidates)))
347 (or (car candidates) "chromium"))
348 "The name by which to invoke Chromium."
349 :type 'string
350 :version "24.1"
351 :group 'browse-url)
352
353 (defcustom browse-url-chromium-arguments nil
354 "A list of strings to pass to Chromium as arguments."
355 :type '(repeat (string :tag "Argument"))
356 :version "24.1"
357 :group 'browse-url)
358
359 (defcustom browse-url-galeon-program "galeon"
360 "The name by which to invoke Galeon."
361 :type 'string
362 :group 'browse-url)
363
364 (defcustom browse-url-galeon-arguments nil
365 "A list of strings to pass to Galeon as arguments."
366 :type '(repeat (string :tag "Argument"))
367 :group 'browse-url)
368
369 (defcustom browse-url-galeon-startup-arguments browse-url-galeon-arguments
370 "A list of strings to pass to Galeon when it starts up.
371 Defaults to the value of `browse-url-galeon-arguments' at the time
372 `browse-url' is loaded."
373 :type '(repeat (string :tag "Argument"))
374 :group 'browse-url)
375
376 (defcustom browse-url-epiphany-program "epiphany"
377 "The name by which to invoke Epiphany."
378 :type 'string
379 :group 'browse-url)
380
381 (defcustom browse-url-epiphany-arguments nil
382 "A list of strings to pass to Epiphany as arguments."
383 :type '(repeat (string :tag "Argument"))
384 :group 'browse-url)
385
386 (defcustom browse-url-epiphany-startup-arguments browse-url-epiphany-arguments
387 "A list of strings to pass to Epiphany when it starts up.
388 Defaults to the value of `browse-url-epiphany-arguments' at the time
389 `browse-url' is loaded."
390 :type '(repeat (string :tag "Argument"))
391 :group 'browse-url)
392
393 ;; GNOME means of invoking either Mozilla or Netscape.
394 (defvar browse-url-gnome-moz-program "gnome-moz-remote")
395
396 (defcustom browse-url-gnome-moz-arguments '()
397 "A list of strings passed to the GNOME mozilla viewer as arguments."
398 :version "21.1"
399 :type '(repeat (string :tag "Argument"))
400 :group 'browse-url)
401
402 (defcustom browse-url-mozilla-new-window-is-tab nil
403 "Whether to open up new windows in a tab or a new window.
404 If non-nil, then open the URL in a new tab rather than a new window if
405 `browse-url-mozilla' is asked to open it in a new window."
406 :type 'boolean
407 :group 'browse-url)
408
409 (defcustom browse-url-firefox-new-window-is-tab nil
410 "Whether to open up new windows in a tab or a new window.
411 If non-nil, then open the URL in a new tab rather than a new window if
412 `browse-url-firefox' is asked to open it in a new window.
413
414 This option is currently ignored on MS-Windows, since the necessary
415 functionality is not available there."
416 :type 'boolean
417 :group 'browse-url)
418
419 (defcustom browse-url-galeon-new-window-is-tab nil
420 "Whether to open up new windows in a tab or a new window.
421 If non-nil, then open the URL in a new tab rather than a new window if
422 `browse-url-galeon' is asked to open it in a new window."
423 :type 'boolean
424 :group 'browse-url)
425
426 (defcustom browse-url-epiphany-new-window-is-tab nil
427 "Whether to open up new windows in a tab or a new window.
428 If non-nil, then open the URL in a new tab rather than a new window if
429 `browse-url-epiphany' is asked to open it in a new window."
430 :type 'boolean
431 :group 'browse-url)
432
433 (defcustom browse-url-netscape-new-window-is-tab nil
434 "Whether to open up new windows in a tab or a new window.
435 If non-nil, then open the URL in a new tab rather than a new
436 window if `browse-url-netscape' is asked to open it in a new
437 window."
438 :type 'boolean
439 :group 'browse-url)
440
441 (defcustom browse-url-new-window-flag nil
442 "Non-nil means always open a new browser window with appropriate browsers.
443 Passing an interactive argument to \\[browse-url], or specific browser
444 commands reverses the effect of this variable. Requires Netscape version
445 1.1N or later or XMosaic version 2.5 or later if using those browsers."
446 :type 'boolean
447 :group 'browse-url)
448
449 (defcustom browse-url-mosaic-program "xmosaic"
450 "The name by which to invoke Mosaic (or mMosaic)."
451 :type 'string
452 :version "20.3"
453 :group 'browse-url)
454
455 (defcustom browse-url-mosaic-arguments nil
456 "A list of strings to pass to Mosaic as arguments."
457 :type '(repeat (string :tag "Argument"))
458 :group 'browse-url)
459
460 (defcustom browse-url-mosaic-pidfile "~/.mosaicpid"
461 "The name of the pidfile created by Mosaic."
462 :type 'string
463 :group 'browse-url)
464
465 (defcustom browse-url-filename-alist
466 `(("^/\\(ftp@\\|anonymous@\\)?\\([^:]+\\):/*" . "ftp://\\2/")
467 ;; The above loses the username to avoid the browser prompting for
468 ;; it in anonymous cases. If it's not anonymous the next regexp
469 ;; applies.
470 ("^/\\([^:@]+@\\)?\\([^:]+\\):/*" . "ftp://\\1\\2/")
471 ,@(if (memq system-type '(windows-nt ms-dos))
472 '(("^\\([a-zA-Z]:\\)[\\/]" . "file:///\\1/")
473 ("^[\\/][\\/]+" . "file://")))
474 ("^/+" . "file:///"))
475 "An alist of (REGEXP . STRING) pairs used by `browse-url-of-file'.
476 Any substring of a filename matching one of the REGEXPs is replaced by
477 the corresponding STRING using `replace-match', not treating STRING
478 literally. All pairs are applied in the order given. The default
479 value converts ange-ftp/EFS-style file names into ftp URLs and prepends
480 `file:' to any file name beginning with `/'.
481
482 For example, adding to the default a specific translation of an ange-ftp
483 address to an HTTP URL:
484
485 (setq browse-url-filename-alist
486 '((\"/webmaster@webserver:/home/www/html/\" .
487 \"http://www.acme.co.uk/\")
488 (\"^/\\(ftp@\\|anonymous@\\)?\\([^:]+\\):/*\" . \"ftp://\\2/\")
489 (\"^/\\([^:@]+@\\)?\\([^:]+\\):/*\" . \"ftp://\\1\\2/\")
490 (\"^/+\" . \"file:/\")))"
491 :type '(repeat (cons :format "%v"
492 (regexp :tag "Regexp")
493 (string :tag "Replacement")))
494 :version "23.1"
495 :group 'browse-url)
496
497 (defcustom browse-url-save-file nil
498 "If non-nil, save the buffer before displaying its file.
499 Used by the `browse-url-of-file' command."
500 :type 'boolean
501 :group 'browse-url)
502
503 (defcustom browse-url-of-file-hook nil
504 "Run after `browse-url-of-file' has asked a browser to load a file.
505
506 Set this to `browse-url-netscape-reload' to force Netscape to load the
507 file rather than displaying a cached copy."
508 :type 'hook
509 :options '(browse-url-netscape-reload)
510 :group 'browse-url)
511
512 (defcustom browse-url-CCI-port 3003
513 "Port to access XMosaic via CCI.
514 This can be any number between 1024 and 65535 but must correspond to
515 the value set in the browser."
516 :type 'integer
517 :group 'browse-url)
518
519 (defcustom browse-url-CCI-host "localhost"
520 "Host to access XMosaic via CCI.
521 This should be the host name of the machine running XMosaic with CCI
522 enabled. The port number should be set in `browse-url-CCI-port'."
523 :type 'string
524 :group 'browse-url)
525
526 (defvar browse-url-temp-file-name nil)
527 (make-variable-buffer-local 'browse-url-temp-file-name)
528
529 (defcustom browse-url-xterm-program "xterm"
530 "The name of the terminal emulator used by `browse-url-text-xterm'.
531 This might, for instance, be a separate color version of xterm."
532 :type 'string
533 :group 'browse-url)
534
535 (defcustom browse-url-xterm-args nil
536 "A list of strings defining options for `browse-url-xterm-program'.
537 These might set its size, for instance."
538 :type '(repeat (string :tag "Argument"))
539 :group 'browse-url)
540
541 (defcustom browse-url-gnudoit-program "gnudoit"
542 "The name of the `gnudoit' program used by `browse-url-w3-gnudoit'."
543 :type 'string
544 :group 'browse-url)
545
546 (defcustom browse-url-gnudoit-args '("-q")
547 "A list of strings defining options for `browse-url-gnudoit-program'.
548 These might set the port, for instance."
549 :type '(repeat (string :tag "Argument"))
550 :group 'browse-url)
551
552 (defcustom browse-url-generic-program nil
553 "The name of the browser program used by `browse-url-generic'."
554 :type '(choice string (const :tag "None" nil))
555 :group 'browse-url)
556
557 (defcustom browse-url-generic-args nil
558 "A list of strings defining options for `browse-url-generic-program'."
559 :type '(repeat (string :tag "Argument"))
560 :group 'browse-url)
561
562 (defcustom browse-url-temp-dir temporary-file-directory
563 "The name of a directory for browse-url's temporary files.
564 Such files are generated by functions like `browse-url-of-region'.
565 You might want to set this to somewhere with restricted read permissions
566 for privacy's sake."
567 :type 'string
568 :group 'browse-url)
569
570 (defcustom browse-url-netscape-version 3
571 "The version of Netscape you are using.
572 This affects how URL reloading is done; the mechanism changed
573 incompatibly at version 4."
574 :type 'number
575 :group 'browse-url)
576
577 (defcustom browse-url-text-browser "lynx"
578 "The name of the text browser to invoke."
579 :type 'string
580 :group 'browse-url
581 :version "23.1")
582
583 (defcustom browse-url-text-emacs-args (and (not window-system)
584 '("-show_cursor"))
585 "A list of strings defining options for a text browser in an Emacs buffer.
586
587 The default is none in a window system, otherwise `-show_cursor' to
588 indicate the position of the current link in the absence of
589 highlighting, assuming the normal default for showing the cursor."
590 :type '(repeat (string :tag "Argument"))
591 :version "23.1"
592 :group 'browse-url)
593
594 (defcustom browse-url-text-input-field 'avoid
595 "Action on selecting an existing text browser buffer at an input field.
596 What to do when sending a new URL to an existing text browser buffer in Emacs
597 if the browser cursor is on an input field (in which case the `g' command
598 would be entered as data). Such fields are recognized by the
599 underlines ____. Allowed values: nil: disregard it, `warn': warn the
600 user and don't emit the URL, `avoid': try to avoid the field by moving
601 down (this *won't* always work)."
602 :type '(choice (const :tag "Move to try to avoid field" :value avoid)
603 (const :tag "Disregard" :value nil)
604 (const :tag "Warn, don't emit URL" :value warn))
605 :version "23.1"
606 :group 'browse-url)
607
608 (defcustom browse-url-text-input-attempts 10
609 "How many times to try to move down from a series of text browser input fields."
610 :type 'integer
611 :version "23.1"
612 :group 'browse-url)
613
614 (defcustom browse-url-text-input-delay 0.2
615 "Seconds to wait for a text browser between moves down from an input field."
616 :type 'number
617 :version "23.1"
618 :group 'browse-url)
619
620 (defcustom browse-url-kde-program "kfmclient"
621 "The name by which to invoke the KDE web browser."
622 :type 'string
623 :version "21.1"
624 :group 'browse-url)
625
626 (defcustom browse-url-kde-args '("openURL")
627 "A list of strings defining options for `browse-url-kde-program'."
628 :type '(repeat (string :tag "Argument"))
629 :group 'browse-url)
630
631 (defcustom browse-url-elinks-wrapper '("xterm" "-e")
632 "Wrapper command prepended to the Elinks command-line."
633 :type '(repeat (string :tag "Wrapper"))
634 :group 'browse-url)
635
636 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
637 ;; URL encoding
638
639 (defun browse-url-url-encode-chars (text chars)
640 "URL-encode the chars in TEXT that match CHARS.
641 CHARS is a regexp-like character alternative (e.g., \"[)$]\")."
642 (let ((encoded-text (copy-sequence text))
643 (s 0))
644 (while (setq s (string-match chars encoded-text s))
645 (setq encoded-text
646 (replace-match (format "%%%X"
647 (string-to-char (match-string 0 encoded-text)))
648 t t encoded-text)
649 s (1+ s)))
650 encoded-text))
651
652 (defun browse-url-encode-url (url)
653 "Escape annoying characters in URL.
654 The annoying characters are those that can mislead a web browser
655 regarding its parameter treatment."
656 ;; FIXME: Is there an actual example of a web browser getting
657 ;; confused? (This used to encode commas, but at least Firefox
658 ;; handles commas correctly and doesn't accept encoded commas.)
659 (browse-url-url-encode-chars url "[\")$] "))
660
661 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
662 ;; URL input
663
664 (defun browse-url-url-at-point ()
665 (or (thing-at-point 'url t)
666 ;; assume that the user is pointing at something like gnu.org/gnu
667 (let ((f (thing-at-point 'filename t)))
668 (and f (concat "http://" f)))))
669
670 ;; Having this as a separate function called by the browser-specific
671 ;; functions allows them to be stand-alone commands, making it easier
672 ;; to switch between browsers.
673
674 (defun browse-url-interactive-arg (prompt)
675 "Read a URL from the minibuffer, prompting with PROMPT.
676 If `transient-mark-mode' is non-nil and the mark is active,
677 it defaults to the current region, else to the URL at or before
678 point. If invoked with a mouse button, it moves point to the
679 position clicked before acting.
680
681 This function returns a list (URL NEW-WINDOW-FLAG)
682 for use in `interactive'."
683 (let ((event (elt (this-command-keys) 0)))
684 (and (listp event) (mouse-set-point event)))
685 (list (read-string prompt (or (and transient-mark-mode mark-active
686 ;; rfc2396 Appendix E.
687 (replace-regexp-in-string
688 "[\t\r\f\n ]+" ""
689 (buffer-substring-no-properties
690 (region-beginning) (region-end))))
691 (browse-url-url-at-point)))
692 (not (eq (null browse-url-new-window-flag)
693 (null current-prefix-arg)))))
694
695 ;; called-interactive-p needs to be called at a function's top-level, hence
696 ;; this macro. We use that rather than interactive-p because
697 ;; use in a keyboard macro should not change this behavior.
698 (defmacro browse-url-maybe-new-window (arg)
699 `(if (or noninteractive (not (called-interactively-p 'any)))
700 ,arg
701 browse-url-new-window-flag))
702
703 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
704 ;; Browse current buffer
705
706 ;;;###autoload
707 (defun browse-url-of-file (&optional file)
708 "Ask a WWW browser to display FILE.
709 Display the current buffer's file if FILE is nil or if called
710 interactively. Turn the filename into a URL with function
711 `browse-url-file-url'. Pass the URL to a browser using the
712 `browse-url' function then run `browse-url-of-file-hook'."
713 (interactive)
714 (or file
715 (setq file (buffer-file-name))
716 (error "Current buffer has no file"))
717 (let ((buf (get-file-buffer file)))
718 (if buf
719 (with-current-buffer buf
720 (cond ((not (buffer-modified-p)))
721 (browse-url-save-file (save-buffer))
722 (t (message "%s modified since last save" file))))))
723 (browse-url (browse-url-file-url file))
724 (run-hooks 'browse-url-of-file-hook))
725
726 (defun browse-url-file-url (file)
727 "Return the URL corresponding to FILE.
728 Use variable `browse-url-filename-alist' to map filenames to URLs."
729 (let ((coding (if (equal system-type 'windows-nt)
730 ;; W32 pretends that file names are UTF-8 encoded.
731 'utf-8
732 (and (default-value 'enable-multibyte-characters)
733 (or file-name-coding-system
734 default-file-name-coding-system)))))
735 (if coding (setq file (encode-coding-string file coding))))
736 (setq file (browse-url-url-encode-chars file "[*\"()',=;?% ]"))
737 (dolist (map browse-url-filename-alist)
738 (when (and map (string-match (car map) file))
739 (setq file (replace-match (cdr map) t nil file))))
740 file)
741
742 ;;;###autoload
743 (defun browse-url-of-buffer (&optional buffer)
744 "Ask a WWW browser to display BUFFER.
745 Display the current buffer if BUFFER is nil. Display only the
746 currently visible part of BUFFER (from a temporary file) if buffer is
747 narrowed."
748 (interactive)
749 (save-excursion
750 (and buffer (set-buffer buffer))
751 (let ((file-name
752 ;; Ignore real name if restricted
753 (and (not (buffer-narrowed-p))
754 (or buffer-file-name
755 (and (boundp 'dired-directory) dired-directory)))))
756 (or file-name
757 (progn
758 (or browse-url-temp-file-name
759 (setq browse-url-temp-file-name
760 (convert-standard-filename
761 (make-temp-file
762 (expand-file-name "burl" browse-url-temp-dir)
763 nil ".html"))))
764 (setq file-name browse-url-temp-file-name)
765 (write-region (point-min) (point-max) file-name nil 'no-message)))
766 (browse-url-of-file file-name))))
767
768 (defun browse-url-delete-temp-file (&optional temp-file-name)
769 ;; Delete browse-url-temp-file-name from the file system
770 ;; If optional arg TEMP-FILE-NAME is non-nil, delete it instead
771 (let ((file-name (or temp-file-name browse-url-temp-file-name)))
772 (if (and file-name (file-exists-p file-name))
773 (delete-file file-name))))
774
775 (add-hook 'kill-buffer-hook 'browse-url-delete-temp-file)
776
777 (declare-function dired-get-filename "dired"
778 (&optional localp no-error-if-not-filep))
779
780 ;;;###autoload
781 (defun browse-url-of-dired-file ()
782 "In Dired, ask a WWW browser to display the file named on this line."
783 (interactive)
784 (let ((tem (dired-get-filename t t)))
785 (if tem
786 (browse-url-of-file (expand-file-name tem))
787 (error "No file on this line"))))
788
789 ;;;###autoload
790 (defun browse-url-of-region (min max)
791 "Ask a WWW browser to display the current region."
792 (interactive "r")
793 (save-excursion
794 (save-restriction
795 (narrow-to-region min max)
796 (browse-url-of-buffer))))
797
798 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
799 ;; Browser-independent commands
800
801 ;; A generic command to call the current browse-url-browser-function
802
803 ;;;###autoload
804 (defun browse-url (url &rest args)
805 "Ask a WWW browser to load URL.
806 Prompts for a URL, defaulting to the URL at or before point. Variable
807 `browse-url-browser-function' says which browser to use.
808 If the URL is a mailto: URL, consult `browse-url-mailto-function'
809 first, if that exists."
810 (interactive (browse-url-interactive-arg "URL: "))
811 (unless (called-interactively-p 'interactive)
812 (setq args (or args (list browse-url-new-window-flag))))
813 (when (and url-handler-mode (not (file-name-absolute-p url)))
814 (setq url (expand-file-name url)))
815 (let ((process-environment (copy-sequence process-environment))
816 (function (or (and (string-match "\\`mailto:" url)
817 browse-url-mailto-function)
818 browse-url-browser-function))
819 ;; Ensure that `default-directory' exists and is readable (b#6077).
820 (default-directory (or (unhandled-file-name-directory default-directory)
821 (expand-file-name "~/"))))
822 ;; When connected to various displays, be careful to use the display of
823 ;; the currently selected frame, rather than the original start display,
824 ;; which may not even exist any more.
825 (if (stringp (frame-parameter nil 'display))
826 (setenv "DISPLAY" (frame-parameter nil 'display)))
827 (if (and (consp function)
828 (not (functionp function)))
829 ;; The `function' can be an alist; look down it for first match
830 ;; and apply the function (which might be a lambda).
831 (catch 'done
832 (dolist (bf function)
833 (when (string-match (car bf) url)
834 (apply (cdr bf) url args)
835 (throw 'done t)))
836 (error "No browse-url-browser-function matching URL %s"
837 url))
838 ;; Unbound symbols go down this leg, since void-function from
839 ;; apply is clearer than wrong-type-argument from dolist.
840 (apply function url args))))
841
842 ;;;###autoload
843 (defun browse-url-at-point (&optional arg)
844 "Ask a WWW browser to load the URL at or before point.
845 Doesn't let you edit the URL like `browse-url'. Variable
846 `browse-url-browser-function' says which browser to use."
847 (interactive "P")
848 (let ((url (browse-url-url-at-point)))
849 (if url
850 (browse-url url (if arg
851 (not browse-url-new-window-flag)
852 browse-url-new-window-flag))
853 (error "No URL found"))))
854
855 ;;;###autoload
856 (defun browse-url-at-mouse (event)
857 "Ask a WWW browser to load a URL clicked with the mouse.
858 The URL is the one around or before the position of the mouse click
859 but point is not changed. Doesn't let you edit the URL like
860 `browse-url'. Variable `browse-url-browser-function' says which browser
861 to use."
862 (interactive "e")
863 (save-excursion
864 (mouse-set-point event)
865 ;; This handles browse-url-new-window-flag properly
866 ;; when it gets no arg.
867 (browse-url-at-point)))
868
869 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
870 ;; Browser-specific commands
871
872 ;; --- Default MS-Windows browser ---
873
874 (defvar dos-windows-version)
875 (declare-function w32-shell-execute "w32fns.c") ;; Defined in C.
876
877 (defun browse-url-default-windows-browser (url &optional _new-window)
878 (interactive (browse-url-interactive-arg "URL: "))
879 (cond ((eq system-type 'ms-dos)
880 (if dos-windows-version
881 (shell-command (concat "start " (shell-quote-argument url)))
882 (error "Browsing URLs is not supported on this system")))
883 ((eq system-type 'cygwin)
884 (call-process "cygstart" nil nil nil url))
885 (t (w32-shell-execute "open" url))))
886
887 (defun browse-url-default-macosx-browser (url &optional _new-window)
888 (interactive (browse-url-interactive-arg "URL: "))
889 (start-process (concat "open " url) nil "open" url))
890
891 ;; --- Netscape ---
892
893 (defun browse-url-process-environment ()
894 "Set DISPLAY in the environment to the X display the browser will use.
895 This is either the value of variable `browse-url-browser-display' if
896 non-nil, or the same display as Emacs if different from the current
897 environment, otherwise just use the current environment."
898 (let ((display (or browse-url-browser-display (browse-url-emacs-display))))
899 (if display
900 (cons (concat "DISPLAY=" display) process-environment)
901 process-environment)))
902
903 (defun browse-url-emacs-display ()
904 "Return the X display Emacs is running on.
905 This is nil if the display is the same as the DISPLAY environment variable.
906
907 Actually Emacs could be using several displays; this just returns the
908 one showing the selected frame."
909 (let ((display (cdr-safe (assq 'display (frame-parameters)))))
910 (and (not (equal display (getenv "DISPLAY")))
911 display)))
912
913 (defun browse-url-default-browser (url &rest args)
914 "Find a suitable browser and ask it to load URL.
915 Default to the URL around or before point.
916
917 When called interactively, if variable `browse-url-new-window-flag' is
918 non-nil, load the document in a new window, if possible, otherwise use
919 a random existing one. A non-nil interactive prefix argument reverses
920 the effect of `browse-url-new-window-flag'.
921
922 When called non-interactively, optional second argument NEW-WINDOW is
923 used instead of `browse-url-new-window-flag'."
924 (apply
925 (cond
926 ((memq system-type '(windows-nt ms-dos cygwin))
927 'browse-url-default-windows-browser)
928 ((memq system-type '(darwin))
929 'browse-url-default-macosx-browser)
930 ((browse-url-can-use-xdg-open) 'browse-url-xdg-open)
931 ((executable-find browse-url-gnome-moz-program) 'browse-url-gnome-moz)
932 ((executable-find browse-url-mozilla-program) 'browse-url-mozilla)
933 ((executable-find browse-url-firefox-program) 'browse-url-firefox)
934 ((executable-find browse-url-chromium-program) 'browse-url-chromium)
935 ((executable-find browse-url-galeon-program) 'browse-url-galeon)
936 ((executable-find browse-url-kde-program) 'browse-url-kde)
937 ((executable-find browse-url-netscape-program) 'browse-url-netscape)
938 ((executable-find browse-url-mosaic-program) 'browse-url-mosaic)
939 ((executable-find browse-url-xterm-program) 'browse-url-text-xterm)
940 ((locate-library "w3") 'browse-url-w3)
941 (t
942 (lambda (&rest _ignore) (error "No usable browser found"))))
943 url args))
944
945 (defun browse-url-can-use-xdg-open ()
946 "Return non-nil if the \"xdg-open\" program can be used.
947 xdg-open is a desktop utility that calls your preferred web browser.
948 This requires you to be running either Gnome, KDE, Xfce4 or LXDE."
949 (and (getenv "DISPLAY")
950 (executable-find "xdg-open")
951 ;; xdg-open may call gnome-open and that does not wait for its child
952 ;; to finish. This child may then be killed when the parent dies.
953 ;; Use nohup to work around. See bug#7166, bug#8917, bug#9779 and
954 ;; http://lists.gnu.org/archive/html/emacs-devel/2009-07/msg00279.html
955 (executable-find "nohup")
956 (or (getenv "GNOME_DESKTOP_SESSION_ID")
957 ;; GNOME_DESKTOP_SESSION_ID is deprecated, check on Dbus also.
958 (condition-case nil
959 (eq 0 (call-process
960 "dbus-send" nil nil nil
961 "--dest=org.gnome.SessionManager"
962 "--print-reply"
963 "/org/gnome/SessionManager"
964 "org.gnome.SessionManager.CanShutdown"))
965 (error nil))
966 (equal (getenv "KDE_FULL_SESSION") "true")
967 (condition-case nil
968 (eq 0 (call-process
969 "/bin/sh" nil nil nil
970 "-c"
971 ;; FIXME use string-match rather than grep.
972 "xprop -root _DT_SAVE_MODE|grep xfce4"))
973 (error nil))
974 (member (getenv "DESKTOP_SESSION") '("LXDE" "Lubuntu"))
975 (equal (getenv "XDG_CURRENT_DESKTOP") "LXDE"))))
976
977
978 ;;;###autoload
979 (defun browse-url-xdg-open (url &optional ignored)
980 "Pass the specified URL to the \"xdg-open\" command.
981 xdg-open is a desktop utility that calls your preferred web browser.
982 The optional argument IGNORED is not used."
983 (interactive (browse-url-interactive-arg "URL: "))
984 (call-process "xdg-open" nil 0 nil url))
985
986 ;;;###autoload
987 (defun browse-url-netscape (url &optional new-window)
988 "Ask the Netscape WWW browser to load URL.
989 Default to the URL around or before point. The strings in variable
990 `browse-url-netscape-arguments' are also passed to Netscape.
991
992 When called interactively, if variable `browse-url-new-window-flag' is
993 non-nil, load the document in a new Netscape window, otherwise use a
994 random existing one. A non-nil interactive prefix argument reverses
995 the effect of `browse-url-new-window-flag'.
996
997 If `browse-url-netscape-new-window-is-tab' is non-nil, then
998 whenever a document would otherwise be loaded in a new window, it
999 is loaded in a new tab in an existing window instead.
1000
1001 When called non-interactively, optional second argument NEW-WINDOW is
1002 used instead of `browse-url-new-window-flag'."
1003 (interactive (browse-url-interactive-arg "URL: "))
1004 (setq url (browse-url-encode-url url))
1005 (let* ((process-environment (browse-url-process-environment))
1006 (process
1007 (apply 'start-process
1008 (concat "netscape " url) nil
1009 browse-url-netscape-program
1010 (append
1011 browse-url-netscape-arguments
1012 (if (eq window-system 'w32)
1013 (list url)
1014 (append
1015 (if new-window '("-noraise"))
1016 (list "-remote"
1017 (concat "openURL(" url
1018 (if (browse-url-maybe-new-window
1019 new-window)
1020 (if browse-url-netscape-new-window-is-tab
1021 ",new-tab"
1022 ",new-window"))
1023 ")"))))))))
1024 (set-process-sentinel process
1025 `(lambda (process change)
1026 (browse-url-netscape-sentinel process ,url)))))
1027
1028 (defun browse-url-netscape-sentinel (process url)
1029 "Handle a change to the process communicating with Netscape."
1030 (or (eq (process-exit-status process) 0)
1031 (let* ((process-environment (browse-url-process-environment)))
1032 ;; Netscape not running - start it
1033 (message "Starting %s..." browse-url-netscape-program)
1034 (apply 'start-process (concat "netscape" url) nil
1035 browse-url-netscape-program
1036 (append browse-url-netscape-startup-arguments (list url))))))
1037
1038 (defun browse-url-netscape-reload ()
1039 "Ask Netscape to reload its current document.
1040 How depends on `browse-url-netscape-version'."
1041 (interactive)
1042 ;; Backwards incompatibility reported by
1043 ;; <peter.kruse@psychologie.uni-regensburg.de>.
1044 (browse-url-netscape-send (if (>= browse-url-netscape-version 4)
1045 "xfeDoCommand(reload)"
1046 "reload")))
1047
1048 (defun browse-url-netscape-send (command)
1049 "Send a remote control command to Netscape."
1050 (let* ((process-environment (browse-url-process-environment)))
1051 (apply 'start-process "netscape" nil
1052 browse-url-netscape-program
1053 (append browse-url-netscape-arguments
1054 (list "-remote" command)))))
1055
1056 ;;;###autoload
1057 (defun browse-url-mozilla (url &optional new-window)
1058 "Ask the Mozilla WWW browser to load URL.
1059 Default to the URL around or before point. The strings in variable
1060 `browse-url-mozilla-arguments' are also passed to Mozilla.
1061
1062 When called interactively, if variable `browse-url-new-window-flag' is
1063 non-nil, load the document in a new Mozilla window, otherwise use a
1064 random existing one. A non-nil interactive prefix argument reverses
1065 the effect of `browse-url-new-window-flag'.
1066
1067 If `browse-url-mozilla-new-window-is-tab' is non-nil, then whenever a
1068 document would otherwise be loaded in a new window, it is loaded in a
1069 new tab in an existing window instead.
1070
1071 When called non-interactively, optional second argument NEW-WINDOW is
1072 used instead of `browse-url-new-window-flag'."
1073 (interactive (browse-url-interactive-arg "URL: "))
1074 (setq url (browse-url-encode-url url))
1075 (let* ((process-environment (browse-url-process-environment))
1076 (process
1077 (apply 'start-process
1078 (concat "mozilla " url) nil
1079 browse-url-mozilla-program
1080 (append
1081 browse-url-mozilla-arguments
1082 (list "-remote"
1083 (concat "openURL("
1084 url
1085 (if (browse-url-maybe-new-window
1086 new-window)
1087 (if browse-url-mozilla-new-window-is-tab
1088 ",new-tab"
1089 ",new-window"))
1090 ")"))))))
1091 (set-process-sentinel process
1092 `(lambda (process change)
1093 (browse-url-mozilla-sentinel process ,url)))))
1094
1095 (defun browse-url-mozilla-sentinel (process url)
1096 "Handle a change to the process communicating with Mozilla."
1097 (or (eq (process-exit-status process) 0)
1098 (let* ((process-environment (browse-url-process-environment)))
1099 ;; Mozilla is not running - start it
1100 (message "Starting %s..." browse-url-mozilla-program)
1101 (apply 'start-process (concat "mozilla " url) nil
1102 browse-url-mozilla-program
1103 (append browse-url-mozilla-startup-arguments (list url))))))
1104
1105 ;;;###autoload
1106 (defun browse-url-firefox (url &optional new-window)
1107 "Ask the Firefox WWW browser to load URL.
1108 Defaults to the URL around or before point. Passes the strings
1109 in the variable `browse-url-firefox-arguments' to Firefox.
1110
1111 Interactively, if the variable `browse-url-new-window-flag' is non-nil,
1112 loads the document in a new Firefox window. A non-nil prefix argument
1113 reverses the effect of `browse-url-new-window-flag'.
1114
1115 If `browse-url-firefox-new-window-is-tab' is non-nil, then
1116 whenever a document would otherwise be loaded in a new window, it
1117 is loaded in a new tab in an existing window instead.
1118
1119 Non-interactively, this uses the optional second argument NEW-WINDOW
1120 instead of `browse-url-new-window-flag'.
1121
1122 On MS Windows, this ignores `browse-url-new-window-flag' and
1123 `browse-url-firefox-new-window-is-tab', as well as the NEW-WINDOW argument.
1124 It always uses a new window."
1125 (interactive (browse-url-interactive-arg "URL: "))
1126 (setq url (browse-url-encode-url url))
1127 (let* ((process-environment (browse-url-process-environment)))
1128 (apply 'start-process
1129 (concat "firefox " url) nil
1130 browse-url-firefox-program
1131 (append
1132 browse-url-firefox-arguments
1133 ;; FIXME someone should check if this limitation
1134 ;; still applies.
1135 (unless (memq system-type '(windows-nt ms-dos))
1136 (if (browse-url-maybe-new-window new-window)
1137 (if browse-url-firefox-new-window-is-tab
1138 '("-new-tab")
1139 '("-new-window"))))
1140 (list url)))))
1141
1142 ;;;###autoload
1143 (defun browse-url-chromium (url &optional _new-window)
1144 "Ask the Chromium WWW browser to load URL.
1145 Default to the URL around or before point. The strings in
1146 variable `browse-url-chromium-arguments' are also passed to
1147 Chromium."
1148 (interactive (browse-url-interactive-arg "URL: "))
1149 (setq url (browse-url-encode-url url))
1150 (let* ((process-environment (browse-url-process-environment)))
1151 (apply 'start-process
1152 (concat "chromium " url) nil
1153 browse-url-chromium-program
1154 (append
1155 browse-url-chromium-arguments
1156 (list url)))))
1157
1158 ;;;###autoload
1159 (defun browse-url-galeon (url &optional new-window)
1160 "Ask the Galeon WWW browser to load URL.
1161 Default to the URL around or before point. The strings in variable
1162 `browse-url-galeon-arguments' are also passed to Galeon.
1163
1164 When called interactively, if variable `browse-url-new-window-flag' is
1165 non-nil, load the document in a new Galeon window, otherwise use a
1166 random existing one. A non-nil interactive prefix argument reverses
1167 the effect of `browse-url-new-window-flag'.
1168
1169 If `browse-url-galeon-new-window-is-tab' is non-nil, then whenever a
1170 document would otherwise be loaded in a new window, it is loaded in a
1171 new tab in an existing window instead.
1172
1173 When called non-interactively, optional second argument NEW-WINDOW is
1174 used instead of `browse-url-new-window-flag'."
1175 (interactive (browse-url-interactive-arg "URL: "))
1176 (setq url (browse-url-encode-url url))
1177 (let* ((process-environment (browse-url-process-environment))
1178 (process (apply 'start-process
1179 (concat "galeon " url)
1180 nil
1181 browse-url-galeon-program
1182 (append
1183 browse-url-galeon-arguments
1184 (if (browse-url-maybe-new-window new-window)
1185 (if browse-url-galeon-new-window-is-tab
1186 '("--new-tab")
1187 '("--new-window" "--noraise"))
1188 '("--existing"))
1189 (list url)))))
1190 (set-process-sentinel process
1191 `(lambda (process change)
1192 (browse-url-galeon-sentinel process ,url)))))
1193
1194 (defun browse-url-galeon-sentinel (process url)
1195 "Handle a change to the process communicating with Galeon."
1196 (or (eq (process-exit-status process) 0)
1197 (let* ((process-environment (browse-url-process-environment)))
1198 ;; Galeon is not running - start it
1199 (message "Starting %s..." browse-url-galeon-program)
1200 (apply 'start-process (concat "galeon " url) nil
1201 browse-url-galeon-program
1202 (append browse-url-galeon-startup-arguments (list url))))))
1203
1204 (defun browse-url-epiphany (url &optional new-window)
1205 "Ask the Epiphany WWW browser to load URL.
1206 Default to the URL around or before point. The strings in variable
1207 `browse-url-galeon-arguments' are also passed to Epiphany.
1208
1209 When called interactively, if variable `browse-url-new-window-flag' is
1210 non-nil, load the document in a new Epiphany window, otherwise use a
1211 random existing one. A non-nil interactive prefix argument reverses
1212 the effect of `browse-url-new-window-flag'.
1213
1214 If `browse-url-epiphany-new-window-is-tab' is non-nil, then whenever a
1215 document would otherwise be loaded in a new window, it is loaded in a
1216 new tab in an existing window instead.
1217
1218 When called non-interactively, optional second argument NEW-WINDOW is
1219 used instead of `browse-url-new-window-flag'."
1220 (interactive (browse-url-interactive-arg "URL: "))
1221 (setq url (browse-url-encode-url url))
1222 (let* ((process-environment (browse-url-process-environment))
1223 (process (apply 'start-process
1224 (concat "epiphany " url)
1225 nil
1226 browse-url-epiphany-program
1227 (append
1228 browse-url-epiphany-arguments
1229 (if (browse-url-maybe-new-window new-window)
1230 (if browse-url-epiphany-new-window-is-tab
1231 '("--new-tab")
1232 '("--new-window" "--noraise"))
1233 '("--existing"))
1234 (list url)))))
1235 (set-process-sentinel process
1236 `(lambda (process change)
1237 (browse-url-epiphany-sentinel process ,url)))))
1238
1239 (defun browse-url-epiphany-sentinel (process url)
1240 "Handle a change to the process communicating with Epiphany."
1241 (or (eq (process-exit-status process) 0)
1242 (let* ((process-environment (browse-url-process-environment)))
1243 ;; Epiphany is not running - start it
1244 (message "Starting %s..." browse-url-epiphany-program)
1245 (apply 'start-process (concat "epiphany " url) nil
1246 browse-url-epiphany-program
1247 (append browse-url-epiphany-startup-arguments (list url))))))
1248
1249 (defvar url-handler-regexp)
1250
1251 ;;;###autoload
1252 (defun browse-url-emacs (url &optional _new-window)
1253 "Ask Emacs to load URL into a buffer and show it in another window."
1254 (interactive (browse-url-interactive-arg "URL: "))
1255 (require 'url-handlers)
1256 (let ((file-name-handler-alist
1257 (cons (cons url-handler-regexp 'url-file-handler)
1258 file-name-handler-alist)))
1259 ;; Ignore `new-window': with all other browsers the URL is always shown
1260 ;; in another window than the current Emacs one since it's shown in
1261 ;; another application's window.
1262 ;; (if new-window (find-file-other-window url) (find-file url))
1263 (find-file-other-window url)))
1264
1265 ;;;###autoload
1266 (defun browse-url-gnome-moz (url &optional new-window)
1267 "Ask Mozilla/Netscape to load URL via the GNOME program `gnome-moz-remote'.
1268 Default to the URL around or before point. The strings in variable
1269 `browse-url-gnome-moz-arguments' are also passed.
1270
1271 When called interactively, if variable `browse-url-new-window-flag' is
1272 non-nil, load the document in a new browser window, otherwise use an
1273 existing one. A non-nil interactive prefix argument reverses the
1274 effect of `browse-url-new-window-flag'.
1275
1276 When called non-interactively, optional second argument NEW-WINDOW is
1277 used instead of `browse-url-new-window-flag'."
1278 (interactive (browse-url-interactive-arg "URL: "))
1279 (apply 'start-process (concat "gnome-moz-remote " url)
1280 nil
1281 browse-url-gnome-moz-program
1282 (append
1283 browse-url-gnome-moz-arguments
1284 (if (browse-url-maybe-new-window new-window)
1285 '("--newwin"))
1286 (list "--raise" url))))
1287
1288 ;; --- Mosaic ---
1289
1290 ;;;###autoload
1291 (defun browse-url-mosaic (url &optional new-window)
1292 "Ask the XMosaic WWW browser to load URL.
1293
1294 Default to the URL around or before point. The strings in variable
1295 `browse-url-mosaic-arguments' are also passed to Mosaic and the
1296 program is invoked according to the variable
1297 `browse-url-mosaic-program'.
1298
1299 When called interactively, if variable `browse-url-new-window-flag' is
1300 non-nil, load the document in a new Mosaic window, otherwise use a
1301 random existing one. A non-nil interactive prefix argument reverses
1302 the effect of `browse-url-new-window-flag'.
1303
1304 When called non-interactively, optional second argument NEW-WINDOW is
1305 used instead of `browse-url-new-window-flag'."
1306 (interactive (browse-url-interactive-arg "Mosaic URL: "))
1307 (let ((pidfile (expand-file-name browse-url-mosaic-pidfile))
1308 pid)
1309 (if (file-readable-p pidfile)
1310 (with-temp-buffer
1311 (insert-file-contents pidfile)
1312 (setq pid (read (current-buffer)))))
1313 (if (and (integerp pid) (zerop (signal-process pid 0))) ; Mosaic running
1314 (progn
1315 (with-temp-buffer
1316 (insert (if (browse-url-maybe-new-window new-window)
1317 "newwin\n"
1318 "goto\n")
1319 url "\n")
1320 (with-file-modes ?\700
1321 (if (file-exists-p
1322 (setq pidfile (format "/tmp/Mosaic.%d" pid)))
1323 (delete-file pidfile))
1324 ;; http://debbugs.gnu.org/17428. Use O_EXCL.
1325 (write-region nil nil pidfile nil 'silent nil 'excl)))
1326 ;; Send signal SIGUSR to Mosaic
1327 (message "Signaling Mosaic...")
1328 (signal-process pid 'SIGUSR1)
1329 ;; Or you could try:
1330 ;; (call-process "kill" nil 0 nil "-USR1" (int-to-string pid))
1331 (message "Signaling Mosaic...done"))
1332 ;; Mosaic not running - start it
1333 (message "Starting %s..." browse-url-mosaic-program)
1334 (apply 'start-process "xmosaic" nil browse-url-mosaic-program
1335 (append browse-url-mosaic-arguments (list url)))
1336 (message "Starting %s...done" browse-url-mosaic-program))))
1337
1338 ;; --- Mosaic using CCI ---
1339
1340 ;;;###autoload
1341 (defun browse-url-cci (url &optional new-window)
1342 "Ask the XMosaic WWW browser to load URL.
1343 Default to the URL around or before point.
1344
1345 This function only works for XMosaic version 2.5 or later. You must
1346 select `CCI' from XMosaic's File menu, set the CCI Port Address to the
1347 value of variable `browse-url-CCI-port', and enable `Accept requests'.
1348
1349 When called interactively, if variable `browse-url-new-window-flag' is
1350 non-nil, load the document in a new browser window, otherwise use a
1351 random existing one. A non-nil interactive prefix argument reverses
1352 the effect of `browse-url-new-window-flag'.
1353
1354 When called non-interactively, optional second argument NEW-WINDOW is
1355 used instead of `browse-url-new-window-flag'."
1356 (interactive (browse-url-interactive-arg "Mosaic URL: "))
1357 (open-network-stream "browse-url" " *browse-url*"
1358 browse-url-CCI-host browse-url-CCI-port)
1359 ;; Todo: start browser if fails
1360 (process-send-string "browse-url"
1361 (concat "get url (" url ") output "
1362 (if (browse-url-maybe-new-window new-window)
1363 "new"
1364 "current")
1365 "\r\n"))
1366 (process-send-string "browse-url" "disconnect\r\n")
1367 (delete-process "browse-url"))
1368
1369 ;; --- W3 ---
1370
1371 ;; External.
1372 (declare-function w3-fetch-other-window "ext:w3m" (&optional url))
1373 (declare-function w3-fetch "ext:w3m" (&optional url target))
1374
1375 ;;;###autoload
1376 (defun browse-url-w3 (url &optional new-window)
1377 "Ask the w3 WWW browser to load URL.
1378 Default to the URL around or before point.
1379
1380 When called interactively, if variable `browse-url-new-window-flag' is
1381 non-nil, load the document in a new window. A non-nil interactive
1382 prefix argument reverses the effect of `browse-url-new-window-flag'.
1383
1384 When called non-interactively, optional second argument NEW-WINDOW is
1385 used instead of `browse-url-new-window-flag'."
1386 (interactive (browse-url-interactive-arg "W3 URL: "))
1387 (require 'w3) ; w3-fetch-other-window not autoloaded
1388 (if (browse-url-maybe-new-window new-window)
1389 (w3-fetch-other-window url)
1390 (w3-fetch url)))
1391
1392 ;;;###autoload
1393 (defun browse-url-w3-gnudoit (url &optional _new-window)
1394 ;; new-window ignored
1395 "Ask another Emacs running gnuserv to load the URL using the W3 browser.
1396 The `browse-url-gnudoit-program' program is used with options given by
1397 `browse-url-gnudoit-args'. Default to the URL around or before point."
1398 (interactive (browse-url-interactive-arg "W3 URL: "))
1399 (apply 'start-process (concat "gnudoit:" url) nil
1400 browse-url-gnudoit-program
1401 (append browse-url-gnudoit-args
1402 (list (concat "(w3-fetch \"" url "\")")
1403 "(raise-frame)"))))
1404
1405 ;; --- Lynx in an xterm ---
1406
1407 ;;;###autoload
1408 (defun browse-url-text-xterm (url &optional _new-window)
1409 ;; new-window ignored
1410 "Ask a text browser to load URL.
1411 URL defaults to the URL around or before point.
1412 This runs the text browser specified by `browse-url-text-browser'.
1413 in an Xterm window using the Xterm program named by `browse-url-xterm-program'
1414 with possible additional arguments `browse-url-xterm-args'."
1415 (interactive (browse-url-interactive-arg "Text browser URL: "))
1416 (apply #'start-process `(,(concat browse-url-text-browser url)
1417 nil ,browse-url-xterm-program
1418 ,@browse-url-xterm-args "-e" ,browse-url-text-browser
1419 ,url)))
1420
1421 ;; --- Lynx in an Emacs "term" window ---
1422
1423 (declare-function term-char-mode "term" ())
1424 (declare-function term-send-down "term" ())
1425 (declare-function term-send-string "term" (proc str))
1426
1427 ;;;###autoload
1428 (defun browse-url-text-emacs (url &optional new-buffer)
1429 "Ask a text browser to load URL.
1430 URL defaults to the URL around or before point.
1431 This runs the text browser specified by `browse-url-text-browser'.
1432 With a prefix argument, it runs a new browser process in a new buffer.
1433
1434 When called interactively, if variable `browse-url-new-window-flag' is
1435 non-nil, load the document in a new browser process in a new term window,
1436 otherwise use any existing one. A non-nil interactive prefix argument
1437 reverses the effect of `browse-url-new-window-flag'.
1438
1439 When called non-interactively, optional second argument NEW-WINDOW is
1440 used instead of `browse-url-new-window-flag'."
1441 (interactive (browse-url-interactive-arg "Text browser URL: "))
1442 (let* ((system-uses-terminfo t) ; Lynx uses terminfo
1443 ;; (term-term-name "vt100") ; ??
1444 (buf (get-buffer "*text browser*"))
1445 (proc (and buf (get-buffer-process buf)))
1446 (n browse-url-text-input-attempts))
1447 (require 'term)
1448 (if (and (browse-url-maybe-new-window new-buffer) buf)
1449 ;; Rename away the OLD buffer. This isn't very polite, but
1450 ;; term insists on working in a buffer named *lynx* and would
1451 ;; choke on *lynx*<1>
1452 (progn (set-buffer buf)
1453 (rename-uniquely)))
1454 (if (or (browse-url-maybe-new-window new-buffer)
1455 (not buf)
1456 (not proc)
1457 (not (memq (process-status proc) '(run stop))))
1458 ;; start a new text browser
1459 (progn
1460 (setq buf
1461 (apply #'make-term
1462 `(,browse-url-text-browser
1463 ,browse-url-text-browser
1464 nil ,@browse-url-text-emacs-args
1465 ,url)))
1466 (switch-to-buffer buf)
1467 (term-char-mode)
1468 (set-process-sentinel
1469 (get-buffer-process buf)
1470 ;; Don't leave around a dead one (especially because of its
1471 ;; munged keymap.)
1472 (lambda (process _event)
1473 (if (not (memq (process-status process) '(run stop)))
1474 (let ((buf (process-buffer process)))
1475 (if buf (kill-buffer buf)))))))
1476 ;; Send the url to the text browser in the old buffer
1477 (let ((win (get-buffer-window buf t)))
1478 (if win
1479 (select-window win)
1480 (switch-to-buffer buf)))
1481 (if (eq (following-char) ?_)
1482 (cond ((eq browse-url-text-input-field 'warn)
1483 (error "Please move out of the input field first"))
1484 ((eq browse-url-text-input-field 'avoid)
1485 (while (and (eq (following-char) ?_) (> n 0))
1486 (term-send-down) ; down arrow
1487 (sit-for browse-url-text-input-delay))
1488 (if (eq (following-char) ?_)
1489 (error "Cannot move out of the input field, sorry")))))
1490 (term-send-string proc (concat "g" ; goto
1491 "\C-u" ; kill default url
1492 url
1493 "\r")))))
1494
1495 ;; --- mailto ---
1496
1497 (autoload 'rfc2368-parse-mailto-url "rfc2368")
1498
1499 ;;;###autoload
1500 (defun browse-url-mail (url &optional new-window)
1501 "Open a new mail message buffer within Emacs for the RFC 2368 URL.
1502 Default to using the mailto: URL around or before point as the
1503 recipient's address. Supplying a non-nil interactive prefix argument
1504 will cause the mail to be composed in another window rather than the
1505 current one.
1506
1507 When called interactively, if variable `browse-url-new-window-flag' is
1508 non-nil use `compose-mail-other-window', otherwise `compose-mail'. A
1509 non-nil interactive prefix argument reverses the effect of
1510 `browse-url-new-window-flag'.
1511
1512 When called non-interactively, optional second argument NEW-WINDOW is
1513 used instead of `browse-url-new-window-flag'."
1514 (interactive (browse-url-interactive-arg "Mailto URL: "))
1515 (save-excursion
1516 (let* ((alist (rfc2368-parse-mailto-url url))
1517 (to (assoc "To" alist))
1518 (subject (assoc "Subject" alist))
1519 (body (assoc "Body" alist))
1520 (rest (delq to (delq subject (delq body alist))))
1521 (to (cdr to))
1522 (subject (cdr subject))
1523 (body (cdr body))
1524 (mail-citation-hook (unless body mail-citation-hook)))
1525 (if (browse-url-maybe-new-window new-window)
1526 (compose-mail-other-window to subject rest nil
1527 (list 'insert-buffer (current-buffer)))
1528 (compose-mail to subject rest nil nil
1529 (list 'insert-buffer (current-buffer))))
1530 (when body
1531 (goto-char (point-min))
1532 (unless (or (search-forward (concat "\n" mail-header-separator "\n")
1533 nil 'move)
1534 (bolp))
1535 (insert "\n"))
1536 (goto-char (prog1
1537 (point)
1538 (insert (replace-regexp-in-string "\r\n" "\n" body))
1539 (unless (bolp)
1540 (insert "\n"))))))))
1541
1542 ;; --- Random browser ---
1543
1544 ;;;###autoload
1545 (defun browse-url-generic (url &optional _new-window)
1546 ;; new-window ignored
1547 "Ask the WWW browser defined by `browse-url-generic-program' to load URL.
1548 Default to the URL around or before point. A fresh copy of the
1549 browser is started up in a new process with possible additional arguments
1550 `browse-url-generic-args'. This is appropriate for browsers which
1551 don't offer a form of remote control."
1552 (interactive (browse-url-interactive-arg "URL: "))
1553 (if (not browse-url-generic-program)
1554 (error "No browser defined (`browse-url-generic-program')"))
1555 (apply 'call-process browse-url-generic-program nil
1556 0 nil
1557 (append browse-url-generic-args (list url))))
1558
1559 ;;;###autoload
1560 (defun browse-url-kde (url &optional _new-window)
1561 "Ask the KDE WWW browser to load URL.
1562 Default to the URL around or before point."
1563 (interactive (browse-url-interactive-arg "KDE URL: "))
1564 (message "Sending URL to KDE...")
1565 (apply #'start-process (concat "KDE " url) nil browse-url-kde-program
1566 (append browse-url-kde-args (list url))))
1567
1568 (defun browse-url-elinks-new-window (url)
1569 "Ask the Elinks WWW browser to load URL in a new window."
1570 (let ((process-environment (browse-url-process-environment)))
1571 (apply #'start-process
1572 (append (list (concat "elinks:" url)
1573 nil)
1574 browse-url-elinks-wrapper
1575 (list "elinks" url)))))
1576
1577 ;;;###autoload
1578 (defun browse-url-elinks (url &optional new-window)
1579 "Ask the Elinks WWW browser to load URL.
1580 Default to the URL around the point.
1581
1582 The document is loaded in a new tab of a running Elinks or, if
1583 none yet running, a newly started instance.
1584
1585 The Elinks command will be prepended by the program+arguments
1586 from `browse-url-elinks-wrapper'."
1587 (interactive (browse-url-interactive-arg "URL: "))
1588 (setq url (browse-url-encode-url url))
1589 (if new-window
1590 (browse-url-elinks-new-window url)
1591 (let ((process-environment (browse-url-process-environment))
1592 (elinks-ping-process (start-process "elinks-ping" nil
1593 "elinks" "-remote" "ping()")))
1594 (set-process-sentinel elinks-ping-process
1595 `(lambda (process change)
1596 (browse-url-elinks-sentinel process ,url))))))
1597
1598 (defun browse-url-elinks-sentinel (process url)
1599 "Determines if Elinks is running or a new one has to be started."
1600 ;; Try to determine if an instance is running or if we have to
1601 ;; create a new one.
1602 (pcase (process-exit-status process)
1603 (5
1604 ;; No instance, start a new one.
1605 (browse-url-elinks-new-window url))
1606 (0
1607 ;; Found an instance, open URL in new tab.
1608 (let ((process-environment (browse-url-process-environment)))
1609 (start-process (concat "elinks:" url) nil
1610 "elinks" "-remote"
1611 (concat "openURL(\"" url "\",new-tab)"))))
1612 (exit-status
1613 (error "Unrecognized exit-code %d of process `elinks'"
1614 exit-status))))
1615
1616 (provide 'browse-url)
1617
1618 ;;; browse-url.el ends here