1 | #! /usr/bin/env python
|
---|
2 | """Interfaces for launching and remotely controlling Web browsers."""
|
---|
3 |
|
---|
4 | import os
|
---|
5 | import sys
|
---|
6 | import stat
|
---|
7 | import subprocess
|
---|
8 | import time
|
---|
9 |
|
---|
10 | __all__ = ["Error", "open", "open_new", "open_new_tab", "get", "register"]
|
---|
11 |
|
---|
12 | class Error(Exception):
|
---|
13 | pass
|
---|
14 |
|
---|
15 | _browsers = {} # Dictionary of available browser controllers
|
---|
16 | _tryorder = [] # Preference order of available browsers
|
---|
17 |
|
---|
18 | def register(name, klass, instance=None, update_tryorder=1):
|
---|
19 | """Register a browser connector and, optionally, connection."""
|
---|
20 | _browsers[name.lower()] = [klass, instance]
|
---|
21 | if update_tryorder > 0:
|
---|
22 | _tryorder.append(name)
|
---|
23 | elif update_tryorder < 0:
|
---|
24 | _tryorder.insert(0, name)
|
---|
25 |
|
---|
26 | def get(using=None):
|
---|
27 | """Return a browser launcher instance appropriate for the environment."""
|
---|
28 | if using is not None:
|
---|
29 | alternatives = [using]
|
---|
30 | else:
|
---|
31 | alternatives = _tryorder
|
---|
32 | for browser in alternatives:
|
---|
33 | if '%s' in browser:
|
---|
34 | # User gave us a command line, split it into name and args
|
---|
35 | return GenericBrowser(browser.split())
|
---|
36 | else:
|
---|
37 | # User gave us a browser name or path.
|
---|
38 | try:
|
---|
39 | command = _browsers[browser.lower()]
|
---|
40 | except KeyError:
|
---|
41 | command = _synthesize(browser)
|
---|
42 | if command[1] is not None:
|
---|
43 | return command[1]
|
---|
44 | elif command[0] is not None:
|
---|
45 | return command[0]()
|
---|
46 | raise Error("could not locate runnable browser")
|
---|
47 |
|
---|
48 | # Please note: the following definition hides a builtin function.
|
---|
49 | # It is recommended one does "import webbrowser" and uses webbrowser.open(url)
|
---|
50 | # instead of "from webbrowser import *".
|
---|
51 |
|
---|
52 | def open(url, new=0, autoraise=1):
|
---|
53 | for name in _tryorder:
|
---|
54 | browser = get(name)
|
---|
55 | if browser.open(url, new, autoraise):
|
---|
56 | return True
|
---|
57 | return False
|
---|
58 |
|
---|
59 | def open_new(url):
|
---|
60 | return open(url, 1)
|
---|
61 |
|
---|
62 | def open_new_tab(url):
|
---|
63 | return open(url, 2)
|
---|
64 |
|
---|
65 |
|
---|
66 | def _synthesize(browser, update_tryorder=1):
|
---|
67 | """Attempt to synthesize a controller base on existing controllers.
|
---|
68 |
|
---|
69 | This is useful to create a controller when a user specifies a path to
|
---|
70 | an entry in the BROWSER environment variable -- we can copy a general
|
---|
71 | controller to operate using a specific installation of the desired
|
---|
72 | browser in this way.
|
---|
73 |
|
---|
74 | If we can't create a controller in this way, or if there is no
|
---|
75 | executable for the requested browser, return [None, None].
|
---|
76 |
|
---|
77 | """
|
---|
78 | cmd = browser.split()[0]
|
---|
79 | if not _iscommand(cmd):
|
---|
80 | return [None, None]
|
---|
81 | name = os.path.basename(cmd)
|
---|
82 | try:
|
---|
83 | command = _browsers[name.lower()]
|
---|
84 | except KeyError:
|
---|
85 | return [None, None]
|
---|
86 | # now attempt to clone to fit the new name:
|
---|
87 | controller = command[1]
|
---|
88 | if controller and name.lower() == controller.basename:
|
---|
89 | import copy
|
---|
90 | controller = copy.copy(controller)
|
---|
91 | controller.name = browser
|
---|
92 | controller.basename = os.path.basename(browser)
|
---|
93 | register(browser, None, controller, update_tryorder)
|
---|
94 | return [None, controller]
|
---|
95 | return [None, None]
|
---|
96 |
|
---|
97 |
|
---|
98 | if sys.platform[:3] == "win":
|
---|
99 | def _isexecutable(cmd):
|
---|
100 | cmd = cmd.lower()
|
---|
101 | if os.path.isfile(cmd) and cmd.endswith((".exe", ".bat")):
|
---|
102 | return True
|
---|
103 | for ext in ".exe", ".bat":
|
---|
104 | if os.path.isfile(cmd + ext):
|
---|
105 | return True
|
---|
106 | return False
|
---|
107 | else:
|
---|
108 | def _isexecutable(cmd):
|
---|
109 | if os.path.isfile(cmd):
|
---|
110 | mode = os.stat(cmd)[stat.ST_MODE]
|
---|
111 | if mode & stat.S_IXUSR or mode & stat.S_IXGRP or mode & stat.S_IXOTH:
|
---|
112 | return True
|
---|
113 | return False
|
---|
114 |
|
---|
115 | def _iscommand(cmd):
|
---|
116 | """Return True if cmd is executable or can be found on the executable
|
---|
117 | search path."""
|
---|
118 | if _isexecutable(cmd):
|
---|
119 | return True
|
---|
120 | path = os.environ.get("PATH")
|
---|
121 | if not path:
|
---|
122 | return False
|
---|
123 | for d in path.split(os.pathsep):
|
---|
124 | exe = os.path.join(d, cmd)
|
---|
125 | if _isexecutable(exe):
|
---|
126 | return True
|
---|
127 | return False
|
---|
128 |
|
---|
129 |
|
---|
130 | # General parent classes
|
---|
131 |
|
---|
132 | class BaseBrowser(object):
|
---|
133 | """Parent class for all browsers. Do not use directly."""
|
---|
134 |
|
---|
135 | args = ['%s']
|
---|
136 |
|
---|
137 | def __init__(self, name=""):
|
---|
138 | self.name = name
|
---|
139 | self.basename = name
|
---|
140 |
|
---|
141 | def open(self, url, new=0, autoraise=1):
|
---|
142 | raise NotImplementedError
|
---|
143 |
|
---|
144 | def open_new(self, url):
|
---|
145 | return self.open(url, 1)
|
---|
146 |
|
---|
147 | def open_new_tab(self, url):
|
---|
148 | return self.open(url, 2)
|
---|
149 |
|
---|
150 |
|
---|
151 | class GenericBrowser(BaseBrowser):
|
---|
152 | """Class for all browsers started with a command
|
---|
153 | and without remote functionality."""
|
---|
154 |
|
---|
155 | def __init__(self, name):
|
---|
156 | if isinstance(name, basestring):
|
---|
157 | self.name = name
|
---|
158 | else:
|
---|
159 | # name should be a list with arguments
|
---|
160 | self.name = name[0]
|
---|
161 | self.args = name[1:]
|
---|
162 | self.basename = os.path.basename(self.name)
|
---|
163 |
|
---|
164 | def open(self, url, new=0, autoraise=1):
|
---|
165 | cmdline = [self.name] + [arg.replace("%s", url)
|
---|
166 | for arg in self.args]
|
---|
167 | try:
|
---|
168 | p = subprocess.Popen(cmdline, close_fds=True)
|
---|
169 | return not p.wait()
|
---|
170 | except OSError:
|
---|
171 | return False
|
---|
172 |
|
---|
173 |
|
---|
174 | class BackgroundBrowser(GenericBrowser):
|
---|
175 | """Class for all browsers which are to be started in the
|
---|
176 | background."""
|
---|
177 |
|
---|
178 | def open(self, url, new=0, autoraise=1):
|
---|
179 | cmdline = [self.name] + [arg.replace("%s", url)
|
---|
180 | for arg in self.args]
|
---|
181 | setsid = getattr(os, 'setsid', None)
|
---|
182 | if not setsid:
|
---|
183 | setsid = getattr(os, 'setpgrp', None)
|
---|
184 | try:
|
---|
185 | p = subprocess.Popen(cmdline, close_fds=True, preexec_fn=setsid)
|
---|
186 | return (p.poll() is None)
|
---|
187 | except OSError:
|
---|
188 | return False
|
---|
189 |
|
---|
190 |
|
---|
191 | class UnixBrowser(BaseBrowser):
|
---|
192 | """Parent class for all Unix browsers with remote functionality."""
|
---|
193 |
|
---|
194 | raise_opts = None
|
---|
195 | remote_args = ['%action', '%s']
|
---|
196 | remote_action = None
|
---|
197 | remote_action_newwin = None
|
---|
198 | remote_action_newtab = None
|
---|
199 | background = False
|
---|
200 | redirect_stdout = True
|
---|
201 |
|
---|
202 | def _invoke(self, args, remote, autoraise):
|
---|
203 | raise_opt = []
|
---|
204 | if remote and self.raise_opts:
|
---|
205 | # use autoraise argument only for remote invocation
|
---|
206 | autoraise = int(bool(autoraise))
|
---|
207 | opt = self.raise_opts[autoraise]
|
---|
208 | if opt: raise_opt = [opt]
|
---|
209 |
|
---|
210 | cmdline = [self.name] + raise_opt + args
|
---|
211 |
|
---|
212 | if remote or self.background:
|
---|
213 | inout = file(os.devnull, "r+")
|
---|
214 | else:
|
---|
215 | # for TTY browsers, we need stdin/out
|
---|
216 | inout = None
|
---|
217 | # if possible, put browser in separate process group, so
|
---|
218 | # keyboard interrupts don't affect browser as well as Python
|
---|
219 | setsid = getattr(os, 'setsid', None)
|
---|
220 | if not setsid:
|
---|
221 | setsid = getattr(os, 'setpgrp', None)
|
---|
222 |
|
---|
223 | p = subprocess.Popen(cmdline, close_fds=True, stdin=inout,
|
---|
224 | stdout=(self.redirect_stdout and inout or None),
|
---|
225 | stderr=inout, preexec_fn=setsid)
|
---|
226 | if remote:
|
---|
227 | # wait five secons. If the subprocess is not finished, the
|
---|
228 | # remote invocation has (hopefully) started a new instance.
|
---|
229 | time.sleep(1)
|
---|
230 | rc = p.poll()
|
---|
231 | if rc is None:
|
---|
232 | time.sleep(4)
|
---|
233 | rc = p.poll()
|
---|
234 | if rc is None:
|
---|
235 | return True
|
---|
236 | # if remote call failed, open() will try direct invocation
|
---|
237 | return not rc
|
---|
238 | elif self.background:
|
---|
239 | if p.poll() is None:
|
---|
240 | return True
|
---|
241 | else:
|
---|
242 | return False
|
---|
243 | else:
|
---|
244 | return not p.wait()
|
---|
245 |
|
---|
246 | def open(self, url, new=0, autoraise=1):
|
---|
247 | if new == 0:
|
---|
248 | action = self.remote_action
|
---|
249 | elif new == 1:
|
---|
250 | action = self.remote_action_newwin
|
---|
251 | elif new == 2:
|
---|
252 | if self.remote_action_newtab is None:
|
---|
253 | action = self.remote_action_newwin
|
---|
254 | else:
|
---|
255 | action = self.remote_action_newtab
|
---|
256 | else:
|
---|
257 | raise Error("Bad 'new' parameter to open(); " +
|
---|
258 | "expected 0, 1, or 2, got %s" % new)
|
---|
259 |
|
---|
260 | args = [arg.replace("%s", url).replace("%action", action)
|
---|
261 | for arg in self.remote_args]
|
---|
262 | success = self._invoke(args, True, autoraise)
|
---|
263 | if not success:
|
---|
264 | # remote invocation failed, try straight way
|
---|
265 | args = [arg.replace("%s", url) for arg in self.args]
|
---|
266 | return self._invoke(args, False, False)
|
---|
267 | else:
|
---|
268 | return True
|
---|
269 |
|
---|
270 |
|
---|
271 | class Mozilla(UnixBrowser):
|
---|
272 | """Launcher class for Mozilla/Netscape browsers."""
|
---|
273 |
|
---|
274 | raise_opts = ["-noraise", "-raise"]
|
---|
275 |
|
---|
276 | remote_args = ['-remote', 'openURL(%s%action)']
|
---|
277 | remote_action = ""
|
---|
278 | remote_action_newwin = ",new-window"
|
---|
279 | remote_action_newtab = ",new-tab"
|
---|
280 |
|
---|
281 | background = True
|
---|
282 |
|
---|
283 | Netscape = Mozilla
|
---|
284 |
|
---|
285 |
|
---|
286 | class Galeon(UnixBrowser):
|
---|
287 | """Launcher class for Galeon/Epiphany browsers."""
|
---|
288 |
|
---|
289 | raise_opts = ["-noraise", ""]
|
---|
290 | remote_args = ['%action', '%s']
|
---|
291 | remote_action = "-n"
|
---|
292 | remote_action_newwin = "-w"
|
---|
293 |
|
---|
294 | background = True
|
---|
295 |
|
---|
296 |
|
---|
297 | class Opera(UnixBrowser):
|
---|
298 | "Launcher class for Opera browser."
|
---|
299 |
|
---|
300 | raise_opts = ["", "-raise"]
|
---|
301 |
|
---|
302 | remote_args = ['-remote', 'openURL(%s%action)']
|
---|
303 | remote_action = ""
|
---|
304 | remote_action_newwin = ",new-window"
|
---|
305 | remote_action_newtab = ",new-page"
|
---|
306 | background = True
|
---|
307 |
|
---|
308 |
|
---|
309 | class Elinks(UnixBrowser):
|
---|
310 | "Launcher class for Elinks browsers."
|
---|
311 |
|
---|
312 | remote_args = ['-remote', 'openURL(%s%action)']
|
---|
313 | remote_action = ""
|
---|
314 | remote_action_newwin = ",new-window"
|
---|
315 | remote_action_newtab = ",new-tab"
|
---|
316 | background = False
|
---|
317 |
|
---|
318 | # elinks doesn't like its stdout to be redirected -
|
---|
319 | # it uses redirected stdout as a signal to do -dump
|
---|
320 | redirect_stdout = False
|
---|
321 |
|
---|
322 |
|
---|
323 | class Konqueror(BaseBrowser):
|
---|
324 | """Controller for the KDE File Manager (kfm, or Konqueror).
|
---|
325 |
|
---|
326 | See the output of ``kfmclient --commands``
|
---|
327 | for more information on the Konqueror remote-control interface.
|
---|
328 | """
|
---|
329 |
|
---|
330 | def open(self, url, new=0, autoraise=1):
|
---|
331 | # XXX Currently I know no way to prevent KFM from opening a new win.
|
---|
332 | if new == 2:
|
---|
333 | action = "newTab"
|
---|
334 | else:
|
---|
335 | action = "openURL"
|
---|
336 |
|
---|
337 | devnull = file(os.devnull, "r+")
|
---|
338 | # if possible, put browser in separate process group, so
|
---|
339 | # keyboard interrupts don't affect browser as well as Python
|
---|
340 | setsid = getattr(os, 'setsid', None)
|
---|
341 | if not setsid:
|
---|
342 | setsid = getattr(os, 'setpgrp', None)
|
---|
343 |
|
---|
344 | try:
|
---|
345 | p = subprocess.Popen(["kfmclient", action, url],
|
---|
346 | close_fds=True, stdin=devnull,
|
---|
347 | stdout=devnull, stderr=devnull)
|
---|
348 | except OSError:
|
---|
349 | # fall through to next variant
|
---|
350 | pass
|
---|
351 | else:
|
---|
352 | p.wait()
|
---|
353 | # kfmclient's return code unfortunately has no meaning as it seems
|
---|
354 | return True
|
---|
355 |
|
---|
356 | try:
|
---|
357 | p = subprocess.Popen(["konqueror", "--silent", url],
|
---|
358 | close_fds=True, stdin=devnull,
|
---|
359 | stdout=devnull, stderr=devnull,
|
---|
360 | preexec_fn=setsid)
|
---|
361 | except OSError:
|
---|
362 | # fall through to next variant
|
---|
363 | pass
|
---|
364 | else:
|
---|
365 | if p.poll() is None:
|
---|
366 | # Should be running now.
|
---|
367 | return True
|
---|
368 |
|
---|
369 | try:
|
---|
370 | p = subprocess.Popen(["kfm", "-d", url],
|
---|
371 | close_fds=True, stdin=devnull,
|
---|
372 | stdout=devnull, stderr=devnull,
|
---|
373 | preexec_fn=setsid)
|
---|
374 | except OSError:
|
---|
375 | return False
|
---|
376 | else:
|
---|
377 | return (p.poll() is None)
|
---|
378 |
|
---|
379 |
|
---|
380 | class Grail(BaseBrowser):
|
---|
381 | # There should be a way to maintain a connection to Grail, but the
|
---|
382 | # Grail remote control protocol doesn't really allow that at this
|
---|
383 | # point. It probably never will!
|
---|
384 | def _find_grail_rc(self):
|
---|
385 | import glob
|
---|
386 | import pwd
|
---|
387 | import socket
|
---|
388 | import tempfile
|
---|
389 | tempdir = os.path.join(tempfile.gettempdir(),
|
---|
390 | ".grail-unix")
|
---|
391 | user = pwd.getpwuid(os.getuid())[0]
|
---|
392 | filename = os.path.join(tempdir, user + "-*")
|
---|
393 | maybes = glob.glob(filename)
|
---|
394 | if not maybes:
|
---|
395 | return None
|
---|
396 | s = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
|
---|
397 | for fn in maybes:
|
---|
398 | # need to PING each one until we find one that's live
|
---|
399 | try:
|
---|
400 | s.connect(fn)
|
---|
401 | except socket.error:
|
---|
402 | # no good; attempt to clean it out, but don't fail:
|
---|
403 | try:
|
---|
404 | os.unlink(fn)
|
---|
405 | except IOError:
|
---|
406 | pass
|
---|
407 | else:
|
---|
408 | return s
|
---|
409 |
|
---|
410 | def _remote(self, action):
|
---|
411 | s = self._find_grail_rc()
|
---|
412 | if not s:
|
---|
413 | return 0
|
---|
414 | s.send(action)
|
---|
415 | s.close()
|
---|
416 | return 1
|
---|
417 |
|
---|
418 | def open(self, url, new=0, autoraise=1):
|
---|
419 | if new:
|
---|
420 | ok = self._remote("LOADNEW " + url)
|
---|
421 | else:
|
---|
422 | ok = self._remote("LOAD " + url)
|
---|
423 | return ok
|
---|
424 |
|
---|
425 |
|
---|
426 | #
|
---|
427 | # Platform support for Unix
|
---|
428 | #
|
---|
429 |
|
---|
430 | # These are the right tests because all these Unix browsers require either
|
---|
431 | # a console terminal or an X display to run.
|
---|
432 |
|
---|
433 | def register_X_browsers():
|
---|
434 | # The default Gnome browser
|
---|
435 | if _iscommand("gconftool-2"):
|
---|
436 | # get the web browser string from gconftool
|
---|
437 | gc = 'gconftool-2 -g /desktop/gnome/url-handlers/http/command 2>/dev/null'
|
---|
438 | out = os.popen(gc)
|
---|
439 | commd = out.read().strip()
|
---|
440 | retncode = out.close()
|
---|
441 |
|
---|
442 | # if successful, register it
|
---|
443 | if retncode is None and commd:
|
---|
444 | register("gnome", None, BackgroundBrowser(commd))
|
---|
445 |
|
---|
446 | # First, the Mozilla/Netscape browsers
|
---|
447 | for browser in ("mozilla-firefox", "firefox",
|
---|
448 | "mozilla-firebird", "firebird",
|
---|
449 | "seamonkey", "mozilla", "netscape"):
|
---|
450 | if _iscommand(browser):
|
---|
451 | register(browser, None, Mozilla(browser))
|
---|
452 |
|
---|
453 | # Konqueror/kfm, the KDE browser.
|
---|
454 | if _iscommand("kfm"):
|
---|
455 | register("kfm", Konqueror, Konqueror("kfm"))
|
---|
456 | elif _iscommand("konqueror"):
|
---|
457 | register("konqueror", Konqueror, Konqueror("konqueror"))
|
---|
458 |
|
---|
459 | # Gnome's Galeon and Epiphany
|
---|
460 | for browser in ("galeon", "epiphany"):
|
---|
461 | if _iscommand(browser):
|
---|
462 | register(browser, None, Galeon(browser))
|
---|
463 |
|
---|
464 | # Skipstone, another Gtk/Mozilla based browser
|
---|
465 | if _iscommand("skipstone"):
|
---|
466 | register("skipstone", None, BackgroundBrowser("skipstone"))
|
---|
467 |
|
---|
468 | # Opera, quite popular
|
---|
469 | if _iscommand("opera"):
|
---|
470 | register("opera", None, Opera("opera"))
|
---|
471 |
|
---|
472 | # Next, Mosaic -- old but still in use.
|
---|
473 | if _iscommand("mosaic"):
|
---|
474 | register("mosaic", None, BackgroundBrowser("mosaic"))
|
---|
475 |
|
---|
476 | # Grail, the Python browser. Does anybody still use it?
|
---|
477 | if _iscommand("grail"):
|
---|
478 | register("grail", Grail, None)
|
---|
479 |
|
---|
480 | # Prefer X browsers if present
|
---|
481 | if os.environ.get("DISPLAY"):
|
---|
482 | register_X_browsers()
|
---|
483 |
|
---|
484 | # Also try console browsers
|
---|
485 | if os.environ.get("TERM"):
|
---|
486 | # The Links/elinks browsers <http://artax.karlin.mff.cuni.cz/~mikulas/links/>
|
---|
487 | if _iscommand("links"):
|
---|
488 | register("links", None, GenericBrowser("links"))
|
---|
489 | if _iscommand("elinks"):
|
---|
490 | register("elinks", None, Elinks("elinks"))
|
---|
491 | # The Lynx browser <http://lynx.isc.org/>, <http://lynx.browser.org/>
|
---|
492 | if _iscommand("lynx"):
|
---|
493 | register("lynx", None, GenericBrowser("lynx"))
|
---|
494 | # The w3m browser <http://w3m.sourceforge.net/>
|
---|
495 | if _iscommand("w3m"):
|
---|
496 | register("w3m", None, GenericBrowser("w3m"))
|
---|
497 |
|
---|
498 | #
|
---|
499 | # Platform support for Windows
|
---|
500 | #
|
---|
501 |
|
---|
502 | if sys.platform[:3] == "win":
|
---|
503 | class WindowsDefault(BaseBrowser):
|
---|
504 | def open(self, url, new=0, autoraise=1):
|
---|
505 | os.startfile(url)
|
---|
506 | return True # Oh, my...
|
---|
507 |
|
---|
508 | _tryorder = []
|
---|
509 | _browsers = {}
|
---|
510 | # Prefer mozilla/netscape/opera if present
|
---|
511 | for browser in ("firefox", "firebird", "seamonkey", "mozilla",
|
---|
512 | "netscape", "opera"):
|
---|
513 | if _iscommand(browser):
|
---|
514 | register(browser, None, BackgroundBrowser(browser))
|
---|
515 | register("windows-default", WindowsDefault)
|
---|
516 |
|
---|
517 | #
|
---|
518 | # Platform support for MacOS
|
---|
519 | #
|
---|
520 |
|
---|
521 | try:
|
---|
522 | import ic
|
---|
523 | except ImportError:
|
---|
524 | pass
|
---|
525 | else:
|
---|
526 | class InternetConfig(BaseBrowser):
|
---|
527 | def open(self, url, new=0, autoraise=1):
|
---|
528 | ic.launchurl(url)
|
---|
529 | return True # Any way to get status?
|
---|
530 |
|
---|
531 | register("internet-config", InternetConfig, update_tryorder=-1)
|
---|
532 |
|
---|
533 | if sys.platform == 'darwin':
|
---|
534 | # Adapted from patch submitted to SourceForge by Steven J. Burr
|
---|
535 | class MacOSX(BaseBrowser):
|
---|
536 | """Launcher class for Aqua browsers on Mac OS X
|
---|
537 |
|
---|
538 | Optionally specify a browser name on instantiation. Note that this
|
---|
539 | will not work for Aqua browsers if the user has moved the application
|
---|
540 | package after installation.
|
---|
541 |
|
---|
542 | If no browser is specified, the default browser, as specified in the
|
---|
543 | Internet System Preferences panel, will be used.
|
---|
544 | """
|
---|
545 | def __init__(self, name):
|
---|
546 | self.name = name
|
---|
547 |
|
---|
548 | def open(self, url, new=0, autoraise=1):
|
---|
549 | assert "'" not in url
|
---|
550 | # hack for local urls
|
---|
551 | if not ':' in url:
|
---|
552 | url = 'file:'+url
|
---|
553 |
|
---|
554 | # new must be 0 or 1
|
---|
555 | new = int(bool(new))
|
---|
556 | if self.name == "default":
|
---|
557 | # User called open, open_new or get without a browser parameter
|
---|
558 | script = 'open location "%s"' % url.replace('"', '%22') # opens in default browser
|
---|
559 | else:
|
---|
560 | # User called get and chose a browser
|
---|
561 | if self.name == "OmniWeb":
|
---|
562 | toWindow = ""
|
---|
563 | else:
|
---|
564 | # Include toWindow parameter of OpenURL command for browsers
|
---|
565 | # that support it. 0 == new window; -1 == existing
|
---|
566 | toWindow = "toWindow %d" % (new - 1)
|
---|
567 | cmd = 'OpenURL "%s"' % url.replace('"', '%22')
|
---|
568 | script = '''tell application "%s"
|
---|
569 | activate
|
---|
570 | %s %s
|
---|
571 | end tell''' % (self.name, cmd, toWindow)
|
---|
572 | # Open pipe to AppleScript through osascript command
|
---|
573 | osapipe = os.popen("osascript", "w")
|
---|
574 | if osapipe is None:
|
---|
575 | return False
|
---|
576 | # Write script to osascript's stdin
|
---|
577 | osapipe.write(script)
|
---|
578 | rc = osapipe.close()
|
---|
579 | return not rc
|
---|
580 |
|
---|
581 | # Don't clear _tryorder or _browsers since OS X can use above Unix support
|
---|
582 | # (but we prefer using the OS X specific stuff)
|
---|
583 | register("MacOSX", None, MacOSX('default'), -1)
|
---|
584 |
|
---|
585 |
|
---|
586 | #
|
---|
587 | # Platform support for OS/2
|
---|
588 | #
|
---|
589 |
|
---|
590 | if sys.platform[:3] == "os2" and _iscommand("netscape"):
|
---|
591 | _tryorder = []
|
---|
592 | _browsers = {}
|
---|
593 | register("os2netscape", None,
|
---|
594 | GenericBrowser(["start", "netscape", "%s"]), -1)
|
---|
595 |
|
---|
596 |
|
---|
597 | # OK, now that we know what the default preference orders for each
|
---|
598 | # platform are, allow user to override them with the BROWSER variable.
|
---|
599 | if "BROWSER" in os.environ:
|
---|
600 | _userchoices = os.environ["BROWSER"].split(os.pathsep)
|
---|
601 | _userchoices.reverse()
|
---|
602 |
|
---|
603 | # Treat choices in same way as if passed into get() but do register
|
---|
604 | # and prepend to _tryorder
|
---|
605 | for cmdline in _userchoices:
|
---|
606 | if cmdline != '':
|
---|
607 | _synthesize(cmdline, -1)
|
---|
608 | cmdline = None # to make del work if _userchoices was empty
|
---|
609 | del cmdline
|
---|
610 | del _userchoices
|
---|
611 |
|
---|
612 | # what to do if _tryorder is now empty?
|
---|
613 |
|
---|
614 |
|
---|
615 | def main():
|
---|
616 | import getopt
|
---|
617 | usage = """Usage: %s [-n | -t] url
|
---|
618 | -n: open new window
|
---|
619 | -t: open new tab""" % sys.argv[0]
|
---|
620 | try:
|
---|
621 | opts, args = getopt.getopt(sys.argv[1:], 'ntd')
|
---|
622 | except getopt.error, msg:
|
---|
623 | print >>sys.stderr, msg
|
---|
624 | print >>sys.stderr, usage
|
---|
625 | sys.exit(1)
|
---|
626 | new_win = 0
|
---|
627 | for o, a in opts:
|
---|
628 | if o == '-n': new_win = 1
|
---|
629 | elif o == '-t': new_win = 2
|
---|
630 | if len(args) <> 1:
|
---|
631 | print >>sys.stderr, usage
|
---|
632 | sys.exit(1)
|
---|
633 |
|
---|
634 | url = args[0]
|
---|
635 | open(url, new_win)
|
---|
636 |
|
---|
637 | print "\a"
|
---|
638 |
|
---|
639 | if __name__ == "__main__":
|
---|
640 | main()
|
---|