Deliver non-client area mouse events to WASM windows

QWasmCompositor now delivers non-client area mouse events to windows as
it should, which fixes a lot of issues with window manipulation. One of
such issues is re-docking of dock widgets.

Fixes: QTBUG-105092
Change-Id: I9de45b7e1b1a80b64387031eb0cc0b31a4be2571
Reviewed-by: Lorn Potter <lorn.potter@gmail.com>
This commit is contained in:
Mikolaj Boc 2022-07-20 14:29:06 +02:00
parent 434595865b
commit 19507dc678
6 changed files with 81 additions and 29 deletions

View File

@ -939,8 +939,6 @@ bool QWasmCompositor::processPointer(const PointerEvent& event)
const QPoint targetPointInScreenCoords = screen()->geometry().topLeft() + event.point;
QEvent::Type buttonEventType = QEvent::None;
QWindow *const targetWindow = ([this, &targetPointInScreenCoords]() -> QWindow * {
auto *targetWindow =
m_windowManipulation.operation() == WindowManipulation::Operation::None ?
@ -968,7 +966,6 @@ bool QWasmCompositor::processPointer(const PointerEvent& event)
switch (event.type) {
case EventType::PointerDown:
{
buttonEventType = QEvent::MouseButtonPress;
if (targetWindow)
targetWindow->requestActivate();
@ -981,8 +978,6 @@ bool QWasmCompositor::processPointer(const PointerEvent& event)
}
case EventType::PointerUp:
{
buttonEventType = QEvent::MouseButtonRelease;
m_windowManipulation.onPointerUp(event);
if (m_pressedWindow) {
@ -997,8 +992,6 @@ bool QWasmCompositor::processPointer(const PointerEvent& event)
}
case EventType::PointerMove:
{
buttonEventType = QEvent::MouseMove;
if (wasmTargetWindow && event.mouseButtons.testFlag(Qt::NoButton)) {
const bool isOnResizeRegion = wasmTargetWindow->isPointOnResizeRegion(targetPointInScreenCoords);
@ -1033,24 +1026,51 @@ bool QWasmCompositor::processPointer(const PointerEvent& event)
leaveWindow(m_lastMouseTargetWindow);
}
bool shouldDeliverEvent = pointerIsWithinTargetWindowBounds;
QWindow *eventTarget = targetWindow;
if (!eventTarget && event.type == EventType::PointerUp) {
eventTarget = m_lastMouseTargetWindow;
m_lastMouseTargetWindow = nullptr;
shouldDeliverEvent = true;
}
const bool eventAccepted =
eventTarget != nullptr && shouldDeliverEvent &&
QWindowSystemInterface::handleMouseEvent<QWindowSystemInterface::SynchronousDelivery>(
eventTarget, QWasmIntegration::getTimestamp(), pointInTargetWindowCoords, targetPointInScreenCoords,
event.mouseButtons, event.mouseButton, buttonEventType, event.modifiers);
const bool eventAccepted = deliverEventToTarget(event, targetWindow);
if (!eventAccepted && event.type == EventType::PointerDown)
QGuiApplicationPrivate::instance()->closeAllPopups();
return eventAccepted;
}
bool QWasmCompositor::deliverEventToTarget(const PointerEvent &event, QWindow *eventTarget)
{
const QPoint pointInScreenCoords = screen()->geometry().topLeft() + event.point;
const QPoint targetPointClippedToScreen(
std::max(screen()->geometry().left(),
std::min(screen()->geometry().right(), pointInScreenCoords.x())),
std::max(screen()->geometry().top(),
std::min(screen()->geometry().bottom(), pointInScreenCoords.y())));
bool deliveringToPreviouslyClickedWindow = false;
if (!eventTarget) {
if (event.type != EventType::PointerUp || !m_lastMouseTargetWindow)
return false;
eventTarget = m_lastMouseTargetWindow;
m_lastMouseTargetWindow = nullptr;
deliveringToPreviouslyClickedWindow = true;
}
WindowArea windowArea = WindowArea::Client;
if (!eventTarget->geometry().contains(targetPointClippedToScreen)
&& !deliveringToPreviouslyClickedWindow) {
if (!eventTarget->frameGeometry().contains(targetPointClippedToScreen))
return false;
windowArea = WindowArea::NonClient;
}
const QEvent::Type eventType =
MouseEvent::mouseEventTypeFromEventType(event.type, windowArea);
return eventType != QEvent::None &&
QWindowSystemInterface::handleMouseEvent<QWindowSystemInterface::SynchronousDelivery>(
eventTarget, QWasmIntegration::getTimestamp(),
eventTarget->mapFromGlobal(targetPointClippedToScreen),
targetPointClippedToScreen, event.mouseButtons, event.mouseButton,
eventType, event.modifiers);
}
QWasmCompositor::WindowManipulation::WindowManipulation(QWasmScreen *screen)
: m_screen(screen)
{
@ -1124,14 +1144,10 @@ void QWasmCompositor::WindowManipulation::onPointerMove(
if (operation() == Operation::None || event.pointerId != m_state->pointerId)
return;
const auto pointInScreenCoords = m_screen->geometry().topLeft() + event.point;
switch (operation()) {
case Operation::Move: {
const QPoint targetPointClippedToScreen(
std::max(m_screen->geometry().left(), std::min(m_screen->geometry().right(), pointInScreenCoords.x())),
std::max(m_screen->geometry().top(), std::min(m_screen->geometry().bottom(), pointInScreenCoords.y())));
const QPoint targetPointClippedToScreen =
m_screen->translateAndClipGlobalPoint(event.point);
const QPoint difference = targetPointClippedToScreen -
std::get<MoveState>(m_state->operationSpecific).m_lastPointInScreenCoords;
@ -1141,6 +1157,7 @@ void QWasmCompositor::WindowManipulation::onPointerMove(
break;
}
case Operation::Resize: {
const auto pointInScreenCoords = m_screen->geometry().topLeft() + event.point;
resizeWindow(pointInScreenCoords -
std::get<ResizeState>(m_state->operationSpecific).m_originInScreenCoords);
break;

View File

@ -208,6 +208,7 @@ private:
static int wheel_cb(int eventType, const EmscriptenWheelEvent *wheelEvent, void *userData);
bool processPointer(const PointerEvent& event);
bool deliverEventToTarget(const PointerEvent& event, QWindow *eventTarget);
static int touchCallback(int eventType, const EmscriptenTouchEvent *ev, void *userData);

View File

@ -8,6 +8,7 @@
#include <QtCore/qglobal.h>
#include <QtCore/qnamespace.h>
#include <QtGui/qevent.h>
#include <QPoint>
@ -29,6 +30,11 @@ enum class PointerType {
Other,
};
enum class WindowArea {
NonClient,
Client,
};
namespace KeyboardModifier {
namespace internal
{
@ -129,7 +135,24 @@ struct Q_CORE_EXPORT MouseEvent : public Event
static constexpr Qt::MouseButtons buttonsFromWeb(unsigned short webButtons) {
// Coincidentally, Qt and web bitfields match.
return Qt::MouseButtons::fromInt(webButtons);
}
}
static constexpr QEvent::Type mouseEventTypeFromEventType(
EventType eventType, WindowArea windowArea) {
switch (eventType) {
case EventType::PointerDown :
return windowArea == WindowArea::Client ?
QEvent::MouseButtonPress : QEvent::NonClientAreaMouseButtonPress;
case EventType::PointerUp :
return windowArea == WindowArea::Client ?
QEvent::MouseButtonRelease : QEvent::NonClientAreaMouseButtonRelease;
case EventType::PointerMove :
return windowArea == WindowArea::Client ?
QEvent::MouseMove : QEvent::NonClientAreaMouseMove;
default:
return QEvent::None;
}
}
};
struct Q_CORE_EXPORT PointerEvent : public MouseEvent

View File

@ -263,6 +263,15 @@ QWindow *QWasmScreen::topLevelAt(const QPoint &p) const
return m_compositor->windowAt(p);
}
QPoint QWasmScreen::translateAndClipGlobalPoint(const QPoint &p) const
{
return QPoint(
std::max(screen()->geometry().left(),
std::min(screen()->geometry().right(), screen()->geometry().left() + p.x())),
std::max(screen()->geometry().top(),
std::min(screen()->geometry().bottom(), screen()->geometry().top() + p.y())));
}
void QWasmScreen::invalidateSize()
{
m_geometry = QRect();

View File

@ -53,6 +53,8 @@ public:
QWindow *topWindow() const;
QWindow *topLevelAt(const QPoint &p) const override;
QPoint translateAndClipGlobalPoint(const QPoint &p) const;
void invalidateSize();
void updateQScreenAndCanvasRenderSize();
void installCanvasResizeObserver();

View File

@ -1079,14 +1079,14 @@ void QDockWidgetPrivate::nonClientAreaMouseEvent(QMouseEvent *event)
if (state == nullptr || !state->dragging)
break;
#ifndef Q_OS_MAC
#if !defined(Q_OS_MAC) && !defined(Q_OS_WASM)
if (state->nca) {
endDrag();
}
#endif
break;
case QEvent::NonClientAreaMouseButtonRelease:
#ifdef Q_OS_MAC
#if defined(Q_OS_MAC) || defined(Q_OS_WASM)
if (state)
endDrag();
#endif