diff options
-rw-r--r-- | src/quicknativestyle/CMakeLists.txt | 2 | ||||
-rw-r--r-- | src/quicknativestyle/items/qquickstyleitem.h | 4 | ||||
-rw-r--r-- | src/quicknativestyle/qstyle/qquicknativestyle.cpp | 117 | ||||
-rw-r--r-- | src/quicknativestyle/qstyle/qquicknativestyle_p.h (renamed from src/quicknativestyle/qstyle/qquicknativestyle.h) | 25 | ||||
-rw-r--r-- | src/quicknativestyle/qtquickcontrols2nativestyleplugin.cpp | 121 |
5 files changed, 154 insertions, 115 deletions
diff --git a/src/quicknativestyle/CMakeLists.txt b/src/quicknativestyle/CMakeLists.txt index f27553955b..e6b95579b3 100644 --- a/src/quicknativestyle/CMakeLists.txt +++ b/src/quicknativestyle/CMakeLists.txt @@ -72,7 +72,7 @@ qt_internal_add_qml_module(qtquickcontrols2nativestyleplugin qstyle/qquickcommonstyle.cpp qstyle/qquickcommonstyle.h qstyle/qquickcommonstyle_p.h qstyle/qquickcommonstylepixmaps_p.h qstyle/qquickdrawutil.cpp qstyle/qquickdrawutil.h - qstyle/qquicknativestyle.h + qstyle/qquicknativestyle.cpp qstyle/qquicknativestyle_p.h qstyle/qquickstyle.cpp qstyle/qquickstyle.h qstyle/qquickstyle_p.h qstyle/qquickstylehelper.cpp qstyle/qquickstylehelper_p.h qstyle/qquickstyleoption.cpp qstyle/qquickstyleoption.h diff --git a/src/quicknativestyle/items/qquickstyleitem.h b/src/quicknativestyle/items/qquickstyleitem.h index e4787ff269..42f131054a 100644 --- a/src/quicknativestyle/items/qquickstyleitem.h +++ b/src/quicknativestyle/items/qquickstyleitem.h @@ -11,7 +11,7 @@ #include <QtQuick/private/qquickitem_p.h> #include <QtQuickTemplates2/private/qquickcontrol_p.h> -#include "qquicknativestyle.h" +#include "qquicknativestyle_p.h" #include "qquickstyle.h" #include "qquickstyleoption.h" @@ -220,7 +220,7 @@ protected: void initStyleOptionBase(QStyleOption &styleOption) const; inline QSize contentSize() const { return QSize(qCeil(m_contentSize.width()), qCeil(m_contentSize.height())); } - inline static QStyle *style() { return QQuickNativeStyle::style(); } + inline static QStyle *style() { return QQC2::style(); } template <class T> inline const T* control() const { #ifdef QT_DEBUG diff --git a/src/quicknativestyle/qstyle/qquicknativestyle.cpp b/src/quicknativestyle/qstyle/qquicknativestyle.cpp new file mode 100644 index 0000000000..6c3ea9f2d0 --- /dev/null +++ b/src/quicknativestyle/qstyle/qquicknativestyle.cpp @@ -0,0 +1,117 @@ +// Copyright (C) 2025 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only +// Qt-Security score:significant reason:default + +#include "qquicknativestyle_p.h" + +#include <QtCore/qapplicationstatic.h> +#include <QtCore/qloggingcategory.h> +#include <QtCore/qthread.h> +#include <QtGui/qguiapplication.h> +#include <QtGui/qstylehints.h> + +#if defined(Q_OS_MACOS) +# include "qquickmacstyle_mac_p.h" +#elif defined(Q_OS_WINDOWS) +# include "qquickwindowsxpstyle_p.h" +#endif + +#include <memory> + +QT_BEGIN_NAMESPACE + +Q_STATIC_LOGGING_CATEGORY(lcNativeStylePlugin, "qt.quick.plugins.nativestyle"); + +namespace QQC2 { + +namespace { + +// When we delete QStyle, it will free up its own internal resources. Especially +// on macOS, this means releasing a lot of NSViews and NSCells from the QMacStyle +// destructor. If we did this from ~QtQuickControls2NativeStylePlugin, it would +// happen when the plugin was unloaded from a Q_DESTRUCTOR_FUNCTION in QLibrary, +// which is very late in the tear-down process, and after qGuiApp has been set to +// nullptr, NSApplication has stopped running, and perhaps also other static platform +// variables (e.g in AppKit?) have been deleted. And to our best guess, this is also why +// we see a crash in AppKit from the destructor in QMacStyle. So for this reason, we +// delete QStyle from a post routine rather than from the destructor. +// +// Furthermore we need to ensure to recreate the QQuickFocusFrame when re-creating the qApplication + +struct StyleSingleton +{ + StyleSingleton(); + ~StyleSingleton(); + QStyle *style() { return m_style.get(); } + +private: + std::unique_ptr<QStyle> m_style; +}; + +Q_APPLICATION_STATIC(StyleSingleton, styleSingleton); + +StyleSingleton::StyleSingleton() +{ + qCDebug(lcNativeStylePlugin) << "Creating native style"; + + // Enable commonstyle as a reference style while + // the native styles are under development. + if (qEnvironmentVariable("QQC2_COMMONSTYLE") == u"true") + m_style = std::make_unique<QCommonStyle>(); + else if (const QString envStyle = qEnvironmentVariable("QQC2_STYLE"); !envStyle.isNull()) { + if (envStyle == u"common") + m_style = std::make_unique<QCommonStyle>(); +#if defined(Q_OS_MACOS) + else if (envStyle == u"mac") + m_style.reset(QMacStyle::create()); +#endif +#if defined(Q_OS_WINDOWS) + else if (envStyle == u"windows") + m_style = std::make_unique<QWindowsStyle>(); + else if (envStyle == u"windowsxp") + m_style = std::make_unique<QWindowsXPStyle>(); +#endif + } + + if (!m_style) { +#if defined(Q_OS_MACOS) + m_style.reset(QMacStyle::create()); +#elif defined(Q_OS_WINDOWS) + m_style = std::make_unique<QWindowsXPStyle>(); + if (QGuiApplication::styleHints()->colorScheme() == Qt::ColorScheme::Dark) + qobject_cast<QWindowsStyle *>(m_style.get())->refreshPalette(); +#endif + } + + if (!m_style) + m_style = std::make_unique<QCommonStyle>(); + + // The native style plugin is neither the current style or fallback style + // during QQuickStylePlugin::registerTypes, so it's not given a chance to + // initialize or update the theme. But since it's used as an implementation + // detail of some of the other style plugins, it might need to know about + // theme changes. + Q_ASSERT(m_style->thread()->isMainThread()); + QObject::connect(QGuiApplication::styleHints(), &QStyleHints::colorSchemeChanged, m_style.get(), + [this] { + m_style->handleThemeChange(); + }); +} + +StyleSingleton::~StyleSingleton() +{ + qCDebug(lcNativeStylePlugin) << "Destroying native style"; + + m_style.reset(); +} + +}; // namespace + +QStyle *style() +{ + return styleSingleton()->style(); +} + +} // namespace QQC2 + +QT_END_NAMESPACE diff --git a/src/quicknativestyle/qstyle/qquicknativestyle.h b/src/quicknativestyle/qstyle/qquicknativestyle_p.h index 1ed40bef69..3f0a32fb6c 100644 --- a/src/quicknativestyle/qstyle/qquicknativestyle.h +++ b/src/quicknativestyle/qstyle/qquicknativestyle_p.h @@ -2,26 +2,29 @@ // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only // Qt-Security score:significant reason:default + #ifndef QQUICKNATIVESTYLE_H #define QQUICKNATIVESTYLE_H -#include "qquickstyle.h" +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// -#include <memory> + +#include "qquickstyle.h" QT_BEGIN_NAMESPACE namespace QQC2 { -class QQuickNativeStyle -{ -public: - static void setStyle(QStyle *style) { s_style.reset(style); } - static QStyle *style() { return s_style.get(); } - -private: - static inline std::unique_ptr<QStyle> s_style; -}; +QStyle *style(); } // namespace QQC2 diff --git a/src/quicknativestyle/qtquickcontrols2nativestyleplugin.cpp b/src/quicknativestyle/qtquickcontrols2nativestyleplugin.cpp index 61443b475b..942f96e5f4 100644 --- a/src/quicknativestyle/qtquickcontrols2nativestyleplugin.cpp +++ b/src/quicknativestyle/qtquickcontrols2nativestyleplugin.cpp @@ -3,22 +3,13 @@ // Qt-Security score:significant reason:default #include <QtQml/qqml.h> +#include <QtQml/qqmlextensionplugin.h> #include <QtQuickControls2/private/qquickstyleplugin_p.h> -#include <QtGui/qguiapplication.h> -#include <QtGui/qpa/qplatformintegration.h> -#include <QtGui/private/qguiapplication_p.h> -#include <QtGui/qstylehints.h> -#include <QtQuickTemplates2/private/qquicktheme_p.h> - -#include "qquicknativestyle.h" -#include "qquickcommonstyle.h" #if defined(Q_OS_MACOS) -#include "qquickmacfocusframe.h" -#include "qquickmacstyle_mac_p.h" +# include "qquickmacfocusframe.h" #elif defined(Q_OS_WINDOWS) -#include "qquickwindowsfocusframe.h" -#include "qquickwindowsxpstyle_p.h" +# include "qquickwindowsfocusframe.h" #endif QT_BEGIN_NAMESPACE @@ -26,7 +17,7 @@ QT_BEGIN_NAMESPACE extern void qml_register_types_QtQuick_NativeStyle(); Q_GHS_KEEP_REFERENCE(qml_register_types_QtQuick_NativeStyle); -using namespace QQC2; +namespace QQC2 { class QtQuickControls2NativeStylePlugin : public QQuickStylePlugin { @@ -35,31 +26,14 @@ class QtQuickControls2NativeStylePlugin : public QQuickStylePlugin public: QtQuickControls2NativeStylePlugin(QObject *parent = nullptr); - ~QtQuickControls2NativeStylePlugin() override; + ~QtQuickControls2NativeStylePlugin() override = default; - void initializeEngine(QQmlEngine *engine, const char *uri) override; - void initializeTheme(QQuickTheme *theme) override; - QString name() const override; + void initializeEngine(QQmlEngine *, const char * /*uri*/) override; -#if defined(Q_OS_MACOS) || defined (Q_OS_WIN) - QScopedPointer<QQuickFocusFrame> m_focusFrame; -#endif + void initializeTheme(QQuickTheme *) override { } + QString name() const override { return QStringLiteral("NativeStyle"); } }; -static void deleteQStyle() -{ - // When we delete QStyle, it will free up it's own internal resources. Especially - // on macOS, this means releasing a lot of NSViews and NSCells from the QMacStyle - // destructor. If we did this from ~QtQuickControls2NativeStylePlugin, it would - // happen when the plugin was unloaded from a Q_DESTRUCTOR_FUNCTION in QLibrary, - // which is very late in the tear-down process, and after qGuiApp has been set to - // nullptr, NSApplication has stopped running, and perhaps also other static platform - // variables (e.g in AppKit?) has been deleted. And to our best guess, this is also why - // we see a crash in AppKit from the destructor in QMacStyle. So for this reason, we - // delete QStyle from a post routine rather than from the destructor. - QQuickNativeStyle::setStyle(nullptr); -} - QtQuickControls2NativeStylePlugin::QtQuickControls2NativeStylePlugin(QObject *parent): QQuickStylePlugin(parent) { @@ -67,82 +41,27 @@ QtQuickControls2NativeStylePlugin::QtQuickControls2NativeStylePlugin(QObject *pa Q_UNUSED(registration); } -QtQuickControls2NativeStylePlugin::~QtQuickControls2NativeStylePlugin() -{ - if (!qGuiApp) - return; - - // QGuiApplication is still running, so we need to remove the post - // routine to not be called after we have been unloaded. - qRemovePostRoutine(deleteQStyle); - QQuickNativeStyle::setStyle(nullptr); -} - -QString QtQuickControls2NativeStylePlugin::name() const -{ - return QStringLiteral("NativeStyle"); -} +static std::unique_ptr<QQuickFocusFrame> g_focusFrame; -void QtQuickControls2NativeStylePlugin::initializeEngine(QQmlEngine *engine, const char *uri) +void QtQuickControls2NativeStylePlugin::initializeEngine(QQmlEngine *, const char *) { - Q_UNUSED(engine); - Q_UNUSED(uri); - // Enable commonstyle as a reference style while - // the native styles are under development. - QStyle *style = nullptr; - if (qEnvironmentVariable("QQC2_COMMONSTYLE") == QStringLiteral("true")) { - style = new QCommonStyle; - } else { - const QString envStyle = qEnvironmentVariable("QQC2_STYLE"); - if (!envStyle.isNull()) { - if (envStyle == QLatin1String("common")) - style = new QCommonStyle; -#if defined(Q_OS_MACOS) - else if (envStyle == QLatin1String("mac")) - style = QMacStyle::create(); -#endif -#if defined(Q_OS_WINDOWS) - else if (envStyle == QLatin1String("windows")) - style = new QWindowsStyle; - else if (envStyle == QLatin1String("windowsxp")) - style = new QWindowsXPStyle; -#endif - } - if (!style) { -#if defined(Q_OS_MACOS) - style = QMacStyle::create(); -#elif defined(Q_OS_WINDOWS) - style = new QWindowsXPStyle; - if (QGuiApplication::styleHints()->colorScheme() == Qt::ColorScheme::Dark) - qobject_cast<QWindowsStyle *>(style)->refreshPalette(); -#else - style = new QCommonStyle; -#endif - } - } + if (g_focusFrame) + return; #if defined(Q_OS_MACOS) - m_focusFrame.reset(new QQuickMacFocusFrame()); + g_focusFrame = std::make_unique<QQuickMacFocusFrame>(); #elif defined(Q_OS_WIN) - m_focusFrame.reset(new QQuickWindowsFocusFrame()); + g_focusFrame = std::make_unique<QQuickWindowsFocusFrame>(); #endif + if (!g_focusFrame) + return; - // The native style plugin is neither the current style or fallback style - // during QQuickStylePlugin::registerTypes, so it's not given a chance to - // initialize or update the theme. But since it's used as an implementation - // detail of some of the other style plugins, it might need to know about - // theme changes. - Q_ASSERT(style->thread()->isMainThread()); - connect(QGuiApplication::styleHints(), &QStyleHints::colorSchemeChanged, - style, [=]{ style->handleThemeChange(); }); - - qAddPostRoutine(deleteQStyle); - QQuickNativeStyle::setStyle(style); + qAddPostRoutine([] { + g_focusFrame.reset(); + }); } -void QtQuickControls2NativeStylePlugin::initializeTheme(QQuickTheme * /*theme*/) -{ -} +} // namespace QQC2 QT_END_NAMESPACE |