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/gui/kernel/qguiapplication.cpp | 4 + src/gui/kernel/qpalette.cpp | 62 ++-- src/gui/kernel/qplatformtheme_qpa.cpp | 36 +++ src/gui/kernel/qplatformtheme_qpa.h | 19 +- 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 + src/plugins/platforms/cocoa/qcocoatheme.h | 2 + src/plugins/platforms/cocoa/qcocoatheme.mm | 12 + .../platforms/windows/qtwindows_additional.h | 4 + src/plugins/platforms/windows/qtwindowsglobal.h | 6 +- src/plugins/platforms/windows/qwindowscontext.cpp | 6 + src/plugins/platforms/windows/qwindowscontext.h | 1 + .../platforms/windows/qwindowsdialoghelpers.cpp | 7 +- .../windows/qwindowsguieventdispatcher.cpp | 3 +- src/plugins/platforms/windows/qwindowstheme.cpp | 175 +++++++++++ src/plugins/platforms/windows/qwindowstheme.h | 24 ++ src/plugins/platforms/xcb/qxcbintegration.cpp | 9 +- src/plugins/platforms/xcb/qxcbintegration.h | 3 + src/widgets/kernel/qapplication.cpp | 15 +- src/widgets/kernel/qapplication_qpa.cpp | 7 +- src/widgets/kernel/qguiplatformplugin.cpp | 159 ---------- src/widgets/kernel/qguiplatformplugin_p.h | 7 - src/widgets/kernel/qicon.cpp | 1 - src/widgets/kernel/qiconloader.cpp | 52 +++- src/widgets/styles/qcommonstyle.cpp | 19 +- .../dialogs/qmessagebox/tst_qmessagebox.cpp | 4 +- 31 files changed, 849 insertions(+), 239 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 diff --git a/src/gui/kernel/qguiapplication.cpp b/src/gui/kernel/qguiapplication.cpp index 5f50fe343a..9f8186424e 100644 --- a/src/gui/kernel/qguiapplication.cpp +++ b/src/gui/kernel/qguiapplication.cpp @@ -48,6 +48,7 @@ #include "qplatformfontdatabase_qpa.h" #include "qplatformwindow_qpa.h" #include "qplatformnativeinterface_qpa.h" +#include "qplatformtheme_qpa.h" #include #include @@ -1382,6 +1383,9 @@ QClipboard * QGuiApplication::clipboard() */ QPalette QGuiApplication::palette() { + if (!QGuiApplicationPrivate::app_pal) + if (const QPalette *themePalette = QGuiApplicationPrivate::platformTheme()->palette()) + QGuiApplicationPrivate::app_pal = new QPalette(*themePalette); if (!QGuiApplicationPrivate::app_pal) QGuiApplicationPrivate::app_pal = new QPalette(Qt::black); return *QGuiApplicationPrivate::app_pal; diff --git a/src/gui/kernel/qpalette.cpp b/src/gui/kernel/qpalette.cpp index 627731ff20..d5b17fa665 100644 --- a/src/gui/kernel/qpalette.cpp +++ b/src/gui/kernel/qpalette.cpp @@ -41,6 +41,7 @@ #include "qpalette.h" #include "qguiapplication.h" +#include "qguiapplication_p.h" #include "qdatastream.h" #include "qvariant.h" #include "qdebug.h" @@ -64,6 +65,29 @@ static QColor qt_mix_colors(QColor a, QColor b) (a.blue() + b.blue()) / 2, (a.alpha() + b.alpha()) / 2); } +static void qt_palette_from_color(QPalette &pal, const QColor &button) +{ + int h, s, v; + button.getHsv(&h, &s, &v); + // inactive and active are the same.. + const QBrush baseBrush = QBrush(v > 128 ? Qt::white : Qt::black); + const QBrush foregroundBrush = QBrush(v > 128 ? Qt::black : Qt::white); + const QBrush buttonBrush = QBrush(button); + const QBrush buttonBrushDark = QBrush(button.darker()); + const QBrush buttonBrushDark150 = QBrush(button.darker(150)); + const QBrush buttonBrushLight150 = QBrush(button.lighter(150)); + const QBrush whiteBrush = QBrush(Qt::white); + pal.setColorGroup(QPalette::Active, foregroundBrush, buttonBrush, buttonBrushLight150, + buttonBrushDark, buttonBrushDark150, foregroundBrush, whiteBrush, + baseBrush, buttonBrush); + pal.setColorGroup(QPalette::Inactive, foregroundBrush, buttonBrush, buttonBrushLight150, + buttonBrushDark, buttonBrushDark150, foregroundBrush, whiteBrush, + baseBrush, buttonBrush); + pal.setColorGroup(QPalette::Disabled, buttonBrushDark, buttonBrush, buttonBrushLight150, + buttonBrushDark, buttonBrushDark150, buttonBrushDark, + whiteBrush, buttonBrush, buttonBrush); +} + /*! \fn const QColor &QPalette::color(ColorRole role) const @@ -488,40 +512,20 @@ static QColor qt_mix_colors(QColor a, QColor b) \sa QApplication::setPalette(), QApplication::palette() */ QPalette::QPalette() - : d(QGuiApplication::palette().d), - current_group(Active), - resolve_mask(0) -{ - d->ref.ref(); -} - -static void qt_palette_from_color(QPalette &pal, const QColor & button) + : d(0), current_group(Active), resolve_mask(0) { - QColor bg = button, - btn = button, - fg, base; - int h, s, v; - bg.getHsv(&h, &s, &v); - if(v > 128) { - fg = Qt::black; - base = Qt::white; + // Initialize to application palette if present, else default to black. + // This makes it possible to instantiate QPalette outside QGuiApplication, + // for example in the platform plugins. + if (QGuiApplicationPrivate::app_pal) { + d = QGuiApplicationPrivate::app_pal->d; + d->ref.ref(); } else { - fg = Qt::white; - base = Qt::black; + init(); + qt_palette_from_color(*this, Qt::black); } - //inactive and active are the same.. - pal.setColorGroup(QPalette::Active, QBrush(fg), QBrush(btn), QBrush(btn.lighter(150)), - QBrush(btn.darker()), QBrush(btn.darker(150)), QBrush(fg), QBrush(Qt::white), - QBrush(base), QBrush(bg)); - pal.setColorGroup(QPalette::Inactive, QBrush(fg), QBrush(btn), QBrush(btn.lighter(150)), - QBrush(btn.darker()), QBrush(btn.darker(150)), QBrush(fg), QBrush(Qt::white), - QBrush(base), QBrush(bg)); - pal.setColorGroup(QPalette::Disabled, QBrush(btn.darker()), QBrush(btn), QBrush(btn.lighter(150)), - QBrush(btn.darker()), QBrush(btn.darker(150)), QBrush(btn.darker()), - QBrush(Qt::white), QBrush(bg), QBrush(bg)); } - /*! Constructs a palette from the \a button color. The other colors are automatically calculated, based on this color. \c Window will be diff --git a/src/gui/kernel/qplatformtheme_qpa.cpp b/src/gui/kernel/qplatformtheme_qpa.cpp index d2ff804ddf..aec465f0ff 100644 --- a/src/gui/kernel/qplatformtheme_qpa.cpp +++ b/src/gui/kernel/qplatformtheme_qpa.cpp @@ -42,6 +42,8 @@ #include "qplatformtheme_qpa.h" #include +#include +#include QT_BEGIN_NAMESPACE @@ -68,6 +70,21 @@ QT_BEGIN_NAMESPACE \value MaximumScrollBarDragDistance (int) Determines the value returned by QStyle::pixelMetric(PM_MaximumDragDistance) + \value ToolButtonStyle (int) A value representing a Qt::ToolButtonStyle. + + \value ToolBarIconSize Icon size for tool bars. + + \value SystemIconThemeName (QString) Name of the icon theme. + + \value SystemIconFallbackThemeName (QString) Name of the fallback icon theme. + + \value IconThemeSearchPaths (QStringList) Search paths for icons. + + \value ItemViewActivateItemOnSingleClick (bool) Activate items by single click. + + \value StyleNames (QStringList) A list of preferred style names. + + \sa themeHint(), QStyle::pixelMetric() */ @@ -95,9 +112,28 @@ QPlatformDialogHelper *QPlatformTheme::createPlatformDialogHelper(DialogType typ return 0; } +const QPalette *QPlatformTheme::palette(Palette type) const +{ + Q_UNUSED(type) + return 0; +} + QVariant QPlatformTheme::themeHint(ThemeHint hint) const { switch (hint) { + case QPlatformTheme::ItemViewActivateItemOnSingleClick: + return QVariant(false); + case QPlatformTheme::ToolButtonStyle: + return QVariant(int(Qt::ToolButtonIconOnly)); + case QPlatformTheme::ToolBarIconSize: + return QVariant(int(0)); + case QPlatformTheme::SystemIconThemeName: + case QPlatformTheme::SystemIconFallbackThemeName: + return QVariant(QString()); + case QPlatformTheme::IconThemeSearchPaths: + return QVariant(QStringList()); + case QPlatformTheme::StyleNames: + return QVariant(QStringList()); case TextCursorWidth: return QVariant(1); case DropShadow: diff --git a/src/gui/kernel/qplatformtheme_qpa.h b/src/gui/kernel/qplatformtheme_qpa.h index 2b87e63287..036432054e 100644 --- a/src/gui/kernel/qplatformtheme_qpa.h +++ b/src/gui/kernel/qplatformtheme_qpa.h @@ -48,13 +48,13 @@ QT_BEGIN_HEADER QT_BEGIN_NAMESPACE - class QMenu; class QMenuBar; class QPlatformMenu; class QPlatformMenuBar; class QPlatformDialogHelper; class QVariant; +class QPalette; class Q_GUI_EXPORT QPlatformTheme { @@ -62,7 +62,14 @@ public: enum ThemeHint { TextCursorWidth, DropShadow, - MaximumScrollBarDragDistance + MaximumScrollBarDragDistance, + ToolButtonStyle, + ToolBarIconSize, + ItemViewActivateItemOnSingleClick, + SystemIconThemeName, + SystemIconFallbackThemeName, + IconThemeSearchPaths, + StyleNames }; enum DialogType { @@ -71,12 +78,20 @@ public: FontDialog }; + enum Palette { + SystemPalette, + ToolTipPalette, + NPalettes + }; + virtual QPlatformMenu *createPlatformMenu(QMenu *menu = 0) const; virtual QPlatformMenuBar *createPlatformMenuBar(QMenuBar *menuBar = 0) const; virtual bool usePlatformNativeDialog(DialogType type) const; virtual QPlatformDialogHelper *createPlatformDialogHelper(DialogType type) const; + virtual const QPalette *palette(Palette type = SystemPalette) const; + virtual QVariant themeHint(ThemeHint hint) const; }; 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) +} diff --git a/src/plugins/platforms/cocoa/qcocoatheme.h b/src/plugins/platforms/cocoa/qcocoatheme.h index 08f813b906..a7dc973937 100644 --- a/src/plugins/platforms/cocoa/qcocoatheme.h +++ b/src/plugins/platforms/cocoa/qcocoatheme.h @@ -59,6 +59,8 @@ public: bool usePlatformNativeDialog(DialogType dialogType) const; QPlatformDialogHelper *createPlatformDialogHelper(DialogType dialogType) const; + + QVariant themeHint(ThemeHint hint) const; }; QT_END_NAMESPACE diff --git a/src/plugins/platforms/cocoa/qcocoatheme.mm b/src/plugins/platforms/cocoa/qcocoatheme.mm index a23faf438d..ad20c2fb27 100644 --- a/src/plugins/platforms/cocoa/qcocoatheme.mm +++ b/src/plugins/platforms/cocoa/qcocoatheme.mm @@ -102,4 +102,16 @@ QPlatformDialogHelper * QCocoaTheme::createPlatformDialogHelper(DialogType dialo } } +QVariant QCocoaTheme::themeHint(ThemeHint hint) const +{ + switch (hint) { + case QPlatformTheme::StyleNames: + return QStringList() << QLatin1Literal("macintosh"); + break; + default: + return QPlatformTheme::themeHint(hint); + break; + } +} + QT_END_NAMESPACE diff --git a/src/plugins/platforms/windows/qtwindows_additional.h b/src/plugins/platforms/windows/qtwindows_additional.h index ab51f36c24..d82240255e 100644 --- a/src/plugins/platforms/windows/qtwindows_additional.h +++ b/src/plugins/platforms/windows/qtwindows_additional.h @@ -45,6 +45,10 @@ #include // get compiler define #include +#ifndef WM_THEMECHANGED +# define WM_THEMECHANGED 0x031A +#endif + /* Complement the definitions and declarations missing * when using MinGW or older Windows SDKs. */ diff --git a/src/plugins/platforms/windows/qtwindowsglobal.h b/src/plugins/platforms/windows/qtwindowsglobal.h index 3445a3c7a8..27cfbdc662 100644 --- a/src/plugins/platforms/windows/qtwindowsglobal.h +++ b/src/plugins/platforms/windows/qtwindowsglobal.h @@ -60,7 +60,8 @@ enum KeyDownEventFlag = 0x200000, TouchEventFlag = 0x400000, ClipboardEventFlag = 0x800000, - ApplicationEventFlag = 0x1000000 + ApplicationEventFlag = 0x1000000, + ThemingEventFlag = 0x2000000 }; enum WindowsEventType // Simplify event types @@ -97,6 +98,7 @@ enum WindowsEventType // Simplify event types InputMethodOpenCandidateWindowEvent = InputMethodEventFlag + 4, InputMethodCloseCandidateWindowEvent = InputMethodEventFlag + 5, InputMethodRequest = InputMethodEventFlag + 6, + ThemeChanged = ThemingEventFlag + 1, DisplayChangedEvent = 437, UnknownEvent = 542 }; @@ -178,6 +180,8 @@ inline QtWindows::WindowsEventType windowsEventType(UINT message, WPARAM wParamI return QtWindows::FocusOutEvent; case WM_DISPLAYCHANGE: return QtWindows::DisplayChangedEvent; + case WM_THEMECHANGED: + return QtWindows::ThemeChanged; default: break; } diff --git a/src/plugins/platforms/windows/qwindowscontext.cpp b/src/plugins/platforms/windows/qwindowscontext.cpp index a257736d98..2706e02cf8 100644 --- a/src/plugins/platforms/windows/qwindowscontext.cpp +++ b/src/plugins/platforms/windows/qwindowscontext.cpp @@ -49,6 +49,7 @@ #include "qwindowsinputcontext.h" #include "qwindowsaccessibility.h" #include "qwindowsscreen.h" +#include "qwindowstheme.h" #include #include @@ -78,6 +79,7 @@ int QWindowsContext::verboseGL = 0; int QWindowsContext::verboseOLE = 0; int QWindowsContext::verboseInputMethods = 0; int QWindowsContext::verboseDialogs = 0; +int QWindowsContext::verboseTheming = 0; // Get verbosity of components from "foo:2,bar:3" static inline int componentVerbose(const char *v, const char *keyWord) @@ -284,6 +286,7 @@ QWindowsContext::QWindowsContext() : QWindowsContext::verboseOLE = componentVerbose(v, "ole"); QWindowsContext::verboseInputMethods = componentVerbose(v, "im"); QWindowsContext::verboseDialogs = componentVerbose(v, "dialogs"); + QWindowsContext::verboseTheming = componentVerbose(v, "theming"); } } @@ -784,6 +787,9 @@ bool QWindowsContext::windowsProc(HWND hwnd, UINT message, case QtWindows::CloseEvent: QWindowSystemInterface::handleCloseEvent(platformWindow->window()); return true; + case QtWindows::ThemeChanged: // ### fixme: Compress these events? + QWindowsTheme::instance()->windowsThemeChanged(platformWindow->window()); + return true; default: break; } diff --git a/src/plugins/platforms/windows/qwindowscontext.h b/src/plugins/platforms/windows/qwindowscontext.h index b5a36c3fe9..9f16ed232b 100644 --- a/src/plugins/platforms/windows/qwindowscontext.h +++ b/src/plugins/platforms/windows/qwindowscontext.h @@ -121,6 +121,7 @@ public: static int verboseOLE; static int verboseInputMethods; static int verboseDialogs; + static int verboseTheming; explicit QWindowsContext(); ~QWindowsContext(); diff --git a/src/plugins/platforms/windows/qwindowsdialoghelpers.cpp b/src/plugins/platforms/windows/qwindowsdialoghelpers.cpp index 8875590e63..25b9336361 100644 --- a/src/plugins/platforms/windows/qwindowsdialoghelpers.cpp +++ b/src/plugins/platforms/windows/qwindowsdialoghelpers.cpp @@ -43,6 +43,7 @@ #include "qwindowscontext.h" #include "qwindowswindow.h" +#include "qwindowstheme.h" // Color conversion helpers #include #include @@ -1268,12 +1269,6 @@ QWindowsNativeColorDialog::QWindowsNativeColorDialog(const SharedPointerColor &c qFill(m_customColors, m_customColors + 16, COLORREF(0)); } -static inline COLORREF qColorToCOLORREF(const QColor &color) -{ return RGB(color.red(), color.green(), color.blue()); } - -static inline QColor COLORREFToQColor(COLORREF cr) -{ return QColor(GetRValue(cr), GetGValue(cr), GetBValue(cr)); } - void QWindowsNativeColorDialog::exec(HWND owner) { typedef BOOL (WINAPI *ChooseColorWType)(LPCHOOSECOLORW); diff --git a/src/plugins/platforms/windows/qwindowsguieventdispatcher.cpp b/src/plugins/platforms/windows/qwindowsguieventdispatcher.cpp index 34ab1665d8..49158dce48 100644 --- a/src/plugins/platforms/windows/qwindowsguieventdispatcher.cpp +++ b/src/plugins/platforms/windows/qwindowsguieventdispatcher.cpp @@ -203,7 +203,8 @@ messageDebugEntries[] = { {WM_IME_ENDCOMPOSITION, "WM_IME_ENDCOMPOSITION"}, {WM_IME_NOTIFY, "WM_IME_NOTIFY"}, {WM_IME_REQUEST, "WM_IME_REQUEST"}, - {WM_DISPLAYCHANGE, "WM_DISPLAYCHANGE"} + {WM_DISPLAYCHANGE, "WM_DISPLAYCHANGE"}, + {WM_THEMECHANGED , "WM_THEMECHANGED"} }; static inline const MessageDebugEntry *messageDebugEntry(UINT msg) diff --git a/src/plugins/platforms/windows/qwindowstheme.cpp b/src/plugins/platforms/windows/qwindowstheme.cpp index 73cff3c9ce..a59b74cef3 100644 --- a/src/plugins/platforms/windows/qwindowstheme.cpp +++ b/src/plugins/platforms/windows/qwindowstheme.cpp @@ -42,12 +42,126 @@ #include "qwindowstheme.h" #include "qwindowsdialoghelpers.h" #include "qwindowscontext.h" +#include "qwindowsintegration.h" #include "qt_windows.h" #include +#include +#include +#include +#include +#include +#include QT_BEGIN_NAMESPACE +static inline QTextStream& operator<<(QTextStream &str, const QColor &c) +{ + str.setIntegerBase(16); + str.setFieldWidth(2); + str.setPadChar(QLatin1Char('0')); + str << " rgb: #" << c.red() << c.green() << c.blue(); + str.setIntegerBase(10); + str.setFieldWidth(0); + return str; +} + +static inline QString paletteToString(const QPalette &palette) +{ + QString result; + QTextStream str(&result); + str << "text=" << palette.color(QPalette::WindowText) + << " background=" << palette.color(QPalette::Window); + return result; +} + +static inline QColor mixColors(const QColor &c1, const QColor &c2) +{ + return QColor ((c1.red() + c2.red()) / 2, + (c1.green() + c2.green()) / 2, + (c1.blue() + c2.blue()) / 2); +} + +static inline QColor getSysColor(int index) +{ + return qColorToCOLORREF(GetSysColor(index)); +} + +static inline QPalette systemPalette() +{ + QPalette result; + result.setColor(QPalette::WindowText, getSysColor(COLOR_WINDOWTEXT)); + result.setColor(QPalette::Button, getSysColor(COLOR_BTNFACE)); + result.setColor(QPalette::Light, getSysColor(COLOR_BTNHIGHLIGHT)); + result.setColor(QPalette::Dark, getSysColor(COLOR_BTNSHADOW)); + result.setColor(QPalette::Mid, result.button().color().darker(150)); + result.setColor(QPalette::Text, getSysColor(COLOR_WINDOWTEXT)); + result.setColor(QPalette::BrightText, getSysColor(COLOR_BTNHIGHLIGHT)); + result.setColor(QPalette::Base, getSysColor(COLOR_WINDOW)); + result.setColor(QPalette::Window, getSysColor(COLOR_BTNFACE)); + result.setColor(QPalette::ButtonText, getSysColor(COLOR_BTNTEXT)); + result.setColor(QPalette::Midlight, getSysColor(COLOR_3DLIGHT)); + result.setColor(QPalette::Shadow, getSysColor(COLOR_3DDKSHADOW)); + result.setColor(QPalette::Highlight, getSysColor(COLOR_HIGHLIGHT)); + result.setColor(QPalette::HighlightedText, getSysColor(COLOR_HIGHLIGHTTEXT)); + result.setColor(QPalette::Link, Qt::blue); + result.setColor(QPalette::LinkVisited, Qt::magenta); + result.setColor(QPalette::Inactive, QPalette::Button, result.button().color()); + result.setColor(QPalette::Inactive, QPalette::Window, result.background().color()); + result.setColor(QPalette::Inactive, QPalette::Light, result.light().color()); + result.setColor(QPalette::Inactive, QPalette::Dark, result.dark().color()); + + if (result.midlight() == result.button()) + result.setColor(QPalette::Midlight, result.button().color().lighter(110)); + if (result.background() != result.base()) { + result.setColor(QPalette::Inactive, QPalette::Highlight, result.color(QPalette::Inactive, QPalette::Window)); + result.setColor(QPalette::Inactive, QPalette::HighlightedText, result.color(QPalette::Inactive, QPalette::Text)); + } + + const QColor disabled = + mixColors(result.foreground().color(), result.button().color()); + + result.setColorGroup(QPalette::Disabled, result.foreground(), result.button(), + result.light(), result.dark(), result.mid(), + result.text(), result.brightText(), result.base(), + result.background()); + result.setColor(QPalette::Disabled, QPalette::WindowText, disabled); + result.setColor(QPalette::Disabled, QPalette::Text, disabled); + result.setColor(QPalette::Disabled, QPalette::ButtonText, disabled); + result.setColor(QPalette::Disabled, QPalette::Highlight, + getSysColor(COLOR_HIGHLIGHT)); + result.setColor(QPalette::Disabled, QPalette::HighlightedText, + getSysColor(COLOR_HIGHLIGHTTEXT)); + result.setColor(QPalette::Disabled, QPalette::Base, + result.background().color()); + return result; +} + +QPalette toolTipPalette(const QPalette &systemPalette) +{ + QPalette result(systemPalette); + const QColor tipBgColor(getSysColor(COLOR_INFOBK)); + const QColor tipTextColor(getSysColor(COLOR_INFOTEXT)); + + result.setColor(QPalette::All, QPalette::Button, tipBgColor); + result.setColor(QPalette::All, QPalette::Window, tipBgColor); + result.setColor(QPalette::All, QPalette::Text, tipTextColor); + result.setColor(QPalette::All, QPalette::WindowText, tipTextColor); + result.setColor(QPalette::All, QPalette::ButtonText, tipTextColor); + result.setColor(QPalette::All, QPalette::Button, tipBgColor); + result.setColor(QPalette::All, QPalette::Window, tipBgColor); + result.setColor(QPalette::All, QPalette::Text, tipTextColor); + result.setColor(QPalette::All, QPalette::WindowText, tipTextColor); + result.setColor(QPalette::All, QPalette::ButtonText, tipTextColor); + const QColor disabled = + mixColors(result.foreground().color(), result.button().color()); + result.setColor(QPalette::Disabled, QPalette::WindowText, disabled); + result.setColor(QPalette::Disabled, QPalette::Text, disabled); + result.setColor(QPalette::Disabled, QPalette::Base, Qt::white); + result.setColor(QPalette::Disabled, QPalette::BrightText, Qt::white); + return result; +} + static inline bool booleanSystemParametersInfo(UINT what, bool defaultValue) { BOOL result; @@ -66,11 +180,53 @@ static inline bool dWordSystemParametersInfo(UINT what, DWORD defaultValue) QWindowsTheme::QWindowsTheme() { + qFill(m_palettes, m_palettes + NPalettes, static_cast(0)); + refresh(); +} + +QWindowsTheme::~QWindowsTheme() +{ + clearPalettes(); +} + +void QWindowsTheme::clearPalettes() +{ + qDeleteAll(m_palettes, m_palettes + NPalettes); + qFill(m_palettes, m_palettes + NPalettes, static_cast(0)); +} + +QWindowsTheme *QWindowsTheme::instance() +{ + return static_cast(QWindowsIntegration::instance()->platformTheme()); +} + +static inline QStringList iconThemeSearchPaths() +{ + const QFileInfo appDir(QCoreApplication::applicationDirPath() + QStringLiteral("/icons")); + return appDir.isDir() ? QStringList(appDir.absoluteFilePath()) : QStringList(); +} + +static inline QStringList styleNames() +{ + QStringList result; + if (QSysInfo::WindowsVersion >= QSysInfo::WV_VISTA) + result.append(QStringLiteral("WindowsVista")); + if (QSysInfo::WindowsVersion >= QSysInfo::WV_XP) + result.append(QStringLiteral("WindowsXP")); + result.append(QStringLiteral("Windows")); + return result; } QVariant QWindowsTheme::themeHint(ThemeHint hint) const { switch (hint) { + case SystemIconThemeName: + break; + case IconThemeSearchPaths: + return QVariant(iconThemeSearchPaths()); + break; + case StyleNames: + return QVariant(styleNames()); case TextCursorWidth: return QVariant(int(dWordSystemParametersInfo(SPI_GETCARETWIDTH, 1u))); case DropShadow: @@ -81,6 +237,19 @@ QVariant QWindowsTheme::themeHint(ThemeHint hint) const return QVariant(); } +void QWindowsTheme::refresh() +{ + clearPalettes(); + if (QGuiApplication::desktopSettingsAware()) { + m_palettes[SystemPalette] = new QPalette(systemPalette()); + m_palettes[ToolTipPalette] = new QPalette(toolTipPalette(*m_palettes[SystemPalette])); + if (QWindowsContext::verboseTheming) + qDebug() << __FUNCTION__ << '\n' + << " system=" << paletteToString(*m_palettes[SystemPalette]) + << " tooltip=" << paletteToString(*m_palettes[ToolTipPalette]); + } +} + bool QWindowsTheme::usePlatformNativeDialog(DialogType type) const { return QWindowsDialogs::useHelper(type); @@ -91,4 +260,10 @@ QPlatformDialogHelper *QWindowsTheme::createPlatformDialogHelper(DialogType type return QWindowsDialogs::createHelper(type); } +void QWindowsTheme::windowsThemeChanged(QWindow * /* window */) +{ + refresh(); + // QWindowSystemInterface::handleThemeChange(window); +} + QT_END_NAMESPACE diff --git a/src/plugins/platforms/windows/qwindowstheme.h b/src/plugins/platforms/windows/qwindowstheme.h index 77c85b2d6e..950c380737 100644 --- a/src/plugins/platforms/windows/qwindowstheme.h +++ b/src/plugins/platforms/windows/qwindowstheme.h @@ -43,19 +43,43 @@ #define QWINDOWSTHEME_H #include +#include + +#include "qtwindows_additional.h" QT_BEGIN_NAMESPACE +class QWindow; + class QWindowsTheme : public QPlatformTheme { public: QWindowsTheme(); + ~QWindowsTheme(); + + static QWindowsTheme *instance(); virtual bool usePlatformNativeDialog(DialogType type) const; virtual QPlatformDialogHelper *createPlatformDialogHelper(DialogType type) const; virtual QVariant themeHint(ThemeHint) const; + virtual const QPalette *palette(Palette type = SystemPalette) const + { return m_palettes[type]; } + + void windowsThemeChanged(QWindow *window); + +private: + void refresh(); + void clearPalettes(); + + QPalette *m_palettes[NPalettes]; }; +static inline COLORREF qColorToCOLORREF(const QColor &color) +{ return RGB(color.red(), color.green(), color.blue()); } + +static inline QColor COLORREFToQColor(COLORREF cr) +{ return QColor(GetRValue(cr), GetGValue(cr), GetBValue(cr)); } + QT_END_NAMESPACE #endif // QWINDOWSTHEME_H diff --git a/src/plugins/platforms/xcb/qxcbintegration.cpp b/src/plugins/platforms/xcb/qxcbintegration.cpp index c976e75dbf..e7cdef4da9 100644 --- a/src/plugins/platforms/xcb/qxcbintegration.cpp +++ b/src/plugins/platforms/xcb/qxcbintegration.cpp @@ -70,6 +70,7 @@ #endif #include +#include #include #if defined(XCB_USE_GLX) @@ -87,7 +88,8 @@ QT_BEGIN_NAMESPACE QXcbIntegration::QXcbIntegration(const QStringList ¶meters) : m_eventDispatcher(createUnixEventDispatcher()), - m_services(new QGenericUnixServices) + m_services(new QGenericUnixServices), + m_theme(QGenericUnixTheme::createUnixTheme()) { QGuiApplicationPrivate::instance()->setEventDispatcher(m_eventDispatcher); @@ -278,4 +280,9 @@ QPlatformServices *QXcbIntegration::services() const return m_services.data(); } +QPlatformTheme *QXcbIntegration::platformTheme() const +{ + return m_theme.data(); +} + QT_END_NAMESPACE diff --git a/src/plugins/platforms/xcb/qxcbintegration.h b/src/plugins/platforms/xcb/qxcbintegration.h index 0f20658c70..457f90d6e0 100644 --- a/src/plugins/platforms/xcb/qxcbintegration.h +++ b/src/plugins/platforms/xcb/qxcbintegration.h @@ -85,6 +85,8 @@ public: QPlatformServices *services() const; + QPlatformTheme *platformTheme() const; + private: QList m_connections; @@ -101,6 +103,7 @@ private: #endif QScopedPointer m_services; + QScopedPointer m_theme; }; QT_END_NAMESPACE diff --git a/src/widgets/kernel/qapplication.cpp b/src/widgets/kernel/qapplication.cpp index b04925d85d..ae4f5e01b7 100644 --- a/src/widgets/kernel/qapplication.cpp +++ b/src/widgets/kernel/qapplication.cpp @@ -62,6 +62,7 @@ #include "qvariant.h" #include "qwidget.h" #include "private/qdnd_p.h" +#include "private/qguiapplication_p.h" #include "qcolormap.h" #include "qdebug.h" #include "private/qstylesheetstyle_p.h" @@ -71,6 +72,7 @@ #include #include #include +#include #include "private/qkeymapper_p.h" @@ -1297,6 +1299,9 @@ QStyle *QApplication::style() // take ownership of the style QApplicationPrivate::app_style->setParent(qApp); + if (!QApplicationPrivate::sys_pal) + if (const QPalette *themePalette = QGuiApplicationPrivate::platformTheme()->palette()) + QApplicationPrivate::setSystemPalette(*themePalette); if (!QApplicationPrivate::sys_pal) QApplicationPrivate::setSystemPalette(QApplicationPrivate::app_style->standardPalette()); if (QApplicationPrivate::set_pal) // repolish set palette with the new style @@ -1850,7 +1855,15 @@ void QApplicationPrivate::setSystemFont(const QFont &font) */ QString QApplicationPrivate::desktopStyleKey() { - return qt_guiPlatformPlugin()->styleName(); + // The platform theme might return a style that is not available, find + // first valid one. + if (const QPlatformTheme *theme = QGuiApplicationPrivate::platformTheme()) { + const QStringList availableKeys = QStyleFactory::keys(); + foreach (const QString &style, theme->themeHint(QPlatformTheme::StyleNames).toStringList()) + if (availableKeys.contains(style, Qt::CaseInsensitive)) + return style; + } + return QString(); } /*! diff --git a/src/widgets/kernel/qapplication_qpa.cpp b/src/widgets/kernel/qapplication_qpa.cpp index e221df7ef7..54c5c39396 100644 --- a/src/widgets/kernel/qapplication_qpa.cpp +++ b/src/widgets/kernel/qapplication_qpa.cpp @@ -41,6 +41,7 @@ #include "qapplication_p.h" #include "qcolormap.h" +#include "qpalette.h" #include "qpixmapcache.h" #ifndef QT_NO_CURSOR #include "private/qcursor_p.h" @@ -53,8 +54,9 @@ #include "qgenericpluginfactory_qpa.h" #include "private/qplatformintegrationfactory_qpa_p.h" #include - #include +#include + #include #include #include "private/qwindowsysteminterface_qpa_p.h" @@ -62,6 +64,7 @@ #include "qdesktopwidget_qpa_p.h" #include "qwidgetwindow_qpa_p.h" +#include "qtooltip.h" #ifdef Q_OS_WIN # include // for qt_win_display_dc() @@ -393,6 +396,8 @@ void qt_init(QApplicationPrivate *priv, int type) qApp->setAttribute(Qt::AA_DontCreateNativeWidgetSiblings); QColormap::initialize(); + if (const QPalette *toolTipPalette = QGuiApplicationPrivate::platformTheme()->palette(QPlatformTheme::ToolTipPalette)) + QToolTip::setPalette(*toolTipPalette); qApp->setObjectName(appName); } diff --git a/src/widgets/kernel/qguiplatformplugin.cpp b/src/widgets/kernel/qguiplatformplugin.cpp index 7646ae417e..f5c8399a0b 100644 --- a/src/widgets/kernel/qguiplatformplugin.cpp +++ b/src/widgets/kernel/qguiplatformplugin.cpp @@ -125,169 +125,10 @@ QGuiPlatformPlugin *qt_guiPlatformPlugin() QGuiPlatformPlugin::QGuiPlatformPlugin(QObject *parent) : QObject(parent) {} QGuiPlatformPlugin::~QGuiPlatformPlugin() {} - -/* return the string key to be used by default the application */ -QString QGuiPlatformPlugin::styleName() -{ -#if defined(Q_WS_WIN) && defined(Q_OS_WINCE) - if (qt_wince_is_smartphone() || qt_wince_is_pocket_pc()) - return QLatin1String("WindowsMobile"); - else - return QLatin1String("WindowsCE"); -#elif defined(Q_OS_WIN) - if ((QSysInfo::WindowsVersion >= QSysInfo::WV_VISTA - && QSysInfo::WindowsVersion < QSysInfo::WV_NT_based)) - return QLatin1String("WindowsVista"); - else if ((QSysInfo::WindowsVersion >= QSysInfo::WV_XP - && QSysInfo::WindowsVersion < QSysInfo::WV_NT_based)) - return QLatin1String("WindowsXP"); - else - return QLatin1String("Windows"); // default styles for Windows -#elif defined(Q_WS_X11) && defined(Q_OS_SOLARIS) - return QLatin1String("CDE"); // default style for X11 on Solaris -#elif defined(Q_WS_X11) && defined(Q_OS_IRIX) - return QLatin1String("SGI"); // default style for X11 on IRIX -#elif defined(Q_OS_MAC) - return QLatin1String("Macintosh"); // default style for all Mac's -#elif defined(Q_WS_X11) - QString stylename; - switch(X11->desktopEnvironment) { - case DE_KDE: - stylename = QKde::kdeStyle(); - break; - case DE_GNOME: { - QStringList availableStyles = QStyleFactory::keys(); - // Set QGtkStyle for GNOME if available - QString gtkStyleKey = QString::fromLatin1("GTK+"); - if (availableStyles.contains(gtkStyleKey)) { - stylename = gtkStyleKey; - break; - } - if (X11->use_xrender) - stylename = QLatin1String("cleanlooks"); - else - stylename = QLatin1String("windows"); - break; - } - case DE_CDE: - stylename = QLatin1String("cde"); - break; - default: - // Don't do anything - break; - } - return stylename; -#else - return QLatin1String("Plastique"); // default style for X11 and small devices -#endif -} - -/* return an additional default palette (only work on X11) */ -QPalette QGuiPlatformPlugin::palette() -{ -#ifdef Q_WS_X11 - if (QApplication::desktopSettingsAware() && X11->desktopEnvironment == DE_KDE) - return QKde::kdePalette(); -#endif - - return QPalette(); -} - -/* the default icon theme name for QIcon::fromTheme. */ -QString QGuiPlatformPlugin::systemIconThemeName() -{ - QString result; -#ifdef Q_WS_X11 - if (X11->desktopEnvironment == DE_GNOME) { - result = QString::fromLatin1("gnome"); -#ifndef QT_NO_STYLE_GTK - result = QGtkStylePrivate::getGConfString(QLatin1String("/desktop/gnome/interface/icon_theme"), result); -#endif - } else if (X11->desktopEnvironment == DE_KDE) { - result = X11->desktopVersion >= 4 ? QString::fromLatin1("oxygen") : QString::fromLatin1("crystalsvg"); - QSettings settings(QKde::kdeHome() + QLatin1String("/share/config/kdeglobals"), QSettings::IniFormat); - settings.beginGroup(QLatin1String("Icons")); - result = settings.value(QLatin1String("Theme"), result).toString(); - } -#endif - return result; -} - - -QStringList QGuiPlatformPlugin::iconThemeSearchPaths() -{ - QStringList paths; -#if defined(Q_WS_X11) - QString xdgDirString = QFile::decodeName(getenv("XDG_DATA_DIRS")); - if (xdgDirString.isEmpty()) - xdgDirString = QLatin1String("/usr/local/share/:/usr/share/"); - - QStringList xdgDirs = xdgDirString.split(QLatin1Char(':')); - - for (int i = 0 ; i < xdgDirs.size() ; ++i) { - QDir dir(xdgDirs[i]); - if (dir.exists()) - paths.append(dir.path() + QLatin1String("/icons")); - } - if (X11->desktopEnvironment == DE_KDE) { - paths << QLatin1Char(':') + QKde::kdeHome() + QLatin1String("/share/icons"); - QStringList kdeDirs = QFile::decodeName(getenv("KDEDIRS")).split(QLatin1Char(':')); - for (int i = 0 ; i< kdeDirs.count() ; ++i) { - QDir dir(QLatin1Char(':') + kdeDirs.at(i) + QLatin1String("/share/icons")); - if (dir.exists()) - paths.append(dir.path()); - } - } - - // Add home directory first in search path - QDir homeDir(QDir::homePath() + QLatin1String("/.icons")); - if (homeDir.exists()) - paths.prepend(homeDir.path()); -#endif - -#if defined(Q_WS_WIN) - paths.append(qApp->applicationDirPath() + QLatin1String("/icons")); -#elif defined(Q_WS_MAC) - paths.append(qApp->applicationDirPath() + QLatin1String("/../Resources/icons")); -#endif - return paths; -} - /* backend for QFileIconProvider, null icon means default */ QIcon QGuiPlatformPlugin::fileSystemIcon(const QFileInfo &) { return QIcon(); } -/* Like QStyle::styleHint */ -int QGuiPlatformPlugin::platformHint(PlatformHint hint) -{ - int ret = 0; - switch(hint) - { - case PH_ToolButtonStyle: - ret = Qt::ToolButtonIconOnly; -#ifdef Q_WS_X11 - if (X11->desktopEnvironment == DE_KDE && X11->desktopVersion >= 4 - && QApplication::desktopSettingsAware()) { - ret = QKde::kdeToolButtonStyle(); - } -#endif - break; - case PH_ToolBarIconSize: -#ifdef Q_WS_X11 - if (X11->desktopEnvironment == DE_KDE && X11->desktopVersion >= 4 - && QApplication::desktopSettingsAware()) { - ret = QKde::kdeToolBarIconSize(); - } -#endif - //by default keep ret = 0 so QCommonStyle will use the style default - break; - default: - break; - } - return ret; -} - - QT_END_NAMESPACE diff --git a/src/widgets/kernel/qguiplatformplugin_p.h b/src/widgets/kernel/qguiplatformplugin_p.h index 09b6564061..c42db3bb92 100644 --- a/src/widgets/kernel/qguiplatformplugin_p.h +++ b/src/widgets/kernel/qguiplatformplugin_p.h @@ -87,14 +87,7 @@ class Q_WIDGETS_EXPORT QGuiPlatformPlugin : public QObject, public QGuiPlatformP virtual QStringList keys() const { return QStringList(QStringLiteral("default")); } - virtual QString styleName(); - virtual QPalette palette(); - virtual QString systemIconThemeName(); - virtual QStringList iconThemeSearchPaths(); virtual QIcon fileSystemIcon(const QFileInfo &); - - enum PlatformHint { PH_ToolButtonStyle, PH_ToolBarIconSize, PH_ItemView_ActivateItemOnSingleClick }; - virtual int platformHint(PlatformHint hint); }; //internal diff --git a/src/widgets/kernel/qicon.cpp b/src/widgets/kernel/qicon.cpp index 1d3236aa46..e579fac4f4 100644 --- a/src/widgets/kernel/qicon.cpp +++ b/src/widgets/kernel/qicon.cpp @@ -53,7 +53,6 @@ #include "qvariant.h" #include "qcache.h" #include "qdebug.h" -#include "private/qguiplatformplugin_p.h" #include "qapplication.h" #ifdef Q_WS_MAC diff --git a/src/widgets/kernel/qiconloader.cpp b/src/widgets/kernel/qiconloader.cpp index 0b86189b5e..2f9576f864 100644 --- a/src/widgets/kernel/qiconloader.cpp +++ b/src/widgets/kernel/qiconloader.cpp @@ -43,11 +43,12 @@ #include #include -#include +#include #include #include #include +#include #include #include #include @@ -73,17 +74,11 @@ Q_GLOBAL_STATIC(QIconLoader, iconLoaderInstance) /* Theme to use in last resort, if the theme does not have the icon, neither the parents */ static QString fallbackTheme() { -#ifdef Q_WS_X11 - if (X11->desktopEnvironment == DE_GNOME) { - return QLatin1String("gnome"); - } else if (X11->desktopEnvironment == DE_KDE) { - return X11->desktopVersion >= 4 - ? QString::fromLatin1("oxygen") - : QString::fromLatin1("crystalsvg"); - } else { - return QLatin1String("hicolor"); + if (const QPlatformTheme *theme = QGuiApplicationPrivate::platformTheme()) { + const QVariant themeHint = theme->themeHint(QPlatformTheme::SystemIconThemeName); + if (themeHint.isValid()) + return themeHint.toString(); } -#endif return QString(); } @@ -94,6 +89,27 @@ QIconLoader::QIconLoader() : // We lazily initialize the loader to make static icons // work. Though we do not officially support this. + +static inline QString systemThemeName() +{ + if (const QPlatformTheme *theme = QGuiApplicationPrivate::platformTheme()) { + const QVariant themeHint = theme->themeHint(QPlatformTheme::SystemIconThemeName); + if (themeHint.isValid()) + return themeHint.toString(); + } + return QString(); +} + +static inline QStringList systemIconSearchPaths() +{ + if (const QPlatformTheme *theme = QGuiApplicationPrivate::platformTheme()) { + const QVariant themeHint = theme->themeHint(QPlatformTheme::IconThemeSearchPaths); + if (themeHint.isValid()) + return themeHint.toStringList(); + } + return QStringList(); +} + void QIconLoader::ensureInitialized() { if (!m_initialized) { @@ -101,7 +117,8 @@ void QIconLoader::ensureInitialized() Q_ASSERT(qApp); - m_systemTheme = qt_guiPlatformPlugin()->systemIconThemeName(); + m_systemTheme = systemThemeName(); + if (m_systemTheme.isEmpty()) m_systemTheme = fallbackTheme(); #ifndef QT_NO_LIBRARY @@ -125,7 +142,7 @@ void QIconLoader::updateSystemTheme() { // Only change if this is not explicitly set by the user if (m_userTheme.isEmpty()) { - QString theme = qt_guiPlatformPlugin()->systemIconThemeName(); + QString theme = systemThemeName(); if (theme.isEmpty()) theme = fallbackTheme(); if (theme != m_systemTheme) { @@ -151,7 +168,7 @@ void QIconLoader::setThemeSearchPath(const QStringList &searchPaths) QStringList QIconLoader::themeSearchPaths() const { if (m_iconDirs.isEmpty()) { - m_iconDirs = qt_guiPlatformPlugin()->iconThemeSearchPaths(); + m_iconDirs = systemIconSearchPaths(); // Always add resource directory as search path m_iconDirs.append(QLatin1String(":/icons")); } @@ -221,8 +238,11 @@ QIconTheme::QIconTheme(const QString &themeName) QLatin1String("Icon Theme/Inherits")).toStringList(); // Ensure a default platform fallback for all themes - if (m_parents.isEmpty()) - m_parents.append(fallbackTheme()); + if (m_parents.isEmpty()) { + const QString fallback = fallbackTheme(); + if (!fallback.isEmpty()) + m_parents.append(fallback); + } // Ensure that all themes fall back to hicolor if (!m_parents.contains(QLatin1String("hicolor"))) diff --git a/src/widgets/styles/qcommonstyle.cpp b/src/widgets/styles/qcommonstyle.cpp index db783d14d4..75476faeeb 100644 --- a/src/widgets/styles/qcommonstyle.cpp +++ b/src/widgets/styles/qcommonstyle.cpp @@ -45,6 +45,7 @@ #include #include #include +#include #include #include #include @@ -75,7 +76,6 @@ #include #include #include -#include #include @@ -4509,9 +4509,11 @@ int QCommonStyle::pixelMetric(PixelMetric m, const QStyleOption *opt, const QWid break; case PM_ToolBarIconSize: - ret = qt_guiPlatformPlugin()->platformHint(QGuiPlatformPlugin::PH_ToolBarIconSize); - if (!ret) - ret = int(QStyleHelper::dpiScaled(24.)); + ret = 0; + if (const QPlatformTheme *theme = QGuiApplicationPrivate::platformTheme()) + ret = theme->themeHint(QPlatformTheme::ToolBarIconSize).toInt(); + if (ret <= 0) + ret = int(QStyleHelper::dpiScaled(24.)); break; case PM_TabBarIconSize: @@ -4903,9 +4905,10 @@ int QCommonStyle::styleHint(StyleHint sh, const QStyleOption *opt, const QWidget break; case SH_ItemView_ActivateItemOnSingleClick: - ret = qt_guiPlatformPlugin()->platformHint(QGuiPlatformPlugin::PH_ItemView_ActivateItemOnSingleClick); + ret = 0; + if (const QPlatformTheme *theme = QGuiApplicationPrivate::platformTheme()) + ret = theme->themeHint(QPlatformTheme::ToolButtonStyle).toBool() ? 1 : 0; break; - case SH_TitleBar_ModifyNotification: ret = true; break; @@ -4997,7 +5000,9 @@ int QCommonStyle::styleHint(StyleHint sh, const QStyleOption *opt, const QWidget ret = true; break; case SH_ToolButtonStyle: - ret = qt_guiPlatformPlugin()->platformHint(QGuiPlatformPlugin::PH_ToolButtonStyle); + ret = 0; + if (const QPlatformTheme *theme = QGuiApplicationPrivate::platformTheme()) + ret = theme->themeHint(QPlatformTheme::ToolButtonStyle).toInt(); break; case SH_RequestSoftwareInputPanel: ret = RSIP_OnMouseClickAndAlreadyFocused; diff --git a/tests/auto/widgets/dialogs/qmessagebox/tst_qmessagebox.cpp b/tests/auto/widgets/dialogs/qmessagebox/tst_qmessagebox.cpp index 9e965ff235..7fc752488d 100644 --- a/tests/auto/widgets/dialogs/qmessagebox/tst_qmessagebox.cpp +++ b/tests/auto/widgets/dialogs/qmessagebox/tst_qmessagebox.cpp @@ -411,8 +411,10 @@ void tst_QMessageBox::staticSourceCompat() if (qobject_cast(qApp->style())) expectedButton = int(QMessageBox::No); #elif !defined(QT_NO_STYLE_CLEANLOOKS) - if (qobject_cast(qApp->style())) + if (qobject_cast(qApp->style())) { + QEXPECT_FAIL("", "Special handling of QMessageBox::information buttons for Cleanlooks not implemented yet, QTBUG-24315", Continue); expectedButton = int(QMessageBox::No); + } #endif QCOMPARE(ret, expectedButton); QCOMPARE(keyToSend, -1); -- cgit v1.2.3