Refactor theme plugin loading.

In the old implementation, the QPlatformIntegration was asked
for the theme first, so there was no way of overriding that
by a custom plugin. Also, there was a memory leak in case
the platform theme was actually created by a plugin.

QGuiApplication now asks the QPlatformIntegration for a list
of potential theme names first, tries to load them using
the plugin loader and finally invokes a factory method of
QPlatformIntegration in case that fails. The theme is now
owned by QGuiApplication.

In the XCB plugin, the environment variable DESKTOP_SESSION
is queried and appended to the list of themes, making it possible
to load plugins for other session types.

Change-Id: I1a4b4e061815bca16c65b23e591bb7563a3e44e2
Reviewed-by: Samuel Rødal <samuel.rodal@nokia.com>
This commit is contained in:
Friedemann Kleint 2012-03-14 13:50:14 +01:00 committed by Qt by Nokia
parent d295b9b9cf
commit f7957f3993
16 changed files with 111 additions and 37 deletions

View File

@ -538,13 +538,22 @@ static void init_platform(const QString &pluginArgument, const QString &platform
}
// Create the platform theme:
// 1) Ask the platform integration to create a platform theme
QGuiApplicationPrivate::platform_theme = QGuiApplicationPrivate::platform_integration->platformTheme();
// 1) Ask the platform integration for a list of names.
const QStringList themeNames = QGuiApplicationPrivate::platform_integration->themeNames();
foreach (const QString &themeName, themeNames) {
QGuiApplicationPrivate::platform_theme = QPlatformThemeFactory::create(themeName, platformPluginPath);
if (QGuiApplicationPrivate::platform_theme)
break;
}
// 2) If none found, look for a theme plugin. Theme plugins are located in the
// same directory as platform plugins.
if (!QGuiApplicationPrivate::platform_theme) {
QGuiApplicationPrivate::platform_theme = QPlatformThemeFactory::create(name, platformPluginPath);
foreach (const QString &themeName, themeNames) {
QGuiApplicationPrivate::platform_theme = QGuiApplicationPrivate::platform_integration->createPlatformTheme(themeName);
if (QGuiApplicationPrivate::platform_theme)
break;
}
// No error message; not having a theme plugin is allowed.
}
@ -748,6 +757,7 @@ QGuiApplicationPrivate::~QGuiApplicationPrivate()
qt_cleanupFontDatabase();
delete platform_theme;
delete platform_integration;
platform_integration = 0;
}

View File

@ -44,6 +44,7 @@
#include <QtGui/QPlatformFontDatabase>
#include <QtGui/QPlatformClipboard>
#include <QtGui/QPlatformAccessibility>
#include <QtGui/QPlatformTheme>
#include <QtGui/private/qguiapplication_p.h>
#include <QtGui/private/qpixmap_raster_p.h>
#include <QtGui/private/qplatformscreen_qpa_p.h>
@ -315,9 +316,15 @@ void QPlatformIntegration::screenAdded(QPlatformScreen *ps)
emit qGuiApp->screenAdded(screen);
}
class QPlatformTheme *QPlatformIntegration::platformTheme() const
QStringList QPlatformIntegration::themeNames() const
{
return 0;
return QStringList();
}
class QPlatformTheme *QPlatformIntegration::createPlatformTheme(const QString &name) const
{
Q_UNUSED(name)
return new QPlatformTheme;
}
QT_END_NAMESPACE

View File

@ -126,7 +126,8 @@ public:
virtual Qt::KeyboardModifiers queryKeyboardModifiers() const;
virtual QPlatformTheme *platformTheme() const;
virtual QStringList themeNames() const;
virtual QPlatformTheme *createPlatformTheme(const QString &name) const;
protected:
void screenAdded(QPlatformScreen *screen);

View File

