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
qquickpaletteproviderprivatebase_p.h
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#ifndef QQUICKPALETTEPROVIDERPRIVATEBASE_H
5#define QQUICKPALETTEPROVIDERPRIVATEBASE_H
6
7//
8// W A R N I N G
9// -------------
10//
11// This file is not part of the Qt API. It exists purely as an
12// implementation detail. This header file may change from version to
13// version without notice, or even be removed.
14//
15// We mean it.
16//
17
18#include <QtQuick/private/qquickpalette_p.h>
19#include <QtQuick/private/qquickabstractpaletteprovider_p.h>
20#include <QtGui/qwindow.h>
21#include <QtQml/private/qlazilyallocated_p.h>
22
23QT_BEGIN_NAMESPACE
24
25class QWindow;
26class QQuickWindow;
27class QQuickWindowPrivate;
28class QQuickItem;
29class QQuickItemPrivate;
30class QQuickPopup;
31class QQuickPopupPrivate;
32
33/*!
34 \internal
35
36 Implements all required operations with palette.
37
38 I -- is interface class (e.g. QQuickItem).
39 Impl -- is implementation class (e.g. QQuickItemPrivate).
40
41 To use this class you need to inherit implementation class from it.
42 */
43template <class I, class Impl>
45{
46 static_assert(std::is_base_of<QObject, I>{}, "The interface class must inherit QObject");
47
48public:
50
51 /*!
52 \internal
53
54 Get current palette.
55
56 \note Palette might be lazily allocated. Signal \p paletteCreated()
57 will be emitted by an object of interface class in this case.
58
59 \note This function doesn't ask an object of interface class to emit
60 paletteChanged() signal in order to avoid problems with
61 property bindigns.
62 */
63 virtual QQuickPalette *palette() const;
64
65 /*!
66 \internal
67
68 Set new palette. Doesn't transfer ownership.
69 */
70 virtual void setPalette(QQuickPalette *p);
71
72 /*!
73 \internal
74
75 Reset palette to the default one.
76 */
77 virtual void resetPalette();
78
79 /*!
80 \internal
81
82 Check if everything is internally allocated and palette exists.
83
84 Use before call \p palette() to avoid unnecessary allocations.
85 */
86 virtual bool providesPalette() const;
87
88 /*!
89 \internal
90
91 The default palette for this component.
92 */
93 QPalette defaultPalette() const override;
94
95 /*!
96 \internal
97
98 The parent palette for this component. Can be null.
99 */
100 QPalette parentPalette(const QPalette &fallbackPalette) const override;
101
102 /*!
103 \internal
104
105 Inherit from \p parentPalette. This function is also called when
106 either parent or window of this item is changed.
107 */
108 void inheritPalette(const QPalette &parentPalette);
109
110 /*!
111 \internal
112
113 Updates children palettes. The default implementation invokes
114 inheritPalette for all visual children.
115
116 This function is also called when palette is changed
117 (signal changed() is emitted).
118 */
119 virtual void updateChildrenPalettes(const QPalette &parentPalette);
120
121protected:
123
124private:
126 using Self = QQuickPaletteProviderPrivateBase<I, Impl>;
127
128 void registerPalette(PalettePtr palette);
129
130 bool isValidPalette(const QQuickPalette *palette) const;
131
132 QQuickPalette *windowPalette() const;
133
134
135 void connectItem();
136
137 const I *itemWithPalette() const;
138 I *itemWithPalette();
139
140 QQuickPalette *paletteData() const;
141
142 QPalette toQPalette() const;
143
144private:
145 PalettePtr m_palette;
146};
147
148template<class I, class Impl>
150{
151 if (!providesPalette()) {
152 // It's required to create a new palette without parent,
153 // because this method can be called from the rendering thread
154 const_cast<Self*>(this)->registerPalette(std::make_unique<QQuickPalette>());
155 Q_EMIT const_cast<Self*>(this)->itemWithPalette()->paletteCreated();
156 }
157
158 return paletteData();
159}
160
161template<class I, class Impl>
162bool QQuickPaletteProviderPrivateBase<I, Impl>::isValidPalette(const QQuickPalette *palette) const
163{
164 if (!palette) {
165 qWarning("Palette cannot be null.");
166 return false;
167 }
168
169 if (providesPalette() && paletteData() == palette) {
170 qWarning("Self assignment makes no sense.");
171 return false;
172 }
173
174 return true;
175}
176
177template<class I, class Impl>
178void QQuickPaletteProviderPrivateBase<I, Impl>::setPalette(QQuickPalette *p)
179{
180 if (isValidPalette(p)) {
181 palette()->fromQPalette(p->toQPalette());
182 }
183}
184
185template<class I, class Impl>
187{
188 if (providesPalette())
189 paletteData()->reset();
190}
191
192template<class I, class Impl>
194{
195 return !!m_palette;
196}
197
198template<class I, class Impl>
200{
201 return QPalette();
202}
203
204template <class Window>
205inline constexpr bool isRootWindow() { return std::is_base_of_v<QWindow, Window>; }
206
207template<class I, class Impl>
208void QQuickPaletteProviderPrivateBase<I, Impl>::registerPalette(PalettePtr palette)
209{
210 if constexpr (!isRootWindow<I>()) {
211 // Connect item only once, before initial data allocation
212 if (!providesPalette()) {
213 connectItem();
214 }
215 }
216
217 m_palette = std::move(palette);
218 m_palette->setPaletteProvider(this);
219 m_palette->inheritPalette(parentPalette(defaultPalette()));
220
222
223 // In order to avoid extra noise, we should connect
224 // the following signals only after everything is already setup
225 I::connect(paletteData(), &QQuickPalette::changed, itemWithPalette(), &I::paletteChanged);
226 I::connect(paletteData(), &QQuickPalette::changed, itemWithPalette(), [this]{ updateChildrenPalettes(toQPalette()); });
227}
228
229template<class T> struct dependent_false : std::false_type {};
230template<class Impl, class I> decltype(auto) getPrivateImpl(I &t) { return Impl::get(&t); }
231
232template <class T>
233decltype(auto) getPrivate(T &item)
234{
235 if constexpr (std::is_base_of_v<T, QQuickWindow>) {
236 return getPrivateImpl<QQuickWindowPrivate>(item);
237 } else if constexpr (std::is_base_of_v<T, QQuickItem>) {
238 return getPrivateImpl<QQuickItemPrivate>(item);
239 } else {
240 static_assert (dependent_false<T>::value, "Extend please.");
241 }
242}
243
244template<class I, class Impl>
245QQuickPalette *QQuickPaletteProviderPrivateBase<I, Impl>::windowPalette() const
246{
247 if constexpr (!isRootWindow<I>()) {
248 if (auto window = itemWithPalette()->window()) {
249 if (getPrivate(*window)->providesPalette()) {
250 return getPrivate(*window)->palette();
251 }
252 }
253 }
254
255 return nullptr;
256}
257
258template<class I, class Impl>
259QPalette QQuickPaletteProviderPrivateBase<I, Impl>::parentPalette(const QPalette &fallbackPalette) const
260{
261 if constexpr (!isRootWindow<I>()) {
262 // Popups should always inherit from their window, even child popups: QTBUG-115707.
263 if (!std::is_base_of_v<QQuickPopup, I>) {
264 for (auto parentItem = itemWithPalette()->parentItem(); parentItem;
265 parentItem = parentItem->parentItem()) {
266
267 // Don't allocate a new palette here. Use only if it's already pre allocated
268 if (parentItem && getPrivate(*parentItem)->providesPalette()) {
269 return getPrivate(*parentItem)->palette()->toQPalette();
270 }
271 }
272 }
273
274 if (auto wp = windowPalette()) {
275 return wp->toQPalette();
276 }
277 }
278
279 return fallbackPalette;
280}
281
282template<class I>
283const QQuickItem* rootItem(const I &item)
284{
285 if constexpr (isRootWindow<I>()) {
286 return item.contentItem();
287 } else if constexpr (std::is_base_of_v<QQuickPopup, I>) {
288 return nullptr;
289 } else {
290 return &item;
291 }
292}
293
294template<class I, class Impl>
295void QQuickPaletteProviderPrivateBase<I, Impl>::inheritPalette(const QPalette &parentPalette)
296{
297 if (providesPalette()) {
298 // If palette is changed, then this function will be invoked
299 // for all children because of connection with signal changed()
300 palette()->inheritPalette(parentPalette);
301 } else {
302 // Otherwise, just propagate parent palette to all children
303 updateChildrenPalettes(parentPalette);
304 }
305}
306
307template<class I, class Impl>
309{
310 if constexpr (!isRootWindow<I>()) {
311 if (providesPalette()) {
312 const bool enabled = itemWithPalette()->isEnabled();
313 const auto window = itemWithPalette()->window();
314 const bool active = window ? window->isActive() : true;
315 palette()->setCurrentGroup(enabled ? (active ? QPalette::Active : QPalette::Inactive)
316 : QPalette::Disabled);
317 }
318 }
319}
320
321template<class I, class Impl>
322void QQuickPaletteProviderPrivateBase<I, Impl>::updateChildrenPalettes(const QPalette &parentPalette)
323{
324 if constexpr (std::is_same_v<QQuickWindow, I> && std::is_same_v<QQuickWindowPrivate, Impl>) {
325 /* QQuickWindowPrivate instantiates this template, but does not include QQuickItemPrivate
326 * This causes an error with the QQuickItemPrivate::inheritPalette call below on MSVC in
327 * static builds, as QQuickItemPrivate is incomplete. To work around this situation, we do
328 * nothing in this instantiation of updateChildrenPalettes and instead add an override in
329 * QQuickWindowPrivate, which does the correct thing.
330 */
331 Q_UNREACHABLE_RETURN(); // You are not supposed to call this function
332 } else {
333 if (auto root = rootItem(*itemWithPalette())) {
334 for (auto &&child : root->childItems()) {
335 if (Q_LIKELY(child)) {
336 getPrivate(*child)->inheritPalette(parentPalette);
337 }
338 }
339 }
340 }
341}
342
343template<class I, class Impl>
344void QQuickPaletteProviderPrivateBase<I, Impl>::connectItem()
345{
346 Q_ASSERT(itemWithPalette());
347
348 if constexpr (!isRootWindow<I>()) {
349 // Item with palette has the same lifetime as its implementation that inherits this class
350 I::connect(itemWithPalette(), &I::parentChanged,
351 itemWithPalette(), [this]() { inheritPalette(parentPalette(defaultPalette())); });
352 I::connect(itemWithPalette(), &I::windowChanged,
353 itemWithPalette(), [this]() { inheritPalette(parentPalette(defaultPalette())); });
354 I::connect(itemWithPalette(), &I::enabledChanged,
355 itemWithPalette(), [this]() { setCurrentColorGroup(); });
356 }
357}
358
359template<class I, class Impl>
360const I *QQuickPaletteProviderPrivateBase<I, Impl>::itemWithPalette() const
361{
362 static_assert(std::is_base_of<QObjectData, Impl>{},
363 "The Impl class must inherit QObjectData");
364
365 return static_cast<const I*>(static_cast<const Impl*>(this)->q_ptr);
366}
367
368template<class I, class Impl>
369I *QQuickPaletteProviderPrivateBase<I, Impl>::itemWithPalette()
370{
371 return const_cast<I*>(const_cast<const Self*>(this)->itemWithPalette());
372}
373
374template<class I, class Impl>
375QQuickPalette *QQuickPaletteProviderPrivateBase<I, Impl>::paletteData() const
376{
377 Q_ASSERT(m_palette); return m_palette.get();
378}
379
380template<class I, class Impl>
381QPalette QQuickPaletteProviderPrivateBase<I, Impl>::toQPalette() const
382{
383 return palette()->toQPalette();
384}
385
386QT_END_NAMESPACE
387
388#endif // QQUICKPALETTEPROVIDERPRIVATEBASE_H
void inheritPalette(const QPalette &parentPalette)
virtual void updateChildrenPalettes(const QPalette &parentPalette)
virtual ~QQuickPaletteProviderPrivateBase()=default
QPalette parentPalette(const QPalette &fallbackPalette) const override
const QQuickItem * rootItem(const I &item)
decltype(auto) getPrivate(T &item)
constexpr bool isRootWindow()
decltype(auto) getPrivateImpl(I &t)