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
qwasmwindowstack.inc
Go to the documentation of this file.
1// Copyright (C) 2025 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
3
4#ifndef QWASMWINDOWSTACK_INC
5#define QWASMWINDOWSTACK_INC
6
7template <typename Window>
8QWasmWindowStack<Window>::QWasmWindowStack(
9 WindowOrderChangedCallbackType windowOrderChangedCallback)
10 : m_windowOrderChangedCallback(std::move(windowOrderChangedCallback)),
11 m_regularWindowsBegin(m_windowStack.begin()),
12 m_alwaysOnTopWindowsBegin(m_windowStack.begin())
13{
14 invariant();
15}
16
17template <typename Window>
19{
20 invariant();
21}
22
23template <typename Window>
24void QWasmWindowStack<Window>::invariant()
25{
26 Q_ASSERT(m_regularWindowsBegin >= m_windowStack.begin());
27 Q_ASSERT(m_regularWindowsBegin <= m_alwaysOnTopWindowsBegin);
28 Q_ASSERT(m_alwaysOnTopWindowsBegin <= m_windowStack.end());
29
30#ifndef NDEBUG
31 for(auto it = begin(); it != end(); ++it)
32 {
33 Q_ASSERT(m_windowStack.count(*it) == 1);
34 }
35#endif
36}
37
38/* insert a window at the correct location.
39 *
40 * There are three groups
41 * StayOnBottom
42 * Regular
43 * StayOnTop
44 *
45 * In addition there is StayAboveParent which
46 * can place the window in either of the
47 * three above groups, depending on which
48 * group the transient parent resides in.
49 *
50 * insertAtRegionBegin controls the placement
51 * within each of the groups. Either at the end
52 * or at the beginning.
53 *
54*/
55template <typename Window>
57 bool insertAtRegionBegin, bool callCallbacks)
58{
59 invariant();
60 Q_ASSERT(m_windowStack.count(window) == 0);
61
62 auto regularDistance = std::distance(m_windowStack.begin(), m_regularWindowsBegin);
63 auto stayOnTopDistance = std::distance(m_windowStack.begin(), m_alwaysOnTopWindowsBegin);
64
65 if (position == PositionPreference::StayAboveTransientParent) {
66 Q_ASSERT(window->transientParent());
67 auto it =
68 std::find(m_windowStack.begin(), m_windowStack.end(), window->transientParent());
69 if (it == m_windowStack.end()) {
70 qWarning() << "QWasmWindowStack<Window>::pushWindow - missing parent"
71 << window->transientParent();
72 pushWindow(window, PositionPreference::Regular, insertAtRegionBegin, callCallbacks);
73 return;
74 } else {
75 if (insertAtRegionBegin) {
76 if (it >= m_alwaysOnTopWindowsBegin) {
77 ;
78 } else if (it >= m_regularWindowsBegin) {
79 ++stayOnTopDistance;
80 } else {
81 ++regularDistance;
82 ++stayOnTopDistance;
83 }
84 ++it;
85 } else {
86 if (it >= m_alwaysOnTopWindowsBegin) {
87 it = m_windowStack.end();
88 } else if (it >= m_regularWindowsBegin) {
89 it = m_alwaysOnTopWindowsBegin;
90 ++stayOnTopDistance;
91 } else {
92 it = m_regularWindowsBegin;
93 ++regularDistance;
94 ++stayOnTopDistance;
95 }
96 }
97
98 m_windowStack.insert(it, window);
99 }
100 } else if (position == PositionPreference::StayOnTop) {
101 if (insertAtRegionBegin)
102 m_windowStack.insert(m_alwaysOnTopWindowsBegin, window);
103 else
104 m_windowStack.insert(m_windowStack.end(), window);
105
106 } else if (position == PositionPreference::Regular) {
107 ++stayOnTopDistance;
108 if (insertAtRegionBegin)
109 m_windowStack.insert(m_regularWindowsBegin, window);
110 else
111 m_windowStack.insert(m_alwaysOnTopWindowsBegin, window);
112
113 } else {
114 // StayOnBottom
115 ++regularDistance;
116 ++stayOnTopDistance;
117
118 if (insertAtRegionBegin)
119 m_windowStack.insert(m_windowStack.begin(), window);
120 else
121 m_windowStack.insert(m_regularWindowsBegin, window);
122 }
123
124 m_regularWindowsBegin = m_windowStack.begin() + regularDistance;
125 m_alwaysOnTopWindowsBegin = m_windowStack.begin() + stayOnTopDistance;
126
127 if (callCallbacks)
128 m_windowOrderChangedCallback();
129
130 Q_ASSERT(m_windowStack.count(window) == 1);
131 invariant();
132}
133
134template <typename Window>
136{
137 invariant();
138 Q_ASSERT(m_windowStack.count(window) == 1);
139
140 auto regularDistance = std::distance(m_windowStack.begin(), m_regularWindowsBegin);
141 auto stayOnTopDistance = std::distance(m_windowStack.begin(), m_alwaysOnTopWindowsBegin);
142
143 auto it = std::find(m_windowStack.begin(), m_windowStack.end(), window);
144
145 Q_ASSERT(it != m_windowStack.end());
146
147 if (it < m_regularWindowsBegin)
148 --regularDistance;
149 if (it < m_alwaysOnTopWindowsBegin)
150 --stayOnTopDistance;
151
152 m_windowStack.erase(it);
153
154 m_regularWindowsBegin = m_windowStack.begin() + regularDistance;
155 m_alwaysOnTopWindowsBegin = m_windowStack.begin() + stayOnTopDistance;
156
157 if (callCallbacks)
158 m_windowOrderChangedCallback();
159
160 Q_ASSERT(m_windowStack.count(window) == 0);
161 invariant();
162}
163
164template <typename Window>
166{
167 if (raiseImpl(window))
168 m_windowOrderChangedCallback();
169}
170
171template <typename Window>
172bool QWasmWindowStack<Window>::raiseImpl(Window *window)
173{
174 invariant();
175 Q_ASSERT(m_windowStack.count(window) == 1);
176
177 {
178 const auto it = std::find(m_windowStack.begin(), m_windowStack.end(), window);
179 const auto itEnd = ([this, it]() {
180 if (it < m_regularWindowsBegin)
181 return m_regularWindowsBegin;
182 if (it < m_alwaysOnTopWindowsBegin)
183 return m_alwaysOnTopWindowsBegin;
184 return m_windowStack.end();
185 })();
186
187 if (it + 1 == itEnd)
188 return false;
189
190 std::rotate(it, it + 1, itEnd);
191 }
192
193 std::vector<Window *> windowsToRaise;
194 {
195 for (auto trit = m_windowStack.begin(); trit != m_windowStack.end(); ++trit) {
196 const auto w = *trit;
197 if ((w != window) &&
198 (getWindowPositionPreference(trit) == PositionPreference::StayAboveTransientParent) &&
199 (w->transientParent() == window)) {
200 windowsToRaise.push_back(w);
201 }
202 }
203 }
204
205 for (const auto w : windowsToRaise)
206 {
207 raiseImpl(w);
208 }
209 invariant();
210 Q_ASSERT(m_windowStack.count(window) == 1);
211 return true;
212}
213
214template <typename Window>
216{
217 if (lowerImpl(window))
218 m_windowOrderChangedCallback();
219}
220
221template <typename Window>
222bool QWasmWindowStack<Window>::lowerImpl(Window *window)
223{
224 invariant();
225 Q_ASSERT(m_windowStack.count(window) == 1);
226
227 {
228 const auto it = std::find(m_windowStack.begin(), m_windowStack.end(), window);
229 const auto itBegin = ([this, it]() {
230 if (it >= m_alwaysOnTopWindowsBegin)
231 return m_alwaysOnTopWindowsBegin;
232 if (it >= m_regularWindowsBegin)
233 return m_regularWindowsBegin;
234 return m_windowStack.begin();
235 })();
236
237 if (itBegin == it)
238 return false;
239
240 std::rotate(itBegin, it, it + 1);
241 }
242
243 std::vector<Window *> windowsToLower;
244 {
245 for (auto trit = m_windowStack.begin(); trit != m_windowStack.end(); ++trit) {
246 const auto w = *trit;
247 if ((w != window) &&
248 (getWindowPositionPreference(trit) == PositionPreference::StayAboveTransientParent) &&
249 (w->transientParent() == window)) {
250 windowsToLower.push_back(w);
251 }
252 }
253 }
254
255 for (const auto w : windowsToLower)
256 {
257 lowerImpl(w);
258 }
259 invariant();
260 Q_ASSERT(m_windowStack.count(window) == 1);
261 return true;
262}
263
264template <typename Window>
266 PositionPreference position)
267{
268 invariant();
269 Q_ASSERT(m_windowStack.count(window) == 1);
270
271 auto it = std::find(m_windowStack.begin(), m_windowStack.end(), window);
272 const auto currentPosition = getWindowPositionPreference(it);
273
274 if (position == currentPosition) {
275 ;
276 } else if (currentPosition == PositionPreference::StayAboveTransientParent) {
277 // Keep position if possible
278 const bool isStayOnBottom ( it < m_regularWindowsBegin);
279 const bool isRegular( !isStayOnBottom && (it < m_alwaysOnTopWindowsBegin));
280 const bool isStayOnTop(!isStayOnBottom && !isRegular);
281
282 if (isStayOnBottom && (position == PositionPreference::StayOnBottom))
283 ;
284 else if (isRegular && (position == PositionPreference::Regular))
285 ;
286 else if (isStayOnTop && (position == PositionPreference::StayOnTop))
287 ;
288 else {
289 auto current = *it;
290 removeWindow(current, false);
291 pushWindow(current, position, false, false);
292 m_windowOrderChangedCallback();
293 }
294 } else {
295 const bool insertAtRegionBegin = (
296 (currentPosition != PositionPreference::StayAboveTransientParent) &&
297 (position != PositionPreference::StayAboveTransientParent) &&
298 ((currentPosition == PositionPreference::StayOnBottom) ||
299 (position == PositionPreference::StayOnTop)));
300
301 auto current = *it;
302 removeWindow(current, false);
303 pushWindow(current, position, insertAtRegionBegin, false);
304 m_windowOrderChangedCallback();
305 }
306 invariant();
307 Q_ASSERT(m_windowStack.count(window) == 1);
308}
309
310template <typename Window>
312{
313 return m_windowStack.rbegin();
314}
315
316template <typename Window>
318{
319 return m_windowStack.rend();
320}
321
322template <typename Window>
324{
325 return m_windowStack.rbegin();
326}
327
328template <typename Window>
330{
331 return m_windowStack.rend();
332}
333
334template <typename Window>
337{
338 return m_windowStack.begin();
339}
340
341template <typename Window>
344{
345 return m_windowStack.end();
346}
347
348template <typename Window>
350{
351 return m_windowStack.empty();
352}
353
354template <typename Window>
356{
357 return m_windowStack.size();
358}
359
360template <typename Window>
362{
363 return m_windowStack.empty() ? nullptr : m_windowStack.last();
364}
365
366template <typename Window>
367bool QWasmWindowStack<Window>::shouldBeAboveTransientParentFlags(Qt::WindowFlags flags) const
368{
369 if (flags.testFlag(Qt::Tool) ||
370 flags.testFlag(Qt::SplashScreen) ||
371 flags.testFlag(Qt::ToolTip) ||
372 flags.testFlag(Qt::Popup))
373 {
374 return true;
375 }
376
377 return false;
378}
379
380template <typename Window>
381bool QWasmWindowStack<Window>::shouldBeAboveTransientParent(const Window *window) const
382{
383 if (!window->transientParent())
384 return false;
385
386 if (window->isModal())
387 return true;
388
389 if (shouldBeAboveTransientParentFlags(window->windowFlags()))
390 return true;
391
392 return false;
393}
394
395template <typename Window>
398 typename StorageType::const_iterator windowIt, bool testStayAbove) const
399{
400 Q_ASSERT(windowIt != m_windowStack.end());
401 Q_ASSERT(m_windowStack.contains(*windowIt));
402 Window *window = *windowIt;
403 if (testStayAbove && shouldBeAboveTransientParent(window))
404 return PositionPreference::StayAboveTransientParent;
405 if (windowIt >= m_alwaysOnTopWindowsBegin)
406 return PositionPreference::StayOnTop;
407 if (windowIt >= m_regularWindowsBegin)
408 return PositionPreference::Regular;
409 return PositionPreference::StayOnBottom;
410}
411
412#endif /* QWASMWINDOWSTACK_INC */
void removeWindow(Window *window, bool callCallbacks=true)
void windowPositionPreferenceChanged(Window *window, PositionPreference position)
typename StorageType::const_reverse_iterator const_iterator
const_reverse_iterator rbegin() const
bool empty() const
typename StorageType::const_iterator const_reverse_iterator
Window * topWindow() const
iterator end()
typename StorageType::reverse_iterator iterator
const_reverse_iterator rend() const
void lower(Window *window)
void pushWindow(Window *window, PositionPreference position, bool insertAtRegionBegin=false, bool callCallbacks=true)
size_t size() const
void raise(Window *window)
PositionPreference getWindowPositionPreference(typename StorageType::const_iterator windowIt, bool testStayAbove=true) const
iterator begin()
[Window class with invokable method]
Definition window.h:11
@ ToolTip
Definition qnamespace.h:225
@ Popup
Definition qnamespace.h:223
@ SplashScreen
Definition qnamespace.h:226
@ Tool
Definition qnamespace.h:224
self window
[2]
#define qWarning
Definition qlogging.h:171
GLfloat GLfloat GLfloat w
[0]
GLbitfield flags
GLuint GLuint end
static qreal position(const QQuickItem *item, QQuickAnchors::Anchor anchorLine)
#define Q_ASSERT(cond)
Definition qrandom.cpp:48
QtPrivate::QRegularExpressionMatchIteratorRangeBasedForIterator begin(const QRegularExpressionMatchIterator &iterator)
QJSValueIterator it(object)