tl;dr:
In Debian xdg-open
(through xdg-mime
) does not follow the mailcap
specifications used by run-mailcap
which I prefer to use. Is there some systematic way to make xdg-open
follow the mailcap
entries? Ideally less hacky than to modify the xdg-open
script to always call run-mailcap
.
Context
Debian (as of 9.5 stretch) has several systems for setting up default applications, or more specifically, associating file extensions, MIME types and programs (or program actions). They are briefly reviewed in this answer. The two main ones with the greatest granularity (in terms of MIME associations) are
- The "more modern" XDG standard aimed at desktop environments
- The older
mailcap
system aimed more at mail agents and terminal environments (or desktop agnostic). It is described quite well in this answer.
The goal
I prefer to use the second mailcap system, because its wildcard mailcap.order
approach makes it very convenient to automatically associate an application with all (or a subset of) the MIME types it supports and can also differentiate between viewers and editors for a given MIME type. This system is also well tied into system updates, i.e. updating packages does not change the association order.
Execution entry points
Two two methods mentioned above have different entry points
- XDG uses
xdg-open
- the mailcap system uses
run-mailcap
or its aliases (view
,edit
)
However, different programs call different entry points, so the results may not be consistent. I'm trying to achieve that though.
xdg-open
may fallback on run-mailcap
Upon inspection of /usr/bin/xdg-open
provided by xdg-utils-1.1.1-1+deb9u1
it seems that xdg-open
will try to use xdg-mime
if a desktop is active (in a very generic sense, not necessarily a desktop environment), otherwise it may fallback on run-mailcap
if it is available.
# ... line 787 in /usr/bin/xdg-open
open_generic()
{
if is_file_url_or_path "$1"; then
local file="$(file_url_to_path "$1")"
check_input_file "$file"
if [ -n "$DISPLAY" ]; then
filetype=`xdg-mime query filetype "$file" | sed "s/;.*//"`
open_generic_xdg_mime "$file" "$filetype"
fi
if which run-mailcap 2>/dev/null 1>&2; then
run-mailcap --action=view "$file"
if [ $? -eq 0 ]; then
exit_success
fi
fi
# ...
Specific example of inconsistency
The goal is to have Evince as the default viewer for PDF, Djvu, etc.
I have evince:*/*
in /etc/mailcap.order
so after running (possibly automatically after updating packages) update-mime
entries such application/pdf; evince %s; test=test -n "$DISPLAY"
will come first in /etc/mailcap
. So launchers using run-mailcap
use Evince as I want.
However, when something uses xdg-open
, it will open PDF in Libreoffice Draw. The reason for this is (determined by inserting set -x
in the script):
xdg-open
callsxdg-mime query filetype file.pdf
to determine that its MIME type isapplication/pdf
- it then queries
xdg-mime
whether there is some default application for this MIME type. - As I have no actual association, it starts looking for
*.dekstop
entries supporting that MIME type. For each*.desktop
file it looks at theInitialPreference
field to determine a good candidate. - as
libreoffice-draw.desktop
happens to haveinitialPreference=5
it uses it.
Here is the detailed log of the xdg-mime query default call
with debugging information:
$ XDG_UTILS_DEBUG_LEVEL=3 xdg-mime query default application/pdf
Checking /home/$USER/.config/mimeapps.list
Checking /etc/xdg/mimeapps.list
Checking /home/$USER/.local/share/applications/mimeapps.list
Checking /usr/share//applications/mimeapps.list
Checking /home/$USER/.local/share/applications/defaults.list and
/home/$USER/.local/share/applications/mimeinfo.cache
Checking /home/$USER/.local/share/applications/defaults.list and
/home/$USER/.local/share/applications/mimeinfo.cache
Checking /usr/local/share//applications/defaults.list and
/usr/local/share//applications/mimeinfo.cache
Checking /usr/local/share//applications/defaults.list and
/usr/local/share//applications/mimeinfo.cache
Checking /usr/share//applications/defaults.list and
/usr/share//applications/mimeinfo.cache
Checking /usr/share//applications/defaults.list and
/usr/share//applications/mimeinfo.cache
Checking /home/$USER/.local/share/applications/wine-extension-pdf.desktop
Select /home/$USER/.local/share/applications/wine-extension-pdf.desktop
[ -1 => 0 ]
Checking /usr/share//applications/FoxitReader.desktop
Checking /usr/share//applications/evince.desktop
Checking /usr/share//applications/gimp.desktop
Checking /usr/share//applications/inkscape.desktop
Checking /usr/share//applications/libreoffice-draw.desktop
Select /usr/share//applications/libreoffice-draw.desktop [ 0 => 05 ]
Checking /usr/share//applications/mcomix.desktop
Checking /usr/share//applications/mupdf.desktop
Checking /usr/share//applications/pdf-presenter-console.desktop
Checking /usr/share//applications/vprerex.desktop
Checking /usr/share//applications/xpdf.desktop
Checking /usr/share//applications/zathura-pdf-poppler.desktop
libreoffice-draw.desktop
The numbers in [ X => ]
are obtained by calls such as awk -F= /InitialPreference=/ {print($2)} /usr/share//applications/libreoffice-draw.desktop
, I determined this by putting set -x
into the xdg-mime
script.
Proposed workarounds so far
Here are workarounds I thought of so far. I'm looking for some nicer, ideally more systematic solution.
-
One option is to modify the
xdg-open
script to always fallback torun-mailcap
. But that is a bit of a hack. Even if I usedpkg-divert
, it still means I have to maintain it myself. -
Use the XDG system and put somethign like
*/*:xdg-open
inmailcap
. But might result in circular calling in terminal sessions.
Best Answer
I'm frequently puzzled by various
xdg-open
limitations, too.I don't pretend to be complete here, but I'm using the following desktop entry:
and delegate everything to it in my
mimeapps.list
:Theoretically, it's possible to convert this and/or your custom diversions of
xdg-open
to a virtualxdg-utils
implementation.