wasm: Qt::WA_ShowWithoutActivating was not respected

The Qt::WA_ShowWithoutActivating flag was not respected
Added test in the part of the code that calls
requestActivateWindow

Added selenium focus test

Fixes: QTBUG-122776
Change-Id: I1a248ed4352f86376d615a4cb7022e7ea095d4e7
Reviewed-by: Piotr Wierciński <piotr.wiercinski@qt.io>
This commit is contained in:
Even Oscar Andersen 2024-02-26 12:46:35 +08:00
parent edb8bac39b
commit 0737fca6b2
4 changed files with 224 additions and 8 deletions

View File

@ -39,8 +39,12 @@ void QWasmWindowTreeNode::onSubtreeChanged(QWasmWindowTreeNodeChangeType changeT
QWasmWindowTreeNode *parent, QWasmWindow *child)
{
if (changeType == QWasmWindowTreeNodeChangeType::NodeInsertion && parent == this
&& m_childStack.topWindow()) {
m_childStack.topWindow()->requestActivateWindow();
&& m_childStack.topWindow()
&& m_childStack.topWindow()->window()) {
const QVariant showWithoutActivating = m_childStack.topWindow()->window()->property("_q_showWithoutActivating");
if (!showWithoutActivating.isValid() || !showWithoutActivating.toBool())
m_childStack.topWindow()->requestActivateWindow();
}
if (parentNode())

View File

@ -12,6 +12,7 @@ qt_internal_add_test(tst_qwasmwindow_harness
LIBRARIES
Qt::Core
Qt::Gui
Qt::Widgets
)
if(CMAKE_HOST_WIN32)

View File

@ -27,9 +27,45 @@ class WidgetTestCase(unittest.TestCase):
self.addTypeEqualityFunc(Color, assert_colors_equal)
self.addTypeEqualityFunc(Rect, assert_rects_equal)
def test_hasFocus_returnsFalse_whenSetNoFocusShowWasCalled(self):
screen = Screen(self._driver, ScreenPosition.FIXED,
x=0, y=0, width=600, height=1200)
w0 = Widget(self._driver, "w0")
w0.show()
self.assertEqual(w0.hasFocus(), True)
w1 = Widget(self._driver, "w1")
w1.setNoFocusShow()
w1.show()
self.assertEqual(w0.hasFocus(), True)
self.assertEqual(w1.hasFocus(), False)
w2 = Widget(self._driver, "w2")
w2.show()
self.assertEqual(w0.hasFocus(), False)
self.assertEqual(w1.hasFocus(), False)
self.assertEqual(w2.hasFocus(), True)
w3 = Widget(self._driver, "w3")
w3.setNoFocusShow()
w3.show()
self.assertEqual(w0.hasFocus(), False)
self.assertEqual(w1.hasFocus(), False)
self.assertEqual(w2.hasFocus(), True)
self.assertEqual(w3.hasFocus(), False)
w3.activate();
self.assertEqual(w0.hasFocus(), False)
self.assertEqual(w1.hasFocus(), False)
self.assertEqual(w2.hasFocus(), False)
self.assertEqual(w3.hasFocus(), True)
clearWidgets(self._driver)
def test_window_resizing(self):
screen = Screen(self._driver, ScreenPosition.FIXED,
x=0, y=0, width=600, height=600)
window = Window(parent=screen, rect=Rect(x=100, y=100, width=200, height=200))
self.assertEqual(window.rect, Rect(x=100, y=100, width=200, height=200))
@ -527,6 +563,48 @@ class Screen:
shadow_container = self.element.find_element(By.CSS_SELECTOR, f'#qt-shadow-container')
return shadow_container.shadow_root.find_element(method, query)
def clearWidgets(driver):
driver.execute_script(
f'''
instance.clearWidgets();
'''
)
class Widget:
def __init__(self, driver, name):
self.name=name
self.driver=driver
self.driver.execute_script(
f'''
instance.createWidget('{self.name}');
'''
)
def setNoFocusShow(self):
self.driver.execute_script(
f'''
instance.setWidgetNoFocusShow('{self.name}');
'''
)
def show(self):
self.driver.execute_script(
f'''
instance.showWidget('{self.name}');
'''
)
def hasFocus(self):
focus = call_instance_function_arg(self.driver, 'hasWidgetFocus', self.name)
return focus
def activate(self):
self.driver.execute_script(
f'''
instance.activateWidget('{self.name}');
'''
)
class Window:
def __init__(self, parent=None, rect=None, title=None, element=None, visible=True):
@ -815,6 +893,13 @@ def call_instance_function(driver, name):
instance.{name}();
return eval(result);''')
def call_instance_function_arg(driver, name, arg):
return driver.execute_script(
f'''let result;
window.{name}Callback = data => result = data;
instance.{name}('{arg}');
return eval(result);''')
def wait_for_animation_frame(driver):
driver.execute_script(
'''

View File

@ -2,6 +2,7 @@
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
#include <QtCore/QEvent>
#include <QtWidgets/qwidget.h>
#include <QtGui/qevent.h>
#include <QtCore/qobject.h>
@ -11,6 +12,10 @@
#include <QtGui/qscreen.h>
#include <QtGui/qwindow.h>
#include <QtGui/qguiapplication.h>
#include <QtWidgets/qlineedit.h>
#include <QApplication>
#include <QDialog>
#include <QSysInfo>
#include <emscripten.h>
#include <emscripten/bind.h>
@ -20,6 +25,12 @@
#include <sstream>
#include <vector>
class TestWidget : public QDialog
{
Q_OBJECT
};
class TestWindow : public QRasterWindow
{
Q_OBJECT
@ -76,6 +87,71 @@ TestWindow *findWindowByTitle(const std::string &title)
});
return window_it == windows.end() ? nullptr : static_cast<TestWindow *>(*window_it);
}
class WidgetStorage
{
private:
~WidgetStorage()
{
}
public:
static WidgetStorage *getInstance()
{
if (!s_instance)
{
s_instance = new WidgetStorage();
}
return s_instance;
}
static void clearInstance()
{
delete s_instance;
s_instance = nullptr;
}
TestWidget *findWidget(const std::string &name)
{
auto it = m_widgets.find(name);
if (it != m_widgets.end())
return it->second.get();
return nullptr;
}
QLineEdit *findEdit(const std::string &name)
{
auto it = m_lineEdits.find(name);
if (it != m_lineEdits.end())
return it->second;
return nullptr;
}
void make(const std::string &name)
{
auto widget = std::make_shared<TestWidget>();
auto *lineEdit = new QLineEdit(widget.get());
widget->setMinimumSize(200, 200);
widget->setMaximumSize(200, 200);
widget->setGeometry(0, m_widgetY, 200, 200);
m_widgetY += 200;
lineEdit->setText("Hello world");
m_widgets[name] = widget;
m_lineEdits[name] = lineEdit;
}
private:
using TestWidgetPtr = std::shared_ptr<TestWidget>;
static WidgetStorage * s_instance;
std::map<std::string, TestWidgetPtr> m_widgets;
std::map<std::string, QLineEdit *> m_lineEdits;
int m_widgetY = 0;
};
WidgetStorage *WidgetStorage::s_instance = nullptr;
} // namespace
using namespace emscripten;
@ -161,8 +237,50 @@ void screenInformation()
emscripten::val(toJSArray(screensAsJsObjects)));
}
void createWindow(int x, int y, int w, int h, std::string parentType, std::string parentId,
std::string title)
void createWidget(const std::string &name)
{
WidgetStorage::getInstance()->make(name);
}
void setWidgetNoFocusShow(const std::string &name)
{
auto w = WidgetStorage::getInstance()->findWidget(name);
if (w)
w->setAttribute(Qt::WA_ShowWithoutActivating);
}
void showWidget(const std::string &name)
{
auto w = WidgetStorage::getInstance()->findWidget(name);
if (w)
w->show();
}
void hasWidgetFocus(const std::string &name)
{
bool focus = false;
auto le = WidgetStorage::getInstance()->findEdit(name);
if (le)
focus = le->hasFocus();
emscripten::val::global("window").call<void>("hasWidgetFocusCallback",
emscripten::val(focus));
}
void activateWidget(const std::string &name)
{
auto w = WidgetStorage::getInstance()->findWidget(name);
if (w)
w->activateWindow();
}
void clearWidgets()
{
WidgetStorage::clearInstance();
}
void createWindow(int x, int y, int w, int h, const std::string &parentType, const std::string &parentId,
const std::string &title)
{
QScreen *parentScreen = nullptr;
QWindow *parentWindow = nullptr;
@ -202,7 +320,7 @@ void createWindow(int x, int y, int w, int h, std::string parentType, std::strin
window->setParent(parentWindow);
}
void setWindowBackgroundColor(std::string title, int r, int g, int b)
void setWindowBackgroundColor(const std::string &title, int r, int g, int b)
{
auto *window = findWindowByTitle(title);
if (!window) {
@ -225,7 +343,7 @@ void setWindowVisible(int windowId, bool visible) {
(*window_it)->setVisible(visible);
}
void setWindowParent(std::string windowTitle, std::string parentTitle)
void setWindowParent(const std::string &windowTitle, const std::string &parentTitle)
{
QWindow *window = findWindowByTitle(windowTitle);
if (!window) {
@ -242,7 +360,7 @@ void setWindowParent(std::string windowTitle, std::string parentTitle)
window->setParent(parent);
}
bool closeWindow(std::string title)
bool closeWindow(const std::string &title)
{
QWindow *window = findWindowByTitle(title);
return window ? window->close() : false;
@ -252,16 +370,24 @@ EMSCRIPTEN_BINDINGS(qwasmwindow)
{
emscripten::function("screenInformation", &screenInformation);
emscripten::function("windowInformation", &windowInformation);
emscripten::function("createWindow", &createWindow);
emscripten::function("setWindowVisible", &setWindowVisible);
emscripten::function("setWindowParent", &setWindowParent);
emscripten::function("closeWindow", &closeWindow);
emscripten::function("setWindowBackgroundColor", &setWindowBackgroundColor);
emscripten::function("createWidget", &createWidget);
emscripten::function("setWidgetNoFocusShow", &setWidgetNoFocusShow);
emscripten::function("showWidget", &showWidget);
emscripten::function("activateWidget", &activateWidget);
emscripten::function("hasWidgetFocus", &hasWidgetFocus);
emscripten::function("clearWidgets", &clearWidgets);
}
int main(int argc, char **argv)
{
QGuiApplication app(argc, argv);
QApplication app(argc, argv);
app.exec();
return 0;