@ -77,6 +77,8 @@ void ResourceHelper::clear()
\ingroup qpa
*/
const char *QGenericUnixTheme::name = "generic";
// Helper to return the icon theme paths from XDG.
QStringList QGenericUnixTheme::xdgIconThemePaths()
{
@ -159,6 +161,8 @@ static inline bool readKdeSystemPalette(const QSettings &kdeSettings, QPalette *
\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)
@ -329,6 +333,8 @@ QPlatformTheme *QKdeTheme::createKdeTheme()
\ingroup qpa
*/
const char *QGnomeTheme::name = "gnome";
QVariant QGnomeTheme::themeHint(QPlatformTheme::ThemeHint hint) const
{
switch (hint) {
@ -358,23 +364,38 @@ QVariant QGnomeTheme::themeHint(QPlatformTheme::ThemeHint hint) const
\brief Creates a UNIX theme according to the detected desktop environment.
*/
QPlatformTheme *QGenericUnixTheme::createUnixTheme()
QPlatformTheme *QGenericUnixTheme::createUnixTheme(const QString &name)
{
QPlatformTheme *result = 0;
if (name == QLatin1String(QGenericUnixTheme::name))
return new QGenericUnixTheme;
if (name == QLatin1String(QKdeTheme::name))
if (QPlatformTheme *kdeTheme = QKdeTheme::createKdeTheme())
return kdeTheme;
if (name == QLatin1String(QGnomeTheme::name))
return new QGnomeTheme;
return new QGenericUnixTheme;
}
QStringList QGenericUnixTheme::themeNames()
{
QStringList result;
if (QGuiApplication::desktopSettingsAware()) {
switch (QGenericUnixServices::desktopEnvironment()) {
case QGenericUnixServices::DE_UNKNOWN:
break;
case QGenericUnixServices::DE_KDE:
result = QKdeTheme::createKdeTheme();
result.push_back(QLatin1String(QKdeTheme::name));
break;
case QGenericUnixServices::DE_GNOME:
result = new QGnomeTheme;
result.push_back(QLatin1String(QGnomeTheme::name));
break;
case QGenericUnixServices::DE_UNKNOWN:
break;
}
}
if (!result)
result = new QGenericUnixTheme;
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;
}

View File

@ -67,11 +67,14 @@ class QGenericUnixTheme : public QPlatformTheme
public:
QGenericUnixTheme() {}
static QPlatformTheme *createUnixTheme();
static QPlatformTheme *createUnixTheme(const QString &name);
static QStringList themeNames();
virtual QVariant themeHint(ThemeHint hint) const;
static QStringList xdgIconThemePaths();
static const char *name;
};
class QKdeTheme : public QPlatformTheme
@ -88,6 +91,8 @@ public:
virtual const QFont *font(Font type) const
{ return m_resources.fonts[type]; }
static const char *name;
private:
QString globalSettingsFile() const;
void refresh();
@ -109,6 +114,8 @@ public:
QGnomeTheme() {}
virtual QVariant themeHint(ThemeHint hint) const;
static const char *name;
private:
};

View File

@ -93,7 +93,9 @@ public:
QPlatformAccessibility *accessibility() const;
QPlatformDrag *drag() const;
QPlatformTheme *platformTheme() const;
QStringList themeNames() const;
QPlatformTheme *createPlatformTheme(const QString &name) const;
private:
QScopedPointer<QPlatformFontDatabase> mFontDb;

View File

@ -93,7 +93,6 @@ QCocoaIntegration::QCocoaIntegration()
, mEventDispatcher(new QCocoaEventDispatcher())
, mInputContext(new QCocoaInputContext)
, mAccessibility(new QPlatformAccessibility)
, mPlatformTheme(new QCocoaTheme)
, mCocoaDrag(new QCocoaDrag)
{
QCocoaAutoReleasePool pool;
@ -212,9 +211,16 @@ QPlatformDrag *QCocoaIntegration::drag() const
return mCocoaDrag.data();
}
QPlatformTheme *QCocoaIntegration::platformTheme() const
QStringList QCocoaIntegration::themeNames() const
{
return mPlatformTheme.data();
return QStringList(QLatin1String(QCocoaTheme::name));
}
QPlatformTheme *QCocoaIntegration::createPlatformTheme(const QString &name) const
{
if (name == QLatin1String(QCocoaTheme::name))
return new QCocoaTheme;
return QPlatformIntegration::createPlatformTheme(name);
}
QT_END_NAMESPACE

View File

@ -64,6 +64,9 @@ public:
const QFont *font(Font type = SystemFont) const;
QVariant themeHint(ThemeHint hint) const;
static const char *name;
private:
mutable QPalette *m_systemPalette;
mutable QHash<QPlatformTheme::Palette, QPalette*> m_palettes;

View File

@ -49,6 +49,8 @@
QT_BEGIN_NAMESPACE
const char *QCocoaTheme::name = "cocoa";
QCocoaTheme::QCocoaTheme()
:m_systemPalette(0)
{

View File

@ -788,7 +788,8 @@ bool QWindowsContext::windowsProc(HWND hwnd, UINT message,
QWindowSystemInterface::handleCloseEvent(platformWindow->window());
return true;
case QtWindows::ThemeChanged: // ### fixme: Compress these events?
QWindowsTheme::instance()->windowsThemeChanged(platformWindow->window());
if (QWindowsTheme *theme = QWindowsTheme::instance())
theme->windowsThemeChanged(platformWindow->window());
return true;
default:
break;

View File

@ -183,7 +183,6 @@ struct QWindowsIntegrationPrivate
QOpenGLStaticContextPtr m_staticOpenGLContext;
QWindowsInputContext m_inputContext;
QWindowsAccessibility m_accessibility;
QWindowsTheme m_theme;
QWindowsServices m_services;
};
@ -362,9 +361,16 @@ QAbstractEventDispatcher * QWindowsIntegration::guiThreadEventDispatcher() const
return d->m_eventDispatcher;
}
QPlatformTheme *QWindowsIntegration::platformTheme() const
QStringList QWindowsIntegration::themeNames() const
{
return &d->m_theme;
return QStringList(QLatin1String(QWindowsTheme::name));
}
QPlatformTheme *QWindowsIntegration::createPlatformTheme(const QString &name) const
{
if (name == QLatin1String(QWindowsTheme::name))
return new QWindowsTheme;
return QPlatformIntegration::createPlatformTheme(name);
}
QPlatformServices *QWindowsIntegration::services() const

View File

@ -69,7 +69,8 @@ public:
virtual QPlatformAccessibility *accessibility() const;
virtual QPlatformNativeInterface *nativeInterface() const;
virtual QPlatformFontDatabase *fontDatabase() const;
virtual QPlatformTheme *platformTheme() const;
virtual QStringList themeNames() const;
virtual QPlatformTheme *createPlatformTheme(const QString &name) const;
QPlatformServices *services() const;
virtual QVariant styleHint(StyleHint hint) const;

View File

@ -229,8 +229,12 @@ static inline QPalette *menuBarPalette(const QPalette &menuPalette)
return result;
}
const char *QWindowsTheme::name = "windows";
QWindowsTheme *QWindowsTheme::m_instance = 0;
QWindowsTheme::QWindowsTheme()
{
m_instance = this;
qFill(m_fonts, m_fonts + NFonts, static_cast<QFont *>(0));
qFill(m_palettes, m_palettes + NPalettes, static_cast<QPalette *>(0));
refresh();
@ -240,11 +244,7 @@ QWindowsTheme::~QWindowsTheme()
{
clearPalettes();
clearFonts();
}
QWindowsTheme *QWindowsTheme::instance()
{
return static_cast<QWindowsTheme *>(QWindowsIntegration::instance()->platformTheme());
m_instance = 0;
}
static inline QStringList iconThemeSearchPaths()

View File

@ -57,7 +57,7 @@ public:
QWindowsTheme();
~QWindowsTheme();
static QWindowsTheme *instance();
static QWindowsTheme *instance() { return m_instance; }
virtual bool usePlatformNativeDialog(DialogType type) const;
virtual QPlatformDialogHelper *createPlatformDialogHelper(DialogType type) const;
@ -69,6 +69,8 @@ public:
void windowsThemeChanged(QWindow *window);
static const char *name;
private:
void refresh() { refreshPalettes(); refreshFonts(); }
void clearPalettes();
@ -76,6 +78,7 @@ private:
void clearFonts();
void refreshFonts();
static QWindowsTheme *m_instance;
QPalette *m_palettes[NPalettes];
QFont *m_fonts[NFonts];
};

