wasm: Fix stacking order problem for transient parent windows
Windows with a transient parent does not reflect the relationship in the stacking order. Essentially AboveTransientParent is missing as a configuration choice. What makes this slightly convoluted is that the window stack does not depend on the window (for testability). We solve this problem by making the stack and treenode templates, and provide test class as arguments when testing. QWasmWindow and QWasmScreen are not templated as before. There is also a new order type StayAboveTransientParent. Which means that we can no longer use order type to get to the group location (Since StayAboveTransientParent can map to either of the three types). The window stack tests have been updated to handle the StayAboveTransientParent type. Finally, we do not do anything with a normal parent child relationship as this should already work correctly. Fixes: QTBUG-131699 Change-Id: Ie08e18f9e0a2339175c4a09da0a831f031df71e1 Reviewed-by: Lorn Potter <lorn.potter@qt.io>
This commit is contained in:
parent
3ad9d5777f
commit
e48c19449e
@ -32,7 +32,7 @@ qt_internal_add_plugin(QWasmIntegrationPlugin
|
|||||||
qwasmwindowtreenode.cpp qwasmwindowtreenode.h
|
qwasmwindowtreenode.cpp qwasmwindowtreenode.h
|
||||||
qwasmwindownonclientarea.cpp qwasmwindownonclientarea.h
|
qwasmwindownonclientarea.cpp qwasmwindownonclientarea.h
|
||||||
qwasminputcontext.cpp qwasminputcontext.h
|
qwasminputcontext.cpp qwasminputcontext.h
|
||||||
qwasmwindowstack.cpp qwasmwindowstack.h
|
qwasmwindowstack.h
|
||||||
DEFINES
|
DEFINES
|
||||||
QT_EGL_NO_X11
|
QT_EGL_NO_X11
|
||||||
QT_NO_FOREACH
|
QT_NO_FOREACH
|
||||||
|
@ -325,7 +325,7 @@ emscripten::val QWasmScreen::containerElement()
|
|||||||
return m_shadowContainer;
|
return m_shadowContainer;
|
||||||
}
|
}
|
||||||
|
|
||||||
QWasmWindowTreeNode *QWasmScreen::parentNode()
|
QWasmWindowTreeNode<> *QWasmScreen::parentNode()
|
||||||
{
|
{
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
@ -25,7 +25,7 @@ class QWasmCompositor;
|
|||||||
class QWasmDeadKeySupport;
|
class QWasmDeadKeySupport;
|
||||||
class QOpenGLContext;
|
class QOpenGLContext;
|
||||||
|
|
||||||
class QWasmScreen : public QObject, public QPlatformScreen, public QWasmWindowTreeNode
|
class QWasmScreen : public QObject, public QPlatformScreen, public QWasmWindowTreeNode<>
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
public:
|
public:
|
||||||
|
@ -37,17 +37,6 @@
|
|||||||
|
|
||||||
QT_BEGIN_NAMESPACE
|
QT_BEGIN_NAMESPACE
|
||||||
|
|
||||||
namespace {
|
|
||||||
QWasmWindowStack::PositionPreference positionPreferenceFromWindowFlags(Qt::WindowFlags flags)
|
|
||||||
{
|
|
||||||
if (flags.testFlag(Qt::WindowStaysOnTopHint))
|
|
||||||
return QWasmWindowStack::PositionPreference::StayOnTop;
|
|
||||||
if (flags.testFlag(Qt::WindowStaysOnBottomHint))
|
|
||||||
return QWasmWindowStack::PositionPreference::StayOnBottom;
|
|
||||||
return QWasmWindowStack::PositionPreference::Regular;
|
|
||||||
}
|
|
||||||
} // namespace
|
|
||||||
|
|
||||||
Q_GUI_EXPORT int qt_defaultDpiX();
|
Q_GUI_EXPORT int qt_defaultDpiX();
|
||||||
|
|
||||||
QWasmWindow::QWasmWindow(QWindow *w, QWasmDeadKeySupport *deadKeySupport,
|
QWasmWindow::QWasmWindow(QWindow *w, QWasmDeadKeySupport *deadKeySupport,
|
||||||
@ -132,6 +121,16 @@ QWasmWindow::QWasmWindow(QWindow *w, QWasmDeadKeySupport *deadKeySupport,
|
|||||||
|
|
||||||
registerEventHandlers();
|
registerEventHandlers();
|
||||||
|
|
||||||
|
m_transientWindowChangedConnection =
|
||||||
|
QObject::connect(
|
||||||
|
window(), &QWindow::transientParentChanged,
|
||||||
|
window(), [this](QWindow *tp) { onTransientParentChanged(tp); });
|
||||||
|
|
||||||
|
m_modalityChangedConnection =
|
||||||
|
QObject::connect(
|
||||||
|
window(), &QWindow::modalityChanged,
|
||||||
|
window(), [this](Qt::WindowModality) { onModalityChanged(); });
|
||||||
|
|
||||||
setParent(parent());
|
setParent(parent());
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -214,6 +213,9 @@ QWasmWindow::~QWasmWindow()
|
|||||||
#if QT_CONFIG(accessibility)
|
#if QT_CONFIG(accessibility)
|
||||||
QWasmAccessibility::onRemoveWindow(window());
|
QWasmAccessibility::onRemoveWindow(window());
|
||||||
#endif
|
#endif
|
||||||
|
QObject::disconnect(m_transientWindowChangedConnection);
|
||||||
|
QObject::disconnect(m_modalityChangedConnection);
|
||||||
|
|
||||||
shutdown();
|
shutdown();
|
||||||
|
|
||||||
emscripten::val::module_property("specialHTMLTargets").delete_(canvasSelector());
|
emscripten::val::module_property("specialHTMLTargets").delete_(canvasSelector());
|
||||||
@ -225,6 +227,37 @@ QWasmWindow::~QWasmWindow()
|
|||||||
emscripten_cancel_animation_frame(m_requestAnimationFrameId);
|
emscripten_cancel_animation_frame(m_requestAnimationFrameId);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void QWasmWindow::shutdown()
|
||||||
|
{
|
||||||
|
if (!window() ||
|
||||||
|
(QGuiApplication::focusWindow() && // Don't act if we have a focus window different from this
|
||||||
|
QGuiApplication::focusWindow() != window()))
|
||||||
|
return;
|
||||||
|
|
||||||
|
// Make a list of all windows sorted on active index.
|
||||||
|
// Skip windows with active index 0 as they have
|
||||||
|
// never been active.
|
||||||
|
std::map<uint64_t, QWasmWindow *> allWindows;
|
||||||
|
for (const auto &w : platformScreen()->allWindows()) {
|
||||||
|
if (w->getActiveIndex() > 0)
|
||||||
|
allWindows.insert({w->getActiveIndex(), w});
|
||||||
|
}
|
||||||
|
|
||||||
|
// window is not in all windows
|
||||||
|
if (getActiveIndex() > 0)
|
||||||
|
allWindows.insert({getActiveIndex(), this});
|
||||||
|
|
||||||
|
if (allWindows.size() >= 2) {
|
||||||
|
const auto lastIt = std::prev(allWindows.end());
|
||||||
|
const auto prevIt = std::prev(lastIt);
|
||||||
|
const auto lastW = lastIt->second;
|
||||||
|
const auto prevW = prevIt->second;
|
||||||
|
|
||||||
|
if (lastW == this) // Only act if window is last to be active
|
||||||
|
prevW->requestActivateWindow();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
QSurfaceFormat QWasmWindow::format() const
|
QSurfaceFormat QWasmWindow::format() const
|
||||||
{
|
{
|
||||||
return window()->requestedFormat();
|
return window()->requestedFormat();
|
||||||
@ -237,6 +270,24 @@ QWasmWindow *QWasmWindow::fromWindow(const QWindow *window)
|
|||||||
return static_cast<QWasmWindow *>(window->handle());
|
return static_cast<QWasmWindow *>(window->handle());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QWasmWindow *QWasmWindow::transientParent() const
|
||||||
|
{
|
||||||
|
if (!window())
|
||||||
|
return nullptr;
|
||||||
|
|
||||||
|
return fromWindow(window()->transientParent());
|
||||||
|
}
|
||||||
|
|
||||||
|
Qt::WindowFlags QWasmWindow::windowFlags() const
|
||||||
|
{
|
||||||
|
return window()->flags();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool QWasmWindow::isModal() const
|
||||||
|
{
|
||||||
|
return window()->isModal();
|
||||||
|
}
|
||||||
|
|
||||||
void QWasmWindow::onRestoreClicked()
|
void QWasmWindow::onRestoreClicked()
|
||||||
{
|
{
|
||||||
window()->setWindowState(Qt::WindowNoState);
|
window()->setWindowState(Qt::WindowNoState);
|
||||||
@ -471,30 +522,14 @@ void QWasmWindow::onActivationChanged(bool active)
|
|||||||
dom::syncCSSClassWith(m_decoratedWindow, "inactive", !active);
|
dom::syncCSSClassWith(m_decoratedWindow, "inactive", !active);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Fix top level window flags in case only the type flags are passed.
|
|
||||||
static inline Qt::WindowFlags fixTopLevelWindowFlags(Qt::WindowFlags flags)
|
|
||||||
{
|
|
||||||
if (!(flags.testFlag(Qt::CustomizeWindowHint))) {
|
|
||||||
if (flags.testFlag(Qt::Window)) {
|
|
||||||
flags |= Qt::WindowTitleHint | Qt::WindowSystemMenuHint
|
|
||||||
|Qt::WindowMaximizeButtonHint|Qt::WindowCloseButtonHint;
|
|
||||||
}
|
|
||||||
if (flags.testFlag(Qt::Dialog) || flags.testFlag(Qt::Tool))
|
|
||||||
flags |= Qt::WindowTitleHint | Qt::WindowSystemMenuHint | Qt::WindowCloseButtonHint;
|
|
||||||
|
|
||||||
if ((flags & Qt::WindowType_Mask) == Qt::SplashScreen)
|
|
||||||
flags |= Qt::FramelessWindowHint;
|
|
||||||
}
|
|
||||||
return flags;
|
|
||||||
}
|
|
||||||
|
|
||||||
void QWasmWindow::setWindowFlags(Qt::WindowFlags flags)
|
void QWasmWindow::setWindowFlags(Qt::WindowFlags flags)
|
||||||
{
|
{
|
||||||
flags = fixTopLevelWindowFlags(flags);
|
flags = fixTopLevelWindowFlags(flags);
|
||||||
|
|
||||||
if (flags.testFlag(Qt::WindowStaysOnTopHint) != m_flags.testFlag(Qt::WindowStaysOnTopHint)
|
if ((flags.testFlag(Qt::WindowStaysOnTopHint) != m_flags.testFlag(Qt::WindowStaysOnTopHint))
|
||||||
|| flags.testFlag(Qt::WindowStaysOnBottomHint)
|
|| (flags.testFlag(Qt::WindowStaysOnBottomHint)
|
||||||
!= m_flags.testFlag(Qt::WindowStaysOnBottomHint)) {
|
!= m_flags.testFlag(Qt::WindowStaysOnBottomHint))
|
||||||
|
|| shouldBeAboveTransientParentFlags(flags) != shouldBeAboveTransientParentFlags(m_flags)) {
|
||||||
onPositionPreferenceChanged(positionPreferenceFromWindowFlags(flags));
|
onPositionPreferenceChanged(positionPreferenceFromWindowFlags(flags));
|
||||||
}
|
}
|
||||||
m_flags = flags;
|
m_flags = flags;
|
||||||
@ -886,6 +921,55 @@ bool QWasmWindow::processWheel(const WheelEvent &event)
|
|||||||
Qt::MouseEventNotSynthesized, event.webkitDirectionInvertedFromDevice);
|
Qt::MouseEventNotSynthesized, event.webkitDirectionInvertedFromDevice);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Fix top level window flags in case only the type flags are passed.
|
||||||
|
Qt::WindowFlags QWasmWindow::fixTopLevelWindowFlags(Qt::WindowFlags flags) const
|
||||||
|
{
|
||||||
|
if (!(flags.testFlag(Qt::CustomizeWindowHint))) {
|
||||||
|
if (flags.testFlag(Qt::Window)) {
|
||||||
|
flags |= Qt::WindowTitleHint | Qt::WindowSystemMenuHint
|
||||||
|
|Qt::WindowMaximizeButtonHint|Qt::WindowCloseButtonHint;
|
||||||
|
}
|
||||||
|
if (flags.testFlag(Qt::Dialog) || flags.testFlag(Qt::Tool))
|
||||||
|
flags |= Qt::WindowTitleHint | Qt::WindowSystemMenuHint | Qt::WindowCloseButtonHint;
|
||||||
|
|
||||||
|
if ((flags & Qt::WindowType_Mask) == Qt::SplashScreen)
|
||||||
|
flags |= Qt::FramelessWindowHint;
|
||||||
|
}
|
||||||
|
return flags;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool QWasmWindow::shouldBeAboveTransientParentFlags(Qt::WindowFlags flags) const
|
||||||
|
{
|
||||||
|
if (!transientParent())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (isModal())
|
||||||
|
return true;
|
||||||
|
|
||||||
|
if (flags.testFlag(Qt::Tool) ||
|
||||||
|
flags.testFlag(Qt::SplashScreen) ||
|
||||||
|
flags.testFlag(Qt::ToolTip) ||
|
||||||
|
flags.testFlag(Qt::Popup))
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
QWasmWindowStack<>::PositionPreference QWasmWindow::positionPreferenceFromWindowFlags(Qt::WindowFlags flags) const
|
||||||
|
{
|
||||||
|
flags = fixTopLevelWindowFlags(flags);
|
||||||
|
|
||||||
|
if (flags.testFlag(Qt::WindowStaysOnTopHint))
|
||||||
|
return QWasmWindowStack<>::PositionPreference::StayOnTop;
|
||||||
|
if (flags.testFlag(Qt::WindowStaysOnBottomHint))
|
||||||
|
return QWasmWindowStack<>::PositionPreference::StayOnBottom;
|
||||||
|
if (shouldBeAboveTransientParentFlags(flags))
|
||||||
|
return QWasmWindowStack<>::PositionPreference::StayAboveTransientParent;
|
||||||
|
return QWasmWindowStack<>::PositionPreference::Regular;
|
||||||
|
}
|
||||||
|
|
||||||
QRect QWasmWindow::normalGeometry() const
|
QRect QWasmWindow::normalGeometry() const
|
||||||
{
|
{
|
||||||
return m_normalGeometry;
|
return m_normalGeometry;
|
||||||
@ -996,6 +1080,22 @@ void QWasmWindow::setMask(const QRegion ®ion)
|
|||||||
m_decoratedWindow["style"].set("clipPath", emscripten::val(cssClipPath.str()));
|
m_decoratedWindow["style"].set("clipPath", emscripten::val(cssClipPath.str()));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void QWasmWindow::onTransientParentChanged(QWindow *newTransientParent)
|
||||||
|
{
|
||||||
|
Q_UNUSED(newTransientParent);
|
||||||
|
|
||||||
|
const auto positionPreference = positionPreferenceFromWindowFlags(window()->flags());
|
||||||
|
QWasmWindowTreeNode::onParentChanged(parentNode(), nullptr, positionPreference);
|
||||||
|
QWasmWindowTreeNode::onParentChanged(nullptr, parentNode(), positionPreference);
|
||||||
|
}
|
||||||
|
|
||||||
|
void QWasmWindow::onModalityChanged()
|
||||||
|
{
|
||||||
|
const auto positionPreference = positionPreferenceFromWindowFlags(window()->flags());
|
||||||
|
QWasmWindowTreeNode::onParentChanged(parentNode(), nullptr, positionPreference);
|
||||||
|
QWasmWindowTreeNode::onParentChanged(nullptr, parentNode(), positionPreference);
|
||||||
|
}
|
||||||
|
|
||||||
void QWasmWindow::setParent(const QPlatformWindow *)
|
void QWasmWindow::setParent(const QPlatformWindow *)
|
||||||
{
|
{
|
||||||
// The window flags depend on whether we are a
|
// The window flags depend on whether we are a
|
||||||
@ -1015,7 +1115,7 @@ emscripten::val QWasmWindow::containerElement()
|
|||||||
return m_window;
|
return m_window;
|
||||||
}
|
}
|
||||||
|
|
||||||
QWasmWindowTreeNode *QWasmWindow::parentNode()
|
QWasmWindowTreeNode<> *QWasmWindow::parentNode()
|
||||||
{
|
{
|
||||||
if (parent())
|
if (parent())
|
||||||
return static_cast<QWasmWindow *>(parent());
|
return static_cast<QWasmWindow *>(parent());
|
||||||
@ -1028,7 +1128,7 @@ QWasmWindow *QWasmWindow::asWasmWindow()
|
|||||||
}
|
}
|
||||||
|
|
||||||
void QWasmWindow::onParentChanged(QWasmWindowTreeNode *previous, QWasmWindowTreeNode *current,
|
void QWasmWindow::onParentChanged(QWasmWindowTreeNode *previous, QWasmWindowTreeNode *current,
|
||||||
QWasmWindowStack::PositionPreference positionPreference)
|
QWasmWindowStack<>::PositionPreference positionPreference)
|
||||||
{
|
{
|
||||||
if (previous)
|
if (previous)
|
||||||
previous->containerElement().call<void>("removeChild", m_decoratedWindow);
|
previous->containerElement().call<void>("removeChild", m_decoratedWindow);
|
||||||
|
@ -37,7 +37,7 @@ struct WheelEvent;
|
|||||||
Q_DECLARE_LOGGING_CATEGORY(qLcQpaWasmInputContext)
|
Q_DECLARE_LOGGING_CATEGORY(qLcQpaWasmInputContext)
|
||||||
|
|
||||||
class QWasmWindow final : public QPlatformWindow,
|
class QWasmWindow final : public QPlatformWindow,
|
||||||
public QWasmWindowTreeNode,
|
public QWasmWindowTreeNode<>,
|
||||||
public QNativeInterface::Private::QWasmWindow
|
public QNativeInterface::Private::QWasmWindow
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
@ -46,6 +46,9 @@ public:
|
|||||||
~QWasmWindow() final;
|
~QWasmWindow() final;
|
||||||
|
|
||||||
static QWasmWindow *fromWindow(const QWindow *window);
|
static QWasmWindow *fromWindow(const QWindow *window);
|
||||||
|
QWasmWindow *transientParent() const;
|
||||||
|
Qt::WindowFlags windowFlags() const;
|
||||||
|
bool isModal() const;
|
||||||
QSurfaceFormat format() const override;
|
QSurfaceFormat format() const override;
|
||||||
|
|
||||||
void registerEventHandlers();
|
void registerEventHandlers();
|
||||||
@ -106,15 +109,23 @@ public:
|
|||||||
emscripten::val containerElement() final;
|
emscripten::val containerElement() final;
|
||||||
QWasmWindowTreeNode *parentNode() final;
|
QWasmWindowTreeNode *parentNode() final;
|
||||||
|
|
||||||
|
public slots:
|
||||||
|
void onTransientParentChanged(QWindow *newTransientParent);
|
||||||
|
void onModalityChanged();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
friend class QWasmScreen;
|
friend class QWasmScreen;
|
||||||
static constexpr auto defaultWindowSize = 160;
|
static constexpr auto defaultWindowSize = 160;
|
||||||
|
|
||||||
|
QMetaObject::Connection m_transientWindowChangedConnection;
|
||||||
|
QMetaObject::Connection m_modalityChangedConnection;
|
||||||
|
|
||||||
// QWasmWindowTreeNode:
|
// QWasmWindowTreeNode:
|
||||||
QWasmWindow *asWasmWindow() final;
|
QWasmWindow *asWasmWindow() final;
|
||||||
void onParentChanged(QWasmWindowTreeNode *previous, QWasmWindowTreeNode *current,
|
void onParentChanged(QWasmWindowTreeNode *previous, QWasmWindowTreeNode *current,
|
||||||
QWasmWindowStack::PositionPreference positionPreference) final;
|
QWasmWindowStack<>::PositionPreference positionPreference) final;
|
||||||
|
|
||||||
|
void shutdown();
|
||||||
void invalidate();
|
void invalidate();
|
||||||
bool hasFrame() const;
|
bool hasFrame() const;
|
||||||
bool hasTitleBar() const;
|
bool hasTitleBar() const;
|
||||||
@ -134,6 +145,9 @@ private:
|
|||||||
bool deliverPointerEvent(const PointerEvent &event);
|
bool deliverPointerEvent(const PointerEvent &event);
|
||||||
void handleWheelEvent(const emscripten::val &event);
|
void handleWheelEvent(const emscripten::val &event);
|
||||||
bool processWheel(const WheelEvent &event);
|
bool processWheel(const WheelEvent &event);
|
||||||
|
Qt::WindowFlags fixTopLevelWindowFlags(Qt::WindowFlags) const;
|
||||||
|
bool shouldBeAboveTransientParentFlags(Qt::WindowFlags flags) const;
|
||||||
|
QWasmWindowStack<>::PositionPreference positionPreferenceFromWindowFlags(Qt::WindowFlags) const;
|
||||||
|
|
||||||
QWasmCompositor *m_compositor = nullptr;
|
QWasmCompositor *m_compositor = nullptr;
|
||||||
QWasmBackingStore *m_backingStore = nullptr;
|
QWasmBackingStore *m_backingStore = nullptr;
|
||||||
|
@ -1,203 +0,0 @@
|
|||||||
// Copyright (C) 2022 The Qt Company Ltd.
|
|
||||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
|
|
||||||
|
|
||||||
#include "qwasmwindowstack.h"
|
|
||||||
|
|
||||||
QT_BEGIN_NAMESPACE
|
|
||||||
|
|
||||||
QWasmWindowStack::QWasmWindowStack(WindowOrderChangedCallbackType windowOrderChangedCallback)
|
|
||||||
: m_windowOrderChangedCallback(std::move(windowOrderChangedCallback)),
|
|
||||||
m_regularWindowsBegin(m_windowStack.begin()),
|
|
||||||
m_alwaysOnTopWindowsBegin(m_windowStack.begin())
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
QWasmWindowStack::~QWasmWindowStack() = default;
|
|
||||||
|
|
||||||
void QWasmWindowStack::pushWindow(QWasmWindow *window, PositionPreference position)
|
|
||||||
{
|
|
||||||
Q_ASSERT(m_windowStack.count(window) == 0);
|
|
||||||
|
|
||||||
if (position == PositionPreference::StayOnTop) {
|
|
||||||
const auto stayOnTopDistance =
|
|
||||||
std::distance(m_windowStack.begin(), m_alwaysOnTopWindowsBegin);
|
|
||||||
const auto regularDistance = std::distance(m_windowStack.begin(), m_regularWindowsBegin);
|
|
||||||
m_windowStack.push_back(window);
|
|
||||||
m_alwaysOnTopWindowsBegin = m_windowStack.begin() + stayOnTopDistance;
|
|
||||||
m_regularWindowsBegin = m_windowStack.begin() + regularDistance;
|
|
||||||
} else if (position == PositionPreference::Regular) {
|
|
||||||
const auto regularDistance = std::distance(m_windowStack.begin(), m_regularWindowsBegin);
|
|
||||||
m_alwaysOnTopWindowsBegin = m_windowStack.insert(m_alwaysOnTopWindowsBegin, window) + 1;
|
|
||||||
m_regularWindowsBegin = m_windowStack.begin() + regularDistance;
|
|
||||||
} else {
|
|
||||||
const auto stayOnTopDistance =
|
|
||||||
std::distance(m_windowStack.begin(), m_alwaysOnTopWindowsBegin);
|
|
||||||
m_regularWindowsBegin = m_windowStack.insert(m_regularWindowsBegin, window) + 1;
|
|
||||||
m_alwaysOnTopWindowsBegin = m_windowStack.begin() + stayOnTopDistance + 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
m_windowOrderChangedCallback();
|
|
||||||
}
|
|
||||||
|
|
||||||
void QWasmWindowStack::removeWindow(QWasmWindow *window)
|
|
||||||
{
|
|
||||||
Q_ASSERT(m_windowStack.count(window) == 1);
|
|
||||||
|
|
||||||
auto it = std::find(m_windowStack.begin(), m_windowStack.end(), window);
|
|
||||||
const auto position = getWindowPositionPreference(it);
|
|
||||||
const auto stayOnTopDistance = std::distance(m_windowStack.begin(), m_alwaysOnTopWindowsBegin);
|
|
||||||
const auto regularDistance = std::distance(m_windowStack.begin(), m_regularWindowsBegin);
|
|
||||||
|
|
||||||
m_windowStack.erase(it);
|
|
||||||
|
|
||||||
m_alwaysOnTopWindowsBegin = m_windowStack.begin() + stayOnTopDistance
|
|
||||||
- (position != PositionPreference::StayOnTop ? 1 : 0);
|
|
||||||
m_regularWindowsBegin = m_windowStack.begin() + regularDistance
|
|
||||||
- (position == PositionPreference::StayOnBottom ? 1 : 0);
|
|
||||||
|
|
||||||
m_windowOrderChangedCallback();
|
|
||||||
}
|
|
||||||
|
|
||||||
void QWasmWindowStack::raise(QWasmWindow *window)
|
|
||||||
{
|
|
||||||
Q_ASSERT(m_windowStack.count(window) == 1);
|
|
||||||
|
|
||||||
if (window == topWindow())
|
|
||||||
return;
|
|
||||||
|
|
||||||
auto it = std::find(m_windowStack.begin(), m_windowStack.end(), window);
|
|
||||||
auto itEnd = ([this, position = getWindowPositionPreference(it)]() {
|
|
||||||
switch (position) {
|
|
||||||
case PositionPreference::StayOnTop:
|
|
||||||
return m_windowStack.end();
|
|
||||||
case PositionPreference::Regular:
|
|
||||||
return m_alwaysOnTopWindowsBegin;
|
|
||||||
case PositionPreference::StayOnBottom:
|
|
||||||
return m_regularWindowsBegin;
|
|
||||||
}
|
|
||||||
})();
|
|
||||||
std::rotate(it, it + 1, itEnd);
|
|
||||||
m_windowOrderChangedCallback();
|
|
||||||
}
|
|
||||||
|
|
||||||
void QWasmWindowStack::lower(QWasmWindow *window)
|
|
||||||
{
|
|
||||||
Q_ASSERT(m_windowStack.count(window) == 1);
|
|
||||||
|
|
||||||
if (window == *m_windowStack.begin())
|
|
||||||
return;
|
|
||||||
|
|
||||||
auto it = std::find(m_windowStack.begin(), m_windowStack.end(), window);
|
|
||||||
auto itBegin = ([this, position = getWindowPositionPreference(it)]() {
|
|
||||||
switch (position) {
|
|
||||||
case PositionPreference::StayOnTop:
|
|
||||||
return m_alwaysOnTopWindowsBegin;
|
|
||||||
case PositionPreference::Regular:
|
|
||||||
return m_regularWindowsBegin;
|
|
||||||
case PositionPreference::StayOnBottom:
|
|
||||||
return m_windowStack.begin();
|
|
||||||
}
|
|
||||||
})();
|
|
||||||
|
|
||||||
std::rotate(itBegin, it, it + 1);
|
|
||||||
m_windowOrderChangedCallback();
|
|
||||||
}
|
|
||||||
|
|
||||||
void QWasmWindowStack::windowPositionPreferenceChanged(QWasmWindow *window,
|
|
||||||
PositionPreference position)
|
|
||||||
{
|
|
||||||
auto it = std::find(m_windowStack.begin(), m_windowStack.end(), window);
|
|
||||||
const auto currentPosition = getWindowPositionPreference(it);
|
|
||||||
|
|
||||||
const auto zones = static_cast<int>(position) - static_cast<int>(currentPosition);
|
|
||||||
Q_ASSERT(zones != 0);
|
|
||||||
|
|
||||||
if (zones < 0) {
|
|
||||||
// Perform right rotation so that the window lands on top of regular windows
|
|
||||||
const auto begin = std::make_reverse_iterator(it + 1);
|
|
||||||
const auto end = position == PositionPreference::Regular
|
|
||||||
? std::make_reverse_iterator(m_alwaysOnTopWindowsBegin)
|
|
||||||
: std::make_reverse_iterator(m_regularWindowsBegin);
|
|
||||||
std::rotate(begin, begin + 1, end);
|
|
||||||
if (zones == -2) {
|
|
||||||
++m_alwaysOnTopWindowsBegin;
|
|
||||||
++m_regularWindowsBegin;
|
|
||||||
} else if (position == PositionPreference::Regular) {
|
|
||||||
++m_alwaysOnTopWindowsBegin;
|
|
||||||
} else {
|
|
||||||
++m_regularWindowsBegin;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// Perform left rotation so that the window lands at the bottom of always on top windows
|
|
||||||
const auto begin = it;
|
|
||||||
const auto end = position == PositionPreference::Regular ? m_regularWindowsBegin
|
|
||||||
: m_alwaysOnTopWindowsBegin;
|
|
||||||
std::rotate(begin, begin + 1, end);
|
|
||||||
if (zones == 2) {
|
|
||||||
--m_alwaysOnTopWindowsBegin;
|
|
||||||
--m_regularWindowsBegin;
|
|
||||||
} else if (position == PositionPreference::Regular) {
|
|
||||||
--m_regularWindowsBegin;
|
|
||||||
} else {
|
|
||||||
--m_alwaysOnTopWindowsBegin;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
m_windowOrderChangedCallback();
|
|
||||||
}
|
|
||||||
|
|
||||||
QWasmWindowStack::iterator QWasmWindowStack::begin()
|
|
||||||
{
|
|
||||||
return m_windowStack.rbegin();
|
|
||||||
}
|
|
||||||
|
|
||||||
QWasmWindowStack::iterator QWasmWindowStack::end()
|
|
||||||
{
|
|
||||||
return m_windowStack.rend();
|
|
||||||
}
|
|
||||||
|
|
||||||
QWasmWindowStack::const_iterator QWasmWindowStack::begin() const
|
|
||||||
{
|
|
||||||
return m_windowStack.rbegin();
|
|
||||||
}
|
|
||||||
|
|
||||||
QWasmWindowStack::const_iterator QWasmWindowStack::end() const
|
|
||||||
{
|
|
||||||
return m_windowStack.rend();
|
|
||||||
}
|
|
||||||
|
|
||||||
QWasmWindowStack::const_reverse_iterator QWasmWindowStack::rbegin() const
|
|
||||||
{
|
|
||||||
return m_windowStack.begin();
|
|
||||||
}
|
|
||||||
|
|
||||||
QWasmWindowStack::const_reverse_iterator QWasmWindowStack::rend() const
|
|
||||||
{
|
|
||||||
return m_windowStack.end();
|
|
||||||
}
|
|
||||||
|
|
||||||
bool QWasmWindowStack::empty() const
|
|
||||||
{
|
|
||||||
return m_windowStack.empty();
|
|
||||||
}
|
|
||||||
|
|
||||||
size_t QWasmWindowStack::size() const
|
|
||||||
{
|
|
||||||
return m_windowStack.size();
|
|
||||||
}
|
|
||||||
|
|
||||||
QWasmWindow *QWasmWindowStack::topWindow() const
|
|
||||||
{
|
|
||||||
return m_windowStack.empty() ? nullptr : m_windowStack.last();
|
|
||||||
}
|
|
||||||
|
|
||||||
QWasmWindowStack::PositionPreference
|
|
||||||
QWasmWindowStack::getWindowPositionPreference(StorageType::iterator windowIt) const
|
|
||||||
{
|
|
||||||
if (windowIt >= m_alwaysOnTopWindowsBegin)
|
|
||||||
return PositionPreference::StayOnTop;
|
|
||||||
if (windowIt >= m_regularWindowsBegin)
|
|
||||||
return PositionPreference::Regular;
|
|
||||||
return PositionPreference::StayOnBottom;
|
|
||||||
}
|
|
||||||
|
|
||||||
QT_END_NAMESPACE
|
|
@ -6,6 +6,7 @@
|
|||||||
|
|
||||||
#include <qglobal.h>
|
#include <qglobal.h>
|
||||||
#include <QtCore/qlist.h>
|
#include <QtCore/qlist.h>
|
||||||
|
#include <QDebug>
|
||||||
|
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
@ -21,31 +22,49 @@ class QWasmWindow;
|
|||||||
// Access to the top element is facilitated by |topWindow|.
|
// Access to the top element is facilitated by |topWindow|.
|
||||||
// Changes to the top element are signaled via the |topWindowChangedCallback| supplied at
|
// Changes to the top element are signaled via the |topWindowChangedCallback| supplied at
|
||||||
// construction.
|
// construction.
|
||||||
|
|
||||||
|
// Requirement Window
|
||||||
|
//
|
||||||
|
// type Window {
|
||||||
|
// Window *transientParent() const;
|
||||||
|
// Qt::WindowFlags windowFlags() const;
|
||||||
|
// bool isModal() const;
|
||||||
|
// };
|
||||||
|
|
||||||
|
template <typename Window=QWasmWindow>
|
||||||
class Q_AUTOTEST_EXPORT QWasmWindowStack
|
class Q_AUTOTEST_EXPORT QWasmWindowStack
|
||||||
{
|
{
|
||||||
|
private:
|
||||||
|
QWasmWindowStack(const QWasmWindowStack &) = delete;
|
||||||
|
QWasmWindowStack(QWasmWindowStack &&) = delete;
|
||||||
|
|
||||||
|
QWasmWindowStack &operator=(const QWasmWindowStack &) = delete;
|
||||||
|
QWasmWindowStack &&operator=(QWasmWindowStack &&) = delete;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
using WindowOrderChangedCallbackType = std::function<void()>;
|
|
||||||
|
|
||||||
using StorageType = QList<QWasmWindow *>;
|
|
||||||
|
|
||||||
using iterator = StorageType::reverse_iterator;
|
|
||||||
using const_iterator = StorageType::const_reverse_iterator;
|
|
||||||
using const_reverse_iterator = StorageType::const_iterator;
|
|
||||||
|
|
||||||
enum class PositionPreference {
|
enum class PositionPreference {
|
||||||
StayOnBottom,
|
StayOnBottom,
|
||||||
Regular,
|
Regular,
|
||||||
StayOnTop,
|
StayOnTop,
|
||||||
|
StayAboveTransientParent // Parent is transientParent()
|
||||||
};
|
};
|
||||||
|
|
||||||
|
using WindowOrderChangedCallbackType = std::function<void()>;
|
||||||
|
using StorageType = QList<Window *>;
|
||||||
|
|
||||||
|
using iterator = typename StorageType::reverse_iterator;
|
||||||
|
using const_iterator = typename StorageType::const_reverse_iterator;
|
||||||
|
using const_reverse_iterator = typename StorageType::const_iterator;
|
||||||
|
|
||||||
explicit QWasmWindowStack(WindowOrderChangedCallbackType topWindowChangedCallback);
|
explicit QWasmWindowStack(WindowOrderChangedCallbackType topWindowChangedCallback);
|
||||||
~QWasmWindowStack();
|
~QWasmWindowStack();
|
||||||
|
|
||||||
void pushWindow(QWasmWindow *window, PositionPreference position);
|
void pushWindow(Window *window, PositionPreference position, bool insertAtRegionBegin = false,
|
||||||
void removeWindow(QWasmWindow *window);
|
bool callCallbacks = true);
|
||||||
void raise(QWasmWindow *window);
|
void removeWindow(Window *window, bool callCallbacks = true);
|
||||||
void lower(QWasmWindow *window);
|
void raise(Window *window);
|
||||||
void windowPositionPreferenceChanged(QWasmWindow *window, PositionPreference position);
|
void lower(Window *window);
|
||||||
|
void windowPositionPreferenceChanged(Window *window, PositionPreference position);
|
||||||
|
|
||||||
// Iterates top-to-bottom
|
// Iterates top-to-bottom
|
||||||
iterator begin();
|
iterator begin();
|
||||||
@ -59,17 +78,25 @@ public:
|
|||||||
|
|
||||||
bool empty() const;
|
bool empty() const;
|
||||||
size_t size() const;
|
size_t size() const;
|
||||||
QWasmWindow *topWindow() const;
|
Window *topWindow() const;
|
||||||
|
|
||||||
|
PositionPreference getWindowPositionPreference(typename StorageType::const_iterator windowIt,
|
||||||
|
bool testStayAbove = true) const;
|
||||||
private:
|
private:
|
||||||
PositionPreference getWindowPositionPreference(StorageType::iterator windowIt) const;
|
bool raiseImpl(Window *window);
|
||||||
|
bool lowerImpl(Window *window);
|
||||||
|
bool shouldBeAboveTransientParent(const Window *window) const;
|
||||||
|
bool shouldBeAboveTransientParentFlags(Qt::WindowFlags flags) const;
|
||||||
|
void invariant();
|
||||||
WindowOrderChangedCallbackType m_windowOrderChangedCallback;
|
WindowOrderChangedCallbackType m_windowOrderChangedCallback;
|
||||||
QList<QWasmWindow *> m_windowStack;
|
|
||||||
StorageType::iterator m_regularWindowsBegin;
|
StorageType m_windowStack;
|
||||||
StorageType::iterator m_alwaysOnTopWindowsBegin;
|
typename StorageType::iterator m_regularWindowsBegin;
|
||||||
|
typename StorageType::iterator m_alwaysOnTopWindowsBegin;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#include "qwasmwindowstack.inc"
|
||||||
|
|
||||||
QT_END_NAMESPACE
|
QT_END_NAMESPACE
|
||||||
|
|
||||||
#endif // QWASMWINDOWSTACK_H
|
#endif // QWASMWINDOWSTACK_H
|
||||||
|
384
src/plugins/platforms/wasm/qwasmwindowstack.inc
Normal file
384
src/plugins/platforms/wasm/qwasmwindowstack.inc
Normal file
@ -0,0 +1,384 @@
|
|||||||
|
// Copyright (C) 2025 The Qt Company Ltd.
|
||||||
|
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
|
||||||
|
|
||||||
|
#ifndef QWASMWINDOWSTACK_INC
|
||||||
|
#define QWASMWINDOWSTACK_INC
|
||||||
|
|
||||||
|
template <typename Window>
|
||||||
|
QWasmWindowStack<Window>::QWasmWindowStack(
|
||||||
|
WindowOrderChangedCallbackType windowOrderChangedCallback)
|
||||||
|
: m_windowOrderChangedCallback(std::move(windowOrderChangedCallback)),
|
||||||
|
m_regularWindowsBegin(m_windowStack.begin()),
|
||||||
|
m_alwaysOnTopWindowsBegin(m_windowStack.begin())
|
||||||
|
{
|
||||||
|
invariant();
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename Window>
|
||||||
|
QWasmWindowStack<Window>::~QWasmWindowStack()
|
||||||
|
{
|
||||||
|
invariant();
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename Window>
|
||||||
|
void QWasmWindowStack<Window>::invariant()
|
||||||
|
{
|
||||||
|
Q_ASSERT(m_regularWindowsBegin >= m_windowStack.begin());
|
||||||
|
Q_ASSERT(m_regularWindowsBegin <= m_alwaysOnTopWindowsBegin);
|
||||||
|
Q_ASSERT(m_alwaysOnTopWindowsBegin <= m_windowStack.end());
|
||||||
|
}
|
||||||
|
|
||||||
|
/* insert a window at the correct location.
|
||||||
|
*
|
||||||
|
* There are three groups
|
||||||
|
* StayOnBottom
|
||||||
|
* Regular
|
||||||
|
* StayOnTop
|
||||||
|
*
|
||||||
|
* In addition there is StayAboveParent which
|
||||||
|
* can place the window in either of the
|
||||||
|
* three above groups, depending on which
|
||||||
|
* group the transient parent resides in.
|
||||||
|
*
|
||||||
|
* insertAtRegionBegin controls the placement
|
||||||
|
* within each of the groups. Either at the end
|
||||||
|
* or at the beginning.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
template <typename Window>
|
||||||
|
void QWasmWindowStack<Window>::pushWindow(Window *window, PositionPreference position,
|
||||||
|
bool insertAtRegionBegin, bool callCallbacks)
|
||||||
|
{
|
||||||
|
invariant();
|
||||||
|
Q_ASSERT(m_windowStack.count(window) == 0);
|
||||||
|
|
||||||
|
auto regularDistance = std::distance(m_windowStack.begin(), m_regularWindowsBegin);
|
||||||
|
auto stayOnTopDistance = std::distance(m_windowStack.begin(), m_alwaysOnTopWindowsBegin);
|
||||||
|
|
||||||
|
if (position == PositionPreference::StayAboveTransientParent) {
|
||||||
|
Q_ASSERT(window->transientParent());
|
||||||
|
const auto it =
|
||||||
|
std::find(m_windowStack.begin(), m_windowStack.end(), window->transientParent());
|
||||||
|
if (it == m_windowStack.end()) {
|
||||||
|
qWarning() << "QWasmWindowStack<Window>::pushWindow - missing parent"
|
||||||
|
<< window->transientParent();
|
||||||
|
pushWindow(window, PositionPreference::Regular, insertAtRegionBegin, callCallbacks);
|
||||||
|
return;
|
||||||
|
} else {
|
||||||
|
if (it >= m_alwaysOnTopWindowsBegin)
|
||||||
|
;
|
||||||
|
else if (it >= m_regularWindowsBegin)
|
||||||
|
++stayOnTopDistance;
|
||||||
|
else {
|
||||||
|
++regularDistance;
|
||||||
|
++stayOnTopDistance;
|
||||||
|
}
|
||||||
|
m_windowStack.insert(it + 1, window);
|
||||||
|
}
|
||||||
|
} else if (position == PositionPreference::StayOnTop) {
|
||||||
|
if (insertAtRegionBegin)
|
||||||
|
m_windowStack.insert(m_alwaysOnTopWindowsBegin, window);
|
||||||
|
else
|
||||||
|
m_windowStack.insert(m_windowStack.end(), window);
|
||||||
|
|
||||||
|
} else if (position == PositionPreference::Regular) {
|
||||||
|
++stayOnTopDistance;
|
||||||
|
if (insertAtRegionBegin)
|
||||||
|
m_windowStack.insert(m_regularWindowsBegin, window);
|
||||||
|
else
|
||||||
|
m_windowStack.insert(m_alwaysOnTopWindowsBegin, window);
|
||||||
|
|
||||||
|
} else {
|
||||||
|
// StayOnBottom
|
||||||
|
++regularDistance;
|
||||||
|
++stayOnTopDistance;
|
||||||
|
|
||||||
|
if (insertAtRegionBegin)
|
||||||
|
m_windowStack.insert(m_windowStack.begin(), window);
|
||||||
|
else
|
||||||
|
m_windowStack.insert(m_regularWindowsBegin, window);
|
||||||
|
}
|
||||||
|
|
||||||
|
m_regularWindowsBegin = m_windowStack.begin() + regularDistance;
|
||||||
|
m_alwaysOnTopWindowsBegin = m_windowStack.begin() + stayOnTopDistance;
|
||||||
|
|
||||||
|
if (callCallbacks)
|
||||||
|
m_windowOrderChangedCallback();
|
||||||
|
|
||||||
|
Q_ASSERT(m_windowStack.count(window) == 1);
|
||||||
|
invariant();
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename Window>
|
||||||
|
void QWasmWindowStack<Window>::removeWindow(Window *window, bool callCallbacks)
|
||||||
|
{
|
||||||
|
invariant();
|
||||||
|
Q_ASSERT(m_windowStack.count(window) == 1);
|
||||||
|
|
||||||
|
auto regularDistance = std::distance(m_windowStack.begin(), m_regularWindowsBegin);
|
||||||
|
auto stayOnTopDistance = std::distance(m_windowStack.begin(), m_alwaysOnTopWindowsBegin);
|
||||||
|
|
||||||
|
auto it = std::find(m_windowStack.begin(), m_windowStack.end(), window);
|
||||||
|
|
||||||
|
Q_ASSERT(it != m_windowStack.end());
|
||||||
|
|
||||||
|
if (it < m_regularWindowsBegin)
|
||||||
|
--regularDistance;
|
||||||
|
if (it < m_alwaysOnTopWindowsBegin)
|
||||||
|
--stayOnTopDistance;
|
||||||
|
|
||||||
|
m_windowStack.erase(it);
|
||||||
|
|
||||||
|
m_regularWindowsBegin = m_windowStack.begin() + regularDistance;
|
||||||
|
m_alwaysOnTopWindowsBegin = m_windowStack.begin() + stayOnTopDistance;
|
||||||
|
|
||||||
|
if (callCallbacks)
|
||||||
|
m_windowOrderChangedCallback();
|
||||||
|
|
||||||
|
Q_ASSERT(m_windowStack.count(window) == 0);
|
||||||
|
invariant();
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename Window>
|
||||||
|
void QWasmWindowStack<Window>::raise(Window *window)
|
||||||
|
{
|
||||||
|
if (raiseImpl(window))
|
||||||
|
m_windowOrderChangedCallback();
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename Window>
|
||||||
|
bool QWasmWindowStack<Window>::raiseImpl(Window *window)
|
||||||
|
{
|
||||||
|
invariant();
|
||||||
|
Q_ASSERT(m_windowStack.count(window) == 1);
|
||||||
|
|
||||||
|
{
|
||||||
|
const auto it = std::find(m_windowStack.begin(), m_windowStack.end(), window);
|
||||||
|
const auto itEnd = ([this, it]() {
|
||||||
|
if (it < m_regularWindowsBegin)
|
||||||
|
return m_regularWindowsBegin;
|
||||||
|
if (it < m_alwaysOnTopWindowsBegin)
|
||||||
|
return m_alwaysOnTopWindowsBegin;
|
||||||
|
return m_windowStack.end();
|
||||||
|
})();
|
||||||
|
|
||||||
|
if (it + 1 == itEnd)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
std::rotate(it, it + 1, itEnd);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<Window *> windowsToRaise;
|
||||||
|
{
|
||||||
|
for (auto trit = m_windowStack.begin(); trit != m_windowStack.end(); ++trit) {
|
||||||
|
const auto w = *trit;
|
||||||
|
if ((w != window) &&
|
||||||
|
(getWindowPositionPreference(trit) == PositionPreference::StayAboveTransientParent) &&
|
||||||
|
(w->transientParent() == window)) {
|
||||||
|
windowsToRaise.push_back(w);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const auto w : windowsToRaise)
|
||||||
|
{
|
||||||
|
raiseImpl(w);
|
||||||
|
}
|
||||||
|
invariant();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename Window>
|
||||||
|
void QWasmWindowStack<Window>::lower(Window *window)
|
||||||
|
{
|
||||||
|
if (lowerImpl(window))
|
||||||
|
m_windowOrderChangedCallback();
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename Window>
|
||||||
|
bool QWasmWindowStack<Window>::lowerImpl(Window *window)
|
||||||
|
{
|
||||||
|
invariant();
|
||||||
|
Q_ASSERT(m_windowStack.count(window) == 1);
|
||||||
|
|
||||||
|
{
|
||||||
|
const auto it = std::find(m_windowStack.begin(), m_windowStack.end(), window);
|
||||||
|
const auto itBegin = ([this, it]() {
|
||||||
|
if (it >= m_alwaysOnTopWindowsBegin)
|
||||||
|
return m_alwaysOnTopWindowsBegin;
|
||||||
|
if (it >= m_regularWindowsBegin)
|
||||||
|
return m_regularWindowsBegin;
|
||||||
|
return m_windowStack.begin();
|
||||||
|
})();
|
||||||
|
|
||||||
|
if (itBegin == it)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
std::rotate(itBegin, it, it + 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<Window *> windowsToLower;
|
||||||
|
{
|
||||||
|
for (auto trit = m_windowStack.begin(); trit != m_windowStack.end(); ++trit) {
|
||||||
|
const auto w = *trit;
|
||||||
|
if ((w != window) &&
|
||||||
|
(getWindowPositionPreference(trit) == PositionPreference::StayAboveTransientParent) &&
|
||||||
|
(w->transientParent() == window)) {
|
||||||
|
windowsToLower.push_back(w);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const auto w : windowsToLower)
|
||||||
|
{
|
||||||
|
lowerImpl(w);
|
||||||
|
}
|
||||||
|
invariant();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename Window>
|
||||||
|
void QWasmWindowStack<Window>::windowPositionPreferenceChanged(Window *window,
|
||||||
|
PositionPreference position)
|
||||||
|
{
|
||||||
|
invariant();
|
||||||
|
|
||||||
|
auto it = std::find(m_windowStack.begin(), m_windowStack.end(), window);
|
||||||
|
const auto currentPosition = getWindowPositionPreference(it);
|
||||||
|
|
||||||
|
if (position == currentPosition) {
|
||||||
|
;
|
||||||
|
} else if (currentPosition == PositionPreference::StayAboveTransientParent) {
|
||||||
|
// Keep position if possible
|
||||||
|
const bool isStayOnBottom ( it < m_regularWindowsBegin);
|
||||||
|
const bool isRegular( !isStayOnBottom && (it < m_alwaysOnTopWindowsBegin));
|
||||||
|
const bool isStayOnTop(!isStayOnBottom && !isRegular);
|
||||||
|
|
||||||
|
if (isStayOnBottom && (position == PositionPreference::StayOnBottom))
|
||||||
|
;
|
||||||
|
else if (isRegular && (position == PositionPreference::Regular))
|
||||||
|
;
|
||||||
|
else if (isStayOnTop && (position == PositionPreference::StayOnTop))
|
||||||
|
;
|
||||||
|
else {
|
||||||
|
auto current = *it;
|
||||||
|
removeWindow(current, false);
|
||||||
|
pushWindow(current, position, false, false);
|
||||||
|
m_windowOrderChangedCallback();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
const bool insertAtRegionBegin = (
|
||||||
|
(currentPosition != PositionPreference::StayAboveTransientParent) &&
|
||||||
|
(position != PositionPreference::StayAboveTransientParent) &&
|
||||||
|
((currentPosition == PositionPreference::StayOnBottom) ||
|
||||||
|
(position == PositionPreference::StayOnTop)));
|
||||||
|
|
||||||
|
auto current = *it;
|
||||||
|
removeWindow(current, false);
|
||||||
|
pushWindow(current, position, insertAtRegionBegin, false);
|
||||||
|
m_windowOrderChangedCallback();
|
||||||
|
}
|
||||||
|
invariant();
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename Window>
|
||||||
|
typename QWasmWindowStack<Window>::iterator QWasmWindowStack<Window>::begin()
|
||||||
|
{
|
||||||
|
return m_windowStack.rbegin();
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename Window>
|
||||||
|
typename QWasmWindowStack<Window>::iterator QWasmWindowStack<Window>::end()
|
||||||
|
{
|
||||||
|
return m_windowStack.rend();
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename Window>
|
||||||
|
typename QWasmWindowStack<Window>::const_iterator QWasmWindowStack<Window>::begin() const
|
||||||
|
{
|
||||||
|
return m_windowStack.rbegin();
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename Window>
|
||||||
|
typename QWasmWindowStack<Window>::const_iterator QWasmWindowStack<Window>::end() const
|
||||||
|
{
|
||||||
|
return m_windowStack.rend();
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename Window>
|
||||||
|
typename QWasmWindowStack<Window>::const_reverse_iterator
|
||||||
|
QWasmWindowStack<Window>::rbegin() const
|
||||||
|
{
|
||||||
|
return m_windowStack.begin();
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename Window>
|
||||||
|
typename QWasmWindowStack<Window>::const_reverse_iterator
|
||||||
|
QWasmWindowStack<Window>::rend() const
|
||||||
|
{
|
||||||
|
return m_windowStack.end();
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename Window>
|
||||||
|
bool QWasmWindowStack<Window>::empty() const
|
||||||
|
{
|
||||||
|
return m_windowStack.empty();
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename Window>
|
||||||
|
size_t QWasmWindowStack<Window>::size() const
|
||||||
|
{
|
||||||
|
return m_windowStack.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename Window>
|
||||||
|
Window *QWasmWindowStack<Window>::topWindow() const
|
||||||
|
{
|
||||||
|
return m_windowStack.empty() ? nullptr : m_windowStack.last();
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename Window>
|
||||||
|
bool QWasmWindowStack<Window>::shouldBeAboveTransientParentFlags(Qt::WindowFlags flags) const
|
||||||
|
{
|
||||||
|
if (flags.testFlag(Qt::Tool) ||
|
||||||
|
flags.testFlag(Qt::SplashScreen) ||
|
||||||
|
flags.testFlag(Qt::ToolTip) ||
|
||||||
|
flags.testFlag(Qt::Popup))
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename Window>
|
||||||
|
bool QWasmWindowStack<Window>::shouldBeAboveTransientParent(const Window *window) const
|
||||||
|
{
|
||||||
|
if (!window->transientParent())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (window->isModal())
|
||||||
|
return true;
|
||||||
|
|
||||||
|
if (shouldBeAboveTransientParentFlags(window->windowFlags()))
|
||||||
|
return true;
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename Window>
|
||||||
|
typename QWasmWindowStack<Window>::PositionPreference
|
||||||
|
QWasmWindowStack<Window>::getWindowPositionPreference(
|
||||||
|
typename StorageType::const_iterator windowIt, bool testStayAbove) const
|
||||||
|
{
|
||||||
|
Window *window = *windowIt;
|
||||||
|
if (testStayAbove && shouldBeAboveTransientParent(window))
|
||||||
|
return PositionPreference::StayAboveTransientParent;
|
||||||
|
if (windowIt >= m_alwaysOnTopWindowsBegin)
|
||||||
|
return PositionPreference::StayOnTop;
|
||||||
|
if (windowIt >= m_regularWindowsBegin)
|
||||||
|
return PositionPreference::Regular;
|
||||||
|
return PositionPreference::StayOnBottom;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif /* QWASMWINDOWSTACK_INC */
|
@ -3,149 +3,4 @@
|
|||||||
|
|
||||||
#include "qwasmwindowtreenode.h"
|
#include "qwasmwindowtreenode.h"
|
||||||
|
|
||||||
#include "qwasmwindow.h"
|
uint64_t QWasmWindowTreeNodeBase::s_nextActiveIndex = 0;
|
||||||
#include "qwasmscreen.h"
|
|
||||||
|
|
||||||
uint64_t QWasmWindowTreeNode::s_nextActiveIndex = 0;
|
|
||||||
|
|
||||||
QWasmWindowTreeNode::QWasmWindowTreeNode()
|
|
||||||
: m_childStack(std::bind(&QWasmWindowTreeNode::onTopWindowChanged, this))
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
QWasmWindowTreeNode::~QWasmWindowTreeNode() = default;
|
|
||||||
|
|
||||||
void QWasmWindowTreeNode::shutdown()
|
|
||||||
{
|
|
||||||
QWasmWindow *window = asWasmWindow();
|
|
||||||
if (!window ||
|
|
||||||
!window->window() ||
|
|
||||||
(QGuiApplication::focusWindow() && // Don't act if we have a focus window different from this
|
|
||||||
QGuiApplication::focusWindow() != window->window()))
|
|
||||||
return;
|
|
||||||
|
|
||||||
// Make a list of all windows sorted on active index.
|
|
||||||
// Skip windows with active index 0 as they have
|
|
||||||
// never been active.
|
|
||||||
std::map<uint64_t, QWasmWindow *> allWindows;
|
|
||||||
for (const auto &w : window->platformScreen()->allWindows()) {
|
|
||||||
if (w->getActiveIndex() > 0)
|
|
||||||
allWindows.insert({w->getActiveIndex(), w});
|
|
||||||
}
|
|
||||||
|
|
||||||
// window is not in all windows
|
|
||||||
if (window->getActiveIndex() > 0)
|
|
||||||
allWindows.insert({window->getActiveIndex(), window});
|
|
||||||
|
|
||||||
if (allWindows.size() >= 2) {
|
|
||||||
const auto lastIt = std::prev(allWindows.end());
|
|
||||||
const auto prevIt = std::prev(lastIt);
|
|
||||||
const auto lastW = lastIt->second;
|
|
||||||
const auto prevW = prevIt->second;
|
|
||||||
|
|
||||||
if (lastW == window) // Only act if window is last to be active
|
|
||||||
prevW->requestActivateWindow();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void QWasmWindowTreeNode::onParentChanged(QWasmWindowTreeNode *previousParent,
|
|
||||||
QWasmWindowTreeNode *currentParent,
|
|
||||||
QWasmWindowStack::PositionPreference positionPreference)
|
|
||||||
{
|
|
||||||
auto *window = asWasmWindow();
|
|
||||||
if (previousParent) {
|
|
||||||
previousParent->m_childStack.removeWindow(window);
|
|
||||||
previousParent->onSubtreeChanged(QWasmWindowTreeNodeChangeType::NodeRemoval, previousParent,
|
|
||||||
window);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (currentParent) {
|
|
||||||
currentParent->m_childStack.pushWindow(window, positionPreference);
|
|
||||||
currentParent->onSubtreeChanged(QWasmWindowTreeNodeChangeType::NodeInsertion, currentParent,
|
|
||||||
window);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
QWasmWindow *QWasmWindowTreeNode::asWasmWindow()
|
|
||||||
{
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
void QWasmWindowTreeNode::onSubtreeChanged(QWasmWindowTreeNodeChangeType changeType,
|
|
||||||
QWasmWindowTreeNode *parent, QWasmWindow *child)
|
|
||||||
{
|
|
||||||
if (changeType == QWasmWindowTreeNodeChangeType::NodeInsertion && parent == this
|
|
||||||
&& m_childStack.topWindow()
|
|
||||||
&& m_childStack.topWindow()->window()) {
|
|
||||||
|
|
||||||
const auto flags = m_childStack.topWindow()->window()->flags();
|
|
||||||
const bool notToolOrPopup = ((flags & Qt::ToolTip) != Qt::ToolTip) && ((flags & Qt::Popup) != Qt::Popup);
|
|
||||||
const QVariant showWithoutActivating = m_childStack.topWindow()->window()->property("_q_showWithoutActivating");
|
|
||||||
if (!showWithoutActivating.isValid() || !showWithoutActivating.toBool()) {
|
|
||||||
if (notToolOrPopup)
|
|
||||||
m_childStack.topWindow()->requestActivateWindow();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (parentNode())
|
|
||||||
parentNode()->onSubtreeChanged(changeType, parent, child);
|
|
||||||
}
|
|
||||||
|
|
||||||
void QWasmWindowTreeNode::setWindowZOrder(QWasmWindow *window, int z)
|
|
||||||
{
|
|
||||||
window->setZOrder(z);
|
|
||||||
}
|
|
||||||
|
|
||||||
void QWasmWindowTreeNode::onPositionPreferenceChanged(
|
|
||||||
QWasmWindowStack::PositionPreference positionPreference)
|
|
||||||
{
|
|
||||||
if (parentNode()) {
|
|
||||||
parentNode()->m_childStack.windowPositionPreferenceChanged(asWasmWindow(),
|
|
||||||
positionPreference);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void QWasmWindowTreeNode::setAsActiveNode()
|
|
||||||
{
|
|
||||||
if (parentNode())
|
|
||||||
parentNode()->setActiveChildNode(asWasmWindow());
|
|
||||||
|
|
||||||
// At the end, this is a recursive function
|
|
||||||
m_activeIndex = ++s_nextActiveIndex;
|
|
||||||
}
|
|
||||||
|
|
||||||
void QWasmWindowTreeNode::bringToTop()
|
|
||||||
{
|
|
||||||
if (!parentNode())
|
|
||||||
return;
|
|
||||||
parentNode()->m_childStack.raise(asWasmWindow());
|
|
||||||
parentNode()->bringToTop();
|
|
||||||
}
|
|
||||||
|
|
||||||
void QWasmWindowTreeNode::sendToBottom()
|
|
||||||
{
|
|
||||||
if (!parentNode())
|
|
||||||
return;
|
|
||||||
m_childStack.lower(asWasmWindow());
|
|
||||||
}
|
|
||||||
|
|
||||||
void QWasmWindowTreeNode::onTopWindowChanged()
|
|
||||||
{
|
|
||||||
constexpr int zOrderForElementInFrontOfScreen = 3;
|
|
||||||
int z = zOrderForElementInFrontOfScreen;
|
|
||||||
std::for_each(m_childStack.rbegin(), m_childStack.rend(),
|
|
||||||
[this, &z](QWasmWindow *window) { setWindowZOrder(window, z++); });
|
|
||||||
}
|
|
||||||
|
|
||||||
void QWasmWindowTreeNode::setActiveChildNode(QWasmWindow *activeChild)
|
|
||||||
{
|
|
||||||
m_activeChild = activeChild;
|
|
||||||
|
|
||||||
auto it = m_childStack.begin();
|
|
||||||
if (it == m_childStack.end())
|
|
||||||
return;
|
|
||||||
for (; it != m_childStack.end(); ++it)
|
|
||||||
(*it)->onActivationChanged(*it == m_activeChild);
|
|
||||||
|
|
||||||
setAsActiveNode();
|
|
||||||
}
|
|
||||||
|
@ -6,6 +6,8 @@
|
|||||||
|
|
||||||
#include "qwasmwindowstack.h"
|
#include "qwasmwindowstack.h"
|
||||||
|
|
||||||
|
#include <QVariant>
|
||||||
|
|
||||||
namespace emscripten {
|
namespace emscripten {
|
||||||
class val;
|
class val;
|
||||||
}
|
}
|
||||||
@ -17,7 +19,14 @@ enum class QWasmWindowTreeNodeChangeType {
|
|||||||
NodeRemoval,
|
NodeRemoval,
|
||||||
};
|
};
|
||||||
|
|
||||||
class QWasmWindowTreeNode
|
class QWasmWindowTreeNodeBase
|
||||||
|
{
|
||||||
|
protected:
|
||||||
|
static uint64_t s_nextActiveIndex;
|
||||||
|
};
|
||||||
|
|
||||||
|
template<class Window = QWasmWindow>
|
||||||
|
class QWasmWindowTreeNode : public QWasmWindowTreeNodeBase
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
QWasmWindowTreeNode();
|
QWasmWindowTreeNode();
|
||||||
@ -28,20 +37,20 @@ public:
|
|||||||
|
|
||||||
protected:
|
protected:
|
||||||
virtual void onParentChanged(QWasmWindowTreeNode *previous, QWasmWindowTreeNode *current,
|
virtual void onParentChanged(QWasmWindowTreeNode *previous, QWasmWindowTreeNode *current,
|
||||||
QWasmWindowStack::PositionPreference positionPreference);
|
typename QWasmWindowStack<Window>::PositionPreference positionPreference);
|
||||||
virtual QWasmWindow *asWasmWindow();
|
virtual Window *asWasmWindow();
|
||||||
virtual void onSubtreeChanged(QWasmWindowTreeNodeChangeType changeType,
|
virtual void onSubtreeChanged(QWasmWindowTreeNodeChangeType changeType,
|
||||||
QWasmWindowTreeNode *parent, QWasmWindow *child);
|
QWasmWindowTreeNode *parent, Window *child);
|
||||||
virtual void setWindowZOrder(QWasmWindow *window, int z);
|
virtual void setWindowZOrder(Window *window, int z);
|
||||||
|
|
||||||
void onPositionPreferenceChanged(QWasmWindowStack::PositionPreference positionPreference);
|
void onPositionPreferenceChanged(typename QWasmWindowStack<Window>::PositionPreference positionPreference);
|
||||||
void setAsActiveNode();
|
void setAsActiveNode();
|
||||||
void bringToTop();
|
void bringToTop();
|
||||||
void sendToBottom();
|
void sendToBottom();
|
||||||
void shutdown();
|
|
||||||
|
|
||||||
const QWasmWindowStack &childStack() const { return m_childStack; }
|
const QWasmWindowStack<Window> &childStack() const { return m_childStack; }
|
||||||
QWasmWindow *activeChild() const { return m_activeChild; }
|
QWasmWindowStack<Window> &childStack() { return m_childStack; }
|
||||||
|
Window *activeChild() const { return m_activeChild; }
|
||||||
|
|
||||||
uint64_t getActiveIndex() const {
|
uint64_t getActiveIndex() const {
|
||||||
return m_activeIndex;
|
return m_activeIndex;
|
||||||
@ -49,13 +58,13 @@ protected:
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
void onTopWindowChanged();
|
void onTopWindowChanged();
|
||||||
void setActiveChildNode(QWasmWindow *activeChild);
|
void setActiveChildNode(Window *activeChild);
|
||||||
|
|
||||||
uint64_t m_activeIndex = 0;
|
uint64_t m_activeIndex = 0;
|
||||||
static uint64_t s_nextActiveIndex;
|
|
||||||
|
|
||||||
QWasmWindowStack m_childStack;
|
QWasmWindowStack<Window> m_childStack;
|
||||||
QWasmWindow *m_activeChild = nullptr;
|
Window *m_activeChild = nullptr;
|
||||||
};
|
};
|
||||||
|
#endif
|
||||||
|
|
||||||
#endif // QWASMWINDOWTREENODE_H
|
#include "qwasmwindowtreenode.inc"
|
||||||
|
128
src/plugins/platforms/wasm/qwasmwindowtreenode.inc
Normal file
128
src/plugins/platforms/wasm/qwasmwindowtreenode.inc
Normal file
@ -0,0 +1,128 @@
|
|||||||
|
// Copyright (C) 2025 The Qt Company Ltd.
|
||||||
|
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
|
||||||
|
|
||||||
|
#ifndef QWASMWINDOWTREENODE_INC
|
||||||
|
#define QWASMWINDOWTREENODE_INC
|
||||||
|
|
||||||
|
template<class Window>
|
||||||
|
QWasmWindowTreeNode<Window>::QWasmWindowTreeNode()
|
||||||
|
: m_childStack(std::bind(&QWasmWindowTreeNode<Window>::onTopWindowChanged, this))
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class Window>
|
||||||
|
QWasmWindowTreeNode<Window>::~QWasmWindowTreeNode() = default;
|
||||||
|
|
||||||
|
template<class Window>
|
||||||
|
void QWasmWindowTreeNode<Window>::onParentChanged(QWasmWindowTreeNode *previousParent,
|
||||||
|
QWasmWindowTreeNode *currentParent,
|
||||||
|
typename QWasmWindowStack<Window>::PositionPreference positionPreference)
|
||||||
|
{
|
||||||
|
auto *window = asWasmWindow();
|
||||||
|
if (previousParent) {
|
||||||
|
previousParent->m_childStack.removeWindow(window);
|
||||||
|
previousParent->onSubtreeChanged(QWasmWindowTreeNodeChangeType::NodeRemoval, previousParent,
|
||||||
|
window);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (currentParent) {
|
||||||
|
currentParent->m_childStack.pushWindow(window, positionPreference);
|
||||||
|
currentParent->onSubtreeChanged(QWasmWindowTreeNodeChangeType::NodeInsertion, currentParent,
|
||||||
|
window);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class Window>
|
||||||
|
Window *QWasmWindowTreeNode<Window>::asWasmWindow()
|
||||||
|
{
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class Window>
|
||||||
|
void QWasmWindowTreeNode<Window>::onSubtreeChanged(QWasmWindowTreeNodeChangeType changeType,
|
||||||
|
QWasmWindowTreeNode *parent, Window *child)
|
||||||
|
{
|
||||||
|
if (changeType == QWasmWindowTreeNodeChangeType::NodeInsertion && parent == this
|
||||||
|
&& m_childStack.topWindow()
|
||||||
|
&& m_childStack.topWindow()->window()) {
|
||||||
|
|
||||||
|
const auto flags = m_childStack.topWindow()->window()->flags();
|
||||||
|
const bool notToolOrPopup = ((flags & Qt::ToolTip) != Qt::ToolTip) && ((flags & Qt::Popup) != Qt::Popup);
|
||||||
|
const QVariant showWithoutActivating = m_childStack.topWindow()->window()->property("_q_showWithoutActivating");
|
||||||
|
if (!showWithoutActivating.isValid() || !showWithoutActivating.toBool()) {
|
||||||
|
if (notToolOrPopup)
|
||||||
|
m_childStack.topWindow()->requestActivateWindow();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (parentNode())
|
||||||
|
parentNode()->onSubtreeChanged(changeType, parent, child);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class Window>
|
||||||
|
void QWasmWindowTreeNode<Window>::setWindowZOrder(Window *window, int z)
|
||||||
|
{
|
||||||
|
window->setZOrder(z);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class Window>
|
||||||
|
void QWasmWindowTreeNode<Window>::onPositionPreferenceChanged(
|
||||||
|
typename QWasmWindowStack<Window>::PositionPreference positionPreference)
|
||||||
|
{
|
||||||
|
if (parentNode()) {
|
||||||
|
parentNode()->m_childStack.windowPositionPreferenceChanged(asWasmWindow(),
|
||||||
|
positionPreference);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class Window>
|
||||||
|
void QWasmWindowTreeNode<Window>::setAsActiveNode()
|
||||||
|
{
|
||||||
|
if (parentNode())
|
||||||
|
parentNode()->setActiveChildNode(asWasmWindow());
|
||||||
|
|
||||||
|
// At the end, this is a recursive function
|
||||||
|
m_activeIndex = ++s_nextActiveIndex;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class Window>
|
||||||
|
void QWasmWindowTreeNode<Window>::bringToTop()
|
||||||
|
{
|
||||||
|
if (!parentNode())
|
||||||
|
return;
|
||||||
|
parentNode()->m_childStack.raise(asWasmWindow());
|
||||||
|
parentNode()->bringToTop();
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class Window>
|
||||||
|
void QWasmWindowTreeNode<Window>::sendToBottom()
|
||||||
|
{
|
||||||
|
if (!parentNode())
|
||||||
|
return;
|
||||||
|
m_childStack.lower(asWasmWindow());
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class Window>
|
||||||
|
void QWasmWindowTreeNode<Window>::onTopWindowChanged()
|
||||||
|
{
|
||||||
|
constexpr int zOrderForElementInFrontOfScreen = 3;
|
||||||
|
int z = zOrderForElementInFrontOfScreen;
|
||||||
|
std::for_each(m_childStack.rbegin(), m_childStack.rend(),
|
||||||
|
[this, &z](Window *window) { setWindowZOrder(window, z++); });
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class Window>
|
||||||
|
void QWasmWindowTreeNode<Window>::setActiveChildNode(Window *activeChild)
|
||||||
|
{
|
||||||
|
m_activeChild = activeChild;
|
||||||
|
|
||||||
|
auto it = m_childStack.begin();
|
||||||
|
if (it == m_childStack.end())
|
||||||
|
return;
|
||||||
|
for (; it != m_childStack.end(); ++it)
|
||||||
|
(*it)->onActivationChanged(*it == m_activeChild);
|
||||||
|
|
||||||
|
setAsActiveNode();
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif /* QWASMWINDOWTREENODE_INC */
|
@ -2,15 +2,75 @@
|
|||||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
|
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
|
||||||
|
|
||||||
#include "../../../../src/plugins/platforms/wasm/qwasmwindowstack.h"
|
#include "../../../../src/plugins/platforms/wasm/qwasmwindowstack.h"
|
||||||
|
|
||||||
#include <QtGui/QWindow>
|
#include <QtGui/QWindow>
|
||||||
#include <QTest>
|
#include <QTest>
|
||||||
#include <emscripten/val.h>
|
#include <emscripten/val.h>
|
||||||
|
|
||||||
class QWasmWindow
|
class TestWindow
|
||||||
{
|
{
|
||||||
|
public:
|
||||||
|
TestWindow *transientParent() const { return m_transientParent; }
|
||||||
|
Qt::WindowFlags windowFlags() const { return m_windowFlags; }
|
||||||
|
bool isModal() const { return m_isModal; }
|
||||||
|
|
||||||
|
public:
|
||||||
|
TestWindow *m_transientParent = nullptr;
|
||||||
|
Qt::WindowFlags m_windowFlags = {};
|
||||||
|
bool m_isModal = false;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#define QWasmWindowStack QWasmWindowStack<TestWindow>
|
||||||
|
#define QWasmWindow TestWindow
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
|
QDebug operator<<(QDebug d, const QWasmWindowStack::PositionPreference &pref)
|
||||||
|
{
|
||||||
|
switch (pref) {
|
||||||
|
case QWasmWindowStack::PositionPreference::StayOnBottom:
|
||||||
|
d << "StayOnBottom";
|
||||||
|
break;
|
||||||
|
case QWasmWindowStack::PositionPreference::Regular:
|
||||||
|
d << "Regular";
|
||||||
|
break;
|
||||||
|
case QWasmWindowStack::PositionPreference::StayOnTop:
|
||||||
|
d << "StayOnTop";
|
||||||
|
break;
|
||||||
|
case QWasmWindowStack::PositionPreference::StayAboveTransientParent:
|
||||||
|
d << "StayAboveParent";
|
||||||
|
break;
|
||||||
|
} /* end-switch */
|
||||||
|
return d;
|
||||||
|
}
|
||||||
|
|
||||||
|
class LogWindows
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
LogWindows(QWasmWindow *window, const QWasmWindowStack &stack)
|
||||||
|
: m_window(window), m_stack(&stack)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public:
|
||||||
|
friend QDebug operator<<(QDebug d, const LogWindows &cl)
|
||||||
|
{
|
||||||
|
LogWindows &l = const_cast<LogWindows &>(cl);
|
||||||
|
d << "\n";
|
||||||
|
for (auto it = l.m_stack->rend(); it != l.m_stack->rbegin();) {
|
||||||
|
--it;
|
||||||
|
d << " Window " << (*it) - l.m_window
|
||||||
|
<< l.m_stack->getWindowPositionPreference(it, false)
|
||||||
|
<< l.m_stack->getWindowPositionPreference(it, true) << "\n";
|
||||||
|
}
|
||||||
|
return d;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
QWasmWindow *m_window;
|
||||||
|
const QWasmWindowStack *m_stack;
|
||||||
|
};
|
||||||
|
|
||||||
std::vector<QWasmWindow *> getWindowsFrontToBack(const QWasmWindowStack *stack)
|
std::vector<QWasmWindow *> getWindowsFrontToBack(const QWasmWindowStack *stack)
|
||||||
{
|
{
|
||||||
return std::vector<QWasmWindow *>(stack->begin(), stack->end());
|
return std::vector<QWasmWindow *>(stack->begin(), stack->end());
|
||||||
@ -42,6 +102,11 @@ private slots:
|
|||||||
void removingWithAlwaysOnTop();
|
void removingWithAlwaysOnTop();
|
||||||
void positionPreferenceChanges();
|
void positionPreferenceChanges();
|
||||||
void clearing();
|
void clearing();
|
||||||
|
void stayAboveParentOnBottom1();
|
||||||
|
void stayAboveParentOnBottom2();
|
||||||
|
void stayAboveParentOnBottom3();
|
||||||
|
void stayAboveParentRegular();
|
||||||
|
void stayAboveParentOnTop();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void onTopWindowChanged()
|
void onTopWindowChanged()
|
||||||
@ -97,7 +162,6 @@ void tst_QWasmWindowStack::insertion()
|
|||||||
void tst_QWasmWindowStack::raising()
|
void tst_QWasmWindowStack::raising()
|
||||||
{
|
{
|
||||||
QWasmWindowStack stack(m_mockCallback);
|
QWasmWindowStack stack(m_mockCallback);
|
||||||
|
|
||||||
stack.pushWindow(&m_root, QWasmWindowStack::PositionPreference::StayOnBottom);
|
stack.pushWindow(&m_root, QWasmWindowStack::PositionPreference::StayOnBottom);
|
||||||
stack.pushWindow(&m_window1, QWasmWindowStack::PositionPreference::Regular);
|
stack.pushWindow(&m_window1, QWasmWindowStack::PositionPreference::Regular);
|
||||||
stack.pushWindow(&m_window2, QWasmWindowStack::PositionPreference::Regular);
|
stack.pushWindow(&m_window2, QWasmWindowStack::PositionPreference::Regular);
|
||||||
@ -106,7 +170,6 @@ void tst_QWasmWindowStack::raising()
|
|||||||
stack.pushWindow(&m_window5, QWasmWindowStack::PositionPreference::Regular);
|
stack.pushWindow(&m_window5, QWasmWindowStack::PositionPreference::Regular);
|
||||||
|
|
||||||
clearCallbackCounter();
|
clearCallbackCounter();
|
||||||
|
|
||||||
QCOMPARE(&m_window5, stack.topWindow());
|
QCOMPARE(&m_window5, stack.topWindow());
|
||||||
|
|
||||||
m_onTopLevelChangedAction = [this, &stack]() { QVERIFY(stack.topWindow() == &m_window1); };
|
m_onTopLevelChangedAction = [this, &stack]() { QVERIFY(stack.topWindow() == &m_window1); };
|
||||||
@ -710,5 +773,254 @@ void tst_QWasmWindowStack::clearing()
|
|||||||
QCOMPARE(0u, stack.size());
|
QCOMPARE(0u, stack.size());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void tst_QWasmWindowStack::stayAboveParentOnBottom1()
|
||||||
|
{
|
||||||
|
QWasmWindow windows[5];
|
||||||
|
windows[4].m_transientParent = &windows[0];
|
||||||
|
windows[4].m_windowFlags = Qt::Tool;
|
||||||
|
|
||||||
|
QWasmWindowStack stack(m_mockCallback);
|
||||||
|
|
||||||
|
stack.pushWindow(windows + 0, QWasmWindowStack::PositionPreference::StayOnBottom);
|
||||||
|
stack.pushWindow(windows + 1, QWasmWindowStack::PositionPreference::StayOnBottom);
|
||||||
|
stack.pushWindow(windows + 2, QWasmWindowStack::PositionPreference::Regular);
|
||||||
|
stack.pushWindow(windows + 3, QWasmWindowStack::PositionPreference::StayOnTop);
|
||||||
|
stack.pushWindow(windows + 4, QWasmWindowStack::PositionPreference::StayAboveTransientParent);
|
||||||
|
|
||||||
|
{
|
||||||
|
const std::vector expectedWindowOrder = {
|
||||||
|
windows + 3,
|
||||||
|
windows + 2,
|
||||||
|
windows + 1,
|
||||||
|
windows + 4,
|
||||||
|
windows + 0
|
||||||
|
};
|
||||||
|
|
||||||
|
qDebug() << LogWindows(windows + 0, stack);
|
||||||
|
|
||||||
|
QVERIFY(std::equal(expectedWindowOrder.begin(), expectedWindowOrder.end(),
|
||||||
|
getWindowsFrontToBack(&stack).begin()));
|
||||||
|
}
|
||||||
|
{
|
||||||
|
// Check that window is moved to correct group:
|
||||||
|
// it was: StayAboveParent, in group StayOnBottom
|
||||||
|
// it is: StayOnTop
|
||||||
|
stack.windowPositionPreferenceChanged(
|
||||||
|
windows + 4,
|
||||||
|
QWasmWindowStack::PositionPreference::StayOnTop);
|
||||||
|
|
||||||
|
const std::vector expectedWindowOrder = {
|
||||||
|
windows + 4,
|
||||||
|
windows + 3,
|
||||||
|
windows + 2,
|
||||||
|
windows + 1,
|
||||||
|
windows + 0
|
||||||
|
};
|
||||||
|
|
||||||
|
qDebug() << LogWindows(windows + 0, stack);
|
||||||
|
|
||||||
|
QVERIFY(std::equal(expectedWindowOrder.begin(), expectedWindowOrder.end(),
|
||||||
|
getWindowsFrontToBack(&stack).begin()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void tst_QWasmWindowStack::stayAboveParentOnBottom2()
|
||||||
|
{
|
||||||
|
QWasmWindow windows[5];
|
||||||
|
windows[4].m_transientParent = &windows[0];
|
||||||
|
windows[4].m_windowFlags = Qt::Tool;
|
||||||
|
|
||||||
|
QWasmWindowStack stack(m_mockCallback);
|
||||||
|
|
||||||
|
stack.pushWindow(windows + 0, QWasmWindowStack::PositionPreference::StayOnBottom);
|
||||||
|
stack.pushWindow(windows + 1, QWasmWindowStack::PositionPreference::StayOnBottom);
|
||||||
|
stack.pushWindow(windows + 2, QWasmWindowStack::PositionPreference::Regular);
|
||||||
|
stack.pushWindow(windows + 3, QWasmWindowStack::PositionPreference::StayOnTop);
|
||||||
|
stack.pushWindow(windows + 4, QWasmWindowStack::PositionPreference::StayAboveTransientParent);
|
||||||
|
|
||||||
|
{
|
||||||
|
const std::vector expectedWindowOrder = {
|
||||||
|
windows + 3,
|
||||||
|
windows + 2,
|
||||||
|
windows + 1,
|
||||||
|
windows + 4,
|
||||||
|
windows + 0
|
||||||
|
};
|
||||||
|
|
||||||
|
qDebug() << LogWindows(windows + 0, stack);
|
||||||
|
|
||||||
|
QVERIFY(std::equal(expectedWindowOrder.begin(), expectedWindowOrder.end(),
|
||||||
|
getWindowsFrontToBack(&stack).begin()));
|
||||||
|
}
|
||||||
|
{
|
||||||
|
// Check that order does not change:
|
||||||
|
// it was: StayAboveParent, in group StayOnBottom
|
||||||
|
// it is: StayOnBottom
|
||||||
|
stack.windowPositionPreferenceChanged(
|
||||||
|
windows + 4,
|
||||||
|
QWasmWindowStack::PositionPreference::StayOnBottom);
|
||||||
|
|
||||||
|
const std::vector expectedWindowOrder = {
|
||||||
|
windows + 3,
|
||||||
|
windows + 2,
|
||||||
|
windows + 1,
|
||||||
|
windows + 4,
|
||||||
|
windows + 0
|
||||||
|
};
|
||||||
|
|
||||||
|
qDebug() << LogWindows(windows + 0, stack);
|
||||||
|
|
||||||
|
QVERIFY(std::equal(expectedWindowOrder.begin(), expectedWindowOrder.end(),
|
||||||
|
getWindowsFrontToBack(&stack).begin()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void tst_QWasmWindowStack::stayAboveParentOnBottom3()
|
||||||
|
{
|
||||||
|
QWasmWindow windows[5];
|
||||||
|
windows[4].m_transientParent = &windows[0];
|
||||||
|
windows[4].m_windowFlags = Qt::Tool;
|
||||||
|
|
||||||
|
QWasmWindowStack stack(m_mockCallback);
|
||||||
|
|
||||||
|
stack.pushWindow(windows + 0, QWasmWindowStack::PositionPreference::StayOnBottom);
|
||||||
|
stack.pushWindow(windows + 1, QWasmWindowStack::PositionPreference::StayOnBottom);
|
||||||
|
stack.pushWindow(windows + 2, QWasmWindowStack::PositionPreference::Regular);
|
||||||
|
stack.pushWindow(windows + 3, QWasmWindowStack::PositionPreference::StayOnTop);
|
||||||
|
stack.pushWindow(windows + 4, QWasmWindowStack::PositionPreference::StayAboveTransientParent);
|
||||||
|
|
||||||
|
{
|
||||||
|
const std::vector expectedWindowOrder = {
|
||||||
|
windows + 3,
|
||||||
|
windows + 2,
|
||||||
|
windows + 1,
|
||||||
|
windows + 4,
|
||||||
|
windows + 0
|
||||||
|
};
|
||||||
|
|
||||||
|
qDebug() << LogWindows(windows + 0, stack);
|
||||||
|
|
||||||
|
QVERIFY(std::equal(expectedWindowOrder.begin(), expectedWindowOrder.end(),
|
||||||
|
getWindowsFrontToBack(&stack).begin()));
|
||||||
|
}
|
||||||
|
{
|
||||||
|
// Check that windows is moved to correct group
|
||||||
|
// it was: StayAboveParent, in group StayOnBottom
|
||||||
|
// it is: Regular
|
||||||
|
stack.windowPositionPreferenceChanged(
|
||||||
|
windows + 4,
|
||||||
|
QWasmWindowStack::PositionPreference::Regular);
|
||||||
|
|
||||||
|
const std::vector expectedWindowOrder = {
|
||||||
|
windows + 3,
|
||||||
|
windows + 4,
|
||||||
|
windows + 2,
|
||||||
|
windows + 1,
|
||||||
|
windows + 0
|
||||||
|
};
|
||||||
|
|
||||||
|
qDebug() << LogWindows(windows + 0, stack);
|
||||||
|
|
||||||
|
QVERIFY(std::equal(expectedWindowOrder.begin(), expectedWindowOrder.end(),
|
||||||
|
getWindowsFrontToBack(&stack).begin()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void tst_QWasmWindowStack::stayAboveParentRegular()
|
||||||
|
{
|
||||||
|
QWasmWindow windows[5];
|
||||||
|
windows[4].m_transientParent = &windows[1];
|
||||||
|
windows[4].m_windowFlags = Qt::Tool;
|
||||||
|
|
||||||
|
QWasmWindowStack stack(m_mockCallback);
|
||||||
|
|
||||||
|
stack.pushWindow(windows + 0, QWasmWindowStack::PositionPreference::StayOnBottom);
|
||||||
|
stack.pushWindow(windows + 1, QWasmWindowStack::PositionPreference::Regular);
|
||||||
|
stack.pushWindow(windows + 2, QWasmWindowStack::PositionPreference::Regular);
|
||||||
|
stack.pushWindow(windows + 3, QWasmWindowStack::PositionPreference::StayOnTop);
|
||||||
|
stack.pushWindow(windows + 4, QWasmWindowStack::PositionPreference::StayAboveTransientParent);
|
||||||
|
|
||||||
|
{
|
||||||
|
const std::vector expectedWindowOrder = {
|
||||||
|
windows + 3,
|
||||||
|
windows + 2,
|
||||||
|
windows + 4,
|
||||||
|
windows + 1,
|
||||||
|
windows + 0
|
||||||
|
};
|
||||||
|
|
||||||
|
qDebug() << LogWindows(windows + 0, stack);
|
||||||
|
|
||||||
|
QVERIFY(std::equal(expectedWindowOrder.begin(), expectedWindowOrder.end(),
|
||||||
|
getWindowsFrontToBack(&stack).begin()));
|
||||||
|
}
|
||||||
|
{
|
||||||
|
stack.windowPositionPreferenceChanged(
|
||||||
|
windows + 4,
|
||||||
|
QWasmWindowStack::PositionPreference::StayOnTop);
|
||||||
|
|
||||||
|
const std::vector expectedWindowOrder = {
|
||||||
|
windows + 4,
|
||||||
|
windows + 3,
|
||||||
|
windows + 2,
|
||||||
|
windows + 1,
|
||||||
|
windows + 0
|
||||||
|
};
|
||||||
|
|
||||||
|
qDebug() << LogWindows(windows + 0, stack);
|
||||||
|
|
||||||
|
QVERIFY(std::equal(expectedWindowOrder.begin(), expectedWindowOrder.end(),
|
||||||
|
getWindowsFrontToBack(&stack).begin()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void tst_QWasmWindowStack::stayAboveParentOnTop()
|
||||||
|
{
|
||||||
|
QWasmWindow windows[5];
|
||||||
|
windows[3].m_transientParent = &windows[2];
|
||||||
|
windows[3].m_windowFlags = Qt::Tool;
|
||||||
|
|
||||||
|
QWasmWindowStack stack(m_mockCallback);
|
||||||
|
|
||||||
|
stack.pushWindow(windows + 0, QWasmWindowStack::PositionPreference::StayOnBottom);
|
||||||
|
stack.pushWindow(windows + 1, QWasmWindowStack::PositionPreference::Regular);
|
||||||
|
stack.pushWindow(windows + 2, QWasmWindowStack::PositionPreference::StayOnTop);
|
||||||
|
stack.pushWindow(windows + 3, QWasmWindowStack::PositionPreference::StayAboveTransientParent);
|
||||||
|
stack.pushWindow(windows + 4, QWasmWindowStack::PositionPreference::StayOnTop);
|
||||||
|
|
||||||
|
{
|
||||||
|
const std::vector expectedWindowOrder = {
|
||||||
|
windows + 4,
|
||||||
|
windows + 3,
|
||||||
|
windows + 2,
|
||||||
|
windows + 1,
|
||||||
|
windows + 0
|
||||||
|
};
|
||||||
|
|
||||||
|
qDebug() << LogWindows(windows + 0, stack);
|
||||||
|
QVERIFY(std::equal(expectedWindowOrder.begin(), expectedWindowOrder.end(),
|
||||||
|
getWindowsFrontToBack(&stack).begin()));
|
||||||
|
}
|
||||||
|
{
|
||||||
|
stack.windowPositionPreferenceChanged(
|
||||||
|
windows + 3,
|
||||||
|
QWasmWindowStack::PositionPreference::StayOnTop);
|
||||||
|
|
||||||
|
const std::vector expectedWindowOrder = {
|
||||||
|
windows + 4,
|
||||||
|
windows + 3,
|
||||||
|
windows + 2,
|
||||||
|
windows + 1,
|
||||||
|
windows + 0
|
||||||
|
};
|
||||||
|
|
||||||
|
qDebug() << LogWindows(windows + 0, stack);
|
||||||
|
|
||||||
|
QVERIFY(std::equal(expectedWindowOrder.begin(), expectedWindowOrder.end(),
|
||||||
|
getWindowsFrontToBack(&stack).begin()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
QTEST_MAIN(tst_QWasmWindowStack)
|
QTEST_MAIN(tst_QWasmWindowStack)
|
||||||
#include "tst_qwasmwindowstack.moc"
|
#include "tst_qwasmwindowstack.moc"
|
||||||
|
@ -6,28 +6,33 @@
|
|||||||
#include <QTest>
|
#include <QTest>
|
||||||
#include <emscripten/val.h>
|
#include <emscripten/val.h>
|
||||||
|
|
||||||
class QWasmWindow
|
class TestQWindow
|
||||||
{
|
{
|
||||||
|
public:
|
||||||
|
int flags() { return 0; }
|
||||||
|
QVariant property(const char *) { return QVariant(); }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class TestWindowTreeNode;
|
||||||
|
|
||||||
using OnSubtreeChangedCallback = std::function<void(
|
using OnSubtreeChangedCallback = std::function<void(
|
||||||
QWasmWindowTreeNodeChangeType changeType, QWasmWindowTreeNode *parent, QWasmWindow *child)>;
|
QWasmWindowTreeNodeChangeType changeType, QWasmWindowTreeNode<TestWindowTreeNode> *parent, TestWindowTreeNode *child)>;
|
||||||
using SetWindowZOrderCallback = std::function<void(QWasmWindow *window, int z)>;
|
using SetWindowZOrderCallback = std::function<void(TestWindowTreeNode *window, int z)>;
|
||||||
|
|
||||||
struct OnSubtreeChangedCallData
|
struct OnSubtreeChangedCallData
|
||||||
{
|
{
|
||||||
QWasmWindowTreeNodeChangeType changeType;
|
QWasmWindowTreeNodeChangeType changeType;
|
||||||
QWasmWindowTreeNode *parent;
|
QWasmWindowTreeNode<TestWindowTreeNode> *parent;
|
||||||
QWasmWindow *child;
|
TestWindowTreeNode *child;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct SetWindowZOrderCallData
|
struct SetWindowZOrderCallData
|
||||||
{
|
{
|
||||||
QWasmWindow *window;
|
TestWindowTreeNode *window;
|
||||||
int z;
|
int z;
|
||||||
};
|
};
|
||||||
|
|
||||||
class TestWindowTreeNode final : public QWasmWindowTreeNode, public QWasmWindow
|
class TestWindowTreeNode final : public QWasmWindowTreeNode<TestWindowTreeNode>
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
TestWindowTreeNode(OnSubtreeChangedCallback onSubtreeChangedCallback,
|
TestWindowTreeNode(OnSubtreeChangedCallback onSubtreeChangedCallback,
|
||||||
@ -42,7 +47,7 @@ public:
|
|||||||
{
|
{
|
||||||
auto *previous = m_parent;
|
auto *previous = m_parent;
|
||||||
m_parent = parent;
|
m_parent = parent;
|
||||||
onParentChanged(previous, parent, QWasmWindowStack::PositionPreference::Regular);
|
onParentChanged(previous, parent, QWasmWindowStack<TestWindowTreeNode>::PositionPreference::Regular);
|
||||||
}
|
}
|
||||||
|
|
||||||
void setContainerElement(emscripten::val container) { m_containerElement = container; }
|
void setContainerElement(emscripten::val container) { m_containerElement = container; }
|
||||||
@ -51,30 +56,42 @@ public:
|
|||||||
|
|
||||||
void sendToBottom() { QWasmWindowTreeNode::sendToBottom(); }
|
void sendToBottom() { QWasmWindowTreeNode::sendToBottom(); }
|
||||||
|
|
||||||
const QWasmWindowStack &childStack() { return QWasmWindowTreeNode::childStack(); }
|
const QWasmWindowStack<TestWindowTreeNode> &childStack() { return QWasmWindowTreeNode::childStack(); }
|
||||||
|
|
||||||
emscripten::val containerElement() final { return m_containerElement; }
|
emscripten::val containerElement() final { return m_containerElement; }
|
||||||
|
|
||||||
QWasmWindowTreeNode *parentNode() final { return m_parent; }
|
QWasmWindowTreeNode *parentNode() final { return m_parent; }
|
||||||
|
|
||||||
QWasmWindow *asWasmWindow() final { return this; }
|
TestWindowTreeNode *asWasmWindow() final { return this; }
|
||||||
|
TestWindowTreeNode *transientParent() const {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
TestQWindow *window() { return &m_qWindow; }
|
||||||
|
void requestActivateWindow() { ; }
|
||||||
|
void setZOrder(int) { ; }
|
||||||
|
bool isModal() const { return false; }
|
||||||
|
Qt::WindowFlags windowFlags() const { return Qt::WindowFlags(); }
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void onSubtreeChanged(QWasmWindowTreeNodeChangeType changeType, QWasmWindowTreeNode *parent,
|
void onSubtreeChanged(QWasmWindowTreeNodeChangeType changeType, QWasmWindowTreeNode<TestWindowTreeNode> *parent,
|
||||||
QWasmWindow *child) final
|
TestWindowTreeNode *child) final
|
||||||
{
|
{
|
||||||
m_onSubtreeChangedCallback(changeType, parent, child);
|
m_onSubtreeChangedCallback(changeType, parent, child);
|
||||||
}
|
}
|
||||||
|
|
||||||
void setWindowZOrder(QWasmWindow *window, int z) final { m_setWindowZOrderCallback(window, z); }
|
void setWindowZOrder(TestWindowTreeNode *window, int z) final { m_setWindowZOrderCallback(window, z); }
|
||||||
|
|
||||||
TestWindowTreeNode *m_parent = nullptr;
|
TestWindowTreeNode *m_parent = nullptr;
|
||||||
emscripten::val m_containerElement = emscripten::val::undefined();
|
emscripten::val m_containerElement = emscripten::val::undefined();
|
||||||
|
|
||||||
OnSubtreeChangedCallback m_onSubtreeChangedCallback;
|
OnSubtreeChangedCallback m_onSubtreeChangedCallback;
|
||||||
SetWindowZOrderCallback m_setWindowZOrderCallback;
|
SetWindowZOrderCallback m_setWindowZOrderCallback;
|
||||||
|
TestQWindow m_qWindow;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#define QWasmWindowTreeNode QWasmWindowTreeNode<TestWindowTreeNode>
|
||||||
|
#define QWasmWindow TestWindowTreeNode
|
||||||
|
|
||||||
class tst_QWasmWindowTreeNode : public QObject
|
class tst_QWasmWindowTreeNode : public QObject
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
Loading…
x
Reference in New Issue
Block a user