Resolve window focusing problems on WASM

- Moved the modal window resolution to
QWasmWindow::requestActivateWindow so that multiple async activation
events are not issued in unpredictable patterns.
- Request activation on added windows and on stack top in case of
window removal

Pick-to: 6.4
Change-Id: I6f02cf1b7e83abb7961caf311ffc83e91c8bf810
Reviewed-by: Morten Johan Sørvig <morten.sorvig@qt.io>
This commit is contained in:
Mikolaj Boc 2022-08-23 14:24:36 +02:00
parent 0acb56518d
commit 11f12521bc
6 changed files with 30 additions and 53 deletions

View File

@ -53,7 +53,7 @@ EMSCRIPTEN_BINDINGS(qtMouseModule) {
QWasmCompositor::QWasmCompositor(QWasmScreen *screen)
: QObject(screen),
m_windowManipulation(screen),
m_windowStack(std::bind(&QWasmCompositor::onTopWindowChanged, this, std::placeholders::_1)),
m_windowStack(std::bind(&QWasmCompositor::onTopWindowChanged, this)),
m_blitter(new QOpenGLTextureBlitter),
m_eventTranslator(std::make_unique<QWasmEventTranslator>())
{
@ -174,6 +174,7 @@ void QWasmCompositor::addWindow(QWasmWindow *window)
{
m_windowVisibility.insert(window, false);
m_windowStack.pushWindow(window);
m_windowStack.topWindow()->requestActivateWindow();
}
void QWasmCompositor::removeWindow(QWasmWindow *window)
@ -181,6 +182,8 @@ void QWasmCompositor::removeWindow(QWasmWindow *window)
m_windowVisibility.remove(window);
m_requestUpdateWindows.remove(window);
m_windowStack.removeWindow(window);
if (m_windowStack.topWindow())
m_windowStack.topWindow()->requestActivateWindow();
}
void QWasmCompositor::setVisible(QWasmWindow *window, bool visible)
@ -755,21 +758,8 @@ void QWasmCompositor::WindowManipulation::resizeWindow(const QPoint& amount)
));
}
void QWasmCompositor::onTopWindowChanged(QWasmWindow *window)
void QWasmCompositor::onTopWindowChanged()
{
if (!QGuiApplication::focusWindow())
window->requestActivateWindow();
QWindow *modalWindow;
const bool isTargetWindowBlocked =
QGuiApplicationPrivate::instance()->isWindowBlocked(window->window(), &modalWindow);
if (isTargetWindowBlocked) {
modalWindow->requestActivate();
raise(asWasmWindow(modalWindow));
return;
}
requestUpdate();
}

View File

@ -176,7 +176,7 @@ private:
std::unique_ptr<OperationState> m_state;
};
void onTopWindowChanged(QWasmWindow *window);
void onTopWindowChanged();
void drawWindow(QOpenGLTextureBlitter *blitter, QWasmScreen *screen, const QWasmWindow *window);
void drawWindowContent(QOpenGLTextureBlitter *blitter, QWasmScreen *screen,
const QWasmWindow *window);

View File

@ -421,6 +421,12 @@ bool QWasmWindow::windowIsPopupType(Qt::WindowFlags flags) const
void QWasmWindow::requestActivateWindow()
{
QWindow *modalWindow;
if (QGuiApplicationPrivate::instance()->isWindowBlocked(window(), &modalWindow)) {
static_cast<QWasmWindow *>(modalWindow->handle())->requestActivateWindow();
return;
}
if (window()->isTopLevel())
raise();
QPlatformWindow::requestActivateWindow();

View File

@ -18,7 +18,7 @@ void QWasmWasmWindowStack::pushWindow(QWasmWindow *window)
m_windowStack.push_back(window);
m_topWindowChangedCallback(window);
m_topWindowChangedCallback();
}
void QWasmWasmWindowStack::removeWindow(QWasmWindow *window)
@ -34,7 +34,7 @@ void QWasmWasmWindowStack::removeWindow(QWasmWindow *window)
m_windowStack.erase(it);
if (removingTop)
m_topWindowChangedCallback(topWindow());
m_topWindowChangedCallback();
}
void QWasmWasmWindowStack::raise(QWasmWindow *window)
@ -46,7 +46,7 @@ void QWasmWasmWindowStack::raise(QWasmWindow *window)
auto it = std::find(regularWindowsBegin(), m_windowStack.end(), window);
std::rotate(it, it + 1, m_windowStack.end());
m_topWindowChangedCallback(topWindow());
m_topWindowChangedCallback();
}
void QWasmWasmWindowStack::lower(QWasmWindow *window)
@ -60,7 +60,7 @@ void QWasmWasmWindowStack::lower(QWasmWindow *window)
auto it = std::find(regularWindowsBegin(), m_windowStack.end(), window);
std::rotate(regularWindowsBegin(), it, it + 1);
if (loweringTopWindow && topWindow() != window)
m_topWindowChangedCallback(topWindow());
m_topWindowChangedCallback();
}
QWasmWasmWindowStack::iterator QWasmWasmWindowStack::begin()

View File

