diff --git a/src/core/iconimageprovider.cpp b/src/core/iconimageprovider.cpp index 1dbe3e76..48b2bb3d 100644 --- a/src/core/iconimageprovider.cpp +++ b/src/core/iconimageprovider.cpp @@ -2,19 +2,136 @@ #include #include +#include +#include +#include #include #include #include #include +#include #include #include +namespace { +// Get the system's color scheme preference +bool getSystemDarkPreference() { + // Check KDE + const QSettings kdeSettings(QDir::homePath() + "/.config/kdeglobals", QSettings::IniFormat); + if (kdeSettings.value("General/ColorScheme").toString().toLower().contains("dark")) { + return true; + } + + // Check GTK + const QSettings gtk4Settings( + QDir::homePath() + "/.config/gtk-4.0/settings.ini", + QSettings::IniFormat + ); + + return gtk4Settings.value("Settings/gtk-application-prefer-dark-theme", false).toBool(); +} + +QStringList listThemes() { + QStringList themes; + for (const auto& basePath: QIcon::themeSearchPaths()) { + const QDir dir(basePath); + if (!dir.exists()) continue; + themes.append(dir.entryList(QDir::Dirs | QDir::NoDotAndDotDot)); + } + + themes.removeDuplicates(); + themes.sort(); + + return themes; +} + +QStringList getThemes() { + QStringList themes; + + const QStringList available = listThemes(); + const bool preferDark = getSystemDarkPreference(); + + // If dark mode is preferred, prioritize dark themes + if (preferDark) { + for (const auto& theme: available) { + const QString lower = theme.toLower(); + if (lower.contains("dark") || lower.contains("-night") || lower.contains("_dark")) { + themes.append(theme); + } + } + } else { + for (const auto& theme: available) { + const QString lower = theme.toLower(); + if (lower.contains("light") || lower.contains("-day") || lower.contains("_light")) { + themes.append(theme); + } + } + } + + for (const auto& theme: available) { + if (!themes.contains(theme)) { + themes.append(theme); + } + } + + return themes; +} + +QIcon findIconAcrossThemes(const QString& iconName) { + const QStringList themes = getThemes(); + const QStringList categories = {"status", "apps", "actions", "places", "devices"}; + const QStringList sizes = {"scalable", "symbolic", "16", "22", "24", "32", "48", "64", "128"}; + const QStringList extensions = {".png", ".svg"}; + + for (const auto& base: QIcon::themeSearchPaths()) { + for (const auto& theme: themes) { + for (const auto& category: categories) { + for (const auto& size: sizes) { + for (const auto& ext: extensions) { + const QString path = + QString("%1/%2/%3/%4/%5%6").arg(base, theme, category, size, iconName, ext); + + if (QFile::exists(path)) { + return QIcon(path); + } + } + } + } + } + } + + return QIcon(); +} + +} // namespace + QPixmap IconImageProvider::requestPixmap(const QString& id, QSize* size, const QSize& requestedSize) { QString iconName; QString fallbackName; QString path; + static bool pathsFixed = false; + static bool themeSet = false; + + if (!pathsFixed) { + auto paths = QIcon::themeSearchPaths(); + paths.append("/usr/local/share/icons"); // unix + paths.append("/usr/share/icons"); // tux + + QIcon::setThemeSearchPaths(paths); + pathsFixed = true; + } + + if (!themeSet) { + const QString selectedTheme = getThemes().first(); + if (!selectedTheme.isEmpty()) { + QIcon::setThemeName(selectedTheme); + } + + themeSet = true; + } + auto splitIdx = id.indexOf("?path="); if (splitIdx != -1) { iconName = id.sliced(0, splitIdx); @@ -31,8 +148,37 @@ IconImageProvider::requestPixmap(const QString& id, QSize* size, const QSize& re } auto icon = QIcon::fromTheme(iconName); + if (icon.isNull() && !fallbackName.isEmpty()) icon = QIcon::fromTheme(fallbackName); + if (icon.isNull()) { + const QStringList loosePaths = { + // homedir + QString("%1/.local/share/icons/%2.png").arg(QDir::homePath(), iconName), + QString("%1/.local/share/icons/%2.svg").arg(QDir::homePath(), iconName), + // unix + QString("/usr/local/share/icons/%1.png").arg(iconName), + QString("/usr/local/share/icons/%1.svg").arg(iconName), + QString("/usr/local/share/pixmaps/%1.png").arg(iconName), + QString("/usr/local/share/pixmaps/%1.svg").arg(iconName), + // tux + QString("/usr/share/icons/%1.png").arg(iconName), + QString("/usr/share/icons/%1.svg").arg(iconName), + QString("/usr/share/pixmaps/%1.png").arg(iconName), + QString("/usr/share/pixmaps/%1.svg").arg(iconName), + }; + + for (const auto& loosePath: loosePaths) { + if (QFile::exists(loosePath)) { + icon = QIcon(loosePath); + break; + } + } + } + if (icon.isNull() && !path.isEmpty()) icon = QPixmap(path); + if (icon.isNull()) { + icon = findIconAcrossThemes(iconName); + } auto targetSize = requestedSize.isValid() ? requestedSize : QSize(100, 100); if (targetSize.width() == 0 || targetSize.height() == 0) targetSize = QSize(2, 2);