summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/plugins/platforms/wasm/CMakeLists.txt1
-rw-r--r--src/plugins/platforms/wasm/qwasmcompositor.cpp120
-rw-r--r--src/plugins/platforms/wasm/qwasmcompositor.h14
-rw-r--r--src/plugins/platforms/wasm/qwasmwindowstack.cpp123
-rw-r--r--src/plugins/platforms/wasm/qwasmwindowstack.h70
-rw-r--r--tests/auto/wasm/CMakeLists.txt13
-rw-r--r--tests/auto/wasm/tst_qwasmwindowstack.cpp264
7 files changed, 536 insertions, 69 deletions
diff --git a/src/plugins/platforms/wasm/CMakeLists.txt b/src/plugins/platforms/wasm/CMakeLists.txt
index 94a26da371..557ef2f223 100644
--- a/src/plugins/platforms/wasm/CMakeLists.txt
+++ b/src/plugins/platforms/wasm/CMakeLists.txt
@@ -34,6 +34,7 @@ qt_internal_add_plugin(QWasmIntegrationPlugin
qwasmwindow.cpp qwasmwindow.h
qwasminputcontext.cpp qwasminputcontext.h
qwasmdrag.cpp qwasmdrag.h
+ qwasmwindowstack.cpp qwasmwindowstack.h
DEFINES
QT_EGL_NO_X11
QT_NO_FOREACH
diff --git a/src/plugins/platforms/wasm/qwasmcompositor.cpp b/src/plugins/platforms/wasm/qwasmcompositor.cpp
index e93098cf79..53daa62bed 100644
--- a/src/plugins/platforms/wasm/qwasmcompositor.cpp
+++ b/src/plugins/platforms/wasm/qwasmcompositor.cpp
@@ -27,7 +27,8 @@
#include <emscripten/bind.h>
namespace {
-QWasmWindow *AsWasmWindow(QWindow *window) {
+QWasmWindow *asWasmWindow(QWindow *window)
+{
return static_cast<QWasmWindow*>(window->handle());
}
} // namespace
@@ -50,10 +51,11 @@ EMSCRIPTEN_BINDINGS(qtMouseModule) {
}
QWasmCompositor::QWasmCompositor(QWasmScreen *screen)
- : QObject(screen)
- , m_windowManipulation(screen)
- , m_blitter(new QOpenGLTextureBlitter)
- , m_eventTranslator(std::make_unique<QWasmEventTranslator>())
+ : QObject(screen),
+ m_windowManipulation(screen),
+ m_windowStack(std::bind(&QWasmCompositor::onTopWindowChanged, this, std::placeholders::_1)),
+ m_blitter(new QOpenGLTextureBlitter),
+ m_eventTranslator(std::make_unique<QWasmEventTranslator>())
{
m_touchDevice = std::make_unique<QPointingDevice>(
"touchscreen", 1, QInputDevice::DeviceType::TouchScreen,
@@ -171,23 +173,14 @@ void QWasmCompositor::setEnabled(bool enabled)
void QWasmCompositor::addWindow(QWasmWindow *window)
{
m_windowVisibility.insert(window, false);
-
- m_windowStack.append(window);
-
- notifyTopWindowChanged(window);
+ m_windowStack.pushWindow(window);
}
void QWasmCompositor::removeWindow(QWasmWindow *window)
{
- m_windowStack.removeAll(window);
m_windowVisibility.remove(window);
m_requestUpdateWindows.remove(window);
-
- if (!m_windowStack.isEmpty() && !QGuiApplication::focusWindow()) {
- auto m_lastMouseTargetWindow = m_windowStack.last();
- m_lastMouseTargetWindow->requestActivateWindow();
- notifyTopWindowChanged(m_lastMouseTargetWindow);
- }
+ m_windowStack.removeWindow(window);
}
void QWasmCompositor::setVisible(QWasmWindow *window, bool visible)
@@ -205,47 +198,36 @@ void QWasmCompositor::setVisible(QWasmWindow *window, bool visible)
void QWasmCompositor::raise(QWasmWindow *window)
{
- if (m_windowStack.size() <= 1)
- return;
-
- m_windowStack.removeAll(window);
- m_windowStack.append(window);
-
- notifyTopWindowChanged(window);
+ m_windowStack.raise(window);
}
void QWasmCompositor::lower(QWasmWindow *window)
{
- if (m_windowStack.size() <= 1)
- return;
-
- m_windowStack.removeAll(window);
- m_windowStack.prepend(window);
m_globalDamage = window->window()->geometry(); // repaint previously covered area.
-
- notifyTopWindowChanged(window);
+ m_windowStack.lower(window);
}
int QWasmCompositor::windowCount() const
{
- return m_windowStack.count();
+ return m_windowStack.size();
}
QWindow *QWasmCompositor::windowAt(QPoint targetPointInScreenCoords, int padding) const
{
- const auto found = std::find_if(m_windowStack.rbegin(), m_windowStack.rend(),
- [this, padding, &targetPointInScreenCoords](const QWasmWindow* window) {
- const QRect geometry = window->windowFrameGeometry()
- .adjusted(-padding, -padding, padding, padding);
-
- return m_windowVisibility[window] && geometry.contains(targetPointInScreenCoords);
- });
- return found != m_windowStack.rend() ? (*found)->window() : nullptr;
+ const auto found = std::find_if(
+ m_windowStack.begin(), m_windowStack.end(),
+ [this, padding, &targetPointInScreenCoords](const QWasmWindow *window) {
+ const QRect geometry = window->windowFrameGeometry().adjusted(-padding, -padding,
+ padding, padding);
+
+ return m_windowVisibility[window] && geometry.contains(targetPointInScreenCoords);
+ });
+ return found != m_windowStack.end() ? (*found)->window() : nullptr;
}
QWindow *QWasmCompositor::keyWindow() const
{
- return m_windowStack.at(m_windowStack.count() - 1)->window();
+ return m_windowStack.topWindow() ? m_windowStack.topWindow()->window() : nullptr;
}
void QWasmCompositor::blit(QOpenGLTextureBlitter *blitter, QWasmScreen *screen, const QOpenGLTexture *texture, QRect targetGeometry)
@@ -267,7 +249,8 @@ void QWasmCompositor::blit(QOpenGLTextureBlitter *blitter, QWasmScreen *screen,
blitter->blit(texture->textureId(), m, QOpenGLTextureBlitter::OriginTopLeft);
}
-void QWasmCompositor::drawWindowContent(QOpenGLTextureBlitter *blitter, QWasmScreen *screen, QWasmWindow *window)
+void QWasmCompositor::drawWindowContent(QOpenGLTextureBlitter *blitter, QWasmScreen *screen,
+ const QWasmWindow *window)
{
QWasmBackingStore *backingStore = window->backingStore();
if (!backingStore)
@@ -498,7 +481,8 @@ QWasmCompositor::QWasmTitleBarOptions QWasmCompositor::makeTitleBarOptions(const
return titleBarOptions;
}
-void QWasmCompositor::drawWindowDecorations(QOpenGLTextureBlitter *blitter, QWasmScreen *screen, QWasmWindow *window)
+void QWasmCompositor::drawWindowDecorations(QOpenGLTextureBlitter *blitter, QWasmScreen *screen,
+ const QWasmWindow *window)
{
int width = window->windowFrameGeometry().width();
int height = window->windowFrameGeometry().height();
@@ -753,7 +737,8 @@ void QWasmCompositor::drawShadePanel(QWasmTitleBarOptions options, QPainter *pai
}
-void QWasmCompositor::drawWindow(QOpenGLTextureBlitter *blitter, QWasmScreen *screen, QWasmWindow *window)
+void QWasmCompositor::drawWindow(QOpenGLTextureBlitter *blitter, QWasmScreen *screen,
+ const QWasmWindow *window)
{
if (window->window()->type() != Qt::Popup && !(window->m_windowState & Qt::WindowFullScreen))
drawWindowDecorations(blitter, screen, window);
@@ -767,9 +752,9 @@ void QWasmCompositor::frame()
QWasmWindow *someWindow = nullptr;
- for (QWasmWindow *window : qAsConst(m_windowStack)) {
+ for (QWasmWindow *window : m_windowStack) {
if (window->window()->surfaceClass() == QSurface::Window
- && qt_window_private(static_cast<QWindow *>(window->window()))->receivedExpose) {
+ && qt_window_private(window->window())->receivedExpose) {
someWindow = window;
break;
}
@@ -801,10 +786,10 @@ void QWasmCompositor::frame()
m_blitter->bind();
m_blitter->setRedBlueSwizzle(true);
- for (QWasmWindow *window : qAsConst(m_windowStack)) {
+ std::for_each(m_windowStack.rbegin(), m_windowStack.rend(), [this](const QWasmWindow *window) {
if (m_windowVisibility[window])
drawWindow(m_blitter.data(), screen(), window);
- }
+ });
m_blitter->release();
@@ -835,14 +820,18 @@ void QWasmCompositor::WindowManipulation::resizeWindow(const QPoint& amount)
));
}
-void QWasmCompositor::notifyTopWindowChanged(QWasmWindow *window)
+void QWasmCompositor::onTopWindowChanged(QWasmWindow *window)
{
+ if (!QGuiApplication::focusWindow())
+ window->requestActivateWindow();
+
QWindow *modalWindow;
- bool isTargetWindowBlocked = QGuiApplicationPrivate::instance()->isWindowBlocked(window->window(), &modalWindow);
+ const bool isTargetWindowBlocked =
+ QGuiApplicationPrivate::instance()->isWindowBlocked(window->window(), &modalWindow);
if (isTargetWindowBlocked) {
modalWindow->requestActivate();
- raise(AsWasmWindow(modalWindow));
+ raise(asWasmWindow(modalWindow));
return;
}
@@ -913,7 +902,7 @@ bool QWasmCompositor::processPointer(const PointerEvent& event)
m_windowUnderMouse = targetWindow;
}
- QWasmWindow *wasmTargetWindow = AsWasmWindow(targetWindow);
+ QWasmWindow *wasmTargetWindow = asWasmWindow(targetWindow);
Qt::WindowStates windowState = targetWindow->windowState();
const bool isTargetWindowResizable = !windowState.testFlag(Qt::WindowMaximized) && !windowState.testFlag(Qt::WindowFullScreen);
@@ -936,7 +925,9 @@ bool QWasmCompositor::processPointer(const PointerEvent& event)
if (m_pressedWindow) {
// Always deliver the released event to the same window that was pressed
- AsWasmWindow(m_pressedWindow)->injectMouseReleased(pointInTargetWindowCoords, targetPointInScreenCoords, event.mouseButton, event.modifiers);
+ asWasmWindow(m_pressedWindow)
+ ->injectMouseReleased(pointInTargetWindowCoords, targetPointInScreenCoords,
+ event.mouseButton, event.modifiers);
if (event.mouseButton == Qt::MouseButton::LeftButton)
m_pressedWindow = nullptr;
} else {
@@ -1064,20 +1055,21 @@ void QWasmCompositor::WindowManipulation::onPointerDown(
const auto pointInScreenCoords = m_screen->geometry().topLeft() + event.point;
std::unique_ptr<std::variant<ResizeState, MoveState>> operationSpecific;
- if (AsWasmWindow(windowAtPoint)->isPointOnTitle(pointInScreenCoords)) {
+ if (asWasmWindow(windowAtPoint)->isPointOnTitle(pointInScreenCoords)) {
operationSpecific = std::make_unique<std::variant<ResizeState, MoveState>>(MoveState {
.m_lastPointInScreenCoords = pointInScreenCoords
});
- } else if (AsWasmWindow(windowAtPoint)->isPointOnResizeRegion(pointInScreenCoords)) {
- operationSpecific = std::make_unique<std::variant<ResizeState, MoveState>>(ResizeState {
- .m_resizeMode = AsWasmWindow(windowAtPoint)->resizeModeAtPoint(pointInScreenCoords),
- .m_originInScreenCoords = pointInScreenCoords,
- .m_initialWindowBounds = windowAtPoint->geometry(),
- .m_minShrink = QPoint(windowAtPoint->minimumWidth() - windowAtPoint->geometry().width(),
- windowAtPoint->minimumHeight() - windowAtPoint->geometry().height()),
- .m_maxGrow = QPoint(
- windowAtPoint->maximumWidth() - windowAtPoint->geometry().width(),
- windowAtPoint->maximumHeight() - windowAtPoint->geometry().height()),
+ } else if (asWasmWindow(windowAtPoint)->isPointOnResizeRegion(pointInScreenCoords)) {
+ operationSpecific = std::make_unique<std::variant<ResizeState, MoveState>>(ResizeState{
+ .m_resizeMode = asWasmWindow(windowAtPoint)->resizeModeAtPoint(pointInScreenCoords),
+ .m_originInScreenCoords = pointInScreenCoords,
+ .m_initialWindowBounds = windowAtPoint->geometry(),
+ .m_minShrink =
+ QPoint(windowAtPoint->minimumWidth() - windowAtPoint->geometry().width(),
+ windowAtPoint->minimumHeight() - windowAtPoint->geometry().height()),
+ .m_maxGrow =
+ QPoint(windowAtPoint->maximumWidth() - windowAtPoint->geometry().width(),
+ windowAtPoint->maximumHeight() - windowAtPoint->geometry().height()),
});
} else {
return;
@@ -1204,7 +1196,7 @@ int QWasmCompositor::handleTouch(int eventType, const EmscriptenTouchEvent *touc
{
QList<QWindowSystemInterface::TouchPoint> touchPointList;
touchPointList.reserve(touchEvent->numTouches);
- QWindow *targetWindow;
+ QWindow *targetWindow = nullptr;
for (int i = 0; i < touchEvent->numTouches; i++) {
diff --git a/src/plugins/platforms/wasm/qwasmcompositor.h b/src/plugins/platforms/wasm/qwasmcompositor.h
index c883fc310d..b2e526c9ff 100644
--- a/src/plugins/platforms/wasm/qwasmcompositor.h
+++ b/src/plugins/platforms/wasm/qwasmcompositor.h
@@ -4,6 +4,8 @@
#ifndef QWASMCOMPOSITOR_H
#define QWASMCOMPOSITOR_H
+#include "qwasmwindowstack.h"
+
#include <QtGui/qregion.h>
#include <qpa/qplatformwindow.h>
@@ -174,12 +176,14 @@ private:
std::unique_ptr<OperationState> m_state;
};
- void notifyTopWindowChanged(QWasmWindow *window);
- void drawWindow(QOpenGLTextureBlitter *blitter, QWasmScreen *screen, QWasmWindow *window);
- void drawWindowContent(QOpenGLTextureBlitter *blitter, QWasmScreen *screen, QWasmWindow *window);
+ void onTopWindowChanged(QWasmWindow *window);
+ void drawWindow(QOpenGLTextureBlitter *blitter, QWasmScreen *screen, const QWasmWindow *window);
+ void drawWindowContent(QOpenGLTextureBlitter *blitter, QWasmScreen *screen,
+ const QWasmWindow *window);
void blit(QOpenGLTextureBlitter *blitter, QWasmScreen *screen, const QOpenGLTexture *texture, QRect targetGeometry);
- void drawWindowDecorations(QOpenGLTextureBlitter *blitter, QWasmScreen *screen, QWasmWindow *window);
+ void drawWindowDecorations(QOpenGLTextureBlitter *blitter, QWasmScreen *screen,
+ const QWasmWindow *window);
static QPalette makeWindowPalette();
@@ -199,12 +203,12 @@ private:
static int touchCallback(int eventType, const EmscriptenTouchEvent *ev, void *userData);
WindowManipulation m_windowManipulation;
+ QWasmWasmWindowStack m_windowStack;
QScopedPointer<QOpenGLContext> m_context;
QScopedPointer<QOpenGLTextureBlitter> m_blitter;
QHash<const QWasmWindow *, bool> m_windowVisibility;
- QList<QWasmWindow *> m_windowStack;
QRegion m_globalDamage; // damage caused by expose, window close, etc.
bool m_needComposit = false;
bool m_inFlush = false;
diff --git a/src/plugins/platforms/wasm/qwasmwindowstack.cpp b/src/plugins/platforms/wasm/qwasmwindowstack.cpp
new file mode 100644
index 0000000000..9ce6689c8d
--- /dev/null
+++ b/src/plugins/platforms/wasm/qwasmwindowstack.cpp
@@ -0,0 +1,123 @@
+// Copyright (C) 2022 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+
+#include "qwasmwindowstack.h"
+
+QT_BEGIN_NAMESPACE
+
+QWasmWasmWindowStack::QWasmWasmWindowStack(TopWindowChangedCallbackType topWindowChangedCallback)
+ : m_topWindowChangedCallback(std::move(topWindowChangedCallback))
+{
+}
+
+QWasmWasmWindowStack::~QWasmWasmWindowStack() = default;
+
+void QWasmWasmWindowStack::pushWindow(QWasmWindow *window)
+{
+ Q_ASSERT(m_windowStack.count(window) == 0);
+
+ m_windowStack.push_back(window);
+
+ m_topWindowChangedCallback(window);
+}
+
+void QWasmWasmWindowStack::removeWindow(QWasmWindow *window)
+{
+ Q_ASSERT(m_windowStack.count(window) == 1);
+
+ auto it = std::find(m_windowStack.begin(), m_windowStack.end(), window);
+ const bool removingBottom = m_windowStack.begin() == it;
+ const bool removingTop = m_windowStack.end() - 1 == it;
+ if (removingBottom)
+ m_firstWindowTreatment = FirstWindowTreatment::Regular;
+
+ m_windowStack.erase(it);
+
+ if (removingTop)
+ m_topWindowChangedCallback(topWindow());
+}
+
+void QWasmWasmWindowStack::raise(QWasmWindow *window)
+{
+ Q_ASSERT(m_windowStack.count(window) == 1);
+
+ if (window == rootWindow() || window == topWindow())
+ return;
+
+ auto it = std::find(regularWindowsBegin(), m_windowStack.end(), window);
+ std::rotate(it, it + 1, m_windowStack.end());
+ m_topWindowChangedCallback(topWindow());
+}
+
+void QWasmWasmWindowStack::lower(QWasmWindow *window)
+{
+ Q_ASSERT(m_windowStack.count(window) == 1);
+
+ if (window == rootWindow())
+ return;
+
+ const bool loweringTopWindow = topWindow() == window;
+ auto it = std::find(regularWindowsBegin(), m_windowStack.end(), window);
+ std::rotate(regularWindowsBegin(), it, it + 1);
+ if (loweringTopWindow && topWindow() != window)
+ m_topWindowChangedCallback(topWindow());
+}
+
+QWasmWasmWindowStack::iterator QWasmWasmWindowStack::begin()
+{
+ return m_windowStack.rbegin();
+}
+
+QWasmWasmWindowStack::iterator QWasmWasmWindowStack::end()
+{
+ return m_windowStack.rend();
+}
+
+QWasmWasmWindowStack::const_iterator QWasmWasmWindowStack::begin() const
+{
+ return m_windowStack.rbegin();
+}
+
+QWasmWasmWindowStack::const_iterator QWasmWasmWindowStack::end() const
+{
+ return m_windowStack.rend();
+}
+
+QWasmWasmWindowStack::const_reverse_iterator QWasmWasmWindowStack::rbegin() const
+{
+ return m_windowStack.begin();
+}
+
+QWasmWasmWindowStack::const_reverse_iterator QWasmWasmWindowStack::rend() const
+{
+ return m_windowStack.end();
+}
+
+bool QWasmWasmWindowStack::empty() const
+{
+ return m_windowStack.empty();
+}
+
+size_t QWasmWasmWindowStack::size() const
+{
+ return m_windowStack.size();
+}
+
+QWasmWindow *QWasmWasmWindowStack::rootWindow() const
+{
+ return m_firstWindowTreatment == FirstWindowTreatment::AlwaysAtBottom ? m_windowStack.first()
+ : nullptr;
+}
+
+QWasmWindow *QWasmWasmWindowStack::topWindow() const
+{
+ return m_windowStack.last();
+}
+
+QWasmWasmWindowStack::StorageType::iterator QWasmWasmWindowStack::regularWindowsBegin()
+{
+ return m_windowStack.begin()
+ + (m_firstWindowTreatment == FirstWindowTreatment::AlwaysAtBottom ? 1 : 0);
+}
+
+QT_END_NAMESPACE
diff --git a/src/plugins/platforms/wasm/qwasmwindowstack.h b/src/plugins/platforms/wasm/qwasmwindowstack.h
new file mode 100644
index 0000000000..68ce4a51b7
--- /dev/null
+++ b/src/plugins/platforms/wasm/qwasmwindowstack.h
@@ -0,0 +1,70 @@
+// Copyright (C) 2022 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
+
+#ifndef QWASMWINDOWSTACK_H
+#define QWASMWINDOWSTACK_H
+
+#include <qglobal.h>
+#include <QtCore/qlist.h>
+
+#include <vector>
+
+QT_BEGIN_NAMESPACE
+
+class QWasmWindow;
+
+// Maintains a z-order hierarchy for a set of windows. The first added window is always treated as
+// the 'root', which always stays at the bottom. Other windows are 'regular', which means they are
+// subject to z-order changes via |raise| and |lower|/
+// If the root is ever removed, all of the current and future windows in the stack are treated as
+// regular.
+// Access to the top element is facilitated by |topWindow|.
+// Changes to the top element are signaled via the |topWindowChangedCallback| supplied at
+// construction.
+Q_AUTOTEST_EXPORT class QWasmWasmWindowStack
+{
+public:
+ using TopWindowChangedCallbackType = std::function<void(QWasmWindow *window)>;
+
+ using StorageType = QList<QWasmWindow *>;
+
+ using iterator = StorageType::reverse_iterator;
+ using const_iterator = StorageType::const_reverse_iterator;
+ using const_reverse_iterator = StorageType::const_iterator;
+
+ explicit QWasmWasmWindowStack(TopWindowChangedCallbackType topWindowChangedCallback);
+ ~QWasmWasmWindowStack();
+
+ void pushWindow(QWasmWindow *window);
+ void removeWindow(QWasmWindow *window);
+ void raise(QWasmWindow *window);
+ void lower(QWasmWindow *window);
+
+ // Iterates top-to-bottom
+ iterator begin();
+ iterator end();
+ const_iterator begin() const;
+ const_iterator end() const;
+
+ // Iterates bottom-to-top
+ const_reverse_iterator rbegin() const;
+ const_reverse_iterator rend() const;
+
+ bool empty() const;
+ size_t size() const;
+ QWasmWindow *topWindow() const;
+
+private:
+ enum class FirstWindowTreatment { AlwaysAtBottom, Regular };
+
+ QWasmWindow *rootWindow() const;
+ StorageType::iterator regularWindowsBegin();
+
+ TopWindowChangedCallbackType m_topWindowChangedCallback;
+ QList<QWasmWindow *> m_windowStack;
+ FirstWindowTreatment m_firstWindowTreatment = FirstWindowTreatment::AlwaysAtBottom;
+};
+
+QT_END_NAMESPACE
+
+#endif // QWASMWINDOWSTACK_H
diff --git a/tests/auto/wasm/CMakeLists.txt b/tests/auto/wasm/CMakeLists.txt
index a53dfcb4c0..ecf8546aa7 100644
--- a/tests/auto/wasm/CMakeLists.txt
+++ b/tests/auto/wasm/CMakeLists.txt
@@ -17,3 +17,16 @@ qt_internal_add_test(tst_localfileapi
Qt::Gui
Qt::Widgets
)
+
+qt_internal_add_test(tst_qwasmwindowstack
+ SOURCES
+ tst_qwasmwindowstack.cpp
+ DEFINES
+ QT_NO_FOREACH
+ LIBRARIES
+ Qt::GuiPrivate
+ PUBLIC_LIBRARIES
+ Qt::Core
+ Qt::Gui
+ Qt::Widgets
+)
diff --git a/tests/auto/wasm/tst_qwasmwindowstack.cpp b/tests/auto/wasm/tst_qwasmwindowstack.cpp
new file mode 100644
index 0000000000..3c1165353c
--- /dev/null
+++ b/tests/auto/wasm/tst_qwasmwindowstack.cpp
@@ -0,0 +1,264 @@
+// Copyright (C) 2022 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#include "../../../src/plugins/platforms/wasm/qwasmwindowstack.h"
+#include <QtGui/QWindow>
+#include <QTest>
+#include <emscripten/val.h>
+
+class QWasmWindow
+{
+};
+
+namespace {
+std::vector<QWasmWindow *> getWindowsFrontToBack(const QWasmWasmWindowStack *stack)
+{
+ return std::vector<QWasmWindow *>(stack->begin(), stack->end());
+}
+}
+
+class tst_QWasmWindowStack : public QObject
+{
+ Q_OBJECT
+
+public:
+ tst_QWasmWindowStack()
+ : m_mockCallback(
+ std::bind(&tst_QWasmWindowStack::onTopWindowChanged, this, std::placeholders::_1))
+ {
+ }
+
+private slots:
+ void init();
+
+ void insertion();
+ void raisingTheRootIsImpossible();
+ void raising();
+ void lowering();
+ void removing();
+ void removingTheRoot();
+
+private:
+ void onTopWindowChanged(QWasmWindow *topWindow)
+ {
+ ++m_topLevelChangedCallCount;
+ if (m_onTopLevelChangedAction)
+ m_onTopLevelChangedAction(topWindow);
+ }
+
+ void verifyTopWindowChangedCalled(int expected = 1)
+ {
+ QCOMPARE(expected, m_topLevelChangedCallCount);
+ clearCallbackCounter();
+ }
+
+ void clearCallbackCounter() { m_topLevelChangedCallCount = 0; }
+
+ QWasmWasmWindowStack::TopWindowChangedCallbackType m_mockCallback;
+ QWasmWasmWindowStack::TopWindowChangedCallbackType m_onTopLevelChangedAction;
+ int m_topLevelChangedCallCount = 0;
+
+ QWasmWindow m_root;
+ QWasmWindow m_window1;
+ QWasmWindow m_window2;
+ QWasmWindow m_window3;
+ QWasmWindow m_window4;
+ QWasmWindow m_window5;
+};
+
+void tst_QWasmWindowStack::init()
+{
+ m_onTopLevelChangedAction = QWasmWasmWindowStack::TopWindowChangedCallbackType();
+ clearCallbackCounter();
+}
+
+void tst_QWasmWindowStack::insertion()
+{
+ QWasmWasmWindowStack stack(m_mockCallback);
+
+ m_onTopLevelChangedAction = [this](QWasmWindow *topWindow) { QVERIFY(topWindow == &m_root); };
+ stack.pushWindow(&m_root);
+ verifyTopWindowChangedCalled();
+
+ m_onTopLevelChangedAction = [this](QWasmWindow *topWindow) {
+ QVERIFY(topWindow == &m_window1);
+ };
+ stack.pushWindow(&m_window1);
+ verifyTopWindowChangedCalled();
+
+ m_onTopLevelChangedAction = [this](QWasmWindow *topWindow) {
+ QVERIFY(topWindow == &m_window2);
+ };
+ stack.pushWindow(&m_window2);
+ verifyTopWindowChangedCalled();
+}
+
+void tst_QWasmWindowStack::raisingTheRootIsImpossible()
+{
+ QWasmWasmWindowStack stack(m_mockCallback);
+
+ stack.pushWindow(&m_root);
+ stack.pushWindow(&m_window1);
+ stack.pushWindow(&m_window2);
+ stack.pushWindow(&m_window3);
+ stack.pushWindow(&m_window4);
+ stack.pushWindow(&m_window5);
+
+ clearCallbackCounter();
+
+ stack.raise(&m_root);
+ verifyTopWindowChangedCalled(0);
+
+ QCOMPARE(&m_window5, stack.topWindow());
+
+ m_onTopLevelChangedAction = [this](QWasmWindow *topWindow) {
+ QVERIFY(topWindow == &m_window2);
+ };
+ stack.raise(&m_window2);
+ verifyTopWindowChangedCalled();
+}
+
+void tst_QWasmWindowStack::raising()
+{
+ QWasmWasmWindowStack stack(m_mockCallback);
+
+ stack.pushWindow(&m_root);
+ stack.pushWindow(&m_window1);
+ stack.pushWindow(&m_window2);
+ stack.pushWindow(&m_window3);
+ stack.pushWindow(&m_window4);
+ stack.pushWindow(&m_window5);
+
+ clearCallbackCounter();
+
+ QCOMPARE(&m_window5, stack.topWindow());
+
+ m_onTopLevelChangedAction = [this](QWasmWindow *topWindow) {
+ QVERIFY(topWindow == &m_window1);
+ };
+ stack.raise(&m_window1);
+ verifyTopWindowChangedCalled();
+ QCOMPARE(&m_window1, stack.topWindow());
+
+ stack.raise(&m_window1);
+ verifyTopWindowChangedCalled(0);
+ QCOMPARE(&m_window1, stack.topWindow());
+
+ m_onTopLevelChangedAction = [this](QWasmWindow *topWindow) {
+ QVERIFY(topWindow == &m_window3);
+ };
+ stack.raise(&m_window3);
+ verifyTopWindowChangedCalled();
+ QCOMPARE(&m_window3, stack.topWindow());
+}
+
+void tst_QWasmWindowStack::lowering()
+{
+ QWasmWasmWindowStack stack(m_mockCallback);
+
+ stack.pushWindow(&m_root);
+ stack.pushWindow(&m_window1);
+ stack.pushWindow(&m_window2);
+ stack.pushWindow(&m_window3);
+ stack.pushWindow(&m_window4);
+ stack.pushWindow(&m_window5);
+ // Window order: 5 4 3 2 1 R
+
+ clearCallbackCounter();
+
+ QCOMPARE(&m_window5, stack.topWindow());
+
+ m_onTopLevelChangedAction = [this](QWasmWindow *topWindow) {
+ QVERIFY(topWindow == &m_window4);
+ };
+ stack.lower(&m_window5);
+ // Window order: 4 3 2 1 5 R
+ verifyTopWindowChangedCalled();
+ QCOMPARE(&m_window4, stack.topWindow());
+
+ stack.lower(&m_window3);
+ // Window order: 4 2 1 5 3 R
+ verifyTopWindowChangedCalled(0);
+ std::vector<QWasmWindow *> expectedWindowOrder = { &m_window4, &m_window2, &m_window1,
+ &m_window5, &m_window3, &m_root };
+ QVERIFY(std::equal(expectedWindowOrder.begin(), expectedWindowOrder.end(),
+ getWindowsFrontToBack(&stack).begin()));
+}
+
+void tst_QWasmWindowStack::removing()
+{
+ QWasmWasmWindowStack stack(m_mockCallback);
+
+ stack.pushWindow(&m_root);
+ stack.pushWindow(&m_window1);
+ stack.pushWindow(&m_window2);
+ stack.pushWindow(&m_window3);
+ stack.pushWindow(&m_window4);
+ stack.pushWindow(&m_window5);
+ // Window order: 5 4 3 2 1 R
+
+ clearCallbackCounter();
+
+ QCOMPARE(&m_window5, stack.topWindow());
+
+ m_onTopLevelChangedAction = [this](QWasmWindow *topWindow) {
+ QVERIFY(topWindow == &m_window4);
+ };
+ stack.removeWindow(&m_window5);
+ // Window order: 4 3 2 1 R
+ verifyTopWindowChangedCalled();
+ QCOMPARE(&m_window4, stack.topWindow());
+
+ stack.removeWindow(&m_window2);
+ // Window order: 4 3 1 R
+ verifyTopWindowChangedCalled(0);
+ std::vector<QWasmWindow *> expectedWindowOrder = { &m_window4, &m_window3, &m_window1,
+ &m_root };
+ QVERIFY(std::equal(expectedWindowOrder.begin(), expectedWindowOrder.end(),
+ getWindowsFrontToBack(&stack).begin()));
+}
+
+void tst_QWasmWindowStack::removingTheRoot()
+{
+ QWasmWasmWindowStack stack(m_mockCallback);
+
+ stack.pushWindow(&m_root);
+ stack.pushWindow(&m_window1);
+ stack.pushWindow(&m_window2);
+ stack.pushWindow(&m_window3);
+ // Window order: 3 2 1 R
+
+ clearCallbackCounter();
+
+ QCOMPARE(&m_window3, stack.topWindow());
+
+ stack.removeWindow(&m_root);
+ // Window order: 3 2 1
+ verifyTopWindowChangedCalled(0);
+ QCOMPARE(&m_window3, stack.topWindow());
+
+ m_onTopLevelChangedAction = [this](QWasmWindow *topWindow) {
+ QVERIFY(topWindow == &m_window1);
+ };
+ // Check that the new bottom window is not treated specially as a root
+ stack.raise(&m_window1);
+ // Window order: 1 3 2
+ verifyTopWindowChangedCalled();
+ std::vector<QWasmWindow *> expectedWindowOrder = { &m_window1, &m_window3, &m_window2 };
+ QVERIFY(std::equal(expectedWindowOrder.begin(), expectedWindowOrder.end(),
+ getWindowsFrontToBack(&stack).begin()));
+
+ m_onTopLevelChangedAction = [this](QWasmWindow *topWindow) {
+ QVERIFY(topWindow == &m_window3);
+ };
+ // Check that the new bottom window is not treated specially as a root
+ stack.lower(&m_window1);
+ // Window order: 3 2 1
+ verifyTopWindowChangedCalled();
+ expectedWindowOrder = { &m_window3, &m_window2, &m_window1 };
+ QVERIFY(std::equal(expectedWindowOrder.begin(), expectedWindowOrder.end(),
+ getWindowsFrontToBack(&stack).begin()));
+}
+
+QTEST_MAIN(tst_QWasmWindowStack)
+#include "tst_qwasmwindowstack.moc"