An icon theme is a set of icons that share a common look and feel. The user can then select the icon theme that they want to use, and all apps use icons from the theme. The initial user of icon themes is the icon field of the desktop file specification, but in the future it can have other uses (such as mimetype icons).
From a programmer perspective an icon theme is just a mapping. Given a set of directories to look for icons in and a theme name it maps from icon name and nominal icon size to an icon filename.
An icon theme is a named set of icons. It is used to map from an iconname and size to a file. Themes may inherit from other themes as a way to extend them.
An icon file is an image that can be loaded and used as an icon. The supported image file formats are PNG, XPM and SVG. PNG is the recommended bitmap format, and SVG is for vectorized icons. XPM is supported due to backwards compability reasons, and it is not recommended that new themes use XPM files. Support for SVGs is optional.
Icons and themes are searched for in a set of directories, called base directories. The themes are stored in subdirectories of the base directories.
On very high density (high dpi) screens the UI is often scaled to avoid the UI being so small it is hard to see. In order to support this icons can have a target scale, describing what scale factor they are designed for.
For instance, an icon with a directory size of 48 but scale 2x would be 96x96 pixels, but designed to have the same level of detail as a 48x48 icon at scale 1x. This can be used on high density displays where a 48x48 icon would be too small (or ugly upscaled) and a normal 96x96 icon would have a lot of detail that is hard to see.
Icons and themes are looked for in a set of directories. By default, apps should look in $HOME/.icons (for backwards compatibility), in $XDG_DATA_DIRS/icons and in /usr/share/pixmaps (in that order). Applications may further add their own icon directories to this list, and users may extend or change the list (in application/desktop specific ways). In each of these directories themes are stored as subdirectories. A theme can be spread across several base directories by having subdirectories of the same name. This way users can extend and override system themes.
In order to have a place for third party applications to install their icons there should always exist a theme called "hicolor" [1]. The data for the hicolor theme is available for download at: http://www.freedesktop.org/software/icon-theme/. Implementations are required to look in the "hicolor" theme if an icon was not found in the current theme.
Each theme is stored as subdirectories of the base directories. The internal name of the theme is the name of the subdirectory, although the user-visible name as specified by the theme may be different. Hence, theme names are case sensitive, and are limited to ASCII characters. Theme names may also not contain comma or space.
In at least one of the theme directories there must be a file called index.theme that describes the theme. The first index.theme found while searching the base directories in order is used. This file describes the general attributes of the theme.
In the theme directory are also a set of subdirectories containing image files. Each directory contains icons designed for a certain nominal icon size and scale, as described by the index.theme file. The subdirectories are allowed to be several levels deep, e.g. the subdirectory "48x48/apps" in the theme "hicolor" would end up at $basedir/hicolor/48x48/apps.
The image files must be one of the types: PNG, XPM, or SVG, and the extension must be ".png", ".xpm", or ".svg" (lower case). The support for SVG files is optional. Implementations that do not support SVGs should just ignore any ".svg" files. In addition to this there may be an additional file with extra icon-data for each file. It should have the same basename as the image file, with the extension ".icon". e.g. if the icon file is called "mime_source_c.png" the corresponding file would be named "mime_source_c.icon".
Both the icon theme description file and the icon data files are ini-style text files, as described in the desktop file specification. They don't have any encoding field. Instead, they must always be stored in UTF-8 encoding.
The index.theme file must start with a section called Icon Theme, with contents according to table 1 below. All lists are comma-separated.
Key | Description | Value Type | Required |
---|---|---|---|
Name | short name of the icon theme, used in e.g. lists when selecting themes. | localestring | YES |
Comment | longer string describing the theme | localestring | YES |
Inherits |
The name of the theme that this theme inherits from. If an icon name is not found in the current theme, it is searched for in the inherited theme (and recursively in all the inherited themes). If no theme is specified, implementations are required to add the "hicolor" theme to the inheritance tree. An implementation may optionally add other default themes in between the last specified theme and the hicolor theme. Themes that are inherited from explicitly must be present on the system. | strings | NO |
Directories | list of subdirectories for this theme. For every subdirectory there must be a section in the index.theme file describing that directory. | strings | YES |
ScaledDirectories | Additional list of subdirectories for this theme, in addition to the ones in Directories. These directories should only be read by implementations supporting scaled directories and was added to keep compatibility with old implementations that don't support these. | strings | NO |
Hidden | Whether to hide the theme in a theme selection user interface. This is used for things such as fallback-themes that are not supposed to be visible to the user. | boolean | NO |
Example | The name of an icon that should be used as an example of how this theme looks. | string | NO |
Each directory specified in the Directory key has a corresponding section with the same name as the directory. The contents of this section is listed in table 2 below.
Key | Description | Value Type | Required | Type |
---|---|---|---|---|
Size | Nominal (unscaled) size of the icons in this directory. | integer | YES | |
Scale | Target scale of of the icons in this directory. Defaults to the value 1 if not present. Any directory with a scale other than 1 should be listed in the ScaledDirectories list rather than Directories for backwards compatibility. | integer | NO | |
Context | The context the icon is normally used in. This is in detail discussed in Section 4.1, “Context”. | string | NO | |
Type | The type of icon sizes for the icons in this directory. Valid types are Fixed, Scalable and Threshold. The type decides what other keys in the section are used. If not specified, the default is Threshold. | string | NO | |
MaxSize | Specifies the maximum (unscaled) size that the icons in this directory can be scaled to. Defaults to the value of Size if not present. | integer | NO | Scalable |
MinSize | Specifies the minimum (unscaled) size that the icons in this directory can be scaled to. Defaults to the value of Size if not present. | integer | NO | Scalable |
Threshold | The icons in this directory can be used if the size differ at most this much from the desired (unscaled) size. Defaults to 2 if not present. | integer | NO | Threshold |
In addition to these groups you may add extra groups to the index.theme file in order to extend it. These extensions must begin with "X-", and can be used to add desktop specific information to the theme file. Example group names would be "X-KDE Icon Theme" or "X-Gnome Icon Theme".
The optional filename.icon file contains a group called "Icon Data", with the content listed in table 3.
Key | Description | Value Type | Required |
---|---|---|---|
DisplayName | A translated UTF8 string that can be used instead of the icon name when the icon is listed in e.g. a user interface. | localestring | NO |
EmbeddedTextRectangle | If this exists, it specifies the four corners of a rectangle where the program displaying the icon can embed text. This is normally used by e.g. file managers that want to display a preview of text file contents in the icon. The corners are specified by a list of four values: x0,y0,x1,y1. The values are pixel coordinates from the top left corner of the icon, except for SVG files, where they are specified in a 1000x1000 coordinate space that is scaled to the final rendered size of the icon. | integers | NO |
AttachPoints | A list of points, separated by "|" that may be used as anchor points for emblems/overlays. The points are pixel coordinates from the top left corner of the icon, except for SVG files, where they are specified in a 1000x1000 coordinate space that is scaled to the final rendered size of the icon. | points | NO |
Extensions to the filename.icon file are allowed, but the keys must be begin with "X-" to avoid collisions with future standardized extensions to this format.
The Context
allows
the designer to group icons on a conceptual level.
It doesn't act as a namespace in the file system, such
that icons can have identical names, but allows
implementations to categorize and sort by it, for example.
These are the available contexts:
Actions. Icons representing actions which the user initiates, such as Save As.
Devices. Icons representing real world devices, such as printers and mice. It's not for file system nodes such as character or block devices.
FileSystems. Icons for objects which are represented as part of the file system. This is for example, the local network, “Home”, and “Desktop” folders.
MimeTypes. Icons representing MIME types.
The icon lookup mechanism has two global settings, the list of base directories and the internal name of the current theme. Given these we need to specify how to look up an icon file from the icon name, the nominal size and the scale.
The lookup is done first in the current theme, and then recursively in each of the current theme's parents, and finally in the default theme called "hicolor" (implementations may add more default themes before "hicolor", but "hicolor" must be last). As soon as there is an icon of any size that matches in a theme, the search is stopped. Even if there may be an icon with a size closer to the correct one in an inherited theme, we don't want to use it. Doing so may generate an inconsistant change in an icon when you change icon sizes (e.g. zoom in).
The lookup inside a theme is done in three phases. First all the directories are scanned for an exact match, e.g. one where the allowed size of the icon files match what was looked up. Then all the directories are scanned for any icon that matches the name. If that fails we finally fall back on unthemed icons. If we fail to find any icon at all it is up to the application to pick a good fallback, as the correct choice depends on the context.
The exact algorithm (in pseudocode) for looking up an icon in a theme (if the implementation supports SVG) is:
FindIcon(icon, size, scale) { filename = FindIconHelper(icon, size, scale, user selected theme); if filename != none return filename filename = FindIconHelper(icon, size, scale, "hicolor"); if filename != none return filename return LookupFallbackIcon (icon) } FindIconHelper(icon, size, scale, theme) { filename = LookupIcon (icon, size, scale, theme) if filename != none return filename if theme has parents parents = theme.parents for parent in parents { filename = FindIconHelper (icon, size, scale, parent) if filename != none return filename } return none }
With the following helper functions:
LookupIcon (iconname, size, scale, theme) { for each subdir in $(theme subdir list) { for each directory in $(basename list) { for extension in ("png", "svg", "xpm") { if DirectoryMatchesSize(subdir, size, scale) { filename = directory/$(themename)/subdir/iconname.extension if exist filename return filename } } } } minimal_size = MAXINT for each subdir in $(theme subdir list) { for each directory in $(basename list) { for extension in ("png", "svg", "xpm") { filename = directory/$(themename)/subdir/iconname.extension if exist filename and DirectorySizeDistance(subdir, size, scale) < minimal_size { closest_filename = filename minimal_size = DirectorySizeDistance(subdir, size, scale) } } } } if closest_filename set return closest_filename return none } LookupFallbackIcon (iconname) { for each directory in $(basename list) { for extension in ("png", "svg", "xpm") { if exists directory/iconname.extension return directory/iconname.extension } } return none } DirectoryMatchesSize(subdir, iconsize, iconscale) { read Type and size data from subdir if Scale != iconscale return False; if Type is Fixed return Size == iconsize if Type is Scaled return MinSize <= iconsize <= MaxSize if Type is Threshold return Size - Threshold <= iconsize <= Size + Threshold } DirectorySizeDistance(subdir, iconsize, iconscale) { read Type and size data from subdir if Type is Fixed return abs(Size*Scale - iconsize*iconscale) if Type is Scaled if iconsize*iconscale < MinSize*Scale return MinSize*Scale - iconsize*iconscale if iconsize*iconscale > MaxSize*Scale return iconsize*iconscale - MaxSize*Scale return 0 if Type is Threshold if iconsize*iconscale < (Size - Threshold)*Scale return MinSize*Scale - iconsize*iconscale if iconsize*iconsize > (Size + Threshold)*Scale return iconsize*iconsize - MaxSize*Scale return 0 }
In some cases you don't always want to fall back to an icon in an inherited theme. For instance, sometimes you look for a set of icons, prefering any of them before using an icon from an inherited theme. To support such operations implementations can contain a function that finds the first of a list of icon names in the inheritance hierarchy. I.E. It would look something like this:
FindBestIcon(iconList, size, scale) { filename = FindBestIconHelper(iconList, size, scale, user selected theme); if filename != none return filename filename = FindBestIconHelper(iconList, size, scale, "hicolor"); if filename != none return filename for icon in iconList { filename = LookupFallbackIcon (icon) if filename != none return filename } return none; } FindBestIconHelper(iconList, size, scale, theme) { for icon in iconList { filename = LookupIcon (icon, size, theme) if filename != none return filename } if theme has parents parents = theme.parents for parent in parents { filename = FindBestIconHelper (iconList, size, scale, parent) if filename != none return filename } return none }
This can be very useful for example when handling mimetype icons, where there are more and less "specific" versions of icons.
Here is an example index.theme file:
[Icon Theme] Name=Birch Name[sv]=Björk Comment=Icon theme with a wooden look Comment[sv]=Träinspirerat ikontema Inherits=wood,default Directories=48x48/apps,48x48@2/apps48x48/mimetypes,32x32/apps,32x32@2/apps,scalable/apps,scalable/mimetypes [scalable/apps] Size=48 Type=Scalable MinSize=1 MaxSize=256 Context=Applications [scalable/mimetypes] Size=48 Type=Scalable MinSize=1 MaxSize=256 Context=MimeTypes [32x32/apps] Size=32 Type=Fixed Context=Applications [32x32@2/apps] Size=32 Scale=2 Type=Fixed Context=Applications [48x48/apps] Size=48 Type=Fixed Context=Applications [48x48@2/apps] Size=48 Scale=2 Type=Fixed Context=Applications [48x48/mimetypes] Size=48 Type=Fixed Context=MimeTypes
The corresponding directory tree in the /usr/share/icons directory could look like this:
birch/index.theme birch/scalable/apps/mozilla.svg birch/scalable/mimetypes/mime_text_plain.svg birch/scalable/mimetypes/mime_text_plain.icon birch/48x48/apps/mozilla.png birch/48x48@2/apps/mozilla.png birch/32x32/apps/mozilla.png birch/32x32@2/apps/mozilla.png birch/48x48/mimetypes/mime_text_plain.png birch/48x48/mimetypes/mime_text_plain.icon
Where birch/scalable/mimetypes/mime_text_plain.icon contains:
[Icon Data] DisplayName=Mime text/plain EmbeddedTextRectangle=100,100,900,900 AttachPoints=200,200|800,200|500,500|200,800|800,800
And birch/48x48/mimetypes/mime_text_plain.icon contains:
[Icon Data] DisplayName=Mime text/plain EmbeddedTextRectangle=8,8,40,40 AttachPoints=20,20|40,40|50,10|10,50
In this example a lookup of "mozilla" would get the prerendered 48x48 and 32x32 icons before the SVG icons due to the order of Directories.
So, you're an application author, and want to install application icons so that they work in the KDE and Gnome menus. Minimally you should install a 48x48 icon in the hicolor theme. This means installing a PNG file in $prefix/share/icons/hicolor/48x48/apps. Optionally you can install icons in different sizes. For example, installing a svg icon in $prefix/share/icons/hicolor/scalable/apps means most desktops will have one icon that works for all sizes. You might even want to install icons with a look that matches other well known themes so your application will fit in with some specific desktop environment.
It is recommended that the icons installed in the hicolor theme look neutral, since it is a fallback theme that will be used in combination with some very different looking themes. But if you don't have any neutral icon, please install whatever icon you have in the hicolor theme so that all applications get at least some icon in all themes.
The algorithm as described in this document works by always looking up filenames in directories (a stat in unix terminology). A good implementation is expected to read the directories once, and do all lookups in memory using that information.
This caching can make it impossible for users to add icons without having to restart applications. In order to handle this, any implementation that does caching is required to look at the mtime of the toplevel icon directories when doing a cache lookup, unless it already did so less than 5 seconds ago. This means that any icon editor or theme installation program need only to change the mtime of the the toplevel directory where it changed the theme to make sure that the new icons will eventually get used.
The icon theme specification is based on the original KDE icon theme system designed by Antonio Larossa, Geert Janssen and Torsten Rahn. The common specification mostly adds support for .icon files, renames the icon theme description files and removes a few references to kde in them.
Version 0.13, July 2 2013, Alexander Larsson.
Add icon Scales.
Version 0.12, 24 December 2006, Octavio Alvarez.
Fixed "hicolor" lookup in the pseudocode, so it works with multiple parents.
Version 0.11, 7 February 2006, Alexander Larsson.
Fixed icon lookup clarification to work with multiple inheritance.
Version 0.10, 7 February 2006, Alexander Larsson.
Clarify that icon lookup looks in all parent themes before falling back to nonthemed icons.
Added lookup function that takes a list of icon names (FindBestIcon)
Version 0.9, 4 April 2005, Alexander Larsson.
Cleanups and fixes to language from Rodney Dawes and Frans Englich.
Added section describing Contexts in more details (by Frans Englich).
Version 0.8, 5 February 2004, Alexander Larsson.
Fix language problems as pointed out by Rodney Dawes and Michael Terry.
Added background section.
Version 0.7, 13 September 2003, Heinrich Wendel.
Converted to basedir spec.
Changed type of MaxSize, MinSize and Threshold to integer.
Removed typo in code example.
Corrected path to default-icon-theme.
Version 0.6, 2 December 2002, Alexander Larsson.
Added Hidden key.
Removed multiple inheritance.
Renamed the default theme hicolor.
Added the application icon install section.
Fixed some xml issues.
Version 0.5, 18 September 2002, Alexander Larsson.
Added DisplayName to icon data.
Fixed up example svg icon data.
Fixed some spelling and grammar errors.
Version 0.4, 16 May 2002, Alexander Larsson.
Fixed some spelling and grammar errors.
Version 0.3, 14 May 2002, Alexander Larsson.
Made support for SVGs optional.
Added a default fallback theme.
Changed the example directory layout a bit to match the default theme.
Version 0.2, 29 April 2002, Alexander Larsson.
Changed search order to png, svg, xpm.
Added comment to say that xpm is supported for backwards compat and not recommended in new themes.
Default Type for a directory is now Threshold
Added implementation notes section.
Added Example key.
Version 0.1, 22 April 2002, Alexander Larsson.
Created initial draft.