Contents

The xdg package

Introduction

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/.

lsxdg

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.

Base directories

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.

Mime types

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.

From file name to mime type

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.

Alternative mime types

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.

Icon names

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.

Icon themes

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

Specifying a theme

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.

Icon names to files

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

File names to icon files

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

Desktop entries

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.

Application associations

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
)

mimeapps.list

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

mimeinfo.cache

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

Extensions

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.

Launch commands

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"

Customizing

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.

Adding a custom mime type

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

Adding a new desktop file

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.

Download runemacs.desktop

[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) :-

Download runemacs.sh

#!/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.

Changing mime type associations and application ordering

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
...

Unwanted desktop files

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.

Changing an icon association

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

Refreshing

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.

Contents