This page describes the classes in the xdg package. These provide an interface to that part of the freedesktop XDG database which contains information about mime types, applications and icons, as described in the specifications found on https://specifications.freedesktop.org/.
This program, found in the examples
subdirectory, is useful for examining the results from various calls into the xdg
classes. Run
lsxdg -?
to get a list of the various query commands; these are described in detail below.
The xdg.BaseDir
class provides some static methods to determine the XDG base directories, as described in https://specifications.freedesktop.org/basedir-spec/basedir-spec-latest.html.
Run
lsxdg dirs
to see the various directory settings. Example output might be :-
Data Home: /home/rparlett/.local/share
Data Dirs: /usr/local/share (C)
Data Dirs: /usr/share (C)
Data Dirs: /var/lib/snapd/desktop (C)
Config Home: /home/rparlett/.config
Config Dirs: /etc/xdg
The “(C)” indicates a directory which will use a “mimeinfo.cache” file if present; this is described further below.
The xdg.Mime
class provides static methods to lookup mime information. The relevant specification is https://specifications.freedesktop.org/shared-mime-info-spec/shared-mime-info-spec-latest.html.
The most basic method, xdg.Mime.get_mime_type_for_file()
, maps a file name (just the name, not a path) to a mime type. Note that the content of a file is not examined; in fact it makes no difference whether the file even exists. The derivation depends solely on the name itself. Thus, the sections in the above specification relating to “magic” data are not implemented by the xdg
package.
The mime
command of lsxdg
shows the output for a given name or names :-
$ lsxdg mime junk.pdf junk.jpg README Makefile junk
junk.pdf: application/pdf
junk.jpg: image/jpeg
README: text/x-readme
Makefile: text/x-makefile
Note that the last one, “junk”, gave no result, meaning get_mime_type_for_file()
failed because no mime type could be deduced from that name.
Each mime type may have alternative mime types. Each alternative is either equivalent, or a broader type than the original. xdg.Mime.alternative_mime_types()
generates the alternatives for a mime type, and lsxdg
may be used to see the results :-
$ lsxdg alt-mime application/xml
application/xml
text/xml
text/plain
application/octet-stream
Note that the original input is the first result generated. The method tries to generate the other results in a reasonable order, with the closest alternatives first, and the most general last.
The Mime
class also maps mime types to icon names. These are distinct from actual icon files. The further mapping from icon names to icon files depends on the particular icon theme in use, and is described below.
The specification describes two icon mappings - “icons” and “generic icons”. These mappings are retrieved with the methods xdg.Mime.gen_icons()
and xdg.Mime.gen_generic_icons()
respectively. lsxdg
has two corresponding commands :-
$ lsxdg icons video/webm
video-x-generic
$ lsxdg generic-icons application/x-archive
package-x-generic
More useful is the xdg.Mime.gen_all_icons()
which combines both of the above methods, and adds between them a default icon name based on the mime type name itself. lsxdg
has a corresponding command :-
$ lsxdg all-icons video/webm
video-x-generic
video-webm
mira $ lsxdg all-icons application/x-archive
application-x-archive
package-x-generic
Note how, in the video/webm
example above, the name from the “icons” entry comes before the default name (video-webm
), and thus overrides it when searching for an actual icon file.
The xdg.IconTheme
class provides static methods to find icon files from the icon names described in the last section. The relevant specification is https://specifications.freedesktop.org/icon-theme-spec/icon-theme-spec-latest.html
The environment variable OI_THEME
can be used to specify the theme to use. Themes are searched for in the “icons” subdirectory of the data directories. To check the theme has been found, use
lsxdg theme
which will report the name of the theme in use.
If no theme is specified with OI_THEME
, then, if present, the “oxygen” or “gnome” themes are used. As a final fallback, “hicolor” is used.
The xdg.IconTheme.find_icon()
method searches for an icon of a particular name, size and scale. The latter setting is optional, and defaults to the gui package’s scale setting.. lsxdg
may be used to see the results of this method, as follows :-
$ lsxdg find-icon application-pdf 35
/usr/share/icons/oxygen/base/32x32/mimetypes/application-pdf.png
To combine the mapping from file names to icon names described in the previous section, with the mapping from icon names to icon files described in this section, the method xdg.Mime.find_icon_for_file()
can be used. lsxdg
may again be used to test this method :-
$ lsxdg icon-file junk.pdf 35
/usr/share/icons/oxygen/base/32x32/mimetypes/application-pdf.png
The xdg.Mime
class described above also provides methods to lookup desktop entries. These are “.desktop” files, each of which contains information about a particular application. The relevant specification in this case is https://specifications.freedesktop.org/desktop-entry-spec/desktop-entry-spec-latest.html.
The method xdg.Mime.gen_desktop_entries()
generates the desktop entries for a given mime type. lsxdg
can be used to show the results as follows :-
$ lsxdg de application/pdf
object xdg.DesktopEntry#6(
name=u"Okular"
icon="okular"
source="/usr/share/applications/okularApplication_pdf.desktop"
exec=u"okular %U"
exec_line=&null
path=&null
terminal=&null
initial_preference=8
)
object xdg.DesktopEntry#9(
name=u"Document Viewer"
icon="org.gnome.Evince"
source="/usr/share/applications/org.gnome.Evince.desktop"
exec=u"evince %U"
exec_line=&null
path=&null
terminal=&null
initial_preference=0
)
... etc
The results are generated in “preferred order”, with the most preferred coming first.
xdg.Mime.gen_all_desktop_entries()
is like the above, but extends the results by including those additional desktop entries for any alternative mime types. The corresponding lsxdg
command is all-de
. So, for example we can contrast :-
$ lsxdg de application/xml
object xdg.DesktopEntry#1(
name=u"Firefox Web Browser"
icon="firefox"
source="/usr/share/applications/firefox.desktop"
exec=u"firefox %u"
exec_line=&null
path=&null
terminal=&null
initial_preference=0
)
object xdg.DesktopEntry#2(
name=u"Google Chrome"
icon="google-chrome"
source="/usr/share/applications/google-chrome.desktop"
exec=u"/usr/bin/google-chrome-stable %U"
exec_line=&null
path=&null
terminal=&null
initial_preference=0
)
with
$ lsxdg all-de application/xml
object xdg.DesktopEntry#1(
name=u"Firefox Web Browser"
icon="firefox"
source="/usr/share/applications/firefox.desktop"
exec=u"firefox %u"
exec_line=&null
path=&null
terminal=&null
initial_preference=0
)
object xdg.DesktopEntry#2(
name=u"Google Chrome"
icon="google-chrome"
source="/usr/share/applications/google-chrome.desktop"
exec=u"/usr/bin/google-chrome-stable %U"
exec_line=&null
path=&null
terminal=&null
initial_preference=0
)
object xdg.DesktopEntry#3(
name=u"Run GNU Emacs"
icon="emacs"
source="/home/rparlett/.local/share/applications/runemacs.desktop"
exec=u"/home/rparlett/bin/runemacs.sh %F"
exec_line=u"/home/rparlett/bin/runemacs.sh +%P %F"
path=&null
terminal=&null
initial_preference=20
)
... etc, for more text editors and viewers
Note how the second command includes more general, but still useful, commands relating to application/xml
’s parent type of text/plain
.
Two further useful methods use the last method with file names. xdg.Mime.gen_desktop_entries_for_file()
takes a file (not a path), finds its mime type, and then generates the results of gen_all_desktop_entries()
. The corresponding lsxdg
command is de-file
. Thus :-
$ lsxdg de-file junk.xml
will generate the same results as the second command shown above.
xdg.Mime.gen_desktop_entries_for_path()
, is similar, but takes a file path (instead of a simple name), and checks whether it is a directory. If so, it generates the desktop entries for the special mime type inode/directory
; otherwise it takes the last path element and applies it to gen_desktop_entries_for_file()
. The corresponding lsxdg
command is de-path
:-
$ lsxdg de-path /
object xdg.DesktopEntry#2(
name=u"Google Chrome"
icon="google-chrome"
source="/usr/share/applications/google-chrome.desktop"
exec=u"/usr/bin/google-chrome-stable %U"
exec_line=&null
path=&null
terminal=&null
initial_preference=0
)
object xdg.DesktopEntry#1(
name=u"Firefox Web Browser"
icon="firefox"
source="/usr/share/applications/firefox.desktop"
exec=u"firefox %u"
exec_line=&null
path=&null
terminal=&null
initial_preference=0
)
This file is used to customize the mime-type to desktop file associations, and their preferred order. The relevant specification in this case is https://specifications.freedesktop.org/mime-apps-spec/mime-apps-spec-latest.html. Note that the xdg
package does not handle the “Default Applications” section in line with the specification. Having a default application as well as a most preferred application is too confusing; thus the “Default Applications” section is treated in the same way as the “Added Associations” section, with the former having priority. In other words, a mimeapps.list
file like this :-
[Added Associations]
text/html=a.desktop;b.desktop
[Default Applications]
text/html=x.desktop;y.desktop
is treated as if it were :-
[Added Associations]
text/html=x.desktop;y.desktop;a.desktop;b.desktop
These files, which don’t seem to be mentioned in any of the above standards, contain a summary of the mappings of the mime associations contained in the “desktop” files in a particular directory. This saves having to open, read and parse all of the desktop files when initializing the database. The downside of course is that the cache file may be out of date.
By default, the xdg
package only uses cache files which reside in the system data directories (ie, those specified by the environment variable XDG_DATA_DIRS
). Any cache file in XDG_DATA_HOME
will be ignored. This allows easier editing and testing of desktop files in the user’s personal directory.
This behaviour may be altered my setting the environment variable OI_XDG_MIMEINFO_CACHE_DIRS
. If this variable is unset, or empty, then the behaviour is as just described. If it is set, then it specifies a path variable, and only directories in one of its elements will use a cache file.
Which data directories may use a cache may be seen with the dirs
command of lsxdg
and noting which has a “(C)” after its name. So for example :-
$ lsxdg dirs
Data Home: /home/rparlett/.local/share
Data Dirs: /usr/local/share (C)
Data Dirs: /usr/share (C)
Data Dirs: /var/lib/snapd/desktop (C)
Config Home: /home/rparlett/.config
Config Dirs: /etc/xdg
$ # Restrict cache use to just one directory
$ export OI_XDG_MIMEINFO_CACHE_DIRS=/usr/share
mira $ lsxdg dirs
Data Home: /home/rparlett/.local/share
Data Dirs: /usr/local/share
Data Dirs: /usr/share (C)
Data Dirs: /var/lib/snapd/desktop
Config Home: /home/rparlett/.config
Config Dirs: /etc/xdg
The xdg
package adds a non-standard key to the desktop file, namely ExecLine
. This is used to enable a command with additional non-standard field codes to be used. These are described further in the documentation for flowterm, the program for which they were devised.
To see the command lines, derived from the desktop files, which may be used to launch a particular application for a file (or URL), use the following lsxdg
commands :-
$ lsxdg cmd junk.pdf
okular /tmp/junk.pdf
evince /tmp/junk.pdf
... etc
$ lsxdg cmd-url http://junk.com
/usr/bin/google-chrome-stable http://junk.com/
firefox http://junk.com/
Some desktop files specify that their application should be launched in a terminal window (an example is the vim
editor). The particular terminal program that the xdg
package uses to launch such applications can be seen by running :-
$ lsxdg term-cmd
xterm -e
This setting can be customized by setting the environment variable OI_XDG_TERM_CMD
; for example to use konsole
:-
export OI_XDG_TERM_CMD="konsole -e"
This section contains some notes about how the various XDG database files can be edited to customize various settings. Of course most desktop environments will provide software which will perform at least some of these tasks in a more user-friendly way.
If you are using Object Icon (or Icon) as a programming language, it is very useful to add a custom mime type to associate with “.icn” files. To do this, create a mime/packages
directory under your XDG_DATA_HOME
directory, which is by default ~/.local/share
:-
mkdir -p ~/.local/share/mime/packages
Then copy this file into the directory.
Download text-x-objecticon.xml
<?xml version="1.0" encoding="UTF-8"?>
<mime-info xmlns="http://www.freedesktop.org/standards/shared-mime-info">
<mime-type type="text/x-objecticon">
<comment>Object Icon source code</comment>
<sub-class-of type="text/plain"/>
<glob pattern="*.icn"/>
</mime-type>
</mime-info>
Finally, run :-
update-mime-database ~/.local/share/mime
to create the various XDG database files. Now lsxdg
and other programs should recognise “.icn” files :-
$ lsxdg mime junk.icn
junk.icn: text/x-objecticon
$ lsxdg alt-mime text/x-objecticon
text/x-objecticon
text/plain
application/octet-stream
$ lsxdg de-file junk.icn
object xdg.DesktopEntry#1(
name=u"Run GNU Emacs"
icon="emacs"
source="/home/rparlett/.local/share/applications/runemacs.desktop"
exec=u"/home/rparlett/bin/runemacs.sh %F"
exec_line=u"/home/rparlett/bin/runemacs.sh +%P %F"
path=&null
terminal=&null
initial_preference=20
)
... etc, for more text editors and viewers associated with text/plain
Desktop files contain information about a particular application, including the command needed to start the application, and the mime types with which it is associated.
New desktop files can be placed in the applications
subdirectory of the XDG_DATA_HOME
directory; normally that is ~/.local/share/applications
. These override desktop files of the same name in the system data directories, so it is quite possible to copy a desktop file from one of the system data directories to your XDG_DATA_HOME
directory, and then edit it as you please; for example :-
$ cp /usr/share/applications/vim.desktop ~/.local/share/applications
$ edit ~/.local/share/applications/vim.desktop
Here is an example of a custom desktop file which I use to launch emacs using the emacsclient
program, which makes use of an existing running emacs, rather than starting a new emacs for each invocation. It also uses the non-standard ExecLine
key, as described above.
[Desktop Entry]
Version=1.0
Encoding=UTF-8
Name=Run GNU Emacs
GenericName=Text Editor
Comment=View and edit files
MimeType=text/english;text/plain;text/x-makefile;text/x-c++hdr;text/x-c++src;text/x-chdr;text/x-csrc;text/x-java;text/x-moc;text/x-pascal;text/x-tcl;text/x-tex;application/x-shellscript;text/x-c;text/x-c++;application/json;text/markdown
Exec=/home/rparlett/bin/runemacs.sh %F
ExecLine=/home/rparlett/bin/runemacs.sh +%P %F
TryExec=/home/rparlett/bin/runemacs.sh
Icon=emacs
Type=Application
Terminal=false
Categories=Utility;Development;TextEditor;
InitialPreference=20
The referenced script file just starts a fresh copy of emacs if emacsclient
fails (presumably because emacs isn’t already running) :-
#!/bin/bash
if ! emacsclient -n "$@" &>/dev/null; then
setsid -f emacs "$@" </dev/null &>/dev/null
fi
After adding a desktop file, it may be wise for compatibility’s sake, to run the following command :-
update-desktop-database -v ~/.local/share/applications
This will create a mimeinfo.cache
file in the given directory. As described above, by default the xdg
package will ignore this file in the XDG_DATA_HOME
directory, but other software may not.
It is often desirable to customize the associations between a particular mime type and various applications, as specified in the desktop files (with the “MimeType” key). To do this, a mimeapps.list
file may be created, which is best placed in XDG_CONFIG_HOME
, where it will override any other similar files. This file contains three sections :-
[Added Associations]
...
[Removed Associations]
...
[Default Applications]
...
Each section contains a list of mime types associated destkop IDs. A desktop ID is just the desktop file name (without the path), unless the file is in a subdirectory of applications
; in which case substitute directory slashes with hyphens. The file name is easily found from the lsxdg
output of DesktopEntry
instances as the “source” member.
The first section, “Added Associations”, adds desktop files to the association for a particular mime type, in the order given. So a line like :-
application/pdf=okularApplication_pdf.desktop;org.gnome.Evince.desktop
will put okular
as the most preferred desktop file for the mime type application/pdf
, with evince
in second place. Any other associations specified in other desktop files will still be recognised, and will appear as lower preference entries; for example :-
$ lsxdg de application/pdf
object xdg.DesktopEntry#6(
name=u"Okular"
icon="okular"
source="/usr/share/applications/okularApplication_pdf.desktop"
exec=u"okular %U"
exec_line=&null
path=&null
terminal=&null
initial_preference=8
)
object xdg.DesktopEntry#9(
name=u"Document Viewer"
icon="org.gnome.Evince"
source="/usr/share/applications/org.gnome.Evince.desktop"
exec=u"evince %U"
exec_line=&null
path=&null
terminal=&null
initial_preference=0
)
object xdg.DesktopEntry#4(
name=u"Google Chrome"
icon="google-chrome"
source="/usr/share/applications/google-chrome.desktop"
exec=u"/usr/bin/google-chrome-stable %U"
exec_line=&null
path=&null
terminal=&null
initial_preference=0
)
... more lower preference desktop entries
The second section, “Removed Associations” is less useful. It simply removes the listed desktop files from the association with a particular mime type. So the following line :-
application/pdf=google-chrome.desktop
would remove the third entry shown above from the lsxdg
results.
As described above, the third section, “Default Applications” is treated by the xdg
package as another “Added Associations”, with higher precedence. However, other software may behave differently. For that reason, I suggest keeping the two sections synchronized to the extent that the first item in each “Added Associations” entry appears as an entry in “Default Applications”. Thus, I would have :-
[Added Associations]
application/pdf=okularApplication_pdf.desktop;org.gnome.Evince.desktop
...
[Default Applications]
application/pdf=okularApplication_pdf.desktop
...
A desktop file in one of the XDG_DATA_DIRS
directories can be deactivated entirely by creating an empty desktop file with the same desktop ID in the XDG_DATA_HOME
directory.
For example, if I wished to deactivate /usr/share/applications/vim.desktop
, then I would just run :-
touch /home/rparlett/.local/share/applications/vim.desktop
Thereafter, the above overrides the desktop file in /usr/share/applications
, and since it is empty, doesn’t have any other effect.
The process can of course be reversed by simply removing the empty vim.desktop
file.
To make a custom association between a mime type and an icon name, create an “icons” file in the “mime” subdirectory of the XDG_DATA_HOME
directory. Then add a line like :-
application/x-shellscript:application-x-shellscript
To make a custom associaton between an icon name and an actual icon file, create additional theme subdirectories under the “icons” subdirectory of the XDG_DATA_HOME
directory. For example :-
$ ls ~/.local/share/icons/hicolor/32x32/apps
adobe.pdf.png
AdobeReader9.png
vnd.adobe.pdx.png
vnd.adobe.xdp+xml.png
vnd.adobe.xfdf.png
vnd.fdf.png
...
$ lsxdg find-icon vnd.adobe.pdx 32
/home/rparlett/.local/share/icons/hicolor/32x32/apps/vnd.adobe.pdx.png
Further “fallback” icons can be added to the “icons” directory :-
$ ls ~/.local/share/icons
hicolor/
junk.png
$ lsxdg find-icon junk 32
/home/rparlett/.local/share/icons/junk.png
After changes have been made to the underlying XDG database files, the various cached values in the xdg
classes may be out of date. To reset them, two methods are provided :-
xdg.IconTheme.refresh()
resets everything connected with the icon theme mapping from icon names to files; and xdg.Mime.refresh()
resets all other mime type and desktop file data.