440 lines
16 KiB
C++
440 lines
16 KiB
C++
/****************************************************************************
|
|
**
|
|
** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies).
|
|
** Contact: http://www.qt-project.org/legal
|
|
**
|
|
** This file is part of the plugins of the Qt Toolkit.
|
|
**
|
|
** $QT_BEGIN_LICENSE:LGPL$
|
|
** Commercial License Usage
|
|
** Licensees holding valid commercial Qt licenses may use this file in
|
|
** accordance with the commercial license agreement provided with the
|
|
** Software or, alternatively, in accordance with the terms contained in
|
|
** a written agreement between you and Digia. For licensing terms and
|
|
** conditions see http://qt.digia.com/licensing. For further information
|
|
** use the contact form at http://qt.digia.com/contact-us.
|
|
**
|
|
** GNU Lesser General Public License Usage
|
|
** Alternatively, 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, Digia gives you certain additional
|
|
** rights. These rights are described in the Digia 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.
|
|
**
|
|
**
|
|
** $QT_END_LICENSE$
|
|
**
|
|
****************************************************************************/
|
|
|
|
#include "qgenericunixthemes_p.h"
|
|
#include "../../services/genericunix/qgenericunixservices_p.h"
|
|
|
|
#include <QtGui/QPalette>
|
|
#include <QtGui/QFont>
|
|
#include <QtGui/QGuiApplication>
|
|
#include <QtCore/QDir>
|
|
#include <QtCore/QFileInfo>
|
|
#include <QtCore/QFile>
|
|
#include <QtCore/QDebug>
|
|
#include <QtCore/QSettings>
|
|
#include <QtCore/QVariant>
|
|
#include <QtCore/QStringList>
|
|
#include <private/qguiapplication_p.h>
|
|
#include <qpa/qplatformintegration.h>
|
|
#include <qpa/qplatformservices.h>
|
|
|
|
QT_BEGIN_NAMESPACE
|
|
|
|
ResourceHelper::ResourceHelper()
|
|
{
|
|
qFill(palettes, palettes + QPlatformTheme::NPalettes, static_cast<QPalette *>(0));
|
|
qFill(fonts, fonts + QPlatformTheme::NFonts, static_cast<QFont *>(0));
|
|
}
|
|
|
|
void ResourceHelper::clear()
|
|
{
|
|
qDeleteAll(palettes, palettes + QPlatformTheme::NPalettes);
|
|
qDeleteAll(fonts, fonts + QPlatformTheme::NFonts);
|
|
qFill(palettes, palettes + QPlatformTheme::NPalettes, static_cast<QPalette *>(0));
|
|
qFill(fonts, fonts + QPlatformTheme::NFonts, static_cast<QFont *>(0));
|
|
}
|
|
|
|
/*!
|
|
\class QGenericX11ThemeQKdeTheme
|
|
\brief QGenericX11Theme is a generic theme implementation for X11.
|
|
\since 5.0
|
|
\internal
|
|
\ingroup qpa
|
|
*/
|
|
|
|
const char *QGenericUnixTheme::name = "generic";
|
|
|
|
// Default system font, corresponding to the value returned by 4.8 for
|
|
// XRender/FontConfig which we can now assume as default.
|
|
static const char defaultSystemFontNameC[] = "Sans Serif";
|
|
enum { defaultSystemFontSize = 9 };
|
|
|
|
QGenericUnixTheme::QGenericUnixTheme()
|
|
: m_systemFont(QLatin1String(defaultSystemFontNameC), defaultSystemFontSize)
|
|
{
|
|
}
|
|
|
|
const QFont *QGenericUnixTheme::font(Font type) const
|
|
{
|
|
if (type == QPlatformTheme::SystemFont)
|
|
return &m_systemFont;
|
|
return 0;
|
|
}
|
|
|
|
// 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::DialogButtonBoxButtonsHaveIcons:
|
|
return QVariant(true);
|
|
case QPlatformTheme::StyleNames: {
|
|
QStringList styleNames;
|
|
styleNames << QStringLiteral("Fusion") << QStringLiteral("Windows");
|
|
return QVariant(styleNames);
|
|
}
|
|
case QPlatformTheme::KeyboardScheme:
|
|
return QVariant(int(X11KeyboardScheme));
|
|
default:
|
|
break;
|
|
}
|
|
return QPlatformTheme::themeHint(hint);
|
|
}
|
|
|
|
#ifndef QT_NO_SETTINGS
|
|
|
|
// 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;
|
|
}
|
|
|
|
static inline void readKdeSystemPalette(const QSettings &kdeSettings, QPalette *pal)
|
|
{
|
|
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
|
|
*/
|
|
|
|
const char *QKdeTheme::name = "kde";
|
|
|
|
QKdeTheme::QKdeTheme(const QString &kdeHome, int kdeVersion) :
|
|
m_kdeHome(kdeHome), m_kdeVersion(kdeVersion),
|
|
m_toolButtonStyle(Qt::ToolButtonTextBesideIcon), m_toolBarIconSize(0)
|
|
{
|
|
refresh();
|
|
}
|
|
|
|
static inline QFont *readKdeFontSetting(const QSettings &settings, const QString &key)
|
|
{
|
|
const QVariant fontValue = settings.value(key);
|
|
if (fontValue.isValid()) {
|
|
// Read font value: Might be a QStringList as KDE stores fonts without quotes.
|
|
// Also retrieve the family for the constructor since we cannot use the
|
|
// default constructor of QFont, which accesses QGuiApplication::systemFont()
|
|
// causing recursion.
|
|
QString fontDescription;
|
|
QString fontFamily;
|
|
if (fontValue.type() == QVariant::StringList) {
|
|
const QStringList list = fontValue.toStringList();
|
|
if (!list.isEmpty()) {
|
|
fontFamily = list.first();
|
|
fontDescription = list.join(QLatin1Char(','));
|
|
}
|
|
} else {
|
|
fontDescription = fontFamily = fontValue.toString();
|
|
}
|
|
if (!fontDescription.isEmpty()) {
|
|
QFont font(fontFamily);
|
|
if (font.fromString(fontDescription))
|
|
return new QFont(font);
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
void QKdeTheme::refresh()
|
|
{
|
|
m_resources.clear();
|
|
|
|
m_toolButtonStyle = Qt::ToolButtonTextBesideIcon;
|
|
m_toolBarIconSize = 0;
|
|
m_styleNames.clear();
|
|
m_styleNames << QStringLiteral("Oxygen") << QStringLiteral("fusion") << 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 = QPalette();
|
|
readKdeSystemPalette(kdeSettings, &systemPalette);
|
|
m_resources.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;
|
|
}
|
|
|
|
// Read system font, ignore 'fixed' 'smallestReadableFont'
|
|
if (QFont *systemFont = readKdeFontSetting(kdeSettings, QStringLiteral("font"))) {
|
|
m_resources.fonts[SystemFont] = systemFont;
|
|
} else {
|
|
m_resources.fonts[SystemFont] = new QFont(QLatin1String(defaultSystemFontNameC), defaultSystemFontSize);
|
|
}
|
|
}
|
|
|
|
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::UseFullScreenForPopupMenu:
|
|
return QVariant(true);
|
|
case QPlatformTheme::DialogButtonBoxButtonsHaveIcons:
|
|
return QVariant(true);
|
|
case QPlatformTheme::DialogButtonBoxLayout:
|
|
return QVariant(2); // QDialogButtonBox::KdeLayout
|
|
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);
|
|
case QPlatformTheme::KeyboardScheme:
|
|
return QVariant(int(KdeKeyboardScheme));
|
|
default:
|
|
break;
|
|
}
|
|
return QPlatformTheme::themeHint(hint);
|
|
}
|
|
|
|
QPlatformTheme *QKdeTheme::createKdeTheme()
|
|
{
|
|
// Check for version >= 4 and determine home folder from environment,
|
|
// defaulting to ~/.kde<version>, ~/.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;
|
|
}
|
|
|
|
#endif // QT_NO_SETTINGS
|
|
|
|
/*!
|
|
\class QGnomeTheme
|
|
\brief QGnomeTheme is a theme implementation for the Gnome desktop.
|
|
\since 5.0
|
|
\internal
|
|
\ingroup qpa
|
|
*/
|
|
|
|
const char *QGnomeTheme::name = "gnome";
|
|
|
|
QGnomeTheme::QGnomeTheme()
|
|
: m_systemFont(QLatin1String(defaultSystemFontNameC), defaultSystemFontSize)
|
|
{
|
|
}
|
|
|
|
QVariant QGnomeTheme::themeHint(QPlatformTheme::ThemeHint hint) const
|
|
{
|
|
switch (hint) {
|
|
case QPlatformTheme::DialogButtonBoxButtonsHaveIcons:
|
|
return QVariant(true);
|
|
case QPlatformTheme::DialogButtonBoxLayout:
|
|
return QVariant(3); // QDialogButtonBox::GnomeLayout
|
|
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);
|
|
}
|
|
case QPlatformTheme::KeyboardScheme:
|
|
return QVariant(int(GnomeKeyboardScheme));
|
|
default:
|
|
break;
|
|
}
|
|
return QPlatformTheme::themeHint(hint);
|
|
}
|
|
|
|
const QFont *QGnomeTheme::font(Font type) const
|
|
{
|
|
if (type == QPlatformTheme::SystemFont)
|
|
return &m_systemFont;
|
|
return 0;
|
|
}
|
|
|
|
/*!
|
|
\brief Creates a UNIX theme according to the detected desktop environment.
|
|
*/
|
|
|
|
QPlatformTheme *QGenericUnixTheme::createUnixTheme(const QString &name)
|
|
{
|
|
if (name == QLatin1String(QGenericUnixTheme::name))
|
|
return new QGenericUnixTheme;
|
|
#ifndef QT_NO_SETTINGS
|
|
if (name == QLatin1String(QKdeTheme::name))
|
|
if (QPlatformTheme *kdeTheme = QKdeTheme::createKdeTheme())
|
|
return kdeTheme;
|
|
#endif
|
|
if (name == QLatin1String(QGnomeTheme::name))
|
|
return new QGnomeTheme;
|
|
return new QGenericUnixTheme;
|
|
}
|
|
|
|
QStringList QGenericUnixTheme::themeNames()
|
|
{
|
|
QStringList result;
|
|
if (QGuiApplication::desktopSettingsAware()) {
|
|
if (QGuiApplicationPrivate::platformIntegration()->services()->desktopEnvironment() == QByteArray("KDE")) {
|
|
#ifndef QT_NO_SETTINGS
|
|
result.push_back(QLatin1String(QKdeTheme::name));
|
|
#endif
|
|
} else if (QGuiApplicationPrivate::platformIntegration()->services()->desktopEnvironment() == QByteArray("GNOME")) {
|
|
result.push_back(QLatin1String(QGnomeTheme::name));
|
|
}
|
|
const QByteArray session = qgetenv("DESKTOP_SESSION");
|
|
if (!session.isEmpty() && session != "default")
|
|
result.push_back(QString::fromLocal8Bit(session));
|
|
} // desktopSettingsAware
|
|
if (result.isEmpty())
|
|
result.push_back(QLatin1String(QGenericUnixTheme::name));
|
|
return result;
|
|
}
|
|
|
|
QT_END_NAMESPACE
|