diff --git a/src/plugins/platforms/wasm/qwasmevent.cpp b/src/plugins/platforms/wasm/qwasmevent.cpp index 5ff6f4f12cc..0278ad4af55 100644 --- a/src/plugins/platforms/wasm/qwasmevent.cpp +++ b/src/plugins/platforms/wasm/qwasmevent.cpp @@ -62,6 +62,8 @@ Qt::Key webKeyToQtKey(const std::string &code, const std::string &key, bool isDe return Qt::Key_unknown; } } else if (auto mapping = QWasmKeyTranslator::mapWebKeyTextToQtKey(key.c_str())) { + if (modifiers.testFlag(Qt::ShiftModifier) && (*mapping == Qt::Key::Key_Tab)) + *mapping = Qt::Key::Key_Backtab; return *mapping; } diff --git a/src/plugins/platforms/wasm/qwasminputcontext.cpp b/src/plugins/platforms/wasm/qwasminputcontext.cpp index df4b95b7b4b..5ce24588973 100644 --- a/src/plugins/platforms/wasm/qwasminputcontext.cpp +++ b/src/plugins/platforms/wasm/qwasminputcontext.cpp @@ -352,16 +352,16 @@ void QWasmInputContext::setFocusObject(QObject *object) if (m_focusObject && !m_preeditString.isEmpty()) commitPreeditAndClear(); - if (inputMethodAccepted()) { + if (object) { m_inputElement.call("focus"); - m_usingTextInput = true; - + m_usingTextInput = inputMethodAccepted(); m_focusObject = object; - } else { + } else if (m_focusObject) { m_inputElement.call("blur"); m_usingTextInput = false; - m_focusObject = nullptr; + } else { + m_usingTextInput = false; } QPlatformInputContext::setFocusObject(object); } diff --git a/src/plugins/platforms/wasm/qwasmwindow.cpp b/src/plugins/platforms/wasm/qwasmwindow.cpp index 8b01b9d33e7..65277e78d44 100644 --- a/src/plugins/platforms/wasm/qwasmwindow.cpp +++ b/src/plugins/platforms/wasm/qwasmwindow.cpp @@ -133,6 +133,8 @@ QWasmWindow::QWasmWindow(QWindow *w, QWasmDeadKeySupport *deadKeySupport, QWasmWindow::~QWasmWindow() { + shutdown(); + emscripten::val::module_property("specialHTMLTargets").delete_(canvasSelector()); m_canvasContainer.call("removeChild", m_canvas); m_context2d = emscripten::val::undefined(); diff --git a/src/plugins/platforms/wasm/qwasmwindowtreenode.cpp b/src/plugins/platforms/wasm/qwasmwindowtreenode.cpp index f11adf9b78c..08eb7e327b1 100644 --- a/src/plugins/platforms/wasm/qwasmwindowtreenode.cpp +++ b/src/plugins/platforms/wasm/qwasmwindowtreenode.cpp @@ -4,6 +4,9 @@ #include "qwasmwindowtreenode.h" #include "qwasmwindow.h" +#include "qwasmscreen.h" + +uint64_t QWasmWindowTreeNode::s_nextActiveIndex = 0; QWasmWindowTreeNode::QWasmWindowTreeNode() : m_childStack(std::bind(&QWasmWindowTreeNode::onTopWindowChanged, this)) @@ -12,6 +15,39 @@ QWasmWindowTreeNode::QWasmWindowTreeNode() 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 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) @@ -73,6 +109,9 @@ void QWasmWindowTreeNode::setAsActiveNode() { if (parentNode()) parentNode()->setActiveChildNode(asWasmWindow()); + + // At the end, this is a recursive function + m_activeIndex = ++s_nextActiveIndex; } void QWasmWindowTreeNode::bringToTop() diff --git a/src/plugins/platforms/wasm/qwasmwindowtreenode.h b/src/plugins/platforms/wasm/qwasmwindowtreenode.h index 344fdb43cbd..170d777f02a 100644 --- a/src/plugins/platforms/wasm/qwasmwindowtreenode.h +++ b/src/plugins/platforms/wasm/qwasmwindowtreenode.h @@ -38,14 +38,22 @@ protected: void setAsActiveNode(); void bringToTop(); void sendToBottom(); + void shutdown(); const QWasmWindowStack &childStack() const { return m_childStack; } QWasmWindow *activeChild() const { return m_activeChild; } + uint64_t getActiveIndex() const { + return m_activeIndex; + } + private: void onTopWindowChanged(); void setActiveChildNode(QWasmWindow *activeChild); + uint64_t m_activeIndex = 0; + static uint64_t s_nextActiveIndex; + QWasmWindowStack m_childStack; QWasmWindow *m_activeChild = nullptr; }; diff --git a/tests/auto/wasm/selenium/qwasmwindow.py b/tests/auto/wasm/selenium/qwasmwindow.py index d02272c432b..73ee2745d0b 100644 --- a/tests/auto/wasm/selenium/qwasmwindow.py +++ b/tests/auto/wasm/selenium/qwasmwindow.py @@ -68,6 +68,18 @@ class WidgetTestCase(unittest.TestCase): self.assertEqual(w2.hasFocus(), False) self.assertEqual(w3.hasFocus(), True) + w3.close(); + self.assertEqual(w0.hasFocus(), False) + self.assertEqual(w1.hasFocus(), False) + self.assertEqual(w2.hasFocus(), True) + + w2.close(); + self.assertEqual(w0.hasFocus(), True) + self.assertEqual(w1.hasFocus(), False) + + w1.close(); + self.assertEqual(w0.hasFocus(), True) + clearWidgets(self._driver) #Looks weird, no asserts, the test is that @@ -691,6 +703,13 @@ class Widget: ''' ) + def close(self): + self.driver.execute_script( + f''' + instance.closeWidget('{self.name}'); + ''' + ) + class Window: def __init__(self, parent=None, rect=None, title=None, element=None, visible=True, opengl=0): self.driver = parent.driver diff --git a/tests/auto/wasm/selenium/tst_qwasmwindow_harness.cpp b/tests/auto/wasm/selenium/tst_qwasmwindow_harness.cpp index 5a8246935c3..443a32ea1dd 100644 --- a/tests/auto/wasm/selenium/tst_qwasmwindow_harness.cpp +++ b/tests/auto/wasm/selenium/tst_qwasmwindow_harness.cpp @@ -455,6 +455,16 @@ public: m_spinBoxes[name] = spinBox; } + bool closeWidget(const std::string &name) + { + TestWidget *widget = findWidget(name); + if (!widget) + return false; + + widget->close(); + return true; + } + private: using TestWidgetPtr = std::shared_ptr; @@ -603,6 +613,11 @@ void activateWidget(const std::string &name) w->activateWindow(); } +bool closeWidget(const std::string &name) +{ + return WidgetStorage::getInstance()->closeWidget(name); +} + void clearWidgets() { WidgetStorage::clearInstance(); @@ -751,6 +766,7 @@ EMSCRIPTEN_BINDINGS(qwasmwindow) emscripten::function("showToolTipWidget", &showToolTipWidget); emscripten::function("setWidgetNoFocusShow", &setWidgetNoFocusShow); emscripten::function("showWidget", &showWidget); + emscripten::function("closeWidget", &closeWidget); emscripten::function("activateWidget", &activateWidget); emscripten::function("hasWidgetFocus", &hasWidgetFocus); emscripten::function("clearWidgets", &clearWidgets);