190f5ba538bf40bcf4fd41049c7bf4296d3ffc9c7Benjamin Peterson#! /usr/bin/env python3 20a8c29be4b5314d4bf72cb391ab078f7483cf3f7Ka-Ping Yee"""Interfaces for launching and remotely controlling Web browsers.""" 3992d4a3e6e67a05b85350820157028a61d1f22cfGuido van Rossum# Maintained by Georg Brandl. 4c70b4483d2c5042c68198dc7c4945ef3cfc95b27Fred Drake 5c70b4483d2c5042c68198dc7c4945ef3cfc95b27Fred Drakeimport os 6d8faa3654c2887eaa146dcdb553a9f9793bd2e5aGuido van Rossumimport shlex 7540dcba28beaac416dcac22a155770be8d33a5a3Serhiy Storchakaimport shutil 8c70b4483d2c5042c68198dc7c4945ef3cfc95b27Fred Drakeimport sys 923929f2828078ee8fb115968f732d26bb9e4c1e3Georg Brandlimport subprocess 10c70b4483d2c5042c68198dc7c4945ef3cfc95b27Fred Drake 11e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl__all__ = ["Error", "open", "open_new", "open_new_tab", "get", "register"] 1240fc16059f04ee8fda0b5956cc4883eb21ca8f8cSkip Montanaro 13c70b4483d2c5042c68198dc7c4945ef3cfc95b27Fred Drakeclass Error(Exception): 14c70b4483d2c5042c68198dc7c4945ef3cfc95b27Fred Drake pass 15c70b4483d2c5042c68198dc7c4945ef3cfc95b27Fred Drake 16658cba6706eb4a2ad8b3e235cf0db9fe1c8e9e6bTim Peters_browsers = {} # Dictionary of available browser controllers 17658cba6706eb4a2ad8b3e235cf0db9fe1c8e9e6bTim Peters_tryorder = [] # Preference order of available browsers 18c70b4483d2c5042c68198dc7c4945ef3cfc95b27Fred Drake 19e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandldef register(name, klass, instance=None, update_tryorder=1): 20c70b4483d2c5042c68198dc7c4945ef3cfc95b27Fred Drake """Register a browser connector and, optionally, connection.""" 21c70b4483d2c5042c68198dc7c4945ef3cfc95b27Fred Drake _browsers[name.lower()] = [klass, instance] 22e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl if update_tryorder > 0: 23e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl _tryorder.append(name) 24e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl elif update_tryorder < 0: 25e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl _tryorder.insert(0, name) 26c70b4483d2c5042c68198dc7c4945ef3cfc95b27Fred Drake 27f7f185116a8274b105edc1be64ffc9c8061c7f43Eric S. Raymonddef get(using=None): 28f7f185116a8274b105edc1be64ffc9c8061c7f43Eric S. Raymond """Return a browser launcher instance appropriate for the environment.""" 2910ff706e2788a7c7ef9f8ea0108a5ede625fedadRaymond Hettinger if using is not None: 30f7f185116a8274b105edc1be64ffc9c8061c7f43Eric S. Raymond alternatives = [using] 31f7f185116a8274b105edc1be64ffc9c8061c7f43Eric S. Raymond else: 32f7f185116a8274b105edc1be64ffc9c8061c7f43Eric S. Raymond alternatives = _tryorder 33f7f185116a8274b105edc1be64ffc9c8061c7f43Eric S. Raymond for browser in alternatives: 34bac788a3cd348203a5fdabba52e5faf65bf35c5eRaymond Hettinger if '%s' in browser: 3523929f2828078ee8fb115968f732d26bb9e4c1e3Georg Brandl # User gave us a command line, split it into name and args 36d8faa3654c2887eaa146dcdb553a9f9793bd2e5aGuido van Rossum browser = shlex.split(browser) 37d8faa3654c2887eaa146dcdb553a9f9793bd2e5aGuido van Rossum if browser[-1] == '&': 38d8faa3654c2887eaa146dcdb553a9f9793bd2e5aGuido van Rossum return BackgroundBrowser(browser[:-1]) 39d8faa3654c2887eaa146dcdb553a9f9793bd2e5aGuido van Rossum else: 40d8faa3654c2887eaa146dcdb553a9f9793bd2e5aGuido van Rossum return GenericBrowser(browser) 41f7f185116a8274b105edc1be64ffc9c8061c7f43Eric S. Raymond else: 42e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl # User gave us a browser name or path. 43f4e5bd9df540aa5b24e47d03dbb798ed277793f7Fred Drake try: 44f4e5bd9df540aa5b24e47d03dbb798ed277793f7Fred Drake command = _browsers[browser.lower()] 45f4e5bd9df540aa5b24e47d03dbb798ed277793f7Fred Drake except KeyError: 46f4e5bd9df540aa5b24e47d03dbb798ed277793f7Fred Drake command = _synthesize(browser) 47e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl if command[1] is not None: 48f7f185116a8274b105edc1be64ffc9c8061c7f43Eric S. Raymond return command[1] 49e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl elif command[0] is not None: 50e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl return command[0]() 51f7f185116a8274b105edc1be64ffc9c8061c7f43Eric S. Raymond raise Error("could not locate runnable browser") 52c70b4483d2c5042c68198dc7c4945ef3cfc95b27Fred Drake 53c70b4483d2c5042c68198dc7c4945ef3cfc95b27Fred Drake# Please note: the following definition hides a builtin function. 54e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl# It is recommended one does "import webbrowser" and uses webbrowser.open(url) 55e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl# instead of "from webbrowser import *". 56c70b4483d2c5042c68198dc7c4945ef3cfc95b27Fred Drake 57e223eb8477c2d3241641a8a3e266a28d6dcd0c0eAlexandre Vassalottidef open(url, new=0, autoraise=True): 58e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl for name in _tryorder: 59e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl browser = get(name) 60e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl if browser.open(url, new, autoraise): 61e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl return True 62e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl return False 63c70b4483d2c5042c68198dc7c4945ef3cfc95b27Fred Drake 643f8f1643c8418a3e1980138c6fdb218e5be8c186Fred Drakedef open_new(url): 65e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl return open(url, 1) 66c70b4483d2c5042c68198dc7c4945ef3cfc95b27Fred Drake 67e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandldef open_new_tab(url): 68e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl return open(url, 2) 69f4e5bd9df540aa5b24e47d03dbb798ed277793f7Fred Drake 70e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl 71e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandldef _synthesize(browser, update_tryorder=1): 72f4e5bd9df540aa5b24e47d03dbb798ed277793f7Fred Drake """Attempt to synthesize a controller base on existing controllers. 73f4e5bd9df540aa5b24e47d03dbb798ed277793f7Fred Drake 74f4e5bd9df540aa5b24e47d03dbb798ed277793f7Fred Drake This is useful to create a controller when a user specifies a path to 75f4e5bd9df540aa5b24e47d03dbb798ed277793f7Fred Drake an entry in the BROWSER environment variable -- we can copy a general 76f4e5bd9df540aa5b24e47d03dbb798ed277793f7Fred Drake controller to operate using a specific installation of the desired 77f4e5bd9df540aa5b24e47d03dbb798ed277793f7Fred Drake browser in this way. 78f4e5bd9df540aa5b24e47d03dbb798ed277793f7Fred Drake 79f4e5bd9df540aa5b24e47d03dbb798ed277793f7Fred Drake If we can't create a controller in this way, or if there is no 80f4e5bd9df540aa5b24e47d03dbb798ed277793f7Fred Drake executable for the requested browser, return [None, None]. 81f4e5bd9df540aa5b24e47d03dbb798ed277793f7Fred Drake 82f4e5bd9df540aa5b24e47d03dbb798ed277793f7Fred Drake """ 83e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl cmd = browser.split()[0] 84540dcba28beaac416dcac22a155770be8d33a5a3Serhiy Storchaka if not shutil.which(cmd): 85f4e5bd9df540aa5b24e47d03dbb798ed277793f7Fred Drake return [None, None] 86e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl name = os.path.basename(cmd) 87f4e5bd9df540aa5b24e47d03dbb798ed277793f7Fred Drake try: 88f4e5bd9df540aa5b24e47d03dbb798ed277793f7Fred Drake command = _browsers[name.lower()] 89f4e5bd9df540aa5b24e47d03dbb798ed277793f7Fred Drake except KeyError: 90f4e5bd9df540aa5b24e47d03dbb798ed277793f7Fred Drake return [None, None] 91f4e5bd9df540aa5b24e47d03dbb798ed277793f7Fred Drake # now attempt to clone to fit the new name: 92f4e5bd9df540aa5b24e47d03dbb798ed277793f7Fred Drake controller = command[1] 93f4e5bd9df540aa5b24e47d03dbb798ed277793f7Fred Drake if controller and name.lower() == controller.basename: 94f4e5bd9df540aa5b24e47d03dbb798ed277793f7Fred Drake import copy 95f4e5bd9df540aa5b24e47d03dbb798ed277793f7Fred Drake controller = copy.copy(controller) 96f4e5bd9df540aa5b24e47d03dbb798ed277793f7Fred Drake controller.name = browser 97f4e5bd9df540aa5b24e47d03dbb798ed277793f7Fred Drake controller.basename = os.path.basename(browser) 98e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl register(browser, None, controller, update_tryorder) 99f4e5bd9df540aa5b24e47d03dbb798ed277793f7Fred Drake return [None, controller] 100118aa5337c745dece455f4782799c83b9e3a7d4fAndrew M. Kuchling return [None, None] 101f4e5bd9df540aa5b24e47d03dbb798ed277793f7Fred Drake 1023f8f1643c8418a3e1980138c6fdb218e5be8c186Fred Drake 103e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl# General parent classes 104e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl 105e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandlclass BaseBrowser(object): 10623929f2828078ee8fb115968f732d26bb9e4c1e3Georg Brandl """Parent class for all browsers. Do not use directly.""" 107887c080a800215250a9ebdcc589becc0bf6cac0dTim Peters 10823929f2828078ee8fb115968f732d26bb9e4c1e3Georg Brandl args = ['%s'] 109887c080a800215250a9ebdcc589becc0bf6cac0dTim Peters 110e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl def __init__(self, name=""): 111e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl self.name = name 112b980113a8df699797b837f103ac6d2049a214551Georg Brandl self.basename = name 113536cf99536bce562cfcb44a856fac1c84b9de4c3Tim Peters 114e223eb8477c2d3241641a8a3e266a28d6dcd0c0eAlexandre Vassalotti def open(self, url, new=0, autoraise=True): 115196f733d935bd51f8674c9761420ce990694f33aNeal Norwitz raise NotImplementedError 116196f733d935bd51f8674c9761420ce990694f33aNeal Norwitz 117e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl def open_new(self, url): 118e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl return self.open(url, 1) 119e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl 120e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl def open_new_tab(self, url): 121e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl return self.open(url, 2) 122e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl 1233f8f1643c8418a3e1980138c6fdb218e5be8c186Fred Drake 124e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandlclass GenericBrowser(BaseBrowser): 125e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl """Class for all browsers started with a command 126e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl and without remote functionality.""" 1273f8f1643c8418a3e1980138c6fdb218e5be8c186Fred Drake 12823929f2828078ee8fb115968f732d26bb9e4c1e3Georg Brandl def __init__(self, name): 1293172c5d263eeffff1e89d03d79be3ccc1d60fbdeGuido van Rossum if isinstance(name, str): 13023929f2828078ee8fb115968f732d26bb9e4c1e3Georg Brandl self.name = name 131992d4a3e6e67a05b85350820157028a61d1f22cfGuido van Rossum self.args = ["%s"] 13223929f2828078ee8fb115968f732d26bb9e4c1e3Georg Brandl else: 13323929f2828078ee8fb115968f732d26bb9e4c1e3Georg Brandl # name should be a list with arguments 13423929f2828078ee8fb115968f732d26bb9e4c1e3Georg Brandl self.name = name[0] 13523929f2828078ee8fb115968f732d26bb9e4c1e3Georg Brandl self.args = name[1:] 136b980113a8df699797b837f103ac6d2049a214551Georg Brandl self.basename = os.path.basename(self.name) 1373f8f1643c8418a3e1980138c6fdb218e5be8c186Fred Drake 138e223eb8477c2d3241641a8a3e266a28d6dcd0c0eAlexandre Vassalotti def open(self, url, new=0, autoraise=True): 139887c080a800215250a9ebdcc589becc0bf6cac0dTim Peters cmdline = [self.name] + [arg.replace("%s", url) 14023929f2828078ee8fb115968f732d26bb9e4c1e3Georg Brandl for arg in self.args] 14123929f2828078ee8fb115968f732d26bb9e4c1e3Georg Brandl try: 14289f507fe8c497b3f70fdcecce8bc240f9af2bbe2Thomas Wouters if sys.platform[:3] == 'win': 14389f507fe8c497b3f70fdcecce8bc240f9af2bbe2Thomas Wouters p = subprocess.Popen(cmdline) 14489f507fe8c497b3f70fdcecce8bc240f9af2bbe2Thomas Wouters else: 14589f507fe8c497b3f70fdcecce8bc240f9af2bbe2Thomas Wouters p = subprocess.Popen(cmdline, close_fds=True) 14623929f2828078ee8fb115968f732d26bb9e4c1e3Georg Brandl return not p.wait() 14723929f2828078ee8fb115968f732d26bb9e4c1e3Georg Brandl except OSError: 14823929f2828078ee8fb115968f732d26bb9e4c1e3Georg Brandl return False 14923929f2828078ee8fb115968f732d26bb9e4c1e3Georg Brandl 15023929f2828078ee8fb115968f732d26bb9e4c1e3Georg Brandl 15123929f2828078ee8fb115968f732d26bb9e4c1e3Georg Brandlclass BackgroundBrowser(GenericBrowser): 15223929f2828078ee8fb115968f732d26bb9e4c1e3Georg Brandl """Class for all browsers which are to be started in the 15323929f2828078ee8fb115968f732d26bb9e4c1e3Georg Brandl background.""" 15423929f2828078ee8fb115968f732d26bb9e4c1e3Georg Brandl 155e223eb8477c2d3241641a8a3e266a28d6dcd0c0eAlexandre Vassalotti def open(self, url, new=0, autoraise=True): 15623929f2828078ee8fb115968f732d26bb9e4c1e3Georg Brandl cmdline = [self.name] + [arg.replace("%s", url) 15723929f2828078ee8fb115968f732d26bb9e4c1e3Georg Brandl for arg in self.args] 15823929f2828078ee8fb115968f732d26bb9e4c1e3Georg Brandl try: 15989f507fe8c497b3f70fdcecce8bc240f9af2bbe2Thomas Wouters if sys.platform[:3] == 'win': 16089f507fe8c497b3f70fdcecce8bc240f9af2bbe2Thomas Wouters p = subprocess.Popen(cmdline) 16189f507fe8c497b3f70fdcecce8bc240f9af2bbe2Thomas Wouters else: 162feac3980ced0d80dc21982d87658876644c60e72Gregory P. Smith p = subprocess.Popen(cmdline, close_fds=True, 163feac3980ced0d80dc21982d87658876644c60e72Gregory P. Smith start_new_session=True) 16423929f2828078ee8fb115968f732d26bb9e4c1e3Georg Brandl return (p.poll() is None) 16523929f2828078ee8fb115968f732d26bb9e4c1e3Georg Brandl except OSError: 16623929f2828078ee8fb115968f732d26bb9e4c1e3Georg Brandl return False 1673f8f1643c8418a3e1980138c6fdb218e5be8c186Fred Drake 1683f8f1643c8418a3e1980138c6fdb218e5be8c186Fred Drake 169e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandlclass UnixBrowser(BaseBrowser): 170e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl """Parent class for all Unix browsers with remote functionality.""" 1713f8f1643c8418a3e1980138c6fdb218e5be8c186Fred Drake 172e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl raise_opts = None 17394dd7cb0c71dd9e43bd79df2281a8baa4f3f76caR David Murray background = False 17494dd7cb0c71dd9e43bd79df2281a8baa4f3f76caR David Murray redirect_stdout = True 17594dd7cb0c71dd9e43bd79df2281a8baa4f3f76caR David Murray # In remote_args, %s will be replaced with the requested URL. %action will 17694dd7cb0c71dd9e43bd79df2281a8baa4f3f76caR David Murray # be replaced depending on the value of 'new' passed to open. 17794dd7cb0c71dd9e43bd79df2281a8baa4f3f76caR David Murray # remote_action is used for new=0 (open). If newwin is not None, it is 17894dd7cb0c71dd9e43bd79df2281a8baa4f3f76caR David Murray # used for new=1 (open_new). If newtab is not None, it is used for 17994dd7cb0c71dd9e43bd79df2281a8baa4f3f76caR David Murray # new=3 (open_new_tab). After both substitutions are made, any empty 18094dd7cb0c71dd9e43bd79df2281a8baa4f3f76caR David Murray # strings in the transformed remote_args list will be removed. 18123929f2828078ee8fb115968f732d26bb9e4c1e3Georg Brandl remote_args = ['%action', '%s'] 182e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl remote_action = None 183e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl remote_action_newwin = None 184e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl remote_action_newtab = None 18523929f2828078ee8fb115968f732d26bb9e4c1e3Georg Brandl 18623929f2828078ee8fb115968f732d26bb9e4c1e3Georg Brandl def _invoke(self, args, remote, autoraise): 18723929f2828078ee8fb115968f732d26bb9e4c1e3Georg Brandl raise_opt = [] 18823929f2828078ee8fb115968f732d26bb9e4c1e3Georg Brandl if remote and self.raise_opts: 18923929f2828078ee8fb115968f732d26bb9e4c1e3Georg Brandl # use autoraise argument only for remote invocation 190e223eb8477c2d3241641a8a3e266a28d6dcd0c0eAlexandre Vassalotti autoraise = int(autoraise) 19123929f2828078ee8fb115968f732d26bb9e4c1e3Georg Brandl opt = self.raise_opts[autoraise] 19223929f2828078ee8fb115968f732d26bb9e4c1e3Georg Brandl if opt: raise_opt = [opt] 19323929f2828078ee8fb115968f732d26bb9e4c1e3Georg Brandl 19423929f2828078ee8fb115968f732d26bb9e4c1e3Georg Brandl cmdline = [self.name] + raise_opt + args 195887c080a800215250a9ebdcc589becc0bf6cac0dTim Peters 19623929f2828078ee8fb115968f732d26bb9e4c1e3Georg Brandl if remote or self.background: 19702ca144b92eef8d2b8da10c7b70b4e9d42480b9bR David Murray inout = subprocess.DEVNULL 19823929f2828078ee8fb115968f732d26bb9e4c1e3Georg Brandl else: 19923929f2828078ee8fb115968f732d26bb9e4c1e3Georg Brandl # for TTY browsers, we need stdin/out 20023929f2828078ee8fb115968f732d26bb9e4c1e3Georg Brandl inout = None 20123929f2828078ee8fb115968f732d26bb9e4c1e3Georg Brandl p = subprocess.Popen(cmdline, close_fds=True, stdin=inout, 20223929f2828078ee8fb115968f732d26bb9e4c1e3Georg Brandl stdout=(self.redirect_stdout and inout or None), 2038f7724f9a4ec57d689a436a064e2e047b2ad0d97Gregory P. Smith stderr=inout, start_new_session=True) 20423929f2828078ee8fb115968f732d26bb9e4c1e3Georg Brandl if remote: 205c9aa321a016343187e76fdae13d3a4c75e75afdeJesus Cea # wait at most five seconds. If the subprocess is not finished, the 20623929f2828078ee8fb115968f732d26bb9e4c1e3Georg Brandl # remote invocation has (hopefully) started a new instance. 207c9aa321a016343187e76fdae13d3a4c75e75afdeJesus Cea try: 208c9aa321a016343187e76fdae13d3a4c75e75afdeJesus Cea rc = p.wait(5) 209c9aa321a016343187e76fdae13d3a4c75e75afdeJesus Cea # if remote call failed, open() will try direct invocation 210c9aa321a016343187e76fdae13d3a4c75e75afdeJesus Cea return not rc 211c9aa321a016343187e76fdae13d3a4c75e75afdeJesus Cea except subprocess.TimeoutExpired: 212c9aa321a016343187e76fdae13d3a4c75e75afdeJesus Cea return True 21323929f2828078ee8fb115968f732d26bb9e4c1e3Georg Brandl elif self.background: 21423929f2828078ee8fb115968f732d26bb9e4c1e3Georg Brandl if p.poll() is None: 21523929f2828078ee8fb115968f732d26bb9e4c1e3Georg Brandl return True 21623929f2828078ee8fb115968f732d26bb9e4c1e3Georg Brandl else: 21723929f2828078ee8fb115968f732d26bb9e4c1e3Georg Brandl return False 21823929f2828078ee8fb115968f732d26bb9e4c1e3Georg Brandl else: 21923929f2828078ee8fb115968f732d26bb9e4c1e3Georg Brandl return not p.wait() 2203f8f1643c8418a3e1980138c6fdb218e5be8c186Fred Drake 221e223eb8477c2d3241641a8a3e266a28d6dcd0c0eAlexandre Vassalotti def open(self, url, new=0, autoraise=True): 222e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl if new == 0: 223e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl action = self.remote_action 224e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl elif new == 1: 225e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl action = self.remote_action_newwin 226e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl elif new == 2: 227e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl if self.remote_action_newtab is None: 228e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl action = self.remote_action_newwin 229e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl else: 230e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl action = self.remote_action_newtab 2313f8f1643c8418a3e1980138c6fdb218e5be8c186Fred Drake else: 23223929f2828078ee8fb115968f732d26bb9e4c1e3Georg Brandl raise Error("Bad 'new' parameter to open(); " + 23323929f2828078ee8fb115968f732d26bb9e4c1e3Georg Brandl "expected 0, 1, or 2, got %s" % new) 234887c080a800215250a9ebdcc589becc0bf6cac0dTim Peters 23523929f2828078ee8fb115968f732d26bb9e4c1e3Georg Brandl args = [arg.replace("%s", url).replace("%action", action) 23623929f2828078ee8fb115968f732d26bb9e4c1e3Georg Brandl for arg in self.remote_args] 23794dd7cb0c71dd9e43bd79df2281a8baa4f3f76caR David Murray args = [arg for arg in args if arg] 23823929f2828078ee8fb115968f732d26bb9e4c1e3Georg Brandl success = self._invoke(args, True, autoraise) 23923929f2828078ee8fb115968f732d26bb9e4c1e3Georg Brandl if not success: 24023929f2828078ee8fb115968f732d26bb9e4c1e3Georg Brandl # remote invocation failed, try straight way 24123929f2828078ee8fb115968f732d26bb9e4c1e3Georg Brandl args = [arg.replace("%s", url) for arg in self.args] 24223929f2828078ee8fb115968f732d26bb9e4c1e3Georg Brandl return self._invoke(args, False, False) 24323929f2828078ee8fb115968f732d26bb9e4c1e3Georg Brandl else: 24423929f2828078ee8fb115968f732d26bb9e4c1e3Georg Brandl return True 2453f8f1643c8418a3e1980138c6fdb218e5be8c186Fred Drake 2463f8f1643c8418a3e1980138c6fdb218e5be8c186Fred Drake 247e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandlclass Mozilla(UnixBrowser): 248c9b750d249136b88125c28cd139c4bc694c18003Serhiy Storchaka """Launcher class for Mozilla browsers.""" 249c9b750d249136b88125c28cd139c4bc694c18003Serhiy Storchaka 250c9b750d249136b88125c28cd139c4bc694c18003Serhiy Storchaka remote_args = ['%action', '%s'] 251c9b750d249136b88125c28cd139c4bc694c18003Serhiy Storchaka remote_action = "" 252c9b750d249136b88125c28cd139c4bc694c18003Serhiy Storchaka remote_action_newwin = "-new-window" 253c9b750d249136b88125c28cd139c4bc694c18003Serhiy Storchaka remote_action_newtab = "-new-tab" 254c9b750d249136b88125c28cd139c4bc694c18003Serhiy Storchaka background = True 255c9b750d249136b88125c28cd139c4bc694c18003Serhiy Storchaka 256c9b750d249136b88125c28cd139c4bc694c18003Serhiy Storchaka 257c9b750d249136b88125c28cd139c4bc694c18003Serhiy Storchakaclass Netscape(UnixBrowser): 258c9b750d249136b88125c28cd139c4bc694c18003Serhiy Storchaka """Launcher class for Netscape browser.""" 2593f8f1643c8418a3e1980138c6fdb218e5be8c186Fred Drake 26023929f2828078ee8fb115968f732d26bb9e4c1e3Georg Brandl raise_opts = ["-noraise", "-raise"] 26123929f2828078ee8fb115968f732d26bb9e4c1e3Georg Brandl remote_args = ['-remote', 'openURL(%s%action)'] 26223929f2828078ee8fb115968f732d26bb9e4c1e3Georg Brandl remote_action = "" 26323929f2828078ee8fb115968f732d26bb9e4c1e3Georg Brandl remote_action_newwin = ",new-window" 26423929f2828078ee8fb115968f732d26bb9e4c1e3Georg Brandl remote_action_newtab = ",new-tab" 26523929f2828078ee8fb115968f732d26bb9e4c1e3Georg Brandl background = True 2668dd28eb973a1c072448d961a6fb6a8a12cc3c950Neal Norwitz 2678dd28eb973a1c072448d961a6fb6a8a12cc3c950Neal Norwitz 268e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandlclass Galeon(UnixBrowser): 269e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl """Launcher class for Galeon/Epiphany browsers.""" 270e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl 27123929f2828078ee8fb115968f732d26bb9e4c1e3Georg Brandl raise_opts = ["-noraise", ""] 27223929f2828078ee8fb115968f732d26bb9e4c1e3Georg Brandl remote_args = ['%action', '%s'] 27323929f2828078ee8fb115968f732d26bb9e4c1e3Georg Brandl remote_action = "-n" 27423929f2828078ee8fb115968f732d26bb9e4c1e3Georg Brandl remote_action_newwin = "-w" 27523929f2828078ee8fb115968f732d26bb9e4c1e3Georg Brandl background = True 276e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl 277e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl 278ea6b4187cf78ce1ac260c1620b1d4c0fd069bebaSenthil Kumaranclass Chrome(UnixBrowser): 279ea6b4187cf78ce1ac260c1620b1d4c0fd069bebaSenthil Kumaran "Launcher class for Google Chrome browser." 280ea6b4187cf78ce1ac260c1620b1d4c0fd069bebaSenthil Kumaran 281ea6b4187cf78ce1ac260c1620b1d4c0fd069bebaSenthil Kumaran remote_args = ['%action', '%s'] 282ea6b4187cf78ce1ac260c1620b1d4c0fd069bebaSenthil Kumaran remote_action = "" 283ea6b4187cf78ce1ac260c1620b1d4c0fd069bebaSenthil Kumaran remote_action_newwin = "--new-window" 284ea6b4187cf78ce1ac260c1620b1d4c0fd069bebaSenthil Kumaran remote_action_newtab = "" 285ea6b4187cf78ce1ac260c1620b1d4c0fd069bebaSenthil Kumaran background = True 286ea6b4187cf78ce1ac260c1620b1d4c0fd069bebaSenthil Kumaran 287ea6b4187cf78ce1ac260c1620b1d4c0fd069bebaSenthil KumaranChromium = Chrome 288ea6b4187cf78ce1ac260c1620b1d4c0fd069bebaSenthil Kumaran 289ea6b4187cf78ce1ac260c1620b1d4c0fd069bebaSenthil Kumaran 29023929f2828078ee8fb115968f732d26bb9e4c1e3Georg Brandlclass Opera(UnixBrowser): 29123929f2828078ee8fb115968f732d26bb9e4c1e3Georg Brandl "Launcher class for Opera browser." 2923f8f1643c8418a3e1980138c6fdb218e5be8c186Fred Drake 293dad532f7def9917707d9705fcd9201413e42ef75Terry Reedy raise_opts = ["-noraise", ""] 29423929f2828078ee8fb115968f732d26bb9e4c1e3Georg Brandl remote_args = ['-remote', 'openURL(%s%action)'] 29523929f2828078ee8fb115968f732d26bb9e4c1e3Georg Brandl remote_action = "" 29623929f2828078ee8fb115968f732d26bb9e4c1e3Georg Brandl remote_action_newwin = ",new-window" 29723929f2828078ee8fb115968f732d26bb9e4c1e3Georg Brandl remote_action_newtab = ",new-page" 29823929f2828078ee8fb115968f732d26bb9e4c1e3Georg Brandl background = True 2993f8f1643c8418a3e1980138c6fdb218e5be8c186Fred Drake 300e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl 30123929f2828078ee8fb115968f732d26bb9e4c1e3Georg Brandlclass Elinks(UnixBrowser): 30223929f2828078ee8fb115968f732d26bb9e4c1e3Georg Brandl "Launcher class for Elinks browsers." 303e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl 30423929f2828078ee8fb115968f732d26bb9e4c1e3Georg Brandl remote_args = ['-remote', 'openURL(%s%action)'] 30523929f2828078ee8fb115968f732d26bb9e4c1e3Georg Brandl remote_action = "" 30623929f2828078ee8fb115968f732d26bb9e4c1e3Georg Brandl remote_action_newwin = ",new-window" 30723929f2828078ee8fb115968f732d26bb9e4c1e3Georg Brandl remote_action_newtab = ",new-tab" 30823929f2828078ee8fb115968f732d26bb9e4c1e3Georg Brandl background = False 3093f8f1643c8418a3e1980138c6fdb218e5be8c186Fred Drake 31023929f2828078ee8fb115968f732d26bb9e4c1e3Georg Brandl # elinks doesn't like its stdout to be redirected - 31123929f2828078ee8fb115968f732d26bb9e4c1e3Georg Brandl # it uses redirected stdout as a signal to do -dump 31223929f2828078ee8fb115968f732d26bb9e4c1e3Georg Brandl redirect_stdout = False 3133f8f1643c8418a3e1980138c6fdb218e5be8c186Fred Drake 3143f8f1643c8418a3e1980138c6fdb218e5be8c186Fred Drake 31523929f2828078ee8fb115968f732d26bb9e4c1e3Georg Brandlclass Konqueror(BaseBrowser): 31623929f2828078ee8fb115968f732d26bb9e4c1e3Georg Brandl """Controller for the KDE File Manager (kfm, or Konqueror). 317e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl 31823929f2828078ee8fb115968f732d26bb9e4c1e3Georg Brandl See the output of ``kfmclient --commands`` 31923929f2828078ee8fb115968f732d26bb9e4c1e3Georg Brandl for more information on the Konqueror remote-control interface. 32023929f2828078ee8fb115968f732d26bb9e4c1e3Georg Brandl """ 321e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl 322e223eb8477c2d3241641a8a3e266a28d6dcd0c0eAlexandre Vassalotti def open(self, url, new=0, autoraise=True): 32323929f2828078ee8fb115968f732d26bb9e4c1e3Georg Brandl # XXX Currently I know no way to prevent KFM from opening a new win. 32423929f2828078ee8fb115968f732d26bb9e4c1e3Georg Brandl if new == 2: 32523929f2828078ee8fb115968f732d26bb9e4c1e3Georg Brandl action = "newTab" 32623929f2828078ee8fb115968f732d26bb9e4c1e3Georg Brandl else: 32723929f2828078ee8fb115968f732d26bb9e4c1e3Georg Brandl action = "openURL" 328887c080a800215250a9ebdcc589becc0bf6cac0dTim Peters 32902ca144b92eef8d2b8da10c7b70b4e9d42480b9bR David Murray devnull = subprocess.DEVNULL 330887c080a800215250a9ebdcc589becc0bf6cac0dTim Peters 33123929f2828078ee8fb115968f732d26bb9e4c1e3Georg Brandl try: 33223929f2828078ee8fb115968f732d26bb9e4c1e3Georg Brandl p = subprocess.Popen(["kfmclient", action, url], 33323929f2828078ee8fb115968f732d26bb9e4c1e3Georg Brandl close_fds=True, stdin=devnull, 33423929f2828078ee8fb115968f732d26bb9e4c1e3Georg Brandl stdout=devnull, stderr=devnull) 33523929f2828078ee8fb115968f732d26bb9e4c1e3Georg Brandl except OSError: 33623929f2828078ee8fb115968f732d26bb9e4c1e3Georg Brandl # fall through to next variant 33723929f2828078ee8fb115968f732d26bb9e4c1e3Georg Brandl pass 33823929f2828078ee8fb115968f732d26bb9e4c1e3Georg Brandl else: 33923929f2828078ee8fb115968f732d26bb9e4c1e3Georg Brandl p.wait() 34023929f2828078ee8fb115968f732d26bb9e4c1e3Georg Brandl # kfmclient's return code unfortunately has no meaning as it seems 34123929f2828078ee8fb115968f732d26bb9e4c1e3Georg Brandl return True 342e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl 34323929f2828078ee8fb115968f732d26bb9e4c1e3Georg Brandl try: 34423929f2828078ee8fb115968f732d26bb9e4c1e3Georg Brandl p = subprocess.Popen(["konqueror", "--silent", url], 34523929f2828078ee8fb115968f732d26bb9e4c1e3Georg Brandl close_fds=True, stdin=devnull, 34623929f2828078ee8fb115968f732d26bb9e4c1e3Georg Brandl stdout=devnull, stderr=devnull, 347feac3980ced0d80dc21982d87658876644c60e72Gregory P. Smith start_new_session=True) 34823929f2828078ee8fb115968f732d26bb9e4c1e3Georg Brandl except OSError: 34923929f2828078ee8fb115968f732d26bb9e4c1e3Georg Brandl # fall through to next variant 35023929f2828078ee8fb115968f732d26bb9e4c1e3Georg Brandl pass 35123929f2828078ee8fb115968f732d26bb9e4c1e3Georg Brandl else: 35223929f2828078ee8fb115968f732d26bb9e4c1e3Georg Brandl if p.poll() is None: 35323929f2828078ee8fb115968f732d26bb9e4c1e3Georg Brandl # Should be running now. 35423929f2828078ee8fb115968f732d26bb9e4c1e3Georg Brandl return True 355887c080a800215250a9ebdcc589becc0bf6cac0dTim Peters 35623929f2828078ee8fb115968f732d26bb9e4c1e3Georg Brandl try: 35723929f2828078ee8fb115968f732d26bb9e4c1e3Georg Brandl p = subprocess.Popen(["kfm", "-d", url], 35823929f2828078ee8fb115968f732d26bb9e4c1e3Georg Brandl close_fds=True, stdin=devnull, 35923929f2828078ee8fb115968f732d26bb9e4c1e3Georg Brandl stdout=devnull, stderr=devnull, 360feac3980ced0d80dc21982d87658876644c60e72Gregory P. Smith start_new_session=True) 36123929f2828078ee8fb115968f732d26bb9e4c1e3Georg Brandl except OSError: 36223929f2828078ee8fb115968f732d26bb9e4c1e3Georg Brandl return False 36323929f2828078ee8fb115968f732d26bb9e4c1e3Georg Brandl else: 36423929f2828078ee8fb115968f732d26bb9e4c1e3Georg Brandl return (p.poll() is None) 365e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl 366e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl 367e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandlclass Grail(BaseBrowser): 3683f8f1643c8418a3e1980138c6fdb218e5be8c186Fred Drake # There should be a way to maintain a connection to Grail, but the 3693f8f1643c8418a3e1980138c6fdb218e5be8c186Fred Drake # Grail remote control protocol doesn't really allow that at this 37023929f2828078ee8fb115968f732d26bb9e4c1e3Georg Brandl # point. It probably never will! 3713f8f1643c8418a3e1980138c6fdb218e5be8c186Fred Drake def _find_grail_rc(self): 3723f8f1643c8418a3e1980138c6fdb218e5be8c186Fred Drake import glob 3733f8f1643c8418a3e1980138c6fdb218e5be8c186Fred Drake import pwd 3743f8f1643c8418a3e1980138c6fdb218e5be8c186Fred Drake import socket 3753f8f1643c8418a3e1980138c6fdb218e5be8c186Fred Drake import tempfile 3763f8f1643c8418a3e1980138c6fdb218e5be8c186Fred Drake tempdir = os.path.join(tempfile.gettempdir(), 3773f8f1643c8418a3e1980138c6fdb218e5be8c186Fred Drake ".grail-unix") 37816623fe3e606efdedead8ccccaf7ef583e1be97fFred Drake user = pwd.getpwuid(os.getuid())[0] 3793f8f1643c8418a3e1980138c6fdb218e5be8c186Fred Drake filename = os.path.join(tempdir, user + "-*") 3803f8f1643c8418a3e1980138c6fdb218e5be8c186Fred Drake maybes = glob.glob(filename) 3813f8f1643c8418a3e1980138c6fdb218e5be8c186Fred Drake if not maybes: 3823f8f1643c8418a3e1980138c6fdb218e5be8c186Fred Drake return None 3833f8f1643c8418a3e1980138c6fdb218e5be8c186Fred Drake s = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM) 3843f8f1643c8418a3e1980138c6fdb218e5be8c186Fred Drake for fn in maybes: 3853f8f1643c8418a3e1980138c6fdb218e5be8c186Fred Drake # need to PING each one until we find one that's live 3863f8f1643c8418a3e1980138c6fdb218e5be8c186Fred Drake try: 3873f8f1643c8418a3e1980138c6fdb218e5be8c186Fred Drake s.connect(fn) 3880832af6628ca5ac02d0226899725297dd508470bAndrew Svetlov except OSError: 3893f8f1643c8418a3e1980138c6fdb218e5be8c186Fred Drake # no good; attempt to clean it out, but don't fail: 3903f8f1643c8418a3e1980138c6fdb218e5be8c186Fred Drake try: 3913f8f1643c8418a3e1980138c6fdb218e5be8c186Fred Drake os.unlink(fn) 392f7a17b48d748e1835bcf9df86fb7fb318bb020f8Andrew Svetlov except OSError: 3933f8f1643c8418a3e1980138c6fdb218e5be8c186Fred Drake pass 3943f8f1643c8418a3e1980138c6fdb218e5be8c186Fred Drake else: 3953f8f1643c8418a3e1980138c6fdb218e5be8c186Fred Drake return s 3963f8f1643c8418a3e1980138c6fdb218e5be8c186Fred Drake 3973f8f1643c8418a3e1980138c6fdb218e5be8c186Fred Drake def _remote(self, action): 3983f8f1643c8418a3e1980138c6fdb218e5be8c186Fred Drake s = self._find_grail_rc() 3993f8f1643c8418a3e1980138c6fdb218e5be8c186Fred Drake if not s: 4003f8f1643c8418a3e1980138c6fdb218e5be8c186Fred Drake return 0 4013f8f1643c8418a3e1980138c6fdb218e5be8c186Fred Drake s.send(action) 4023f8f1643c8418a3e1980138c6fdb218e5be8c186Fred Drake s.close() 4033f8f1643c8418a3e1980138c6fdb218e5be8c186Fred Drake return 1 4043f8f1643c8418a3e1980138c6fdb218e5be8c186Fred Drake 405e223eb8477c2d3241641a8a3e266a28d6dcd0c0eAlexandre Vassalotti def open(self, url, new=0, autoraise=True): 4063f8f1643c8418a3e1980138c6fdb218e5be8c186Fred Drake if new: 407e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl ok = self._remote("LOADNEW " + url) 4083f8f1643c8418a3e1980138c6fdb218e5be8c186Fred Drake else: 409e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl ok = self._remote("LOAD " + url) 410e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl return ok 4113f8f1643c8418a3e1980138c6fdb218e5be8c186Fred Drake 412c70b4483d2c5042c68198dc7c4945ef3cfc95b27Fred Drake 413658cba6706eb4a2ad8b3e235cf0db9fe1c8e9e6bTim Peters# 414f7f185116a8274b105edc1be64ffc9c8061c7f43Eric S. Raymond# Platform support for Unix 415f7f185116a8274b105edc1be64ffc9c8061c7f43Eric S. Raymond# 416c70b4483d2c5042c68198dc7c4945ef3cfc95b27Fred Drake 417e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl# These are the right tests because all these Unix browsers require either 418e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl# a console terminal or an X display to run. 419e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl 420196f733d935bd51f8674c9761420ce990694f33aNeal Norwitzdef register_X_browsers(): 421d8faa3654c2887eaa146dcdb553a9f9793bd2e5aGuido van Rossum 422da80b1eb2fa5db8a388fa202e6aada686d243842Matthias Klose # use xdg-open if around 423540dcba28beaac416dcac22a155770be8d33a5a3Serhiy Storchaka if shutil.which("xdg-open"): 424da80b1eb2fa5db8a388fa202e6aada686d243842Matthias Klose register("xdg-open", None, BackgroundBrowser("xdg-open")) 425da80b1eb2fa5db8a388fa202e6aada686d243842Matthias Klose 426da80b1eb2fa5db8a388fa202e6aada686d243842Matthias Klose # The default GNOME3 browser 427540dcba28beaac416dcac22a155770be8d33a5a3Serhiy Storchaka if "GNOME_DESKTOP_SESSION_ID" in os.environ and shutil.which("gvfs-open"): 428da80b1eb2fa5db8a388fa202e6aada686d243842Matthias Klose register("gvfs-open", None, BackgroundBrowser("gvfs-open")) 429da80b1eb2fa5db8a388fa202e6aada686d243842Matthias Klose 430d8faa3654c2887eaa146dcdb553a9f9793bd2e5aGuido van Rossum # The default GNOME browser 431540dcba28beaac416dcac22a155770be8d33a5a3Serhiy Storchaka if "GNOME_DESKTOP_SESSION_ID" in os.environ and shutil.which("gnome-open"): 432d8faa3654c2887eaa146dcdb553a9f9793bd2e5aGuido van Rossum register("gnome-open", None, BackgroundBrowser("gnome-open")) 433d8faa3654c2887eaa146dcdb553a9f9793bd2e5aGuido van Rossum 434d8faa3654c2887eaa146dcdb553a9f9793bd2e5aGuido van Rossum # The default KDE browser 435540dcba28beaac416dcac22a155770be8d33a5a3Serhiy Storchaka if "KDE_FULL_SESSION" in os.environ and shutil.which("kfmclient"): 436d8faa3654c2887eaa146dcdb553a9f9793bd2e5aGuido van Rossum register("kfmclient", Konqueror, Konqueror("kfmclient")) 437d8faa3654c2887eaa146dcdb553a9f9793bd2e5aGuido van Rossum 438f85aca8d1eb7bf15540be3515ab249a0ab335a4cdoko@ubuntu.com if shutil.which("x-www-browser"): 439945c3bbf42bc133d4b21265526254ff2f4e4466bdoko@ubuntu.com register("x-www-browser", None, BackgroundBrowser("x-www-browser")) 440945c3bbf42bc133d4b21265526254ff2f4e4466bdoko@ubuntu.com 441c9b750d249136b88125c28cd139c4bc694c18003Serhiy Storchaka # The Mozilla browsers 442c9b750d249136b88125c28cd139c4bc694c18003Serhiy Storchaka for browser in ("firefox", "iceweasel", "iceape", "seamonkey"): 443540dcba28beaac416dcac22a155770be8d33a5a3Serhiy Storchaka if shutil.which(browser): 4444a5a91838b7318cc89a2ff2018b26940a5960a29Georg Brandl register(browser, None, Mozilla(browser)) 4454a5a91838b7318cc89a2ff2018b26940a5960a29Georg Brandl 446c9b750d249136b88125c28cd139c4bc694c18003Serhiy Storchaka # The Netscape and old Mozilla browsers 447c9b750d249136b88125c28cd139c4bc694c18003Serhiy Storchaka for browser in ("mozilla-firefox", 448c9b750d249136b88125c28cd139c4bc694c18003Serhiy Storchaka "mozilla-firebird", "firebird", 449c9b750d249136b88125c28cd139c4bc694c18003Serhiy Storchaka "mozilla", "netscape"): 450c9b750d249136b88125c28cd139c4bc694c18003Serhiy Storchaka if shutil.which(browser): 451c9b750d249136b88125c28cd139c4bc694c18003Serhiy Storchaka register(browser, None, Netscape(browser)) 452c9b750d249136b88125c28cd139c4bc694c18003Serhiy Storchaka 453e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl # Konqueror/kfm, the KDE browser. 454540dcba28beaac416dcac22a155770be8d33a5a3Serhiy Storchaka if shutil.which("kfm"): 455b980113a8df699797b837f103ac6d2049a214551Georg Brandl register("kfm", Konqueror, Konqueror("kfm")) 456540dcba28beaac416dcac22a155770be8d33a5a3Serhiy Storchaka elif shutil.which("konqueror"): 457b980113a8df699797b837f103ac6d2049a214551Georg Brandl register("konqueror", Konqueror, Konqueror("konqueror")) 458e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl 459e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl # Gnome's Galeon and Epiphany 460e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl for browser in ("galeon", "epiphany"): 461540dcba28beaac416dcac22a155770be8d33a5a3Serhiy Storchaka if shutil.which(browser): 462e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl register(browser, None, Galeon(browser)) 463e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl 464e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl # Skipstone, another Gtk/Mozilla based browser 465540dcba28beaac416dcac22a155770be8d33a5a3Serhiy Storchaka if shutil.which("skipstone"): 46623929f2828078ee8fb115968f732d26bb9e4c1e3Georg Brandl register("skipstone", None, BackgroundBrowser("skipstone")) 467e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl 468ea6b4187cf78ce1ac260c1620b1d4c0fd069bebaSenthil Kumaran # Google Chrome/Chromium browsers 469ea6b4187cf78ce1ac260c1620b1d4c0fd069bebaSenthil Kumaran for browser in ("google-chrome", "chrome", "chromium", "chromium-browser"): 470540dcba28beaac416dcac22a155770be8d33a5a3Serhiy Storchaka if shutil.which(browser): 471ea6b4187cf78ce1ac260c1620b1d4c0fd069bebaSenthil Kumaran register(browser, None, Chrome(browser)) 472ea6b4187cf78ce1ac260c1620b1d4c0fd069bebaSenthil Kumaran 473e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl # Opera, quite popular 474540dcba28beaac416dcac22a155770be8d33a5a3Serhiy Storchaka if shutil.which("opera"): 475e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl register("opera", None, Opera("opera")) 476e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl 477e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl # Next, Mosaic -- old but still in use. 478540dcba28beaac416dcac22a155770be8d33a5a3Serhiy Storchaka if shutil.which("mosaic"): 47923929f2828078ee8fb115968f732d26bb9e4c1e3Georg Brandl register("mosaic", None, BackgroundBrowser("mosaic")) 480e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl 481e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl # Grail, the Python browser. Does anybody still use it? 482540dcba28beaac416dcac22a155770be8d33a5a3Serhiy Storchaka if shutil.which("grail"): 483e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl register("grail", Grail, None) 484e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl 485196f733d935bd51f8674c9761420ce990694f33aNeal Norwitz# Prefer X browsers if present 486196f733d935bd51f8674c9761420ce990694f33aNeal Norwitzif os.environ.get("DISPLAY"): 487196f733d935bd51f8674c9761420ce990694f33aNeal Norwitz register_X_browsers() 488196f733d935bd51f8674c9761420ce990694f33aNeal Norwitz 489e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl# Also try console browsers 490e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandlif os.environ.get("TERM"): 491f85aca8d1eb7bf15540be3515ab249a0ab335a4cdoko@ubuntu.com if shutil.which("www-browser"): 492945c3bbf42bc133d4b21265526254ff2f4e4466bdoko@ubuntu.com register("www-browser", None, GenericBrowser("www-browser")) 493e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl # The Links/elinks browsers <http://artax.karlin.mff.cuni.cz/~mikulas/links/> 494540dcba28beaac416dcac22a155770be8d33a5a3Serhiy Storchaka if shutil.which("links"): 49523929f2828078ee8fb115968f732d26bb9e4c1e3Georg Brandl register("links", None, GenericBrowser("links")) 496540dcba28beaac416dcac22a155770be8d33a5a3Serhiy Storchaka if shutil.which("elinks"): 497e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl register("elinks", None, Elinks("elinks")) 498e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl # The Lynx browser <http://lynx.isc.org/>, <http://lynx.browser.org/> 499540dcba28beaac416dcac22a155770be8d33a5a3Serhiy Storchaka if shutil.which("lynx"): 50023929f2828078ee8fb115968f732d26bb9e4c1e3Georg Brandl register("lynx", None, GenericBrowser("lynx")) 501e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl # The w3m browser <http://w3m.sourceforge.net/> 502540dcba28beaac416dcac22a155770be8d33a5a3Serhiy Storchaka if shutil.which("w3m"): 50323929f2828078ee8fb115968f732d26bb9e4c1e3Georg Brandl register("w3m", None, GenericBrowser("w3m")) 5043f8f1643c8418a3e1980138c6fdb218e5be8c186Fred Drake 505f7f185116a8274b105edc1be64ffc9c8061c7f43Eric S. Raymond# 506f7f185116a8274b105edc1be64ffc9c8061c7f43Eric S. Raymond# Platform support for Windows 507f7f185116a8274b105edc1be64ffc9c8061c7f43Eric S. Raymond# 508c70b4483d2c5042c68198dc7c4945ef3cfc95b27Fred Drake 509f7f185116a8274b105edc1be64ffc9c8061c7f43Eric S. Raymondif sys.platform[:3] == "win": 510e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl class WindowsDefault(BaseBrowser): 511e223eb8477c2d3241641a8a3e266a28d6dcd0c0eAlexandre Vassalotti def open(self, url, new=0, autoraise=True): 512d8faa3654c2887eaa146dcdb553a9f9793bd2e5aGuido van Rossum try: 5132ebd8f5194257d91b076e6866573b8f20f8f40a0Steve Dower os.startfile(url) 5142606a6f197a49f04611cb5cb0d67404d1ab14481Andrew Svetlov except OSError: 515d8faa3654c2887eaa146dcdb553a9f9793bd2e5aGuido van Rossum # [Error 22] No application is associated with the specified 516d8faa3654c2887eaa146dcdb553a9f9793bd2e5aGuido van Rossum # file for this operation: '<URL>' 517d8faa3654c2887eaa146dcdb553a9f9793bd2e5aGuido van Rossum return False 518d8faa3654c2887eaa146dcdb553a9f9793bd2e5aGuido van Rossum else: 519d8faa3654c2887eaa146dcdb553a9f9793bd2e5aGuido van Rossum return True 520e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl 521e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl _tryorder = [] 522e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl _browsers = {} 523d8faa3654c2887eaa146dcdb553a9f9793bd2e5aGuido van Rossum 5242ebd8f5194257d91b076e6866573b8f20f8f40a0Steve Dower # First try to use the default Windows browser 525d8faa3654c2887eaa146dcdb553a9f9793bd2e5aGuido van Rossum register("windows-default", WindowsDefault) 526d8faa3654c2887eaa146dcdb553a9f9793bd2e5aGuido van Rossum 5272ebd8f5194257d91b076e6866573b8f20f8f40a0Steve Dower # Detect some common Windows browsers, fallback to IE 5282ebd8f5194257d91b076e6866573b8f20f8f40a0Steve Dower iexplore = os.path.join(os.environ.get("PROGRAMFILES", "C:\\Program Files"), 5292ebd8f5194257d91b076e6866573b8f20f8f40a0Steve Dower "Internet Explorer\\IEXPLORE.EXE") 5302ebd8f5194257d91b076e6866573b8f20f8f40a0Steve Dower for browser in ("firefox", "firebird", "seamonkey", "mozilla", 5312ebd8f5194257d91b076e6866573b8f20f8f40a0Steve Dower "netscape", "opera", iexplore): 5322ebd8f5194257d91b076e6866573b8f20f8f40a0Steve Dower if shutil.which(browser): 5332ebd8f5194257d91b076e6866573b8f20f8f40a0Steve Dower register(browser, None, BackgroundBrowser(browser)) 534c70b4483d2c5042c68198dc7c4945ef3cfc95b27Fred Drake 535c70b4483d2c5042c68198dc7c4945ef3cfc95b27Fred Drake# 536f7f185116a8274b105edc1be64ffc9c8061c7f43Eric S. Raymond# Platform support for MacOS 537f7f185116a8274b105edc1be64ffc9c8061c7f43Eric S. Raymond# 538c70b4483d2c5042c68198dc7c4945ef3cfc95b27Fred Drake 539e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandlif sys.platform == 'darwin': 540e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl # Adapted from patch submitted to SourceForge by Steven J. Burr 541e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl class MacOSX(BaseBrowser): 542e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl """Launcher class for Aqua browsers on Mac OS X 543e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl 544e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl Optionally specify a browser name on instantiation. Note that this 545e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl will not work for Aqua browsers if the user has moved the application 546e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl package after installation. 547e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl 548e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl If no browser is specified, the default browser, as specified in the 549e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl Internet System Preferences panel, will be used. 550e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl """ 551e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl def __init__(self, name): 552e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl self.name = name 553e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl 554e223eb8477c2d3241641a8a3e266a28d6dcd0c0eAlexandre Vassalotti def open(self, url, new=0, autoraise=True): 555e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl assert "'" not in url 55623929f2828078ee8fb115968f732d26bb9e4c1e3Georg Brandl # hack for local urls 55723929f2828078ee8fb115968f732d26bb9e4c1e3Georg Brandl if not ':' in url: 55823929f2828078ee8fb115968f732d26bb9e4c1e3Georg Brandl url = 'file:'+url 559887c080a800215250a9ebdcc589becc0bf6cac0dTim Peters 560e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl # new must be 0 or 1 561e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl new = int(bool(new)) 562e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl if self.name == "default": 563e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl # User called open, open_new or get without a browser parameter 5641cb179e93fb0f698fdb5f215b3864c578d910d9aGeorg Brandl script = 'open location "%s"' % url.replace('"', '%22') # opens in default browser 565e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl else: 566e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl # User called get and chose a browser 567e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl if self.name == "OmniWeb": 568e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl toWindow = "" 569e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl else: 570e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl # Include toWindow parameter of OpenURL command for browsers 571e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl # that support it. 0 == new window; -1 == existing 572e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl toWindow = "toWindow %d" % (new - 1) 5731cb179e93fb0f698fdb5f215b3864c578d910d9aGeorg Brandl cmd = 'OpenURL "%s"' % url.replace('"', '%22') 574e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl script = '''tell application "%s" 575e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl activate 576e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl %s %s 577e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl end tell''' % (self.name, cmd, toWindow) 578e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl # Open pipe to AppleScript through osascript command 579e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl osapipe = os.popen("osascript", "w") 580e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl if osapipe is None: 581e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl return False 582e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl # Write script to osascript's stdin 583e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl osapipe.write(script) 584e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl rc = osapipe.close() 585e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl return not rc 586e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl 5874d39f6e09a5c0a0e09eb51d678bacd1adaa3f2caRonald Oussoren class MacOSXOSAScript(BaseBrowser): 5884d39f6e09a5c0a0e09eb51d678bacd1adaa3f2caRonald Oussoren def __init__(self, name): 5894d39f6e09a5c0a0e09eb51d678bacd1adaa3f2caRonald Oussoren self._name = name 5904d39f6e09a5c0a0e09eb51d678bacd1adaa3f2caRonald Oussoren 5914d39f6e09a5c0a0e09eb51d678bacd1adaa3f2caRonald Oussoren def open(self, url, new=0, autoraise=True): 5924d39f6e09a5c0a0e09eb51d678bacd1adaa3f2caRonald Oussoren if self._name == 'default': 5934d39f6e09a5c0a0e09eb51d678bacd1adaa3f2caRonald Oussoren script = 'open location "%s"' % url.replace('"', '%22') # opens in default browser 5944d39f6e09a5c0a0e09eb51d678bacd1adaa3f2caRonald Oussoren else: 5954d39f6e09a5c0a0e09eb51d678bacd1adaa3f2caRonald Oussoren script = ''' 5964d39f6e09a5c0a0e09eb51d678bacd1adaa3f2caRonald Oussoren tell application "%s" 5974d39f6e09a5c0a0e09eb51d678bacd1adaa3f2caRonald Oussoren activate 5984d39f6e09a5c0a0e09eb51d678bacd1adaa3f2caRonald Oussoren open location "%s" 5994d39f6e09a5c0a0e09eb51d678bacd1adaa3f2caRonald Oussoren end 6004d39f6e09a5c0a0e09eb51d678bacd1adaa3f2caRonald Oussoren '''%(self._name, url.replace('"', '%22')) 6014d39f6e09a5c0a0e09eb51d678bacd1adaa3f2caRonald Oussoren 6024d39f6e09a5c0a0e09eb51d678bacd1adaa3f2caRonald Oussoren osapipe = os.popen("osascript", "w") 6034d39f6e09a5c0a0e09eb51d678bacd1adaa3f2caRonald Oussoren if osapipe is None: 6044d39f6e09a5c0a0e09eb51d678bacd1adaa3f2caRonald Oussoren return False 6054d39f6e09a5c0a0e09eb51d678bacd1adaa3f2caRonald Oussoren 6064d39f6e09a5c0a0e09eb51d678bacd1adaa3f2caRonald Oussoren osapipe.write(script) 6074d39f6e09a5c0a0e09eb51d678bacd1adaa3f2caRonald Oussoren rc = osapipe.close() 6084d39f6e09a5c0a0e09eb51d678bacd1adaa3f2caRonald Oussoren return not rc 6094d39f6e09a5c0a0e09eb51d678bacd1adaa3f2caRonald Oussoren 6104d39f6e09a5c0a0e09eb51d678bacd1adaa3f2caRonald Oussoren 611e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl # Don't clear _tryorder or _browsers since OS X can use above Unix support 612e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl # (but we prefer using the OS X specific stuff) 6134d39f6e09a5c0a0e09eb51d678bacd1adaa3f2caRonald Oussoren register("safari", None, MacOSXOSAScript('safari'), -1) 6144d39f6e09a5c0a0e09eb51d678bacd1adaa3f2caRonald Oussoren register("firefox", None, MacOSXOSAScript('firefox'), -1) 615b1a751b5c25b1969430197a6f5a58f49c1947effGuido van Rossum register("chrome", None, MacOSXOSAScript('chrome'), -1) 6164d39f6e09a5c0a0e09eb51d678bacd1adaa3f2caRonald Oussoren register("MacOSX", None, MacOSXOSAScript('default'), -1) 617e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl 618f7f185116a8274b105edc1be64ffc9c8061c7f43Eric S. Raymond 619f7f185116a8274b105edc1be64ffc9c8061c7f43Eric S. Raymond# OK, now that we know what the default preference orders for each 620f7f185116a8274b105edc1be64ffc9c8061c7f43Eric S. Raymond# platform are, allow user to override them with the BROWSER variable. 62154f0222547b1e92cd018ef132307a6f793dc9505Raymond Hettingerif "BROWSER" in os.environ: 622e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl _userchoices = os.environ["BROWSER"].split(os.pathsep) 623e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl _userchoices.reverse() 624e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl 625e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl # Treat choices in same way as if passed into get() but do register 626e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl # and prepend to _tryorder 627e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl for cmdline in _userchoices: 628e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl if cmdline != '': 6298719ad5ddefadbc08b56a0af91515f050c89c678Benjamin Peterson cmd = _synthesize(cmdline, -1) 6308719ad5ddefadbc08b56a0af91515f050c89c678Benjamin Peterson if cmd[1] is None: 6318719ad5ddefadbc08b56a0af91515f050c89c678Benjamin Peterson register(cmdline, None, GenericBrowser(cmdline), -1) 632e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl cmdline = None # to make del work if _userchoices was empty 633e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl del cmdline 634e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl del _userchoices 635e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl 636cdab3bf7eb0810fcda21be065868f3da330779a1Skip Montanaro# what to do if _tryorder is now empty? 637e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl 638e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl 639e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandldef main(): 640e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl import getopt 641e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl usage = """Usage: %s [-n | -t] url 642e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl -n: open new window 643e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl -t: open new tab""" % sys.argv[0] 644e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl try: 645e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl opts, args = getopt.getopt(sys.argv[1:], 'ntd') 646b940e113bf90ff71b0ef57414ea2beea9d2a4bc0Guido van Rossum except getopt.error as msg: 647be19ed77ddb047e02fe94d142181062af6d99dccGuido van Rossum print(msg, file=sys.stderr) 648be19ed77ddb047e02fe94d142181062af6d99dccGuido van Rossum print(usage, file=sys.stderr) 649e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl sys.exit(1) 650e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl new_win = 0 651e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl for o, a in opts: 652e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl if o == '-n': new_win = 1 653e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl elif o == '-t': new_win = 2 654b053cd8f40dd19985b16f50661640dcefb69888fGuido van Rossum if len(args) != 1: 655be19ed77ddb047e02fe94d142181062af6d99dccGuido van Rossum print(usage, file=sys.stderr) 656e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl sys.exit(1) 657e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl 658e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl url = args[0] 659e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl open(url, new_win) 660e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl 661be19ed77ddb047e02fe94d142181062af6d99dccGuido van Rossum print("\a") 66223929f2828078ee8fb115968f732d26bb9e4c1e3Georg Brandl 663e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandlif __name__ == "__main__": 664e8f244305ef4f257f6999b69601f4316b31faa5eGeorg Brandl main() 665