The last step of my laptop migration was to fix mime type associations, that seem to associate opening file depending on whatever application was installed last, phases of the moon, and what option is the most annoying.
The state of my system after a fresh install, is that, for application/pdf
,
xdg-open
(used for example by pcmanfm) runs inkscape, and run-mailcap
(used
for example by neomutt) runs the calibre ebook viewer.
It looks like there are at least two systems to understand, debug and fix, instead of one.
xdg-open
This comes from package
xdg-utils, and works using
.desktop
files:
# This runs inkscape
$ xdg-open file.pdf
There is a tool called xdg-mime
that queries what .desktop
file is
associated with a given mime type:
$ xdg-mime query default application/pdf
inkscape.desktop
You can use xdg-mime default
to change an association, and it works nicely:
$ xdg-mime default org.gnome.Evince.desktop application/pdf
$ xdg-mime query default application/pdf
org.gnome.Evince.desktop
However, if you accidentally mistype the name of the .desktop
file, it won't
complain and it will silently reset the association to the arbitrary default:
$ xdg-mime default org.gnome.Evince.desktop application/pdf
$ xdg-mime query default application/pdf
org.gnome.Evince.desktop
$ xdg-mime default evince.desktop application/pdf
$ echo $?
0
$ xdg-mime query default application/pdf
inkscape.desktop
You can use a GUI like xfce4-mime-settings
from the xfce4-settings
package
to perform the same kind of changes avoiding typing mistakes.
The associations seem to be saved in ~/.config/mimeapps.list
run-mailcap
This comes from the package mime-support
You can test things by running it using --norun
:
$ run-mailcap --norun file.pdf
ebook-viewer file.pdf
run-mailcap
uses the ~/.mailcap
and /etc/mailcap
to map mime types to
commands. This is what's in the system default:
$ grep application/pdf /etc/mailcap
application/pdf; ebook-viewer %s; test=test -n "$DISPLAY"
application/pdf; calibre %s; test=test -n "$DISPLAY"
application/pdf; gimp-2.10 %s; test=test -n "$DISPLAY"
application/pdf; evince %s; test=test -n "$DISPLAY"
To fix this, I copypasted the evince line into ~/.mailcap
, and indeed it gets
used:
$ run-mailcap --norun file.pdf
evince file.pdf
There is a /etc/mailcap.order
file providing a limited way to order entries
in /etc/mailcap
, but it can only be manipulated system-wide, and cannot be
used for user preferences.
Sadly, this means that if a package changes its mailcap invocation because of, say, a security issue in the former one, the local override will never get fixed.
I am really not comfortable about that. As a workaround, I put this in my
~/.mailcap
:
application/pdf; xdg-open %s && sleep 0.3s; test=test -n "$DISPLAY"; nametemplate=%s.pdf
The sleep 0.3s
is needed because xdg-open
exits right after starting the
program, and when invoked by mutt it means that mutt could delete the
attachment before evince has a chance to open it. I had to use the same
workaround for sensible-browser
, since the same happens when a browser opens
a document in an existing tab. I feel like writing some wrapper about all this
that forks the viewer, then waits for an IN_OPEN
event on its argument via
inotify before exiting.
I wonder if there is any reason run-mailcap
could not be implemented as a
wrapper to xdg-open
.
I reported #964723 elaborating on these thoughts.
Update: added nametemplate
to the example, thanks François Marier