Qt
Internal/Contributor docs for the Qt SDK. Note: These are NOT official API docs; those are found at https://doc.qt.io/
Loading...
Searching...
No Matches
qquickstyleplugin.cpp
Go to the documentation of this file.
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// Qt-Security score:significant reason:default
4
5#include "qquickstyle.h"
8
9#include <QtCore/private/qfileselector_p.h>
10#include <QtCore/qloggingcategory.h>
11#include <QtGui/qstylehints.h>
12#include <QtGui/qguiapplication.h>
13#include <QtQml/qqmlengine.h>
14#include <QtQml/qqmlfile.h>
15#include <QtQml/private/qqmlmetatype_p.h>
16#include <QtQuickTemplates2/private/qquicktheme_p_p.h>
17
18#include <QtCore/qtyperevision.h>
19
21
22Q_STATIC_LOGGING_CATEGORY(lcStylePlugin, "qt.quick.controls.styleplugin")
23
24class QQuickThemeChangeObserver : public QObject {
25 Q_OBJECT
26public:
27 explicit QQuickThemeChangeObserver()
28 {
29 QStyleHints *styleHints = QGuiApplication::styleHints();
30 moveToThread(styleHints->thread());
31 styleHints->installEventFilter(this);
32 }
33
34Q_SIGNALS:
35 void paletteOrThemeChanged();
36
37protected:
38 bool eventFilter(QObject *object, QEvent *event) override {
39 Q_UNUSED(object);
40 if (event->type() == QEvent::ApplicationPaletteChange || event->type() == QEvent::ThemeChange)
41 emit paletteOrThemeChanged();
42 return false;
43 }
44};
45
46// The custom destructor ensures that all posted events gets processed before the event filter is deleted.
47void QQuickStylePlugin::ObserverDeleter::operator()(QQuickThemeChangeObserver *observer)
48{
49 observer->disconnect();
50 observer->deleteLater();
51}
52
53QQuickStylePlugin::QQuickStylePlugin(QObject *parent)
54 : QQmlExtensionPlugin(parent)
55{
56}
57
58QQuickStylePlugin::~QQuickStylePlugin()
59{
60}
61
62void QQuickStylePlugin::registerTypes(const char *uri)
63{
64 qCDebug(lcStylePlugin).nospace() << "registerTypes called with uri " << uri << "; plugin name is " << name();
65
66 const QTypeRevision latestControlsRevision = QQmlMetaType::latestModuleVersion(QLatin1String("QtQuick.Controls"));
67 // Use the private function because we don't want to cause resolve() to be called,
68 // as the logic that assigns a default style if one wasn't set would interfere with compile-time style selection.
69 QString styleName = QQuickStylePrivate::style();
70 if (!latestControlsRevision.isValid() && styleName.isEmpty()) {
71 // The user hasn't imported QtQuick.Controls, nor set a style via the runtime methods.
72 qCDebug(lcStylePlugin).nospace() << uri << " imported before QtQuick.Controls; using compile-time style selection";
73 QQuickStyle::setStyle(name());
74 styleName = name();
75 }
76
77 // Even if this style plugin isn't for the style set by the user,
78 // we still want to create the theme object, because that function
79 // is also responsible for reading values from qtquickcontrols2.conf.
80 // So, even if a style doesn't have a QQuickTheme, it can still have
81 // values set for (e.g. fonts and palettes) in qtquickcontrols2.conf.
82 const QString effectiveCurrentStyleName = QQuickStylePrivate::effectiveStyleName(styleName);
83 auto theme = QQuickTheme::instance();
84 if (!theme) {
85 qCDebug(lcStylePlugin) << "creating theme";
86 theme = createTheme(effectiveCurrentStyleName);
87 }
88
89 // The primary fallback is the style set by the user. We need to check for that here
90 // so that we can ensure that fallback styles' themes are initialized (QTBUG-117403)
91 // without also allowing the Basic style to be initialized, as it is a secondary fallback
92 // for every built-in style (and only built-in styles can be fallbacks).
93 const bool thisPluginBelongsToCurrentStyle = name() == effectiveCurrentStyleName;
94 const bool isPrimaryFallback = name() == QQuickStylePrivate::fallbackStyle();
95 if (!thisPluginBelongsToCurrentStyle && !isPrimaryFallback) {
96 qCDebug(lcStylePlugin).nospace() << "this style plugin does not belong to the current ("
97 << effectiveCurrentStyleName << ") or fallback (" << QQuickStylePrivate::fallbackStyle()
98 << ") style; not calling initializeTheme()";
99 return;
100 }
101
102 if (thisPluginBelongsToCurrentStyle) {
103 qCDebug(lcStylePlugin).nospace() << "this style plugin belongs to the current style "
104 << effectiveCurrentStyleName << "; calling initializeTheme()";
105 } else {
106 qCDebug(lcStylePlugin).nospace() << "this style plugin belongs to the fallback style "
107 << QQuickStylePrivate::fallbackStyle() << "; calling initializeTheme()";
108 }
109
110 if (!isPrimaryFallback && !styleName.isEmpty())
111 QFileSelectorPrivate::addStatics(QStringList() << styleName);
112
113 // Create and initialize the theme, and hook it up to palette and theme changes.
114 // We are currently in the QML loader thread, but we have to return with an
115 // initialized theme so that controls get the right default values for
116 // palette and font. So we have to initialize the theme right now, even though
117 // that will access QGuiApplication globals (such as a the QPlatformTheme or
118 // QStyleHints singletons) from the wrong thread. It is ok, as the loader
119 // process is blocking the GUI thread anyway, so there are no concurrent
120 // writes to those singletons.
121 initializeTheme(theme);
122
123 // Updates must however go through the main thread. The Observer moves itself
124 // to the same thread as the QStyleHints instance, which is the main thread.
125 themeChangeObserver.reset(new QQuickThemeChangeObserver);
126 connect(themeChangeObserver.get(), &QQuickThemeChangeObserver::paletteOrThemeChanged,
127 this, &QQuickStylePlugin::updateTheme, Qt::DirectConnection);
128}
129
130void QQuickStylePlugin::unregisterTypes()
131{
132 qCDebug(lcStylePlugin) << "unregisterTypes called; plugin name is" << name();
133 if (!QQuickThemePrivate::instance)
134 return;
135
136 themeChangeObserver.reset();
137
138 const bool isPrimaryFallback = name() == QQuickStylePrivate::fallbackStyle();
139 const QString styleName = QQuickStylePrivate::style();
140 if (!isPrimaryFallback && !styleName.isEmpty())
141 QFileSelectorPrivate::removeStatics(QStringList() << styleName);
142
143 // Not every style has a plugin - some styles are QML-only. So, we clean this
144 // stuff up when the first style plugin is unregistered rather than when the
145 // plugin for the current style is unregistered.
146 QQuickThemePrivate::instance.reset();
147 QQuickStylePrivate::reset();
148}
149
150/*!
151 \internal
152
153 Responsible for setting the font and palette settings that were specified in the
154 qtquickcontrols2.conf file.
155
156 Style-specific settings (e.g. Variant=Dense) are read in the constructor of the
157 appropriate style plugin (e.g. QtQuickControls2MaterialStylePlugin).
158
159 Implicit style-specific font and palette values are assigned in the relevant theme
160 (e.g. QQuickMaterialTheme).
161*/
162QQuickTheme *QQuickStylePlugin::createTheme(const QString &name)
163{
164 qCDebug(lcStylePlugin) << "creating QQuickTheme instance to be initialized by style-specific theme of" << name;
165
166 QQuickTheme *theme = new QQuickTheme;
167#if QT_CONFIG(settings)
168 QQuickThemePrivate *p = QQuickThemePrivate::get(theme);
169 QSharedPointer<QSettings> settings = QQuickStylePrivate::settings(name);
170 if (settings) {
171 p->defaultFont.reset(QQuickStylePrivate::readFont(settings));
172 // Set the default font as the System scope, because that's what
173 // QQuickControlPrivate::parentFont() uses as its fallback if no
174 // parent item has a font explicitly set. QQuickControlPrivate::parentFont()
175 // is used as the starting point for font inheritance/resolution.
176 // The same goes for palettes below.
177 theme->setFont(QQuickTheme::System, *p->defaultFont);
178
179 p->defaultPalette.reset(QQuickStylePrivate::readPalette(settings));
180 theme->setPalette(QQuickTheme::System, *p->defaultPalette);
181 }
182#endif
183 QQuickThemePrivate::instance.reset(theme);
184 return theme;
185}
186
187QT_END_NAMESPACE
188
189#include "qquickstyleplugin.moc"
190#include "moc_qquickstyleplugin_p.cpp"
Combined button and popup list for selecting options.