aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTim Blechmann <[email protected]>2025-09-20 09:08:32 +0800
committerTim Blechmann <[email protected]>2025-10-21 08:53:54 +0800
commitb483fc5aaaf208ec8a55580f48a68be76d9dfd8f (patch)
treee9972a37c76b6c7a59f84437a08fc9ad6b5ba4e5
parent89f08f960993bf4b55ed9f72ac7278bb1a772001 (diff)
Native Style: rework style and focus window initializationHEADdev
QStyle is destroyed with the app singleton, but not re-created when a new app is re-created. We change this to lazily initialize the style via application static in QQuickStyleItem::style(). Furthermore the focus window is not re-connected to the new application singleton, either. We lazily construct it and ensure that is cleaned up when the application singleton is destroyed. Pick-to: 6.10 Fixes: QTBUG-140220 Change-Id: I97281aaa91794a8a4e1c1fb3aa524dd54cf19709 Reviewed-by: Richard Moe Gustavsen <[email protected]>
-rw-r--r--src/quicknativestyle/CMakeLists.txt2
-rw-r--r--src/quicknativestyle/items/qquickstyleitem.h4
-rw-r--r--src/quicknativestyle/qstyle/qquicknativestyle.cpp117
-rw-r--r--src/quicknativestyle/qstyle/qquicknativestyle_p.h (renamed from src/quicknativestyle/qstyle/qquicknativestyle.h)25
-rw-r--r--src/quicknativestyle/qtquickcontrols2nativestyleplugin.cpp121
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