Fix the coordinate problems in wasm windows

The QWasmScreen's top left coordinate does not precisely translate
to correct page coordinates, especially when fixed position is used
and page margins are set. Also, this is wrong in complicated setups
with e.g. multiple nested elements.

Therefore, to get the correct coordinates in pointer event handlers,
we have to assume the local coordinates of the screen, and translate
those to the (possibly incorrect) coordinates that QWasmScreen thinks
it has in page.

It is another problem to fix the wrong coordinates QWasmScreen thinks
it has in the page.

This has been checked with complicated setups with screens in scroll
containers, screens with fixed position, screens with relative position,
with and without body margins etc.

Change-Id: I749f2507fec7ae278b6f9d7d13ae288e65472dba
Reviewed-by: Morten Johan Sørvig <morten.sorvig@qt.io>
This commit is contained in:
Mikolaj Boc 2022-12-06 08:42:34 +01:00 committed by Mikołaj Boc
parent 6d780fa0ab
commit 4d07f84307
6 changed files with 29 additions and 15 deletions

View File

@ -369,10 +369,12 @@ bool QWasmCompositor::processPointer(const PointerEvent& event)
if (event.pointerType != PointerType::Mouse)
return false;
QWindow *const targetWindow = ([this, &event]() -> QWindow * {
const auto pointInScreen = screen()->mapFromLocal(event.localPoint);
QWindow *const targetWindow = ([this, pointInScreen]() -> QWindow * {
auto *targetWindow = m_mouseCaptureWindow != nullptr ? m_mouseCaptureWindow.get()
: m_windowManipulation.operation() == WindowManipulation::Operation::None
? screen()->compositor()->windowAt(event.point, 5)
? screen()->compositor()->windowAt(pointInScreen, 5)
: nullptr;
return targetWindow ? targetWindow : m_lastMouseTargetWindow.get();
@ -381,13 +383,13 @@ bool QWasmCompositor::processPointer(const PointerEvent& event)
return false;
m_lastMouseTargetWindow = targetWindow;
const QPoint pointInTargetWindowCoords = targetWindow->mapFromGlobal(event.point);
const bool pointerIsWithinTargetWindowBounds = targetWindow->geometry().contains(event.point);
const QPoint pointInTargetWindowCoords = targetWindow->mapFromGlobal(pointInScreen);
const bool pointerIsWithinTargetWindowBounds = targetWindow->geometry().contains(pointInScreen);
if (m_mouseInScreen && m_windowUnderMouse != targetWindow
&& pointerIsWithinTargetWindowBounds) {
// delayed mouse enter
enterWindow(targetWindow, pointInTargetWindowCoords, event.point);
enterWindow(targetWindow, pointInTargetWindowCoords, pointInScreen);
m_windowUnderMouse = targetWindow;
}
@ -439,11 +441,13 @@ bool QWasmCompositor::deliverEventToTarget(const PointerEvent &event, QWindow *e
{
Q_ASSERT(!m_mouseCaptureWindow || m_mouseCaptureWindow.get() == eventTarget);
const auto pointInScreen = screen()->mapFromLocal(event.localPoint);
const QPoint targetPointClippedToScreen(
std::max(screen()->geometry().left(),
std::min(screen()->geometry().right(), event.point.x())),
std::min(screen()->geometry().right(), pointInScreen.x())),
std::max(screen()->geometry().top(),
std::min(screen()->geometry().bottom(), event.point.y())));
std::min(screen()->geometry().bottom(), pointInScreen.y())));
bool deliveringToPreviouslyClickedWindow = false;
@ -509,12 +513,13 @@ void QWasmCompositor::WindowManipulation::onPointerDown(
if (isTargetWindowBlocked)
return;
if (!asWasmWindow(windowAtPoint)->isPointOnTitle(event.point))
if (!asWasmWindow(windowAtPoint)->isPointOnTitle(event.pointInViewport))
return;
m_state.reset(new OperationState{ .pointerId = event.pointerId,
.window = windowAtPoint,
.lastPointInScreenCoords = event.point });
.lastPointInScreenCoords =
m_screen->mapFromLocal(event.localPoint) });
}
void QWasmCompositor::WindowManipulation::onPointerMove(
@ -525,7 +530,8 @@ void QWasmCompositor::WindowManipulation::onPointerMove(
switch (operation()) {
case Operation::Move: {
const QPoint targetPointClippedToScreen = m_screen->clipPoint(event.point);
const QPoint targetPointClippedToScreen =
m_screen->clipPoint(m_screen->mapFromLocal(event.localPoint));
const QPoint difference = targetPointClippedToScreen - m_state->lastPointInScreenCoords;
m_state->lastPointInScreenCoords = targetPointClippedToScreen;

View File

@ -43,8 +43,9 @@ std::optional<PointerEvent> PointerEvent::fromWeb(emscripten::val event)
PointerType::Mouse : PointerType::Other;
ret.mouseButton = MouseEvent::buttonFromWeb(event["button"].as<int>());
ret.mouseButtons = MouseEvent::buttonsFromWeb(event["buttons"].as<unsigned short>());
ret.point = QPoint(event["offsetX"].as<int>(), event["offsetY"].as<int>());
ret.pointInViewport = QPoint(event["x"].as<int>(), event["y"].as<int>());
ret.localPoint = QPoint(event["offsetX"].as<int>(), event["offsetY"].as<int>());
ret.pointInPage = QPoint(event["pageX"].as<int>(), event["pageY"].as<int>());
ret.pointInViewport = QPoint(event["clientX"].as<int>(), event["clientY"].as<int>());
ret.pointerId = event["pointerId"].as<int>();
ret.modifiers = KeyboardModifier::getForEvent(event);

View File

@ -114,7 +114,8 @@ struct Q_CORE_EXPORT Event
struct Q_CORE_EXPORT MouseEvent : public Event
{
QPoint point;
QPoint localPoint;
QPoint pointInPage;
QPoint pointInViewport;
Qt::MouseButton mouseButton;
Qt::MouseButtons mouseButtons;

View File

@ -223,6 +223,11 @@ QWindow *QWasmScreen::topLevelAt(const QPoint &p) const
return m_compositor->windowAt(p);
}
QPoint QWasmScreen::mapFromLocal(const QPoint &p) const
{
return geometry().topLeft() + p;
}
QPoint QWasmScreen::clipPoint(const QPoint &p) const
{
return QPoint(

View File

@ -52,6 +52,7 @@ public:
QWindow *topWindow() const;
QWindow *topLevelAt(const QPoint &p) const override;
QPoint mapFromLocal(const QPoint &p) const;
QPoint clipPoint(const QPoint &p) const;
void invalidateSize();

View File

@ -133,7 +133,7 @@ public:
m_element.call<void>("setPointerCapture", event.pointerId);
m_capturedPointerId = event.pointerId;
m_resizer->startResize(m_edges, event.pointInViewport);
m_resizer->startResize(m_edges, event.pointInPage);
return true;
}
@ -142,7 +142,7 @@ public:
if (m_capturedPointerId != event.pointerId)
return false;
m_resizer->continueResize(event.pointInViewport);
m_resizer->continueResize(event.pointInPage);
return true;
}