Internal Concepts
Specifications of XDG Icon Theme
- https://specifications.freedesktop.org/icon-theme-spec/latest/
- https://specifications.freedesktop.org/icon-naming-spec/icon-naming-spec-latest.html
Other tutorials
- https://openapplibrary.org/dev-tutorials/qt-icon-themes
Terminology
REPOis this icon repo, that is,tango-remixer/
About Qt 6 C++ API & Freedesktop Supports
Qt 6 follows freedesktop.org XDG's specifications and implement a cross-platform XDG icon theme support for Qt application. So you can use any icon theme pack which follows freedesktop.org standard in your Qt application and run on Linux / Mac / Windows.
Let me start with a simplest example. The directory structure of humanity_0.4.6 looks like this:
# tree -F -L 3 --dirsfirst
./
└── humanity_0.4.6/
├── Humanity/
│ ├── actions/
│ ├── animations/
│ ├── apps/
│ ├── categories/
│ ├── devices/
│ ├── emblems/
│ ├── mimes/
│ ├── places/
│ ├── status/
│ ├── stock/
│ ├── AUTHORS
│ ├── COPYING
│ └── index.theme # <- Must be included in .qrc, so that become accessible via C++ API.
└── Humanity-Dark/
├── actions/
├── apps/
├── devices/
├── status/
├── AUTHORS
├── COPYING
└── index.theme
Then write a simplest workable example like this:
<!DOCTYPE RCC>
<RCC version="1.0">
<qresource prefix="/">
<file>thirdparty/humanity_0.4.6/Humanity/index.theme</file>
<file>thirdparty/humanity_0.4.6/Humanity/apps/24/totem.svg</file>
<file>thirdparty/humanity_0.4.6/Humanity/apps/48/totem.svg</file>
</qresource>
</RCC>
- Specify icon theme folder search paths; Qt will try to search all icon theme folder(s) contining
index.themein this path:/thirdparty/humanity_0.4.6/:
QIcon::setThemeSearchPaths({ ":/thirdparty/humanity_0.4.6" });
- This is optional, for searching your other extra icons which are not included in the XDG icon theme:
QIcon::setFallbackSearchPaths({ ":/MY_OTHER_ICON" });
- Specify a icon theme (the folder name seems have to be the same) under any of
QIcon::themeSearchPaths()(:/src/humanity_0.4.6)
QIcon::setThemeName("Humanity");
- Then
QIcon::fromTheme("ICON_NAME")will automatically traverse across all folders, according to the difinition insideHumanity/index.themeand create a newQIcon.
setWindowIcon(QIcon::fromTheme("totem"));
About Script: What On Earth Is This Script Doing?
{REPO}/thirdparty/humanity_0.4.6/Humanity/apps/24 $ ls -l
-rw-r--r-- 1 ono ono 19186 Dec 4 2009 totem.svg
lrwxrwxrwx 1 ono ono 9 Dec 4 2009 video-player.svg -> totem.svg
{REPO}/thirdparty/humanity_0.4.6/Humanity/apps/48 $ ls -l
-rw-r--r-- 1 ono ono 19186 Dec 4 2009 totem.svg
lrwxrwxrwx 1 ono ono 9 Dec 4 2009 video-player.svg -> totem.svg
So this script will copy the non-symlink files:
{REPO}/thirdparty/humanity_0.4.6/Humanity/apps/24/totem.svg
{REPO}/thirdparty/humanity_0.4.6/Humanity/apps/48/totem.svg
To folder (category like apps, actions are omitted):
{REPO}/dist/OurTango/apps/24/totem.svg
{REPO}/dist/OurTango/apps/48/totem.svg
But attention we need to follow the XDG standard, to fit the folder structure of /usr/share/icons/hicolor:
| Place | Folder Structure | Usage |
|---|---|---|
| Source | apps/16/ |
Convenient for designer and maintainer (convension since SVN / CVS era) |
/usr/share/icons/hicolor |
16x16/apps/ |
The XDG standard directory structure in /usr/share/icons/hicolor (fallback icon theme of all icons) |
/usr/share/icons/hicolor |
16x16@2/apps/ |
The XDG standard directory structure in /usr/share/icons/hicolor (fallback icon theme of all icons) |
/usr/share/icons/breeze |
apps/16 |
Ehh... Not all icon theme pack follows the XDG's hicolor folder structure. This is a real example... (This project currently cannot output such directory structure.) |
index.theme
@2 and Scale=2 Size=32 is extra (but significant) definition. Qt / QIcon will handle these definitions to generate pixmap of corresponding sizes.
- It seems that
@2suffix is merely a naming convention... but:QIconwill use Qt's "@nx" high DPI syntax. (quoted from Qt official doc - QIcon)
High Resolution Versions of Images
It is possible to provide high resolution versions of images should a scaling between device pixels and device independent pixels be in effect.
The high resolution version is marked by the suffix
@2xon the base name. The image read will have its device pixel ratio set to a value of 2.This can be disabled by setting the environment variable
QT_HIGHDPI_DISABLE_2X_IMAGE_LOADING. (quoted from Qt official doc - QImageReader)
Scale=2andSize=32is defined in Freedesktop Icon Theme Specification
The *.svg files themselves already define the image size (via <svg width="16" height="16">.) So when you are using a HiDPI screen:
- If without
@2inindex.theme, Qt may select a (too sophisticated and complex) 32x32 icon and render + draw it directly in a 16x16 area. - If without
Scale=2andSize=32, Qt may select a 16x16 svg, render to a 16x16 pixmap cache, then draw on a 16x16 (actual physical pixel is 32x32) area... Yes, it blurred.
I don't sure the detailed implementation of
@2or@2xnaming convention in Qt... And don't want to do more experiments for it neither. After all, I think the way Humanity did should be "standard enough".
[Icon Theme]
Name=Tango
Comment=Smooth modern theme designed to be intuitive.
Inherits=gnome,hicolor
Example=directory-x-normal
# Directory list (includes extra definition for HiDPI)
Directories=apps/16,apps/48,apps/16@2,apps/48@2
[apps/16]
Size=16
Context=Applications
Type=Fixed
[apps/48]
Size=48
Context=Applications
Type=Fixed
# Following are definition for `{context}/{size}@2`
#
# (Actually, the path `apps/16@2/` is not existed in real file system,
# but it is defined in our .qrc via <file alias="apps/16@2/..."> and
# accessible in Qt, just like a virtual file system.)
# 16 * 2 = 32
[apps/16@2]
Size=32
Scale=2
Context=Applications
Type=Fixed
# 48 * 2 = 96
[apps/48@2]
Size=96
Scale=2
Context=Applications
Type=Fixed
index.qrc
You can see a QRC file description of a virtual file system inside a Qt application.
<!DOCTYPE RCC>
<RCC version="1.0">
<qresource prefix="/xdg_icon_themes/Tango">
<file>index.theme</file>
</qresource>
<qresource prefix="/xdg_icon_themes/Tango">
<file alias="apps/24@2/totem.svg">apps/24/totem.svg</file>
<file alias="apps/24@2/video-player.svg">apps/24/totem.svg</file>
</qresource>
<qresource prefix="/xdg_icon_themes/Tango">
<file alias="apps/48@2/totem.svg">light/48/totem.svg</file>
<file alias="apps/48@2/video-player.svg">light/48/totem.svg</file>
</qresource>
</RCC>
Usage in C++
- CMakeLists
qt_add_executable(qkiss
MANUAL_FINALIZATION
${PROJECT_SOURCES}
resources/tango_icons_for_qt/dist/Tango/index.qrc
)
- mainwindow.cpp
QIcon::setThemeSearchPaths({ ":/xdg_icon_themes" });
QIcon::setThemeName("Tango");
setWindowIcon(QIcon::fromTheme("paprefs"));
Note of qrc:
RCC > qresource[prefix]is not related to the real folder structure. It is only used in Qt for the resource path.
- Totally unrelated to the real file path. (
<file>)- I mean, this is unable to shorten the content of
<file>. This is merely an "prepended extra namespace".- It effects the path when refer resource file in C++. To refer a resource file in C++, the path would be:
:/{prefix}/{file}:/{prefix}/{file_alias}RCC > qresource > file[alias]is used in Qt for the resource path only.RCC > qresource > file's content is ALWAYS and ONLY CAN BE the file path relative to thisqrcfile.Now import
dist/tango_icons.qrcin your Qt project, you can access the icon in Qt by:/tango_icons/light/48/video-player.svg, it will becomedist/tango_icons/light/48/totem.svgin the real file system.
As a reference, the final file-system structure looks like: