X-Git-Url: https://git.quassel-irc.org/?p=quassel.git;a=blobdiff_plain;f=src%2Fqtui%2Fqtui.cpp;h=d899ba8e5858e1422843d1320ea72e896eb6db51;hp=9c7cbbf884a7adf51f40247cd64e0ea6991d31c0;hb=932ab289c1482a8069cc320a16aca9216058523a;hpb=9fc57dc2c000e80fb8bd746a090e2e8210e1278e diff --git a/src/qtui/qtui.cpp b/src/qtui/qtui.cpp index 9c7cbbf8..d899ba8e 100644 --- a/src/qtui/qtui.cpp +++ b/src/qtui/qtui.cpp @@ -1,5 +1,5 @@ /*************************************************************************** - * Copyright (C) 2005-2013 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,10 +20,17 @@ #include "qtui.h" +#include +#include +#include +#include +#include + #include "abstractnotificationbackend.h" #include "buffermodel.h" #include "chatlinemodel.h" #include "contextmenuactionprovider.h" +#include "icon.h" #include "mainwin.h" #include "qtuimessageprocessor.h" #include "qtuisettings.h" @@ -33,26 +40,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(icon::get("quassel")); + setContextMenuActionProvider(new ContextMenuActionProvider(this)); setToolBarActionProvider(new ToolBarActionProvider(this)); @@ -71,8 +85,8 @@ QtUi::~QtUi() { unregisterAllNotificationBackends(); delete _mainWin; - _mainWin = 0; - _instance = 0; + _mainWin = nullptr; + _instance = nullptr; } @@ -252,3 +266,146 @@ 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") }, +#ifdef WITH_OXYGEN_ICONS + { "oxygen", tr("Oxygen") } +#endif + }; + + 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", true).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 +}