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