X-Git-Url: https://git.quassel-irc.org/?p=quassel.git;a=blobdiff_plain;f=src%2Fqtui%2Fqtui.cpp;h=7b658b9c296a9bdbc08b1c1e6fb32fa624d86256;hp=0e637802cab6bd925aac43e21e1013926b9f952e;hb=911f181e0e179eb51279c0880eb701a43163b8b5;hpb=695758015a80eb8c158a9ac4c0f1c0b547e70df3 diff --git a/src/qtui/qtui.cpp b/src/qtui/qtui.cpp index 0e637802..7b658b9c 100644 --- a/src/qtui/qtui.cpp +++ b/src/qtui/qtui.cpp @@ -1,5 +1,5 @@ /*************************************************************************** - * Copyright (C) 2005-2015 by the Quassel Project * + * Copyright (C) 2005-2018 by the Quassel Project * * devel@quassel-irc.org * * * * This program is free software; you can redistribute it and/or modify * @@ -20,6 +20,12 @@ #include "qtui.h" +#include +#include +#include +#include +#include + #include "abstractnotificationbackend.h" #include "buffermodel.h" #include "chatlinemodel.h" @@ -33,26 +39,33 @@ #include "types.h" #include "util.h" -#ifdef Q_WS_X11 -# include -#endif - -QtUi *QtUi::_instance = 0; -MainWin *QtUi::_mainWin = 0; +QtUi *QtUi::_instance = nullptr; +MainWin *QtUi::_mainWin = nullptr; QList QtUi::_notificationBackends; QList QtUi::_notifications; -QtUi::QtUi() : GraphicalUi() +QtUi::QtUi() + : GraphicalUi() + , _systemIconTheme{QIcon::themeName()} { - if (_instance != 0) { + if (_instance != nullptr) { qWarning() << "QtUi has been instantiated again!"; return; } _instance = this; + if (Quassel::isOptionSet("icontheme")) { + _systemIconTheme = Quassel::optionValue("icontheme"); + QIcon::setThemeName(_systemIconTheme); + } + QtUiSettings uiSettings; Quassel::loadTranslation(uiSettings.value("Locale", QLocale::system()).value()); + setupIconTheme(); + + QApplication::setWindowIcon(QIcon::fromTheme("quassel")); + setContextMenuActionProvider(new ContextMenuActionProvider(this)); setToolBarActionProvider(new ToolBarActionProvider(this)); @@ -71,8 +84,8 @@ QtUi::~QtUi() { unregisterAllNotificationBackends(); delete _mainWin; - _mainWin = 0; - _instance = 0; + _mainWin = nullptr; + _instance = nullptr; } @@ -252,3 +265,144 @@ void QtUi::bufferMarkedAsRead(BufferId bufferId) closeNotifications(bufferId); } } + + +std::vector> QtUi::availableIconThemes() const +{ + //: Supported icon theme names + static const std::vector> supported { + { "breeze", tr("Breeze") }, + { "breeze-dark", tr("Breeze Dark") }, + { "oxygen", tr("Oxygen") } + }; + + std::vector> result; + for (auto &&themePair : supported) { + for (auto &&dir : QIcon::themeSearchPaths()) { + if (QFileInfo{dir + "/" + themePair.first + "/index.theme"}.exists()) { + result.push_back(themePair); + break; + } + } + } + + return result; +} + + +QString QtUi::systemIconTheme() const +{ + return _systemIconTheme; +} + + +void QtUi::setupIconTheme() +{ + // Add paths to our own icon sets to the theme search paths + QStringList themePaths = QIcon::themeSearchPaths(); + themePaths.removeAll(":/icons"); // this should come last + for (auto &&dataDir : Quassel::dataDirPaths()) { + QString iconDir{dataDir + "icons"}; + if (QFileInfo{iconDir}.isDir()) { + themePaths << iconDir; + } + } + themePaths << ":/icons"; + QIcon::setThemeSearchPaths(themePaths); + + refreshIconTheme(); +} + + +void QtUi::refreshIconTheme() +{ + // List of available fallback themes + QStringList availableThemes; + for (auto &&themePair : availableIconThemes()) { + availableThemes << themePair.first; + } + + if (availableThemes.isEmpty()) { + // We could probably introduce a more sophisticated fallback handling, such as putting the "most important" icons into hicolor, + // but this just gets complex for no good reason. We really rely on a supported theme to be installed, if not system-wide, then + // as part of the Quassel installation (which is enabled by default anyway). + qWarning() << tr("No supported icon theme installed, you'll lack icons! Supported are the KDE/Plasma themes Breeze, Breeze Dark and Oxygen."); + return; + } + + UiStyleSettings s; + QString fallbackTheme{s.value("Icons/FallbackTheme").toString()}; + + if (fallbackTheme.isEmpty() || !availableThemes.contains(fallbackTheme)) { + if (availableThemes.contains(_systemIconTheme)) { + fallbackTheme = _systemIconTheme; + } + else { + fallbackTheme = availableThemes.first(); + } + } + + if (_systemIconTheme.isEmpty() || _systemIconTheme == fallbackTheme || s.value("Icons/OverrideSystemTheme", false).toBool()) { + // We have a valid fallback theme and want to override the system theme (if it's even defined), so we're basically done + QIcon::setThemeName(fallbackTheme); + emit iconThemeRefreshed(); + return; + } + +#if QT_VERSION >= 0x050000 + // At this point, we have a system theme that we don't want to override, but that may not contain all + // required icons. + // We create a dummy theme that inherits first from the system theme, then from the supported fallback. + // This rather ugly hack allows us to inject the fallback into the inheritance chain, so non-standard + // icons missing in the system theme will be filled in by the fallback. + // Since we can't get notified when the system theme changes, this means that a restart may be required + // to apply a theme change... but you can't have everything, I guess. + if (!_dummyThemeDir) { + _dummyThemeDir.reset(new QTemporaryDir{}); + if (!_dummyThemeDir->isValid() || !QDir{_dummyThemeDir->path()}.mkpath("icons/quassel-icon-proxy/apps/32")) { + qWarning() << "Could not create temporary directory for proxying the system icon theme, using fallback"; + QIcon::setThemeName(fallbackTheme); + emit iconThemeRefreshed(); + return; + } + // Add this to XDG_DATA_DIRS, otherwise KIconLoader complains + auto xdgDataDirs = qgetenv("XDG_DATA_DIRS"); + if (!xdgDataDirs.isEmpty()) + xdgDataDirs += ":"; + xdgDataDirs += _dummyThemeDir->path(); + qputenv("XDG_DATA_DIRS", xdgDataDirs); + + QIcon::setThemeSearchPaths(QIcon::themeSearchPaths() << _dummyThemeDir->path() + "/icons"); + } + + QFile indexFile{_dummyThemeDir->path() + "/icons/quassel-icon-proxy/index.theme"}; + if (!indexFile.open(QFile::WriteOnly|QFile::Truncate)) { + qWarning() << "Could not create index file for proxying the system icon theme, using fallback"; + QIcon::setThemeName(fallbackTheme); + emit iconThemeRefreshed(); + return; + } + + // Write a dummy index file that is sufficient to make QIconLoader happy + auto indexContents = QString{ + "[Icon Theme]\n" + "Name=quassel-icon-proxy\n" + "Inherits=%1,%2\n" + "Directories=apps/32\n" + "[apps/32]\nSize=32\nType=Fixed\n" + }.arg(_systemIconTheme, fallbackTheme); + if (indexFile.write(indexContents.toLatin1()) < 0) { + qWarning() << "Could not write index file for proxying the system icon theme, using fallback"; + QIcon::setThemeName(fallbackTheme); + emit iconThemeRefreshed(); + return; + } + indexFile.close(); + QIcon::setThemeName("quassel-icon-proxy"); +#else + // Qt4 doesn't support QTemporaryDir. Since it's deprecated and slated to be removed soon anyway, we don't bother + // writing a replacement and simply don't support not overriding the system theme. + QIcon::setThemeName(fallbackTheme); + emit iconThemeRefreshed(); +#endif +}