From 4cf0deef73ff2f24a80622ec5f391d10c74ea6c7 Mon Sep 17 00:00:00 2001 From: Friedemann Kleint Date: Fri, 10 Feb 2012 17:17:36 +0100 Subject: Add palette() and further hints to QtGui/QPlatformTheme. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Move palette() from deprecated QtWidgets/QGuiPlatformPlugin to QtGui/QPlatformTheme, Make it return a const * since QPalette does not have isNull(). - Initialize QGuiApplication::palette() and QApplication::systemPalette() from it. - Do not initialize QPalette from QGuiApplication::palette() unless app_pal is non-null (default to Qt::black if it is 0). This avoids initialization order crashes/recursions in the QPA plugin. Streamline initialization function. - Remove styleName(), systemIconThemeName() and iconSearchPaths() from QGuiPlatformPlugin and re-add them as QPlatformTheme::themeHint(). - Remove styleHint() from QGuiPlatformPlugin, add it to QPlatformTheme::themeHint(). - Add UNIX themes with factory function (Generic, KDE, Gnome), taking it from Qt 4.8 code (stripping the KDE 3 code). - Implement Windows palettes. Task-number: QTBUG-24204 Change-Id: Ie27ec035df4f84c42deaffc4816b2e53ce705462 Reviewed-by: Morten Johan Sørvig --- src/platformsupport/platformsupport.pro | 1 + .../services/genericunix/qgenericunixservices.cpp | 9 +- .../services/genericunix/qgenericunixservices_p.h | 5 +- .../themes/genericunix/genericunix.pri | 2 + .../themes/genericunix/qgenericunixthemes.cpp | 325 +++++++++++++++++++++ .../themes/genericunix/qgenericunixthemes_p.h | 106 +++++++ src/platformsupport/themes/themes.pri | 3 + 7 files changed, 445 insertions(+), 6 deletions(-) create mode 100644 src/platformsupport/themes/genericunix/genericunix.pri create mode 100644 src/platformsupport/themes/genericunix/qgenericunixthemes.cpp create mode 100644 src/platformsupport/themes/genericunix/qgenericunixthemes_p.h create mode 100644 src/platformsupport/themes/themes.pri (limited to 'src/platformsupport') diff --git a/src/platformsupport/platformsupport.pro b/src/platformsupport/platformsupport.pro index 4c02a8ff57..8322d4c70f 100644 --- a/src/platformsupport/platformsupport.pro +++ b/src/platformsupport/platformsupport.pro @@ -35,3 +35,4 @@ include(glxconvenience/glxconvenience.pri) include(inputcontext/inputcontext.pri) include(udev/udev.pri) include(services/services.pri) +include(themes/themes.pri) diff --git a/src/platformsupport/services/genericunix/qgenericunixservices.cpp b/src/platformsupport/services/genericunix/qgenericunixservices.cpp index 3c10fb63f6..34f46e4e6e 100644 --- a/src/platformsupport/services/genericunix/qgenericunixservices.cpp +++ b/src/platformsupport/services/genericunix/qgenericunixservices.cpp @@ -122,9 +122,10 @@ static inline bool launch(const QString &launcher, const QUrl &url) return ok; } -QGenericUnixServices::QGenericUnixServices() : - m_desktopEnvironment(detectDesktopEnvironment()) +QGenericUnixServices::DesktopEnvironment QGenericUnixServices::desktopEnvironment() { + static const DesktopEnvironment result = detectDesktopEnvironment(); + return result; } bool QGenericUnixServices::openUrl(const QUrl &url) @@ -132,7 +133,7 @@ bool QGenericUnixServices::openUrl(const QUrl &url) if (url.scheme() == QStringLiteral("mailto")) return openDocument(url); - if (m_webBrowser.isEmpty() && !detectWebBrowser(m_desktopEnvironment, true, &m_webBrowser)) { + if (m_webBrowser.isEmpty() && !detectWebBrowser(desktopEnvironment(), true, &m_webBrowser)) { qWarning("%s: Unable to detect a web browser to launch '%s'", Q_FUNC_INFO, qPrintable(url.toString())); return false; } @@ -141,7 +142,7 @@ bool QGenericUnixServices::openUrl(const QUrl &url) bool QGenericUnixServices::openDocument(const QUrl &url) { - if (m_documentLauncher.isEmpty() && !detectWebBrowser(m_desktopEnvironment, false, &m_documentLauncher)) { + if (m_documentLauncher.isEmpty() && !detectWebBrowser(desktopEnvironment(), false, &m_documentLauncher)) { qWarning("%s: Unable to detect a launcher for '%s'", Q_FUNC_INFO, qPrintable(url.toString())); return false; } diff --git a/src/platformsupport/services/genericunix/qgenericunixservices_p.h b/src/platformsupport/services/genericunix/qgenericunixservices_p.h index 48b790a5b8..3923a45f89 100644 --- a/src/platformsupport/services/genericunix/qgenericunixservices_p.h +++ b/src/platformsupport/services/genericunix/qgenericunixservices_p.h @@ -58,13 +58,14 @@ public: DE_GNOME }; - QGenericUnixServices(); + QGenericUnixServices() {} + + static DesktopEnvironment desktopEnvironment(); virtual bool openUrl(const QUrl &url); virtual bool openDocument(const QUrl &url); private: - const DesktopEnvironment m_desktopEnvironment; QString m_webBrowser; QString m_documentLauncher; }; diff --git a/src/platformsupport/themes/genericunix/genericunix.pri b/src/platformsupport/themes/genericunix/genericunix.pri new file mode 100644 index 0000000000..eed48257d0 --- /dev/null +++ b/src/platformsupport/themes/genericunix/genericunix.pri @@ -0,0 +1,2 @@ +HEADERS += $$PWD/qgenericunixthemes_p.h +SOURCES += $$PWD/qgenericunixthemes.cpp diff --git a/src/platformsupport/themes/genericunix/qgenericunixthemes.cpp b/src/platformsupport/themes/genericunix/qgenericunixthemes.cpp new file mode 100644 index 0000000000..a9f05f6084 --- /dev/null +++ b/src/platformsupport/themes/genericunix/qgenericunixthemes.cpp @@ -0,0 +1,325 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/ +** +** This file is part of the plugins of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qgenericunixthemes_p.h" +#include "../../services/genericunix/qgenericunixservices_p.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +QT_BEGIN_NAMESPACE + +/*! + \class QGenericX11ThemeQKdeTheme + \brief QGenericX11Theme is a generic theme implementation for X11. + \since 5.0 + \internal + \ingroup qpa +*/ + +// Helper to return the icon theme paths from XDG. +QStringList QGenericUnixTheme::xdgIconThemePaths() +{ + QStringList paths; + // Add home directory first in search path + const QFileInfo homeIconDir(QDir::homePath() + QStringLiteral("/.icons")); + if (homeIconDir.isDir()) + paths.prepend(homeIconDir.absoluteFilePath()); + + QString xdgDirString = QFile::decodeName(qgetenv("XDG_DATA_DIRS")); + if (xdgDirString.isEmpty()) + xdgDirString = QLatin1String("/usr/local/share/:/usr/share/"); + foreach (const QString &xdgDir, xdgDirString.split(QLatin1Char(':'))) { + const QFileInfo xdgIconsDir(xdgDir + QStringLiteral("/icons")); + if (xdgIconsDir.isDir()) + paths.append(xdgIconsDir.absoluteFilePath()); + } + return paths; +} + +QVariant QGenericUnixTheme::themeHint(ThemeHint hint) const +{ + switch (hint) { + case QPlatformTheme::SystemIconFallbackThemeName: + return QVariant(QString(QStringLiteral("hicolor"))); + case QPlatformTheme::IconThemeSearchPaths: + return xdgIconThemePaths(); + case QPlatformTheme::StyleNames: { + QStringList styleNames; + styleNames << QStringLiteral("Plastique") << QStringLiteral("Windows"); + return QVariant(styleNames); + } + break; + default: + break; + } + return QPlatformTheme::themeHint(hint); +} + +// Reads the color from the KDE configuration, and store it in the +// palette with the given color role if found. +static inline bool kdeColor(QPalette *pal, QPalette::ColorRole role, + const QSettings &kdeSettings, const QString &key) +{ + const QVariant value = kdeSettings.value(key); + if (!value.isValid()) + return false; + const QStringList values = value.toStringList(); + if (values.size() != 3) + return false; + pal->setBrush(role, QColor(values.at(0).toInt(), values.at(1).toInt(), values.at(2).toInt())); + return true; +} + +// Reads the KDE system palette +static inline bool readKdeSystemPalette(const QSettings &kdeSettings, QPalette *pal) +{ + // Setup KDE palette + return kdeColor(pal, QPalette::Button, kdeSettings, QStringLiteral("Colors:Button/BackgroundNormal")) + || kdeColor(pal, QPalette::Window, kdeSettings, QStringLiteral("Colors:Window/BackgroundNormal")) + || kdeColor(pal, QPalette::Text, kdeSettings, QStringLiteral("Colors:View/ForegroundNormal")) + || kdeColor(pal, QPalette::WindowText, kdeSettings, QStringLiteral("Colors:Window/ForegroundNormal")) + || kdeColor(pal, QPalette::Base, kdeSettings, QStringLiteral("Colors:View/BackgroundNormal")) + || kdeColor(pal, QPalette::Highlight, kdeSettings, QStringLiteral("Colors:Selection/BackgroundNormal")) + || kdeColor(pal, QPalette::HighlightedText, kdeSettings, QStringLiteral("Colors:Selection/ForegroundNormal")) + || kdeColor(pal, QPalette::AlternateBase, kdeSettings, QStringLiteral("Colors:View/BackgroundAlternate")) + || kdeColor(pal, QPalette::ButtonText, kdeSettings, QStringLiteral("Colors:Button/ForegroundNormal")) + || kdeColor(pal, QPalette::Link, kdeSettings, QStringLiteral("Colors:View/ForegroundLink")) + || kdeColor(pal, QPalette::LinkVisited, kdeSettings, QStringLiteral("Colors:View/ForegroundVisited")); +} + +/*! + \class QKdeTheme + \brief QKdeTheme is a theme implementation for the KDE desktop (version 4 or higher). + \since 5.0 + \internal + \ingroup qpa +*/ + +QKdeTheme::QKdeTheme(const QString &kdeHome, int kdeVersion) : + m_kdeHome(kdeHome), m_kdeVersion(kdeVersion), + m_toolButtonStyle(Qt::ToolButtonTextBesideIcon), m_toolBarIconSize(0) +{ + qFill(m_palettes, m_palettes + NPalettes, static_cast(0)); + refresh(); +} + +void QKdeTheme::clearPalettes() +{ + qDeleteAll(m_palettes, m_palettes + NPalettes); + qFill(m_palettes, m_palettes + NPalettes, static_cast(0)); +} + +void QKdeTheme::refresh() +{ + clearPalettes(); + + m_toolButtonStyle = Qt::ToolButtonTextBesideIcon; + m_toolBarIconSize = 0; + m_styleNames.clear(); + m_styleNames << QStringLiteral("Oxygen") << QStringLiteral("plastique") << QStringLiteral("windows"); + m_iconFallbackThemeName = m_iconThemeName = QStringLiteral("oxygen"); + + // Read settings file. + const QString settingsFile = globalSettingsFile(); + if (!QFileInfo(settingsFile).isReadable()) + return; + + const QSettings kdeSettings(settingsFile, QSettings::IniFormat); + + QPalette systemPalette; + if (readKdeSystemPalette(kdeSettings, &systemPalette)) + m_palettes[SystemPalette] = new QPalette(systemPalette); + //## TODO tooltip color + + const QVariant styleValue = kdeSettings.value(QStringLiteral("widgetStyle")); + if (styleValue.isValid()) { + const QString style = styleValue.toString(); + if (style != m_styleNames.front()) + m_styleNames.push_front(style); + } + + const QVariant themeValue = kdeSettings.value(QStringLiteral("Icons/Theme")); + if (themeValue.isValid()) + m_iconThemeName = themeValue.toString(); + + const QVariant toolBarIconSizeValue = kdeSettings.value(QStringLiteral("ToolbarIcons/Size")); + if (toolBarIconSizeValue.isValid()) + m_toolBarIconSize = toolBarIconSizeValue.toInt(); + + const QVariant toolbarStyleValue = kdeSettings.value(QStringLiteral("ToolButtonStyle")); + if (toolbarStyleValue.isValid()) { + const QString toolBarStyle = toolbarStyleValue.toString(); + if (toolBarStyle == QStringLiteral("TextBesideIcon")) + m_toolButtonStyle = Qt::ToolButtonTextBesideIcon; + else if (toolBarStyle == QStringLiteral("TextOnly")) + m_toolButtonStyle = Qt::ToolButtonTextOnly; + else if (toolBarStyle == QStringLiteral("TextUnderIcon")) + m_toolButtonStyle = Qt::ToolButtonTextUnderIcon; + } +} + +QString QKdeTheme::globalSettingsFile() const +{ + return m_kdeHome + QStringLiteral("/share/config/kdeglobals"); +} + +static QStringList kdeIconThemeSearchPaths(const QString &kdeHome) +{ + QStringList candidates = QStringList(kdeHome); + const QString kdeDirs = QFile::decodeName(qgetenv("KDEDIRS")); + if (!kdeDirs.isEmpty()) + candidates.append(kdeDirs.split(QLatin1Char(':'))); + + QStringList paths = QGenericUnixTheme::xdgIconThemePaths(); + const QString iconPath = QStringLiteral("/share/icons"); + foreach (const QString &candidate, candidates) { + const QFileInfo fi(candidate + iconPath); + if (fi.isDir()) + paths.append(fi.absoluteFilePath()); + } + return paths; +} + +QVariant QKdeTheme::themeHint(QPlatformTheme::ThemeHint hint) const +{ + switch (hint) { + case QPlatformTheme::ToolButtonStyle: + return QVariant(m_toolButtonStyle); + case QPlatformTheme::ToolBarIconSize: + return QVariant(m_toolBarIconSize); + case QPlatformTheme::SystemIconThemeName: + return QVariant(m_iconThemeName); + case QPlatformTheme::SystemIconFallbackThemeName: + return QVariant(m_iconFallbackThemeName); + case QPlatformTheme::IconThemeSearchPaths: + return QVariant(kdeIconThemeSearchPaths(m_kdeHome)); + case QPlatformTheme::StyleNames: + return QVariant(m_styleNames); + default: + break; + } + return QPlatformTheme::themeHint(hint); +} + +QPlatformTheme *QKdeTheme::createKdeTheme() +{ + // Check for version >= 4 and determine home folder from environment, + // defaulting to ~/.kde, ~/.kde + const QByteArray kdeVersionBA = qgetenv("KDE_SESSION_VERSION"); + const int kdeVersion = kdeVersionBA.toInt(); + if (kdeVersion < 4) + return 0; + const QString kdeHomePathVar = QString::fromLocal8Bit(qgetenv("KDEHOME")); + if (!kdeHomePathVar.isEmpty()) + return new QKdeTheme(kdeHomePathVar, kdeVersion); + + const QString kdeVersionHomePath = QDir::homePath() + QStringLiteral("/.kde") + QLatin1String(kdeVersionBA); + if (QFileInfo(kdeVersionHomePath).isDir()) + return new QKdeTheme(kdeVersionHomePath, kdeVersion); + + const QString kdeHomePath = QDir::homePath() + QStringLiteral("/.kde"); + if (QFileInfo(kdeHomePath).isDir()) + return new QKdeTheme(kdeHomePath, kdeVersion); + + qWarning("%s: Unable to determine KDEHOME", Q_FUNC_INFO); + return 0; +} + +/*! + \class QGnomeTheme + \brief QGnomeTheme is a theme implementation for the Gnome desktop. + \since 5.0 + \internal + \ingroup qpa +*/ + +QVariant QGnomeTheme::themeHint(QPlatformTheme::ThemeHint hint) const +{ + switch (hint) { + case QPlatformTheme::SystemIconThemeName: + case QPlatformTheme::SystemIconFallbackThemeName: + return QVariant(QString(QStringLiteral("gnome"))); + case QPlatformTheme::IconThemeSearchPaths: + return QVariant(QGenericUnixTheme::xdgIconThemePaths()); + case QPlatformTheme::StyleNames: { + QStringList styleNames; + styleNames << QStringLiteral("GTK+") << QStringLiteral("cleanlooks") << QStringLiteral("windows"); + return QVariant(styleNames); + } + default: + break; + } + return QPlatformTheme::themeHint(hint); +} + +/*! + \brief Creates a UNIX theme according to the detected desktop environment. +*/ + +QPlatformTheme *QGenericUnixTheme::createUnixTheme() +{ + QPlatformTheme *result = 0; + if (QGuiApplication::desktopSettingsAware()) { + switch (QGenericUnixServices::desktopEnvironment()) { + case QGenericUnixServices::DE_UNKNOWN: + break; + case QGenericUnixServices::DE_KDE: + result = QKdeTheme::createKdeTheme(); + break; + case QGenericUnixServices::DE_GNOME: + result = new QGnomeTheme; + break; + } + } + if (!result) + result = new QGenericUnixTheme; + return result; +} + +QT_END_NAMESPACE diff --git a/src/platformsupport/themes/genericunix/qgenericunixthemes_p.h b/src/platformsupport/themes/genericunix/qgenericunixthemes_p.h new file mode 100644 index 0000000000..12937a205f --- /dev/null +++ b/src/platformsupport/themes/genericunix/qgenericunixthemes_p.h @@ -0,0 +1,106 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/ +** +** This file is part of the plugins of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QGENERICUNIXTHEMES_H +#define QGENERICUNIXTHEMES_H + +#include +#include +#include + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +class QGenericUnixTheme : public QPlatformTheme +{ +public: + QGenericUnixTheme() {} + + static QPlatformTheme *createUnixTheme(); + + virtual QVariant themeHint(ThemeHint hint) const; + + static QStringList xdgIconThemePaths(); +}; + +class QKdeTheme : public QPlatformTheme +{ + QKdeTheme(const QString &kdeHome, int kdeVersion); +public: + ~QKdeTheme() { clearPalettes(); } + + static QPlatformTheme *createKdeTheme(); + virtual QVariant themeHint(ThemeHint hint) const; + virtual const QPalette *palette(Palette type = SystemPalette) const + { return m_palettes[type]; } + +private: + QString globalSettingsFile() const; + void clearPalettes(); + void refresh(); + + const QString m_kdeHome; + const int m_kdeVersion; + QPalette *m_palettes[NPalettes]; + QString m_iconThemeName; + QString m_iconFallbackThemeName; + QStringList m_styleNames; + int m_toolButtonStyle; + int m_toolBarIconSize; +}; + +class QGnomeTheme : public QPlatformTheme +{ +public: + QGnomeTheme() {} + virtual QVariant themeHint(ThemeHint hint) const; + +private: +}; + +QPlatformTheme *qt_createUnixTheme(); + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif // QGENERICUNIXTHEMES_H diff --git a/src/platformsupport/themes/themes.pri b/src/platformsupport/themes/themes.pri new file mode 100644 index 0000000000..adee852626 --- /dev/null +++ b/src/platformsupport/themes/themes.pri @@ -0,0 +1,3 @@ +unix:!mac { + include($$PWD/genericunix/genericunix.pri) +} -- cgit v1.2.3