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
mailcapsystem 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-mailcapor 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-opencallsxdg-mime query filetype file.pdfto determine that its MIME type isapplication/pdf- it then queries
xdg-mimewhether there is some default application for this MIME type. - As I have no actual association, it starts looking for
*.dekstopentries supporting that MIME type. For each*.desktopfile it looks at theInitialPreferencefield to determine a good candidate. - as
libreoffice-draw.desktophappens to haveinitialPreference=5it 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-openscript 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-openinmailcap. But might result in circular calling in terminal sessions.