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) QWasmCompositor::QWasmCompositor(QWasmScreen *screen)
: QObject(screen), : QObject(screen),
m_windowManipulation(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_blitter(new QOpenGLTextureBlitter),
m_eventTranslator(std::make_unique<QWasmEventTranslator>()) m_eventTranslator(std::make_unique<QWasmEventTranslator>())
{ {
@ -174,6 +174,7 @@ void QWasmCompositor::addWindow(QWasmWindow *window)
{ {
m_windowVisibility.insert(window, false); m_windowVisibility.insert(window, false);
m_windowStack.pushWindow(window); m_windowStack.pushWindow(window);
m_windowStack.topWindow()->requestActivateWindow();
} }
void QWasmCompositor::removeWindow(QWasmWindow *window) void QWasmCompositor::removeWindow(QWasmWindow *window)
@ -181,6 +182,8 @@ void QWasmCompositor::removeWindow(QWasmWindow *window)
m_windowVisibility.remove(window); m_windowVisibility.remove(window);
m_requestUpdateWindows.remove(window); m_requestUpdateWindows.remove(window);
m_windowStack.removeWindow(window); m_windowStack.removeWindow(window);
if (m_windowStack.topWindow())
m_windowStack.topWindow()->requestActivateWindow();
} }
void QWasmCompositor::setVisible(QWasmWindow *window, bool visible) 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(); requestUpdate();
} }

View File

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

View File

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

View File

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

View File

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

View File

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