xdg-settings: Setting a default browser isn't that simple
Table of Contents
What is xdg-settings?
xdg-settings
is part of the xdg-utils and according to its manpage it can query, check for and set different properties of an XDG-desktop.
Running xdg-settings --list
reveals that it only ever got implementations for setting the default web browser and for setting URL-scheme handlers (which is the more generic case of setting a default web browser).
The reason I started looking into this is because someone opened an issue about
xdg-open
ignoring theBROWSER
variable, which turned out to bexdg-settings
giving out misinformation about the order of variables.
This is good by the way! if you notice something broken with a tool open an issue, even if you are wrong about the part that is broken.
Someone will help figuring out the actual issue, especially in systems with multiple components where a weirdness in one place can be the symptom of an error somewhere else.
I'll take a look at the current git HEAD with the commit hash 0f6385262417f1c0c4d13bc05d95c32578272b64
, though xdg-settings
hasn't been touched for years, so this also applies to the 1.2.1
version you probably still have. (except for Lxqt, that one is new)
xdg-settings makes use of some common functionality I already described when taking apart xdg-open.
Overview over xdg-settings
Inside xdg-settings, it is split up into multiple sections. That is helper functions for browser setting, MIME related functionality, desktop specific functionality.
Desktops that have their own sections are:
- KDE
- Deepin
- GNOME (Gnome 2 that is)
- GNOME 3.x
- Lxqt
- Xfce
- generic
While browsing the sections one will also notice common function prefixes:
get_browser_
check_browser_
set_browser_
get_url_scheme_handler_
check_url_scheme_handler_
set_url_scheme_handler_
There is also a big dispatch function (dispatch_specific
) that calls the appropriate function based on the given handler and the requested command. The handler is derived based on the detected desktop environment (see the xdg-open article on desktops to learn how that works) in a switch statement right at the end of the file.
The desktops are translated as follows:
Desktop | Handler |
---|---|
kde | kde |
deepin | deepin |
gnome | gnome |
gnome3 | gnome3 |
cinnamon | gnome3 |
lxde | lxde |
mate | mate |
lxqt | lxqt |
xfce | xfce |
generic | generic |
enlightenment | generic |
wsl
, cygwin
, darwin
and flatpak
error with "unknown desktop environment".
Listing the supported settings
Listing the supported settings is implemented in an interesting way.
The dispatch function contains multiple switch-case statements for the supported parameters, one of each line is annotated with comment, #PROP: {description goes here}
. The list function greps the file for line containing that comment and then uses some regex magic to format that into a human readable list.
The helper functions
get_browser_mime <mimetype>
- A wrapper around
xdg-mime query default $1
that defaults totext/html
. fix_local_desktop_file <desktop-file-name> <mimetype>
- If a desktop file exists locally for the user make sure it has a given mime-type in its list of supported mime types.
set_browser_mime <desktop-file-name> <mimetype>
- This attempts to undo any desktop changes using
fix_local_desktop_file
and then usesxdg-mime default
to set the default browser, checks if the change happened and sets it back if the change didn't have the desired effect.
Generic Browser configuration
The generic browser configuration makes use of the already mentioned helper functions.
Getting the default Browser
This is implemented in get_browser_generic
.
If the BROWSER
environment variable is set, the script tries resolving the command to a desktop file, and if successful outputs that as the default browser. If not the script continues.
If the mimetype x-scheme-handler/http
resolves to a desktop file that is returned as the default browser. If not the script continues.
Bug Note: The order of first checking the BROWSER
variable and then checking the mimetype is reversed from how xdg-open
reads them. It also puts a less granular configuration mechanism over a more granular one. I consider this a bug.
If the binary x-www-browser
resolves to a desktop file that is returned.
Otherwise the script exits wit exit code 4
(Action failed)
Checking the default Browser
Checking the default Browser is distinct from getting and comparing the default browser in that instead of checking the first setting that gives a sensible value it checks all relevant settings and only returns true if all of those settings apply.
This is implemented in check_browser_generic
.
There are three functions that have to resolve to the given desktop file before the check function says yes
, that is the default browser:
- The browser getting function
get_browser_generic
- Resolving the handler for the
text/html
mimetype - Resolving the scheme handler for
https
Setting the default Browser
This is implemented in set_browser_generic
.
Bug Note: This function errors if the BROWSER
environment variable is set, this is related to xdg-settings
considering BROWSER
to be higher priority than the more granular x-scheme-handler/
mimetypes.
After testing for the BROWSER
environment variable the set function tests if the desktop file resolves to a binary, this makes sure that the requested file exists and has a non-empty Exec
key which is the minimum needed to actually open URLs.
It the n uses the set_browser_mime
to set the following mimetypes to be handled by the requested desktop file:
text/html
x-scheme-handler/http
x-scheme-handler/https
x-scheme-handler/about
x-scheme-handler/unknown
Generic URL scheme configuration
Generic URL scheme configuration is mostly wrapping around the already described helpers with some special treatment for the http
and https
schemes when the BROWSER
environment variables are set.
Getting the scheme handler
This is implemented in get_url_scheme_handler_generic
.
Passes the call through to the get_browser_mime
helper with the mimetype x-scheme-handler/{scheme}
.
Except when BROWSER
is set and the scheme is either http
or https
, then it calls get_browser_generic
.
Checking the scheme handler
This is implemented in check_url_scheme_handler_generic
.
Tests if the desktop file resolves to a binary and if so it tests if it is returned by get_url_scheme_handler_generic
.
Setting the URLs scheme handler
This is implemented in set_url_scheme_handler_generic
.
Bug Note: This function again has special handling for BROWSER
being set the scheme being http
or https
that it refuses to work with an error message that it can't change the BROWSER
variable.
If the desktop file resolves to a command it uses set_browser_mime
with x-scheme-handler/{scheme}
as the mimetype.
To be continued …
This post won't cover the special cases for each desktop. I'm taking a slow start to 2025 and will describe those in a followup post.
Reading through xdg-settings
really shows that it hasn't been maintained for a while (which isn't surprising given that the xdg-utils were effectively abandoned for multiple years).
This is a call to action and for help: See if your favourite desktop is implemented correctly in xdg-settings
and if not open an issue or merge request. I'll help you if you want.
Thanks for reading, I hope you had an incident free calendar rollover!