Correctly focus WASM windows on show
Since first requestActivate may happen before the window div is actually displayed on-screen, we need to sync Qt's activation state with DOM as soon as DOM element becomes visible. Focusing an invisible element is impossible. Fixes: QTBUG-79934 Change-Id: I04cf9b4ead006c9b8b135b3b6967d7938c581833 Reviewed-by: Morten Johan Sørvig <morten.sorvig@qt.io>
This commit is contained in:
parent
5d12d9846a
commit
a1704ee6aa
@ -310,6 +310,8 @@ void QWasmWindow::setVisible(bool visible)
|
|||||||
|
|
||||||
m_compositor->requestUpdateWindow(this, QWasmCompositor::ExposeEventDelivery);
|
m_compositor->requestUpdateWindow(this, QWasmCompositor::ExposeEventDelivery);
|
||||||
m_qtWindow["style"].set("display", visible ? "block" : "none");
|
m_qtWindow["style"].set("display", visible ? "block" : "none");
|
||||||
|
if (window()->isActive())
|
||||||
|
m_canvas.call<void>("focus");
|
||||||
if (visible)
|
if (visible)
|
||||||
applyWindowState();
|
applyWindowState();
|
||||||
}
|
}
|
||||||
|
@ -29,6 +29,7 @@ class WidgetTestCase(unittest.TestCase):
|
|||||||
screen = Screen(self._driver, ScreenPosition.FIXED,
|
screen = Screen(self._driver, ScreenPosition.FIXED,
|
||||||
x=0, y=0, width=600, height=600)
|
x=0, y=0, width=600, height=600)
|
||||||
window = Window(screen, x=100, y=100, width=200, height=200)
|
window = Window(screen, x=100, y=100, width=200, height=200)
|
||||||
|
window.set_visible(True)
|
||||||
self.assertEqual(window.rect, Rect(x=100, y=100, width=200, height=200))
|
self.assertEqual(window.rect, Rect(x=100, y=100, width=200, height=200))
|
||||||
|
|
||||||
window.drag(Handle.TOP_LEFT, direction=UP(10) + LEFT(10))
|
window.drag(Handle.TOP_LEFT, direction=UP(10) + LEFT(10))
|
||||||
@ -62,6 +63,7 @@ class WidgetTestCase(unittest.TestCase):
|
|||||||
screen = Screen(self._driver, ScreenPosition.FIXED,
|
screen = Screen(self._driver, ScreenPosition.FIXED,
|
||||||
x=200, y=200, width=300, height=300)
|
x=200, y=200, width=300, height=300)
|
||||||
window = Window(screen, x=300, y=300, width=100, height=100)
|
window = Window(screen, x=300, y=300, width=100, height=100)
|
||||||
|
window.set_visible(True)
|
||||||
self.assertEqual(window.rect, Rect(x=300, y=300, width=100, height=100))
|
self.assertEqual(window.rect, Rect(x=300, y=300, width=100, height=100))
|
||||||
frame_rect_before_resize = window.frame_rect
|
frame_rect_before_resize = window.frame_rect
|
||||||
|
|
||||||
@ -76,6 +78,7 @@ class WidgetTestCase(unittest.TestCase):
|
|||||||
screen = Screen(self._driver, ScreenPosition.FIXED,
|
screen = Screen(self._driver, ScreenPosition.FIXED,
|
||||||
x=200, y=200, width=300, height=300)
|
x=200, y=200, width=300, height=300)
|
||||||
window = Window(screen, x=300, y=300, width=100, height=100)
|
window = Window(screen, x=300, y=300, width=100, height=100)
|
||||||
|
window.set_visible(True)
|
||||||
self.assertEqual(window.rect, Rect(x=300, y=300, width=100, height=100))
|
self.assertEqual(window.rect, Rect(x=300, y=300, width=100, height=100))
|
||||||
|
|
||||||
window.drag(Handle.TOP_WINDOW_BAR, direction=UP(30))
|
window.drag(Handle.TOP_WINDOW_BAR, direction=UP(30))
|
||||||
@ -91,6 +94,7 @@ class WidgetTestCase(unittest.TestCase):
|
|||||||
screen = Screen(self._driver, ScreenPosition.RELATIVE,
|
screen = Screen(self._driver, ScreenPosition.RELATIVE,
|
||||||
x=200, y=200, width=300, height=300)
|
x=200, y=200, width=300, height=300)
|
||||||
window = Window(screen, x=300, y=300, width=100, height=100)
|
window = Window(screen, x=300, y=300, width=100, height=100)
|
||||||
|
window.set_visible(True)
|
||||||
self.assertEqual(window.rect, Rect(x=300, y=300, width=100, height=100))
|
self.assertEqual(window.rect, Rect(x=300, y=300, width=100, height=100))
|
||||||
|
|
||||||
window.drag(Handle.TOP_WINDOW_BAR, direction=LEFT(300))
|
window.drag(Handle.TOP_WINDOW_BAR, direction=LEFT(300))
|
||||||
@ -102,6 +106,7 @@ class WidgetTestCase(unittest.TestCase):
|
|||||||
container_width=500, container_height=7000)
|
container_width=500, container_height=7000)
|
||||||
screen.scroll_to()
|
screen.scroll_to()
|
||||||
window = Window(screen, x=300, y=2100, width=100, height=100)
|
window = Window(screen, x=300, y=2100, width=100, height=100)
|
||||||
|
window.set_visible(True)
|
||||||
self.assertEqual(window.rect, Rect(x=300, y=2100, width=100, height=100))
|
self.assertEqual(window.rect, Rect(x=300, y=2100, width=100, height=100))
|
||||||
|
|
||||||
window.drag(Handle.TOP_WINDOW_BAR, direction=LEFT(300))
|
window.drag(Handle.TOP_WINDOW_BAR, direction=LEFT(300))
|
||||||
@ -111,6 +116,7 @@ class WidgetTestCase(unittest.TestCase):
|
|||||||
screen = Screen(self._driver, ScreenPosition.RELATIVE,
|
screen = Screen(self._driver, ScreenPosition.RELATIVE,
|
||||||
x=200, y=200, width=300, height=300)
|
x=200, y=200, width=300, height=300)
|
||||||
window = Window(screen, x=300, y=300, width=100, height=100, title='Maximize')
|
window = Window(screen, x=300, y=300, width=100, height=100, title='Maximize')
|
||||||
|
window.set_visible(True)
|
||||||
self.assertEqual(window.rect, Rect(x=300, y=300, width=100, height=100))
|
self.assertEqual(window.rect, Rect(x=300, y=300, width=100, height=100))
|
||||||
|
|
||||||
window.maximize()
|
window.maximize()
|
||||||
@ -122,6 +128,9 @@ class WidgetTestCase(unittest.TestCase):
|
|||||||
windows = [Window(screen, x=50, y=50, width=100, height=100, title='First'),
|
windows = [Window(screen, x=50, y=50, width=100, height=100, title='First'),
|
||||||
Window(screen, x=400, y=400, width=100, height=100, title='Second'),
|
Window(screen, x=400, y=400, width=100, height=100, title='Second'),
|
||||||
Window(screen, x=50, y=400, width=100, height=100, title='Third')]
|
Window(screen, x=50, y=400, width=100, height=100, title='Third')]
|
||||||
|
for window in windows:
|
||||||
|
window.set_visible(True)
|
||||||
|
|
||||||
self.assertEqual(windows[0].rect, Rect(x=50, y=50, width=100, height=100))
|
self.assertEqual(windows[0].rect, Rect(x=50, y=50, width=100, height=100))
|
||||||
self.assertEqual(windows[1].rect, Rect(x=400, y=400, width=100, height=100))
|
self.assertEqual(windows[1].rect, Rect(x=400, y=400, width=100, height=100))
|
||||||
self.assertEqual(windows[2].rect, Rect(x=50, y=400, width=100, height=100))
|
self.assertEqual(windows[2].rect, Rect(x=50, y=400, width=100, height=100))
|
||||||
@ -140,6 +149,9 @@ class WidgetTestCase(unittest.TestCase):
|
|||||||
windows = [Window(screen, x=50, y=50, width=150, height=150, title='First'),
|
windows = [Window(screen, x=50, y=50, width=150, height=150, title='First'),
|
||||||
Window(screen, x=400, y=400, width=150, height=150, title='Second'),
|
Window(screen, x=400, y=400, width=150, height=150, title='Second'),
|
||||||
Window(screen, x=50, y=400, width=150, height=150, title='Third')]
|
Window(screen, x=50, y=400, width=150, height=150, title='Third')]
|
||||||
|
for window in windows:
|
||||||
|
window.set_visible(True)
|
||||||
|
|
||||||
self.assertEqual(windows[0].rect, Rect(x=50, y=50, width=150, height=150))
|
self.assertEqual(windows[0].rect, Rect(x=50, y=50, width=150, height=150))
|
||||||
self.assertEqual(windows[1].rect, Rect(x=400, y=400, width=150, height=150))
|
self.assertEqual(windows[1].rect, Rect(x=400, y=400, width=150, height=150))
|
||||||
self.assertEqual(windows[2].rect, Rect(x=50, y=400, width=150, height=150))
|
self.assertEqual(windows[2].rect, Rect(x=50, y=400, width=150, height=150))
|
||||||
@ -152,6 +164,21 @@ class WidgetTestCase(unittest.TestCase):
|
|||||||
self.assertEqual(windows[1].rect, Rect(x=400, y=420, width=150, height=130))
|
self.assertEqual(windows[1].rect, Rect(x=400, y=420, width=150, height=130))
|
||||||
self.assertEqual(windows[2].rect, Rect(x=50, y=400, width=170, height=130))
|
self.assertEqual(windows[2].rect, Rect(x=50, y=400, width=170, height=130))
|
||||||
|
|
||||||
|
def test_newly_created_window_gets_keyboard_focus(self):
|
||||||
|
screen = Screen(self._driver, ScreenPosition.FIXED,
|
||||||
|
x=0, y=0, width=800, height=800)
|
||||||
|
window = Window(screen, x=0, y=0, width=800, height=800, title='root')
|
||||||
|
window.set_visible(True)
|
||||||
|
|
||||||
|
ActionChains(self._driver).key_down('c').key_up('c').perform()
|
||||||
|
|
||||||
|
events = window.events
|
||||||
|
self.assertEqual(len(events), 2)
|
||||||
|
self.assertEqual(events[-2]['type'], 'keyPress')
|
||||||
|
self.assertEqual(events[-2]['key'], 'c')
|
||||||
|
self.assertEqual(events[-1]['type'], 'keyRelease')
|
||||||
|
self.assertEqual(events[-1]['key'], 'c')
|
||||||
|
|
||||||
def tearDown(self):
|
def tearDown(self):
|
||||||
self._driver.quit()
|
self._driver.quit()
|
||||||
|
|
||||||
@ -227,6 +254,20 @@ class Window:
|
|||||||
geo = self.__window_information()["frameGeometry"]
|
geo = self.__window_information()["frameGeometry"]
|
||||||
return Rect(geo['x'], geo['y'], geo['width'], geo['height'])
|
return Rect(geo['x'], geo['y'], geo['width'], geo['height'])
|
||||||
|
|
||||||
|
@property
|
||||||
|
def events(self):
|
||||||
|
events = self.driver.execute_script(
|
||||||
|
f'''
|
||||||
|
return testSupport.events();
|
||||||
|
'''
|
||||||
|
)
|
||||||
|
return [*filter(lambda e: e['windowTitle'] == self.title, events)]
|
||||||
|
|
||||||
|
def set_visible(self, visible):
|
||||||
|
info = self.__window_information()
|
||||||
|
self.driver.execute_script(
|
||||||
|
f'''instance.setWindowVisible({info['id']}, {'true' if visible else 'false'});''')
|
||||||
|
|
||||||
def drag(self, handle, direction):
|
def drag(self, handle, direction):
|
||||||
ActionChains(self.driver) \
|
ActionChains(self.driver) \
|
||||||
.move_to_element_with_offset(self.element, *self.at(handle)['offset']) \
|
.move_to_element_with_offset(self.element, *self.at(handle)['offset']) \
|
||||||
|
@ -2,6 +2,8 @@
|
|||||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
|
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
|
||||||
|
|
||||||
#include <QtCore/QEvent>
|
#include <QtCore/QEvent>
|
||||||
|
|
||||||
|
#include <QtGui/qevent.h>
|
||||||
#include <QtCore/qobject.h>
|
#include <QtCore/qobject.h>
|
||||||
#include <QtCore/qregularexpression.h>
|
#include <QtCore/qregularexpression.h>
|
||||||
#include <QtGui/qscreen.h>
|
#include <QtGui/qscreen.h>
|
||||||
@ -26,6 +28,26 @@ private:
|
|||||||
Q_UNUSED(ev);
|
Q_UNUSED(ev);
|
||||||
delete this;
|
delete this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void keyPressEvent(QKeyEvent *event) final
|
||||||
|
{
|
||||||
|
auto data = emscripten::val::object();
|
||||||
|
data.set("type", emscripten::val("keyPress"));
|
||||||
|
data.set("windowId", emscripten::val(winId()));
|
||||||
|
data.set("windowTitle", emscripten::val(title().toStdString()));
|
||||||
|
data.set("key", emscripten::val(event->text().toStdString()));
|
||||||
|
emscripten::val::global("window")["testSupport"].call<void>("reportEvent", std::move(data));
|
||||||
|
}
|
||||||
|
|
||||||
|
void keyReleaseEvent(QKeyEvent *event) final
|
||||||
|
{
|
||||||
|
auto data = emscripten::val::object();
|
||||||
|
data.set("type", emscripten::val("keyRelease"));
|
||||||
|
data.set("windowId", emscripten::val(winId()));
|
||||||
|
data.set("windowTitle", emscripten::val(title().toStdString()));
|
||||||
|
data.set("key", emscripten::val(event->text().toStdString()));
|
||||||
|
emscripten::val::global("window")["testSupport"].call<void>("reportEvent", std::move(data));
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
using namespace emscripten;
|
using namespace emscripten;
|
||||||
@ -128,7 +150,19 @@ void createWindow(int x, int y, int w, int h, std::string screenId, std::string
|
|||||||
window->setTitle(QString::fromLatin1(title));
|
window->setTitle(QString::fromLatin1(title));
|
||||||
window->setGeometry(x, y, w, h);
|
window->setGeometry(x, y, w, h);
|
||||||
window->setScreen(*screen_it);
|
window->setScreen(*screen_it);
|
||||||
window->showNormal();
|
}
|
||||||
|
|
||||||
|
void setWindowVisible(int windowId, bool visible) {
|
||||||
|
auto windows = qGuiApp->allWindows();
|
||||||
|
auto window_it = std::find_if(windows.begin(), windows.end(), [windowId](QWindow *window) {
|
||||||
|
return window->winId() == WId(windowId);
|
||||||
|
});
|
||||||
|
if (window_it == windows.end()) {
|
||||||
|
qWarning() << "No such window: " << windowId;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
(*window_it)->setVisible(visible);
|
||||||
}
|
}
|
||||||
|
|
||||||
EMSCRIPTEN_BINDINGS(qwasmwindow)
|
EMSCRIPTEN_BINDINGS(qwasmwindow)
|
||||||
@ -136,6 +170,7 @@ EMSCRIPTEN_BINDINGS(qwasmwindow)
|
|||||||
emscripten::function("screenInformation", &screenInformation);
|
emscripten::function("screenInformation", &screenInformation);
|
||||||
emscripten::function("windowInformation", &windowInformation);
|
emscripten::function("windowInformation", &windowInformation);
|
||||||
emscripten::function("createWindow", &createWindow);
|
emscripten::function("createWindow", &createWindow);
|
||||||
|
emscripten::function("setWindowVisible", &setWindowVisible);
|
||||||
}
|
}
|
||||||
|
|
||||||
int main(int argc, char **argv)
|
int main(int argc, char **argv)
|
||||||
|
@ -11,6 +11,8 @@
|
|||||||
testSandbox.id = 'test-sandbox';
|
testSandbox.id = 'test-sandbox';
|
||||||
document.body.appendChild(testSandbox);
|
document.body.appendChild(testSandbox);
|
||||||
|
|
||||||
|
const eventList = [];
|
||||||
|
|
||||||
const makeSizedDiv = (left, top, width, height) => {
|
const makeSizedDiv = (left, top, width, height) => {
|
||||||
const screenDiv = document.createElement('div');
|
const screenDiv = document.createElement('div');
|
||||||
|
|
||||||
@ -56,7 +58,11 @@
|
|||||||
instance.qtAddContainerElement(screenDiv);
|
instance.qtAddContainerElement(screenDiv);
|
||||||
|
|
||||||
return [scrollContainer, screenDiv];
|
return [scrollContainer, screenDiv];
|
||||||
}
|
},
|
||||||
|
reportEvent: event => {
|
||||||
|
eventList.push(event);
|
||||||
|
},
|
||||||
|
events: () => eventList
|
||||||
};
|
};
|
||||||
})();
|
})();
|
||||||
</script>
|
</script>
|
||||||
|
Loading…
Reference in New Issue
Block a user