2016-06-14
Some notes on how xdg-open
picks which web browser to use
Let's start with my tweet:
It sure would be convenient if xdg-open documented how it picked which browser to use, so you could maybe change that to one you like.
XDG here is what used to be called the 'X Desktop Group' and is now
freedesktop.org (per wikipedia). As you might then
guess, xdg-open
the program is the canonical KDE/GNOME/etc agnostic
way of opening (among other things) an URL in whatever is nominally
your preferred browser. Since providing a web interface as your
package's UI is an increasingly common thing to do these days, there
are any number of programs and scripts and so on that want to do
this and do it by just running xdg-open
, which gives you whatever
strange browser
xdg-open
decided to inflict on you today.
If you read the xdg-open
manpage, it's remarkably
uninformative about how it decides what your default or preferred
web browser is. On the one hand xdg-open
is currently a shell
script so you could just read it to find this out; on the other
hand, it's a 900+ line shell script full of stuff, which makes it
not exactly clear 'documentation'. So here are some notes on the
current behavior, boiled down to the useful bits.
(Because none of this is documented, freedesktop.org is free to change it at any time if they feel like it. They probably won't, though.)
Broadly, xdg-open
does the following when you ask it to open an
URL:
- first, it tries to figure out if you're running a desktop
environment that it knows about. If you are, it uses the
desktop's own mechanism to open URLs if there is one (these
are things like
kde-open
,gvfs-open
, andexo-open
). The important thing here is that this should automatically respect your normal desktop browser preference, since it's using the same mechanism. - if
$BROWSER
is set, it's used immediately. I'll discuss what it can be set to later. - in some but not all versions of
xdg-open
, it will attempt to determine the correct program to handle the nominal MIME type of 'x-scheme-handler/http' (or https, or ftp, or whatever) and then run this program. This determination is made byxdg-mime
; how it works is complicated enough to require another entry.In versions of
xdg-open
that support this, it's extremely likely that this will produce a result andxdg-open
will never go on to its final option. - if all else fails,
xdg-open
tries to run a whole bunch of possible browsers (via the$BROWSER
mechanism). The most important thing about this is that the first default browserxdg-open
tries isx-www-browser
.
Some but not all Linux distributions have a /usr/bin/x-www-browser
.
If yours has one, it may or may not point to something useful or
what you want, and it may vary from version to version (and on what
packages you wind up installing). For example, on our Ubuntu 12.04
and 14.04 machines x-www-browser
points to arora by default,
which is not what I consider a particularly good choice on machines
with Firefox installed (it's certainly likely to puzzle users who
wind up running it). On 16.04 it points to Chromium, which is at
least a plausible default choice.
On current Fedora and Ubuntu 16.04, the full list of (graphical) browsers, in order, is:
x-www-browser firefox iceweasel seamonkey mozilla epiphany konqueror chromium-browser google-chrome
The useful thing here is that xdg-open
searches for all of these
using your $PATH
, so you can create a personal x-www-browser
symlink that points to whatever you want without having to risk
unintended side effects from eg setting $BROWSER
.
If your xdg-open
uses xdg-mime
, you can determine what
program it will use (more or less) by running eg:
$ xdg-mime query default x-scheme-handler/http firefox.desktop
Xdg-mime will let you set this stuff as well as query it, but of
course doing so may have more consequences than just changing
xdg-open
's behavior. However at that point there is no really
good solution; if xdg-open
is consulting xdg-mime
, I think all
you can do is either set $BROWSER
or set xdg-mime
's defaults.
(If you're setting scheme handlers in xdg-mime
, remember to get
at least http
and https
, and perhaps ftp
as well.)
While the xdg-open
manpage will refer you to the xdg-settings
manpage,
this is potentially quite misleading. If you aren't using a desktop
environment, there's no guarantee that what xdg-settings
reports
as your default browser is what xdg-open
will necessarily run.
The two scripts use different code and as far as I can tell, neither
makes any particular attempt to carefully duplicate each other's
logic.
(If you are running a desktop environment that xdg-settings
knows about, well, you're at the mercy of how well it can read
out your DE's default browser. I wouldn't hold my breath there.)
Sidebar: What $BROWSER
can be set to
As xdg-open
interprets it, $BROWSER
is a colon separated list
of commands, not just program names (ie you can include things
like command line switches). A command may contain a %s
, which
will be substituted with the URL to be opened; otherwise the URL
is just tacked on the end of the command. Xdg-open does not exactly
have sophisticated handling of quoting and argument splitting or
anything, so I would do nothing tricky here; I wouldn't even really
trust the %s
substitution. If you think you need it, use a cover
shell script.
How xdg-mime
searches for MIME type handlers (more or less)
XDG is what was once called the X Desktop Group and is now
freedesktop.org. Part of their
work is to create various cross-desktop and desktop agnostic standards
and tools for how to do things like determine what program should
handle a particular MIME type. This includes special 'scheme' MIME
types, like x-scheme-handler/ftp
, which means 'whatever should
handle FTP' (technically this is 'FTP urls').
The XDG tool for mapping MIME types to programs (actually .desktop
files) is xdg-mime
. Like all of
the XDG tools, xdg-mime
uses a collection of environment variables,
which will normally have the default values covered in the XDG
base directory specification.
In theory there are two sorts of data that xdg-mime
looks at. The
first, found in files called <desktop>-mimeapps.list
and
mimeapps.list
, is supposed to be a set of specifically chosen
applications (whether configured by the user or the system). The
second is a general cache of MIME type mapping information based
on what program can handle what MIME types (as listed in each
program's .desktop
file); these are found in files called
defaults.list
and mimeinfo.cache
. In practice, a system
mimeapps.list
file may have just been slapped together based on
what the distribution thought was a good idea, and it may not
correspond to what you want (or even what you have installed).
(Not all Linux distributions ship a system mimeapps.list
.
Fedora does; Ubuntu doesn't.)
Xdg-mime searches for mimeapps.list
in any of $XDG_CONFIG_HOME
,
$XDG_CONFIG_DIRS
, and the 'applications
' subdirectories of
$XDG_DATA_HOME
and $XDG_DATA_DIRS
. It searches for the other
two files only in the applications
subdirectories of $XDG_DATA_HOME
and $XDG_DATA_DIRS
.
Now, we get to an important consequence of this. $XDG_DATA_DIRS
is normally two directories, /usr/local/share
and /usr/share
,
each of which has MIME type information only for itself, and they
are checked in order. The normal result of this is that things
installed into /usr/local
steal MIME types from things installed
in /usr
because xdg-mime
will check the
/usr/local/share/applications
files first.
(I discovered this when I installed Google Chrome on my laptop and
it promptly stole URL handling from Firefox, which I did not want,
because the RPM put bits into /usr/local
instead of /usr
.
Actually finding the files that controlled this was remarkably
hard.)
Normally, nothing automatically generates or updates the system
mimeapps.list
; on Fedora, it's part of the shared-mime-info
RPM
(and kde-settings
for the kde-mimeapps.list
version). The
mimeinfo.cache
files are maintained by update-desktop-database
,
which will normally be automatically run on package installs, removals,
and probably upgrades.
Now, xdg-mime
does not give you an actual program to run. What
it does is give you the name of a .desktop
file, eg firefox.desktop
.
In order to use this to run a program, you must look through the
right magic places to find the .desktop
file and then parse it
to determine the command line to run. Probably you don't want to
do this yourself, but I don't know what your alternative is; as far
as I know, there is no XDG tool script to say 'run this .desktop
command with the following arguments'.
(Note that the .desktop
file is not necessarily in the same
directory as the MIME mapping file that caused it to be the handler
application. For example, your $HOME/.local/share/applications
might just have various MIME type overrides you've set for what
system application should handle what.)
This explanation is somewhat dependent on what exact version of the XDG tools and scripts you have installed. It's also not necessarily totally complete, because I am reading through undocumented shell scripts here and I've left a few things out. See the Arch wiki entry on default applications for much more information.
PS: If you're trying to track down why xdg-mime
is giving you
some strange result, set $XDG_UTILS_DEBUG_LEVEL
to at least
'2'. This will tell you just what files it looked at when,
although I don't think it ever reports what directories it looked
at but didn't find any files in.