Skip to content

Commit e3ce695

Browse files
davesteelencoghlan
authored andcommitted
bpo-24241: Improve preferred webbrowser handling (#85)
- Add 'preferred' argument to webbrowser.register - Use xdg-settings to specify preferred X browser The first change replaces the existing undocumented tri-state 'try_order' parameter with the documented boolean keyword-only 'preferred' parameter. Setting it to True places the browser at the front of the list, preferring it as the return to a subsequent get() call. The second change adds a private `_os_preferred_browser` setting and then uses that to make the default browser reported by `xdg-settings` first in the try list when running under X (or another environment that sets the `DISPLAY` variable). This avoids the problem where the first entry in the tryorder queue otherwise defaults to xdg-open, which doesn't support the "new window" option.
1 parent e3bf4cd commit e3ce695

File tree

4 files changed

+37
-16
lines changed

4 files changed

+37
-16
lines changed

‎Doc/library/webbrowser.rst‎

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -83,17 +83,19 @@ The following functions are defined:
8383
caller's environment.
8484

8585

86-
.. function:: register(name, constructor, instance=None)
86+
.. function:: register(name, constructor, instance=None, *, preferred=False)
8787

8888
Register the browser type *name*. Once a browser type is registered, the
8989
:func:`get` function can return a controller for that browser type. If
9090
*instance* is not provided, or is ``None``, *constructor* will be called without
9191
parameters to create an instance when needed. If *instance* is provided,
9292
*constructor* will never be called, and may be ``None``.
9393

94-
This entry point is only useful if you plan to either set the :envvar:`BROWSER`
95-
variable or call :func:`get` with a nonempty argument matching the name of a
96-
handler you declare.
94+
Setting *preferred* to ``True`` makes this browser a preferred result for
95+
a :func:`get` call with no argument. Otherwise, this entry point is only
96+
useful if you plan to either set the :envvar:`BROWSER` variable or call
97+
:func:`get` with a nonempty argument matching the name of a handler you
98+
declare.
9799

98100
A number of browser types are predefined. This table gives the type names that
99101
may be passed to the :func:`get` function and the corresponding instantiations

‎Lib/webbrowser.py‎

Lines changed: 25 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -13,16 +13,21 @@
1313
class Error(Exception):
1414
pass
1515

16-
_browsers = {} # Dictionary of available browser controllers
17-
_tryorder = [] # Preference order of available browsers
16+
_browsers = {} # Dictionary of available browser controllers
17+
_tryorder = [] # Preference order of available browsers
18+
_os_preferred_browser = None # The preferred browser
1819

19-
def register(name, klass, instance=None, update_tryorder=1):
20-
"""Register a browser connector and, optionally, connection."""
20+
def register(name, klass, instance=None, *, preferred=False):
21+
"""Register a browser connector."""
2122
_browsers[name.lower()] = [klass, instance]
22-
if update_tryorder > 0:
23-
_tryorder.append(name)
24-
elif update_tryorder < 0:
23+
24+
# Preferred browsers go to the front of the list.
25+
# Need to match to the default browser returned by xdg-settings, which
26+
# may be of the form e.g. "firefox.desktop".
27+
if preferred or (_os_preferred_browser and name in _os_preferred_browser):
2528
_tryorder.insert(0, name)
29+
else:
30+
_tryorder.append(name)
2631

2732
def get(using=None):
2833
"""Return a browser launcher instance appropriate for the environment."""
@@ -484,6 +489,14 @@ def register_X_browsers():
484489

485490
# Prefer X browsers if present
486491
if os.environ.get("DISPLAY"):
492+
try:
493+
cmd = "xdg-settings get default-web-browser".split()
494+
result = subprocess.check_output(cmd).decode().strip()
495+
except (FileNotFoundError, subprocess.CalledProcessError):
496+
pass
497+
else:
498+
_os_preferred_browser = result
499+
487500
register_X_browsers()
488501

489502
# Also try console browsers
@@ -610,10 +623,10 @@ def open(self, url, new=0, autoraise=True):
610623

611624
# Don't clear _tryorder or _browsers since OS X can use above Unix support
612625
# (but we prefer using the OS X specific stuff)
613-
register("safari", None, MacOSXOSAScript('safari'), -1)
614-
register("firefox", None, MacOSXOSAScript('firefox'), -1)
615-
register("chrome", None, MacOSXOSAScript('chrome'), -1)
616-
register("MacOSX", None, MacOSXOSAScript('default'), -1)
626+
register("safari", None, MacOSXOSAScript('safari'), preferred=True)
627+
register("firefox", None, MacOSXOSAScript('firefox'), preferred=True)
628+
register("chrome", None, MacOSXOSAScript('chrome'), preferred=True)
629+
register("MacOSX", None, MacOSXOSAScript('default'), preferred=True)
617630

618631

619632
# OK, now that we know what the default preference orders for each
@@ -628,7 +641,7 @@ def open(self, url, new=0, autoraise=True):
628641
if cmdline != '':
629642
cmd = _synthesize(cmdline, -1)
630643
if cmd[1] is None:
631-
register(cmdline, None, GenericBrowser(cmdline), -1)
644+
register(cmdline, None, GenericBrowser(cmdline), preferred=True)
632645
cmdline = None # to make del work if _userchoices was empty
633646
del cmdline
634647
del _userchoices

‎Misc/ACKS‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1458,6 +1458,7 @@ Quentin Stafford-Fraser
14581458
Frank Stajano
14591459
Joel Stanley
14601460
Anthony Starks
1461+
David Steele
14611462
Oliver Steele
14621463
Greg Stein
14631464
Marek Stepniowski

‎Misc/NEWS‎

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -433,6 +433,11 @@ Library
433433
- Issue #23262: The webbrowser module now supports Firefox 36+ and derived
434434
browsers. Based on patch by Oleg Broytman.
435435

436+
- Issue #24241: The webbrowser in an X environment now prefers using the
437+
default browser directly. Also, the webbrowser register() function now has
438+
a documented 'preferred' argument, to specify browsers to be returned by
439+
get() with no arguments. Patch by David Steele
440+
436441
- Issue #27939: Fixed bugs in tkinter.ttk.LabeledScale and tkinter.Scale caused
437442
by representing the scale as float value internally in Tk. tkinter.IntVar
438443
now works if float value is set to underlying Tk variable.

0 commit comments

Comments
 (0)