@ -24,7 +24,7 @@ class QWasmWindow;
Q_AUTOTEST_EXPORT class QWasmWasmWindowStack
{
public:
using TopWindowChangedCallbackType = std::function<void(QWasmWindow *window)>;
using TopWindowChangedCallbackType = std::function<void()>;
using StorageType = QList<QWasmWindow *>;

View File

@ -23,8 +23,7 @@ class tst_QWasmWindowStack : public QObject
public:
tst_QWasmWindowStack()
: m_mockCallback(
std::bind(&tst_QWasmWindowStack::onTopWindowChanged, this, std::placeholders::_1))
: m_mockCallback(std::bind(&tst_QWasmWindowStack::onTopWindowChanged, this))
{
}
@ -39,11 +38,11 @@ private slots:
void removingTheRoot();
private:
void onTopWindowChanged(QWasmWindow *topWindow)
void onTopWindowChanged()
{
++m_topLevelChangedCallCount;
if (m_onTopLevelChangedAction)
m_onTopLevelChangedAction(topWindow);
m_onTopLevelChangedAction();
}
void verifyTopWindowChangedCalled(int expected = 1)
@ -76,19 +75,15 @@ void tst_QWasmWindowStack::insertion()
{
QWasmWasmWindowStack stack(m_mockCallback);
m_onTopLevelChangedAction = [this](QWasmWindow *topWindow) { QVERIFY(topWindow == &m_root); };
m_onTopLevelChangedAction = [this, &stack]() { QVERIFY(stack.topWindow() == &m_root); };
stack.pushWindow(&m_root);
verifyTopWindowChangedCalled();
m_onTopLevelChangedAction = [this](QWasmWindow *topWindow) {
QVERIFY(topWindow == &m_window1);
};
m_onTopLevelChangedAction = [this, &stack]() { QVERIFY(stack.topWindow() == &m_window1); };
stack.pushWindow(&m_window1);
verifyTopWindowChangedCalled();
m_onTopLevelChangedAction = [this](QWasmWindow *topWindow) {
QVERIFY(topWindow == &m_window2);
};
m_onTopLevelChangedAction = [this, &stack]() { QVERIFY(stack.topWindow() == &m_window2); };
stack.pushWindow(&m_window2);
verifyTopWindowChangedCalled();
}
@ -111,9 +106,7 @@ void tst_QWasmWindowStack::raisingTheRootIsImpossible()
QCOMPARE(&m_window5, stack.topWindow());
m_onTopLevelChangedAction = [this](QWasmWindow *topWindow) {
QVERIFY(topWindow == &m_window2);
};
m_onTopLevelChangedAction = [this, &stack]() { QVERIFY(stack.topWindow() == &m_window2); };
stack.raise(&m_window2);
verifyTopWindowChangedCalled();
}
@ -133,9 +126,7 @@ void tst_QWasmWindowStack::raising()
QCOMPARE(&m_window5, stack.topWindow());
m_onTopLevelChangedAction = [this](QWasmWindow *topWindow) {
QVERIFY(topWindow == &m_window1);
};
m_onTopLevelChangedAction = [this, &stack]() { QVERIFY(stack.topWindow() == &m_window1); };
stack.raise(&m_window1);
verifyTopWindowChangedCalled();
QCOMPARE(&m_window1, stack.topWindow());
@ -144,9 +135,7 @@ void tst_QWasmWindowStack::raising()
verifyTopWindowChangedCalled(0);
QCOMPARE(&m_window1, stack.topWindow());
m_onTopLevelChangedAction = [this](QWasmWindow *topWindow) {
QVERIFY(topWindow == &m_window3);
};
m_onTopLevelChangedAction = [this, &stack]() { QVERIFY(stack.topWindow() == &m_window3); };
stack.raise(&m_window3);
verifyTopWindowChangedCalled();
QCOMPARE(&m_window3, stack.topWindow());
@ -168,9 +157,7 @@ void tst_QWasmWindowStack::lowering()
QCOMPARE(&m_window5, stack.topWindow());
m_onTopLevelChangedAction = [this](QWasmWindow *topWindow) {
QVERIFY(topWindow == &m_window4);
};
m_onTopLevelChangedAction = [this, &stack]() { QVERIFY(stack.topWindow() == &m_window4); };
stack.lower(&m_window5);
// Window order: 4 3 2 1 5 R
verifyTopWindowChangedCalled();
@ -201,9 +188,7 @@ void tst_QWasmWindowStack::removing()
QCOMPARE(&m_window5, stack.topWindow());
m_onTopLevelChangedAction = [this](QWasmWindow *topWindow) {
QVERIFY(topWindow == &m_window4);
};
m_onTopLevelChangedAction = [this, &stack]() { QVERIFY(stack.topWindow() == &m_window4); };
stack.removeWindow(&m_window5);
// Window order: 4 3 2 1 R
verifyTopWindowChangedCalled();
@ -237,9 +222,7 @@ void tst_QWasmWindowStack::removingTheRoot()
verifyTopWindowChangedCalled(0);
QCOMPARE(&m_window3, stack.topWindow());
m_onTopLevelChangedAction = [this](QWasmWindow *topWindow) {
QVERIFY(topWindow == &m_window1);
};
m_onTopLevelChangedAction = [this, &stack]() { QVERIFY(stack.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
@ -248,9 +231,7 @@ void tst_QWasmWindowStack::removingTheRoot()
QVERIFY(std::equal(expectedWindowOrder.begin(), expectedWindowOrder.end(),
getWindowsFrontToBack(&stack).begin()));
m_onTopLevelChangedAction = [this](QWasmWindow *topWindow) {
QVERIFY(topWindow == &m_window3);
};
m_onTopLevelChangedAction = [this, &stack]() { QVERIFY(stack.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