diff options
-rw-r--r-- | src/plugins/platforms/wasm/CMakeLists.txt | 1 | ||||
-rw-r--r-- | src/plugins/platforms/wasm/qwasmcompositor.cpp | 120 | ||||
-rw-r--r-- | src/plugins/platforms/wasm/qwasmcompositor.h | 14 | ||||
-rw-r--r-- | src/plugins/platforms/wasm/qwasmwindowstack.cpp | 123 | ||||
-rw-r--r-- | src/plugins/platforms/wasm/qwasmwindowstack.h | 70 | ||||
-rw-r--r-- | tests/auto/wasm/CMakeLists.txt | 13 | ||||
-rw-r--r-- | tests/auto/wasm/tst_qwasmwindowstack.cpp | 264 |
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" |