"""Interfaces for launching and remotely controlling Web browsers."""
__all__
= ["Error", "open", "get", "register"]
_browsers
= {} # Dictionary of available browser controllers
_tryorder
= [] # Preference order of available browsers
def register(name
, klass
, instance
=None):
"""Register a browser connector and, optionally, connection."""
_browsers
[name
.lower()] = [klass
, instance
]
"""Return a browser launcher instance appropriate for the environment."""
for browser
in alternatives
:
# User gave us a command line, don't mess with it.
return GenericBrowser(browser
)
# User gave us a browser name.
command
= _browsers
[browser
.lower()]
command
= _synthesize(browser
)
raise Error("could not locate runnable browser")
# Please note: the following definition hides a builtin function.
def open(url
, new
=0, autoraise
=1):
get().open(url
, new
, autoraise
)
def _synthesize(browser
):
"""Attempt to synthesize a controller base on existing controllers.
This is useful to create a controller when a user specifies a path to
an entry in the BROWSER environment variable -- we can copy a general
controller to operate using a specific installation of the desired
If we can't create a controller in this way, or if there is no
executable for the requested browser, return [None, None].
if not os
.path
.exists(browser
):
name
= os
.path
.basename(browser
)
command
= _browsers
[name
.lower()]
# now attempt to clone to fit the new name:
if controller
and name
.lower() == controller
.basename
:
controller
= copy
.copy(controller
)
controller
.name
= browser
controller
.basename
= os
.path
.basename(browser
)
register(browser
, None, controller
)
return [None, controller
]
"""Return True if cmd can be found on the executable search path."""
path
= os
.environ
.get("PATH")
for d
in path
.split(os
.pathsep
):
exe
= os
.path
.join(d
, cmd
)
PROCESS_CREATION_DELAY
= 4
self
.name
, self
.args
= cmd
.split(None, 1)
self
.basename
= os
.path
.basename(self
.name
)
def open(self
, url
, new
=0, autoraise
=1):
command
= "%s %s" % (self
.name
, self
.args
)
"Launcher class for Netscape browsers."
def __init__(self
, name
):
self
.basename
= os
.path
.basename(name
)
def _remote(self
, action
, autoraise
):
raise_opt
= ("-noraise", "-raise")[autoraise
]
cmd
= "%s %s -remote '%s' >/dev/null 2>&1" % (self
.name
,
os
.system("%s &" % self
.name
)
time
.sleep(PROCESS_CREATION_DELAY
)
def open(self
, url
, new
=0, autoraise
=1):
self
._remote
("openURL(%s,new-window)"%url
, autoraise
)
self
._remote
("openURL(%s)" % url
, autoraise
)
"""Launcher class for Galeon browsers."""
def __init__(self
, name
):
self
.basename
= os
.path
.basename(name
)
def _remote(self
, action
, autoraise
):
raise_opt
= ("--noraise", "")[autoraise
]
cmd
= "%s %s %s >/dev/null 2>&1" % (self
.name
, raise_opt
, action
)
os
.system("%s >/dev/null 2>&1 &" % self
.name
)
time
.sleep(PROCESS_CREATION_DELAY
)
def open(self
, url
, new
=0, autoraise
=1):
self
._remote
("-w '%s'" % url
, autoraise
)
self
._remote
("-n '%s'" % url
, autoraise
)
"""Controller for the KDE File Manager (kfm, or Konqueror).
See http://developer.kde.org/documentation/other/kfmclient.html
for more information on the Konqueror remote-control interface.
if _iscommand("konqueror"):
self
.name
= self
.basename
= "konqueror"
self
.name
= self
.basename
= "kfm"
def _remote(self
, action
):
cmd
= "kfmclient %s >/dev/null 2>&1" % action
if self
.basename
== "konqueror":
os
.system(self
.name
+ " --silent &")
os
.system(self
.name
+ " -d &")
time
.sleep(PROCESS_CREATION_DELAY
)
def open(self
, url
, new
=1, autoraise
=1):
# XXX Currently I know no way to prevent KFM from
self
._remote
("openURL '%s'" % url
)
# There should be a way to maintain a connection to Grail, but the
# Grail remote control protocol doesn't really allow that at this
# point. It probably neverwill!
def _find_grail_rc(self
):
tempdir
= os
.path
.join(tempfile
.gettempdir(),
user
= pwd
.getpwuid(os
.getuid())[0]
filename
= os
.path
.join(tempdir
, user
+ "-*")
maybes
= glob
.glob(filename
)
s
= socket
.socket(socket
.AF_UNIX
, socket
.SOCK_STREAM
)
# need to PING each one until we find one that's live
# no good; attempt to clean it out, but don't fail:
def _remote(self
, action
):
s
= self
._find
_grail
_rc
()
def open(self
, url
, new
=0, autoraise
=1):
self
._remote
("LOADNEW " + url
)
self
._remote
("LOAD " + url
)
def open(self
, url
, new
=0, autoraise
=1):
# Platform support for Unix
# This is the right test because all these Unix browsers require either
# a console terminal of an X display to run. Note that we cannot split
# the TERM and DISPLAY cases, because we might be running Python from inside
if os
.environ
.get("TERM") or os
.environ
.get("DISPLAY"):
_tryorder
= ["links", "lynx", "w3m"]
# Easy cases first -- register console browsers if we have them.
if os
.environ
.get("TERM"):
# The Links browser <http://artax.karlin.mff.cuni.cz/~mikulas/links/>
register("links", None, GenericBrowser("links '%s'"))
# The Lynx browser <http://lynx.browser.org/>
register("lynx", None, GenericBrowser("lynx '%s'"))
# The w3m browser <http://ei5nazha.yz.yamagata-u.ac.jp/~aito/w3m/eng/>
register("w3m", None, GenericBrowser("w3m '%s'"))
# X browsers have more in the way of options
if os
.environ
.get("DISPLAY"):
_tryorder
= ["galeon", "skipstone",
"mozilla-firefox", "mozilla-firebird", "mozilla", "netscape",
"kfm", "grail"] + _tryorder
# First, the Netscape series
for browser
in ("mozilla-firefox", "mozilla-firebird",
register(browser
, None, Netscape(browser
))
# Next, Mosaic -- old but still in use.
register("mosaic", None, GenericBrowser(
"mosaic '%s' >/dev/null &"))
register("galeon", None, Galeon("galeon"))
# Skipstone, another Gtk/Mozilla based browser
if _iscommand("skipstone"):
register("skipstone", None, GenericBrowser(
"skipstone '%s' >/dev/null &"))
# Konqueror/kfm, the KDE browser.
if _iscommand("kfm") or _iscommand("konqueror"):
register("kfm", Konqueror
, Konqueror())
# Grail, the Python browser.
register("grail", Grail
, None)
def open(self
, url
, new
=0, autoraise
=1):
# Platform support for Windows
if sys
.platform
[:3] == "win":
_tryorder
= ["netscape", "windows-default"]
register("windows-default", WindowsDefault
)
# Platform support for MacOS
# internet-config is the only supported controller on MacOS,
# so don't mess with the default!
_tryorder
= ["internet-config"]
register("internet-config", InternetConfig
)
# Platform support for OS/2
if sys
.platform
[:3] == "os2" and _iscommand("netscape.exe"):
_tryorder
= ["os2netscape"]
register("os2netscape", None,
GenericBrowser("start netscape.exe %s"))
# OK, now that we know what the default preference orders for each
# platform are, allow user to override them with the BROWSER variable.
if "BROWSER" in os
.environ
:
# It's the user's responsibility to register handlers for any unknown
# browser referenced by this value, before calling open().
_tryorder
[0:0] = os
.environ
["BROWSER"].split(os
.pathsep
)
if not cmd
.lower() in _browsers
:
if _iscommand(cmd
.lower()):
register(cmd
.lower(), None, GenericBrowser(
"%s '%%s'" % cmd
.lower()))
cmd
= None # to make del work if _tryorder was empty
_tryorder
= filter(lambda x
: x
.lower() in _browsers
or x
.find("%s") > -1, _tryorder
)
# what to do if _tryorder is now empty?