1// Copyright (C) 2020 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3
4#include <QtQml/qqml.h>
5#include <QtQuickControls2/private/qquickstyleplugin_p.h>
6#include <QtGui/qguiapplication.h>
7#include <QtGui/qpa/qplatformintegration.h>
8#include <QtGui/private/qguiapplication_p.h>
9#include <QtGui/qstylehints.h>
10#include <QtQuickTemplates2/private/qquicktheme_p.h>
11
12#include "qquicknativestyle.h"
13#include "qquickcommonstyle.h"
14
15#if defined(Q_OS_MACOS)
16#include "qquickmacstyle_mac_p.h"
17#include "qquickmacfocusframe.h"
18#elif defined(Q_OS_WINDOWS)
19# include "qquickwindowsxpstyle_p.h"
20#endif
21
22QT_BEGIN_NAMESPACE
23
24extern void qml_register_types_QtQuick_NativeStyle();
25Q_GHS_KEEP_REFERENCE(qml_register_types_QtQuick_NativeStyle);
26
27using namespace QQC2;
28
29class QtQuickControls2NativeStylePlugin : public QQuickStylePlugin
30{
31 Q_OBJECT
32 Q_PLUGIN_METADATA(IID QQmlExtensionInterface_iid)
33
34public:
35 QtQuickControls2NativeStylePlugin(QObject *parent = nullptr);
36 ~QtQuickControls2NativeStylePlugin() override;
37
38 void initializeEngine(QQmlEngine *engine, const char *uri) override;
39 void initializeTheme(QQuickTheme *theme) override;
40 QString name() const override;
41
42#if defined(Q_OS_MACOS)
43 QScopedPointer<QQuickMacFocusFrame> m_focusFrame;
44#endif
45};
46
47static void deleteQStyle()
48{
49 // When we delete QStyle, it will free up it's own internal resources. Especially
50 // on macOS, this means releasing a lot of NSViews and NSCells from the QMacStyle
51 // destructor. If we did this from ~QtQuickControls2NativeStylePlugin, it would
52 // happen when the plugin was unloaded from a Q_DESTRUCTOR_FUNCTION in QLibrary,
53 // which is very late in the tear-down process, and after qGuiApp has been set to
54 // nullptr, NSApplication has stopped running, and perhaps also other static platform
55 // variables (e.g in AppKit?) has been deleted. And to our best guess, this is also why
56 // we see a crash in AppKit from the destructor in QMacStyle. So for this reason, we
57 // delete QStyle from a post routine rather than from the destructor.
58 QQuickNativeStyle::setStyle(nullptr);
59}
60
61QtQuickControls2NativeStylePlugin::QtQuickControls2NativeStylePlugin(QObject *parent):
62 QQuickStylePlugin(parent)
63{
64 volatile auto registration = &qml_register_types_QtQuick_NativeStyle;
65 Q_UNUSED(registration);
66}
67
68QtQuickControls2NativeStylePlugin::~QtQuickControls2NativeStylePlugin()
69{
70 if (!qGuiApp)
71 return;
72
73 // QGuiApplication is still running, so we need to remove the post
74 // routine to not be called after we have been unloaded.
75 qRemovePostRoutine(deleteQStyle);
76 QQuickNativeStyle::setStyle(nullptr);
77}
78
79QString QtQuickControls2NativeStylePlugin::name() const
80{
81 return QStringLiteral("NativeStyle");
82}
83
84void QtQuickControls2NativeStylePlugin::initializeEngine(QQmlEngine *engine, const char *uri)
85{
86 Q_UNUSED(engine);
87 Q_UNUSED(uri);
88 // Enable commonstyle as a reference style while
89 // the native styles are under development.
90 QStyle *style = nullptr;
91 if (qEnvironmentVariable(varName: "QQC2_COMMONSTYLE") == QStringLiteral("true")) {
92 style = new QCommonStyle;
93 } else {
94 const QString envStyle = qEnvironmentVariable(varName: "QQC2_STYLE");
95 if (!envStyle.isNull()) {
96 if (envStyle == QLatin1String("common"))
97 style = new QCommonStyle;
98#if defined(Q_OS_MACOS)
99 else if (envStyle == QLatin1String("mac"))
100 style = new QMacStyle;
101#endif
102#if defined(Q_OS_WINDOWS)
103 else if (envStyle == QLatin1String("windows"))
104 style = new QWindowsStyle;
105 else if (envStyle == QLatin1String("windowsxp"))
106 style = new QWindowsXPStyle;
107#endif
108 }
109 if (!style) {
110#if defined(Q_OS_MACOS)
111 style = new QMacStyle;
112#elif defined(Q_OS_WINDOWS)
113 style = new QWindowsXPStyle;
114 if (QGuiApplication::styleHints()->colorScheme() == Qt::ColorScheme::Dark)
115 qobject_cast<QWindowsStyle *>(style)->refreshPalette();
116#else
117 style = new QCommonStyle;
118#endif
119 }
120 }
121
122#if defined(Q_OS_MACOS)
123 m_focusFrame.reset(new QQuickMacFocusFrame());
124#endif
125
126 qAddPostRoutine(deleteQStyle);
127 QQuickNativeStyle::setStyle(style);
128}
129
130void QtQuickControls2NativeStylePlugin::initializeTheme(QQuickTheme * /*theme*/)
131{
132}
133
134QT_END_NAMESPACE
135
136#include "qtquickcontrols2nativestyleplugin.moc"
137

source code of qtdeclarative/src/quicknativestyle/qtquickcontrols2nativestyleplugin.cpp