View File

@ -88,8 +88,7 @@ QT_BEGIN_NAMESPACE
QXcbIntegration::QXcbIntegration(const QStringList &parameters)
: m_eventDispatcher(createUnixEventDispatcher()),
m_services(new QGenericUnixServices),
m_theme(QGenericUnixTheme::createUnixTheme())
m_services(new QGenericUnixServices)
{
QGuiApplicationPrivate::instance()->setEventDispatcher(m_eventDispatcher);
@ -277,9 +276,14 @@ QPlatformServices *QXcbIntegration::services() const
return m_services.data();
}
QPlatformTheme *QXcbIntegration::platformTheme() const
QStringList QXcbIntegration::themeNames() const
{
return m_theme.data();
return QGenericUnixTheme::themeNames();
}
QPlatformTheme *QXcbIntegration::createPlatformTheme(const QString &name) const
{
return QGenericUnixTheme::createUnixTheme(name);
}
QT_END_NAMESPACE

View File

@ -85,7 +85,8 @@ public:
QPlatformServices *services() const;
QPlatformTheme *platformTheme() const;
QStringList themeNames() const;
QPlatformTheme *createPlatformTheme(const QString &name) const;
private:
QList<QXcbConnection *> m_connections;
@ -103,7 +104,6 @@ private:
#endif
QScopedPointer<QPlatformServices> m_services;
QScopedPointer<QPlatformTheme> m_theme;
};
QT_END_NAMESPACE