From 647ad121a51823b96fdafd5a6cb6cee5c145e918 Mon Sep 17 00:00:00 2001 From: Martchus Date: Wed, 15 Mar 2023 21:27:04 +0100 Subject: [PATCH] Improve setting default icon theme * Set the default icon theme when applying Qt settings and the "system" theme is supposed to be used but none could be determined by Qt * Use a bundled icon theme depending on whether the current palette is light or dark * Apply the default not only under Windows anymore; supposedly this makes sense under any platform where Qt cannot determine the icon theme for us --- cmake/modules/QtConfig.cmake | 10 +++- resources/qtconfigarguments.cpp | 6 --- settingsdialog/qtsettings.cpp | 87 ++++++++++++++++++++++----------- 3 files changed, 66 insertions(+), 37 deletions(-) diff --git a/cmake/modules/QtConfig.cmake b/cmake/modules/QtConfig.cmake index 67135a8..19d4a1f 100644 --- a/cmake/modules/QtConfig.cmake +++ b/cmake/modules/QtConfig.cmake @@ -518,6 +518,7 @@ if (REQUIRED_ICONS) list(REMOVE_DUPLICATES ICON_SEARCH_PATHS) set(BUILTIN_ICONS_DIR "${CMAKE_CURRENT_BINARY_DIR}/icons") set(DEFAULT_THEME_INDEX_FILE "${BUILTIN_ICONS_DIR}/default/index.theme") + set(DEFAULT_DARK_THEME_INDEX_FILE "${BUILTIN_ICONS_DIR}/default-dark/index.theme") file(REMOVE_RECURSE "${BUILTIN_ICONS_DIR}") file(MAKE_DIRECTORY "${BUILTIN_ICONS_DIR}") foreach (ICON_THEME ${BUILTIN_ICON_THEMES}) @@ -550,8 +551,13 @@ if (REQUIRED_ICONS) LIST_DIRECTORIES false "${ICON_THEME_PATH}/index.theme") endif () - # make the first specified built-in the default theme - if (NOT EXISTS "${DEFAULT_THEME_INDEX_FILE}") + # make the first non-dark specified built-in theme the "default" theme + # make the first dark specified built-in theme the "default-dark" theme + if (NEW_ICON_THEME_NAME MATCHES ".*-dark" AND NOT EXISTS "${DEFAULT_DARK_THEME_INDEX_FILE}") + file(MAKE_DIRECTORY "${BUILTIN_ICONS_DIR}/default-dark") + file(WRITE "${DEFAULT_DARK_THEME_INDEX_FILE}" "[Icon Theme]\nInherits=${NEW_ICON_THEME_NAME}") + list(APPEND ICON_THEME_FILES "default-dark/index.theme") + elseif (NOT EXISTS "${DEFAULT_THEME_INDEX_FILE}") file(MAKE_DIRECTORY "${BUILTIN_ICONS_DIR}/default") file(WRITE "${DEFAULT_THEME_INDEX_FILE}" "[Icon Theme]\nInherits=${NEW_ICON_THEME_NAME}") list(APPEND ICON_THEME_FILES "default/index.theme") diff --git a/resources/qtconfigarguments.cpp b/resources/qtconfigarguments.cpp index f331199..a13f56d 100644 --- a/resources/qtconfigarguments.cpp +++ b/resources/qtconfigarguments.cpp @@ -152,12 +152,6 @@ void QtConfigArguments::applySettings(bool preventApplyingDefaultFont) const QIcon::setThemeName(qEnvironmentVariable("ICON_THEME")); } } -#ifdef Q_OS_WIN32 - // default configuration under Windows - if (QIcon::themeName().isEmpty()) { - QIcon::setThemeName(QStringLiteral("default")); - } -#endif if (m_fontArg.isPresent()) { QFont font; font.setFamily(QString::fromLocal8Bit(m_fontArg.values().front())); diff --git a/settingsdialog/qtsettings.cpp b/settingsdialog/qtsettings.cpp index 212f665..8766e2f 100644 --- a/settingsdialog/qtsettings.cpp +++ b/settingsdialog/qtsettings.cpp @@ -10,6 +10,8 @@ #include "../resources/resources.h" +#include "../misc/desktoputils.h" + #include "ui_qtappearanceoptionpage.h" #include "ui_qtenvoptionpage.h" #include "ui_qtlanguageoptionpage.h" @@ -141,6 +143,40 @@ void QtSettings::save(QSettings &settings) const settings.endGroup(); } +/*! + * \brief Returns the icon themes present in the specified \a searchPaths. + * \remarks The display name is the key and the actual icon theme name the value. + * This way the map is sorted correctly for display purposes. + */ +static QMap scanIconThemes(const QStringList &searchPaths) +{ + auto res = QMap(); + for (const auto &searchPath : searchPaths) { + const auto dir = QDir(searchPath).entryList(QDir::Dirs | QDir::NoDotAndDotDot, QDir::Name); + for (const auto &iconTheme : dir) { + auto indexFile = QFile(searchPath % QChar('/') % iconTheme % QStringLiteral("/index.theme")); + auto index = QByteArray(); + if (indexFile.open(QFile::ReadOnly) && !(index = indexFile.readAll()).isEmpty()) { + const auto iconThemeSection = index.indexOf("[Icon Theme]"); + const auto nameStart = index.indexOf("Name=", iconThemeSection != -1 ? iconThemeSection : 0); + if (nameStart != -1) { + auto nameLength = index.indexOf("\n", nameStart) - nameStart - 5; + if (nameLength > 0) { + auto displayName = QString::fromUtf8(index.mid(nameStart + 5, nameLength)); + if (displayName != iconTheme) { + displayName += QChar(' ') % QChar('(') % iconTheme % QChar(')'); + } + res[displayName] = iconTheme; + continue; + } + } + } + res[iconTheme] = iconTheme; + } + } + return res; +} + /*! * \brief Applies the current configuration. * \remarks @@ -193,6 +229,19 @@ void QtSettings::apply() } if (m_d->customIconTheme) { QIcon::setThemeName(m_d->iconTheme); + } else if (QIcon::themeName().isEmpty()) { + // use bundled default icon theme matching the current palette + // notes: - It is ok that search paths specified via CLI arguments are not set here yet. When doing so one should also + // specify the desired icon theme explicitly. + // - The icon themes "default" and "default-dark" come from QtConfig.cmake which makes the first non-dark bundled + // icon theme available as "default" and the first dark icon theme available as "default-dark". An icon theme + // is considered dark if it ends with "-dark". + const auto bundledIconThemes = scanIconThemes(QStringList(QStringLiteral(":/icons"))); + if (isPaletteDark() && bundledIconThemes.contains(QStringLiteral("default-dark"))) { + QIcon::setThemeName(QStringLiteral("default-dark")); + } else if (bundledIconThemes.contains(QStringLiteral("default"))) { + QIcon::setThemeName(QStringLiteral("default")); + } } // apply locale @@ -290,35 +339,15 @@ QWidget *QtAppearanceOptionPage::setupWidget() [this] { ui()->paletteToolButton->setPalette(PaletteEditor::getPalette(this->widget(), ui()->paletteToolButton->palette())); }); // setup icon theme selection - const QStringList searchPaths = QIcon::themeSearchPaths() << QStringLiteral("/usr/share/icons/"); - for (const QString &searchPath : searchPaths) { - const auto dir = QDir(searchPath).entryList(QDir::Dirs | QDir::NoDotAndDotDot, QDir::Name); - for (const QString &iconTheme : dir) { - const int existingItemIndex = ui()->iconThemeComboBox->findData(iconTheme); - QFile indexFile(searchPath % QChar('/') % iconTheme % QStringLiteral("/index.theme")); - QByteArray index; - if (indexFile.open(QFile::ReadOnly) && !(index = indexFile.readAll()).isEmpty()) { - const auto iconThemeSection = index.indexOf("[Icon Theme]"); - const auto nameStart = index.indexOf("Name=", iconThemeSection != -1 ? iconThemeSection : 0); - if (nameStart != -1) { - auto nameLength = index.indexOf("\n", nameStart) - nameStart - 5; - if (nameLength > 0) { - QString displayName = index.mid(nameStart + 5, nameLength); - if (displayName != iconTheme) { - displayName += QChar(' ') % QChar('(') % iconTheme % QChar(')'); - } - if (existingItemIndex != -1) { - ui()->iconThemeComboBox->setItemText(existingItemIndex, displayName); - } else { - ui()->iconThemeComboBox->addItem(displayName, iconTheme); - } - continue; - } - } - } - if (existingItemIndex == -1) { - ui()->iconThemeComboBox->addItem(iconTheme, iconTheme); - } + const auto iconThemes = scanIconThemes(QIcon::themeSearchPaths() << QStringLiteral("/usr/share/icons/")); + auto *iconThemeComboBox = ui()->iconThemeComboBox; + for (auto i = iconThemes.begin(), end = iconThemes.end(); i != end; ++i) { + const auto &displayName = i.key(); + const auto &id = i.value(); + if (const auto existingItemIndex = iconThemeComboBox->findData(id); existingItemIndex != -1) { + iconThemeComboBox->setItemText(existingItemIndex, displayName); + } else { + iconThemeComboBox->addItem(displayName, id); } }