From f7957f39937c42aadecc6ad2b73d006559514e00 Mon Sep 17 00:00:00 2001 From: Friedemann Kleint Date: Wed, 14 Mar 2012 13:50:14 +0100 Subject: [PATCH] Refactor theme plugin loading. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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 --- src/gui/kernel/qguiapplication.cpp | 16 ++++++-- src/gui/kernel/qplatformintegration_qpa.cpp | 11 +++++- src/gui/kernel/qplatformintegration_qpa.h | 3 +- .../themes/genericunix/qgenericunixthemes.cpp | 39 ++++++++++++++----- .../themes/genericunix/qgenericunixthemes_p.h | 9 ++++- .../platforms/cocoa/qcocoaintegration.h | 4 +- .../platforms/cocoa/qcocoaintegration.mm | 12 ++++-- src/plugins/platforms/cocoa/qcocoatheme.h | 3 ++ src/plugins/platforms/cocoa/qcocoatheme.mm | 2 + .../platforms/windows/qwindowscontext.cpp | 3 +- .../platforms/windows/qwindowsintegration.cpp | 12 ++++-- .../platforms/windows/qwindowsintegration.h | 3 +- .../platforms/windows/qwindowstheme.cpp | 10 ++--- src/plugins/platforms/windows/qwindowstheme.h | 5 ++- src/plugins/platforms/xcb/qxcbintegration.cpp | 12 ++++-- src/plugins/platforms/xcb/qxcbintegration.h | 4 +- 16 files changed, 111 insertions(+), 37 deletions(-) diff --git a/src/gui/kernel/qguiapplication.cpp b/src/gui/kernel/qguiapplication.cpp index 77b69af3eb..ca1ecbef2b 100644 --- a/src/gui/kernel/qguiapplication.cpp +++ b/src/gui/kernel/qguiapplication.cpp @@ -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; } diff --git a/src/gui/kernel/qplatformintegration_qpa.cpp b/src/gui/kernel/qplatformintegration_qpa.cpp index e8721edce7..c9ccc27ad0 100644 --- a/src/gui/kernel/qplatformintegration_qpa.cpp +++ b/src/gui/kernel/qplatformintegration_qpa.cpp @@ -44,6 +44,7 @@ #include #include #include +#include #include #include #include @@ -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 diff --git a/src/gui/kernel/qplatformintegration_qpa.h b/src/gui/kernel/qplatformintegration_qpa.h index 3f9de9df5e..d6f5b6658a 100644 --- a/src/gui/kernel/qplatformintegration_qpa.h +++ b/src/gui/kernel/qplatformintegration_qpa.h @@ -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); diff --git a/src/platformsupport/themes/genericunix/qgenericunixthemes.cpp b/src/platformsupport/themes/genericunix/qgenericunixthemes.cpp index 602dd6264a..597dbde74f 100644 --- a/src/platformsupport/themes/genericunix/qgenericunixthemes.cpp +++ b/src/platformsupport/themes/genericunix/qgenericunixthemes.cpp @@ -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; } diff --git a/src/platformsupport/themes/genericunix/qgenericunixthemes_p.h b/src/platformsupport/themes/genericunix/qgenericunixthemes_p.h index a9db29e8cd..cabffc0212 100644 --- a/src/platformsupport/themes/genericunix/qgenericunixthemes_p.h +++ b/src/platformsupport/themes/genericunix/qgenericunixthemes_p.h @@ -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: }; diff --git a/src/plugins/platforms/cocoa/qcocoaintegration.h b/src/plugins/platforms/cocoa/qcocoaintegration.h index 2389fc2a55..9248df0d37 100644 --- a/src/plugins/platforms/cocoa/qcocoaintegration.h +++ b/src/plugins/platforms/cocoa/qcocoaintegration.h @@ -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 mFontDb; diff --git a/src/plugins/platforms/cocoa/qcocoaintegration.mm b/src/plugins/platforms/cocoa/qcocoaintegration.mm index d490495be4..96027e0925 100644 --- a/src/plugins/platforms/cocoa/qcocoaintegration.mm +++ b/src/plugins/platforms/cocoa/qcocoaintegration.mm @@ -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 diff --git a/src/plugins/platforms/cocoa/qcocoatheme.h b/src/plugins/platforms/cocoa/qcocoatheme.h index 030db1822c..5cb6f7437d 100644 --- a/src/plugins/platforms/cocoa/qcocoatheme.h +++ b/src/plugins/platforms/cocoa/qcocoatheme.h @@ -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 m_palettes; diff --git a/src/plugins/platforms/cocoa/qcocoatheme.mm b/src/plugins/platforms/cocoa/qcocoatheme.mm index 8ec6e3801e..d17ee30096 100644 --- a/src/plugins/platforms/cocoa/qcocoatheme.mm +++ b/src/plugins/platforms/cocoa/qcocoatheme.mm @@ -49,6 +49,8 @@ QT_BEGIN_NAMESPACE +const char *QCocoaTheme::name = "cocoa"; + QCocoaTheme::QCocoaTheme() :m_systemPalette(0) { diff --git a/src/plugins/platforms/windows/qwindowscontext.cpp b/src/plugins/platforms/windows/qwindowscontext.cpp index e8050d5027..f61e40ef77 100644 --- a/src/plugins/platforms/windows/qwindowscontext.cpp +++ b/src/plugins/platforms/windows/qwindowscontext.cpp @@ -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; diff --git a/src/plugins/platforms/windows/qwindowsintegration.cpp b/src/plugins/platforms/windows/qwindowsintegration.cpp index 7510cded50..ee58a19ca9 100644 --- a/src/plugins/platforms/windows/qwindowsintegration.cpp +++ b/src/plugins/platforms/windows/qwindowsintegration.cpp @@ -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 diff --git a/src/plugins/platforms/windows/qwindowsintegration.h b/src/plugins/platforms/windows/qwindowsintegration.h index 6dd65a02e4..20fd790bfe 100644 --- a/src/plugins/platforms/windows/qwindowsintegration.h +++ b/src/plugins/platforms/windows/qwindowsintegration.h @@ -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; diff --git a/src/plugins/platforms/windows/qwindowstheme.cpp b/src/plugins/platforms/windows/qwindowstheme.cpp index f10595fa79..f3a9d91d00 100644 --- a/src/plugins/platforms/windows/qwindowstheme.cpp +++ b/src/plugins/platforms/windows/qwindowstheme.cpp @@ -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(0)); qFill(m_palettes, m_palettes + NPalettes, static_cast(0)); refresh(); @@ -240,11 +244,7 @@ QWindowsTheme::~QWindowsTheme() { clearPalettes(); clearFonts(); -} - -QWindowsTheme *QWindowsTheme::instance() -{ - return static_cast(QWindowsIntegration::instance()->platformTheme()); + m_instance = 0; } static inline QStringList iconThemeSearchPaths() diff --git a/src/plugins/platforms/windows/qwindowstheme.h b/src/plugins/platforms/windows/qwindowstheme.h index 37346eed3a..7515a13a72 100644 --- a/src/plugins/platforms/windows/qwindowstheme.h +++ b/src/plugins/platforms/windows/qwindowstheme.h @@ -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]; }; diff --git a/src/plugins/platforms/xcb/qxcbintegration.cpp b/src/plugins/platforms/xcb/qxcbintegration.cpp index fe33bd7153..0db9ef9e64 100644 --- a/src/plugins/platforms/xcb/qxcbintegration.cpp +++ b/src/plugins/platforms/xcb/qxcbintegration.cpp @@ -88,8 +88,7 @@ QT_BEGIN_NAMESPACE QXcbIntegration::QXcbIntegration(const QStringList ¶meters) : 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 diff --git a/src/plugins/platforms/xcb/qxcbintegration.h b/src/plugins/platforms/xcb/qxcbintegration.h index 457f90d6e0..4c335f2f06 100644 --- a/src/plugins/platforms/xcb/qxcbintegration.h +++ b/src/plugins/platforms/xcb/qxcbintegration.h @@ -85,7 +85,8 @@ public: QPlatformServices *services() const; - QPlatformTheme *platformTheme() const; + QStringList themeNames() const; + QPlatformTheme *createPlatformTheme(const QString &name) const; private: QList m_connections; @@ -103,7 +104,6 @@ private: #endif QScopedPointer m_services; - QScopedPointer m_theme; }; QT_END_NAMESPACE