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: // Create the platform theme:
// 1) Ask the platform integration to create a platform theme // 1) Ask the platform integration for a list of names.
QGuiApplicationPrivate::platform_theme = QGuiApplicationPrivate::platform_integration->platformTheme(); 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 // 2) If none found, look for a theme plugin. Theme plugins are located in the
// same directory as platform plugins. // same directory as platform plugins.
if (!QGuiApplicationPrivate::platform_theme) { 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. // No error message; not having a theme plugin is allowed.
} }
@ -748,6 +757,7 @@ QGuiApplicationPrivate::~QGuiApplicationPrivate()
qt_cleanupFontDatabase(); qt_cleanupFontDatabase();
delete platform_theme;
delete platform_integration; delete platform_integration;
platform_integration = 0; platform_integration = 0;
} }

View File

@ -44,6 +44,7 @@
#include <QtGui/QPlatformFontDatabase> #include <QtGui/QPlatformFontDatabase>
#include <QtGui/QPlatformClipboard> #include <QtGui/QPlatformClipboard>
#include <QtGui/QPlatformAccessibility> #include <QtGui/QPlatformAccessibility>
#include <QtGui/QPlatformTheme>
#include <QtGui/private/qguiapplication_p.h> #include <QtGui/private/qguiapplication_p.h>
#include <QtGui/private/qpixmap_raster_p.h> #include <QtGui/private/qpixmap_raster_p.h>
#include <QtGui/private/qplatformscreen_qpa_p.h> #include <QtGui/private/qplatformscreen_qpa_p.h>
@ -315,9 +316,15 @@ void QPlatformIntegration::screenAdded(QPlatformScreen *ps)
emit qGuiApp->screenAdded(screen); 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 QT_END_NAMESPACE

View File

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

View File

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

View File

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

View File

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

View File

@ -93,7 +93,6 @@ QCocoaIntegration::QCocoaIntegration()
, mEventDispatcher(new QCocoaEventDispatcher()) , mEventDispatcher(new QCocoaEventDispatcher())
, mInputContext(new QCocoaInputContext) , mInputContext(new QCocoaInputContext)
, mAccessibility(new QPlatformAccessibility) , mAccessibility(new QPlatformAccessibility)
, mPlatformTheme(new QCocoaTheme)
, mCocoaDrag(new QCocoaDrag) , mCocoaDrag(new QCocoaDrag)
{ {
QCocoaAutoReleasePool pool; QCocoaAutoReleasePool pool;
@ -212,9 +211,16 @@ QPlatformDrag *QCocoaIntegration::drag() const
return mCocoaDrag.data(); 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 QT_END_NAMESPACE

View File

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

View File

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

View File

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

View File

@ -183,7 +183,6 @@ struct QWindowsIntegrationPrivate
QOpenGLStaticContextPtr m_staticOpenGLContext; QOpenGLStaticContextPtr m_staticOpenGLContext;
QWindowsInputContext m_inputContext; QWindowsInputContext m_inputContext;
QWindowsAccessibility m_accessibility; QWindowsAccessibility m_accessibility;
QWindowsTheme m_theme;
QWindowsServices m_services; QWindowsServices m_services;
}; };
@ -362,9 +361,16 @@ QAbstractEventDispatcher * QWindowsIntegration::guiThreadEventDispatcher() const
return d->m_eventDispatcher; 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 QPlatformServices *QWindowsIntegration::services() const

View File

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

View File

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

View File

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

View File

@ -88,8 +88,7 @@ QT_BEGIN_NAMESPACE
QXcbIntegration::QXcbIntegration(const QStringList &parameters) QXcbIntegration::QXcbIntegration(const QStringList &parameters)
: m_eventDispatcher(createUnixEventDispatcher()), : m_eventDispatcher(createUnixEventDispatcher()),
m_services(new QGenericUnixServices), m_services(new QGenericUnixServices)
m_theme(QGenericUnixTheme::createUnixTheme())
{ {
QGuiApplicationPrivate::instance()->setEventDispatcher(m_eventDispatcher); QGuiApplicationPrivate::instance()->setEventDispatcher(m_eventDispatcher);
@ -277,9 +276,14 @@ QPlatformServices *QXcbIntegration::services() const
return m_services.data(); 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 QT_END_NAMESPACE

View File

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