Refactor code focused around QWasmCompositor::processMouse

Refactoring of the logic around QWasmCompositor::processMouse has been
performed for readability and easier modification, in preparation for
further fixes for event delivery and handling in windows. There should
be no logic changes, just cleaner code.

Change groups:
Members of QWasmCompositor have been prefixed by m_ for easier discerning
of stateful and stateless variables in functions.

Variables renamed to more descriptive, e.g. window2->targetWindow,
globalPoint->targetPointInScreenCoords.

Magic numbers eliminated, e.g. mouseEvent->button == 0 is now
button == Qt::MouseButton::LeftButton.

Some common condition checks have been wrapped into single constants,
e.g. !(htmlWindow->m_windowState & Qt::WindowFullScreen) &&
!(htmlWindow->m_windowState & Qt::WindowMaximized) ==
isTargetWindowResizable

Some nested if-conditions were collapsed.

Some unnecessary checks have been moved to outer if conditions (e.g. for
draggedWindow in EMSCRIPTEN_EVENT_MOUSEMOVE, since the code would crash
anyway because only some parts are guarded against it being nullptr).

Consts introduced so that variables are only used for one purpose.

Made QWasmEventTranslator::translateMouseButton constexpr

Made QWasmWindow::isPointOnTitle behave correctly when the window has
no title bar so that no flag probing is needed prior to calling it.

Made QWasmCursor::setOverrideWasmCursor accept a const ref - having it
accept pointer suggested it might dangle.

Change-Id: I8910622fddad764ee86eb0260b5ad23c7ee7f97a
Reviewed-by: David Skoland <david.skoland@qt.io>
(cherry picked from commit ec58600cc923d6b7de5266e20e27d377fcc1540a)
This commit is contained in:
Mikolaj Boc 2022-07-14 15:56:38 +02:00
parent d052236a2f
commit d65c618915
7 changed files with 209 additions and 231 deletions

View File

@ -25,6 +25,12 @@
#include <emscripten/bind.h> #include <emscripten/bind.h>
namespace {
QWasmWindow *AsWasmWindow(QWindow *window) {
return static_cast<QWasmWindow*>(window->handle());
}
} // namespace
using namespace emscripten; using namespace emscripten;
Q_GUI_EXPORT int qt_defaultDpiX(); Q_GUI_EXPORT int qt_defaultDpiX();
@ -51,32 +57,22 @@ EMSCRIPTEN_BINDINGS(qtMouseModule) {
} }
QWasmCompositor::QWasmCompositor(QWasmScreen *screen) QWasmCompositor::QWasmCompositor(QWasmScreen *screen)
:QObject(screen) : QObject(screen)
, m_blitter(new QOpenGLTextureBlitter) , m_blitter(new QOpenGLTextureBlitter)
, m_needComposit(false) , m_eventTranslator(std::make_unique<QWasmEventTranslator>())
, m_inFlush(false)
, m_inResize(false)
, m_isEnabled(true)
, m_targetDevicePixelRatio(1)
, draggedWindow(nullptr)
, lastWindow(nullptr)
, pressedButtons(Qt::NoButton)
, resizeMode(QWasmCompositor::ResizeNone)
, eventTranslator(new QWasmEventTranslator())
, mouseInCanvas(false)
{ {
touchDevice = new QPointingDevice( m_touchDevice = std::make_unique<QPointingDevice>(
"touchscreen", 1, QInputDevice::DeviceType::TouchScreen, "touchscreen", 1, QInputDevice::DeviceType::TouchScreen,
QPointingDevice::PointerType::Finger, QPointingDevice::PointerType::Finger,
QPointingDevice::Capability::Position | QPointingDevice::Capability::Area QPointingDevice::Capability::Position | QPointingDevice::Capability::Area
| QPointingDevice::Capability::NormalizedPosition, | QPointingDevice::Capability::NormalizedPosition,
10, 0); 10, 0);
QWindowSystemInterface::registerInputDevice(touchDevice); QWindowSystemInterface::registerInputDevice(m_touchDevice.get());
} }
QWasmCompositor::~QWasmCompositor() QWasmCompositor::~QWasmCompositor()
{ {
windowUnderMouse.clear(); m_windowUnderMouse.clear();
if (m_requestAnimationFrameId != -1) if (m_requestAnimationFrameId != -1)
emscripten_cancel_animation_frame(m_requestAnimationFrameId); emscripten_cancel_animation_frame(m_requestAnimationFrameId);
@ -137,7 +133,7 @@ void QWasmCompositor::initEventHandlers()
{ {
QByteArray canvasSelector = screen()->canvasTargetId().toUtf8(); QByteArray canvasSelector = screen()->canvasTargetId().toUtf8();
eventTranslator->g_usePlatformMacSpecifics m_eventTranslator->g_usePlatformMacSpecifics
= (QWasmIntegration::get()->platform == QWasmIntegration::MacOSPlatform); = (QWasmIntegration::get()->platform == QWasmIntegration::MacOSPlatform);
if (QWasmIntegration::get()->platform == QWasmIntegration::MacOSPlatform) { if (QWasmIntegration::get()->platform == QWasmIntegration::MacOSPlatform) {
if (!emscripten::val::global("window")["safari"].isUndefined()) { if (!emscripten::val::global("window")["safari"].isUndefined()) {
@ -148,23 +144,25 @@ void QWasmCompositor::initEventHandlers()
} }
} }
emscripten_set_keydown_callback(canvasSelector.constData(), (void *)this, 1, &keyboard_cb); constexpr EM_BOOL UseCapture = 1;
emscripten_set_keyup_callback(canvasSelector.constData(), (void *)this, 1, &keyboard_cb);
emscripten_set_mousedown_callback(canvasSelector.constData(), (void *)this, 1, &mouse_cb); emscripten_set_keydown_callback(canvasSelector.constData(), (void *)this, UseCapture, &keyboard_cb);
emscripten_set_mouseup_callback(canvasSelector.constData(), (void *)this, 1, &mouse_cb); emscripten_set_keyup_callback(canvasSelector.constData(), (void *)this, UseCapture, &keyboard_cb);
emscripten_set_mousemove_callback(canvasSelector.constData(), (void *)this, 1, &mouse_cb);
emscripten_set_mouseenter_callback(canvasSelector.constData(), (void *)this, 1, &mouse_cb);
emscripten_set_mouseleave_callback(canvasSelector.constData(), (void *)this, 1, &mouse_cb);
emscripten_set_focus_callback(canvasSelector.constData(), (void *)this, 1, &focus_cb); emscripten_set_mousedown_callback(canvasSelector.constData(), (void *)this, UseCapture, &mouse_cb);
emscripten_set_mouseup_callback(canvasSelector.constData(), (void *)this, UseCapture, &mouse_cb);
emscripten_set_mousemove_callback(canvasSelector.constData(), (void *)this, UseCapture, &mouse_cb);
emscripten_set_mouseenter_callback(canvasSelector.constData(), (void *)this, UseCapture, &mouse_cb);
emscripten_set_mouseleave_callback(canvasSelector.constData(), (void *)this, UseCapture, &mouse_cb);
emscripten_set_wheel_callback(canvasSelector.constData(), (void *)this, 1, &wheel_cb); emscripten_set_focus_callback(canvasSelector.constData(), (void *)this, UseCapture, &focus_cb);
emscripten_set_touchstart_callback(canvasSelector.constData(), (void *)this, 1, &touchCallback); emscripten_set_wheel_callback(canvasSelector.constData(), (void *)this, UseCapture, &wheel_cb);
emscripten_set_touchend_callback(canvasSelector.constData(), (void *)this, 1, &touchCallback);
emscripten_set_touchmove_callback(canvasSelector.constData(), (void *)this, 1, &touchCallback); emscripten_set_touchstart_callback(canvasSelector.constData(), (void *)this, UseCapture, &touchCallback);
emscripten_set_touchcancel_callback(canvasSelector.constData(), (void *)this, 1, &touchCallback); emscripten_set_touchend_callback(canvasSelector.constData(), (void *)this, UseCapture, &touchCallback);
emscripten_set_touchmove_callback(canvasSelector.constData(), (void *)this, UseCapture, &touchCallback);
emscripten_set_touchcancel_callback(canvasSelector.constData(), (void *)this, UseCapture, &touchCallback);
val canvas = screen()->canvas(); val canvas = screen()->canvas();
canvas.call<void>("addEventListener", canvas.call<void>("addEventListener",
@ -208,9 +206,9 @@ void QWasmCompositor::removeWindow(QWasmWindow *window)
m_requestUpdateWindows.remove(window); m_requestUpdateWindows.remove(window);
if (!m_windowStack.isEmpty() && !QGuiApplication::focusWindow()) { if (!m_windowStack.isEmpty() && !QGuiApplication::focusWindow()) {
auto lastWindow = m_windowStack.last(); auto m_lastMouseTargetWindow = m_windowStack.last();
lastWindow->requestActivateWindow(); m_lastMouseTargetWindow->requestActivateWindow();
notifyTopWindowChanged(lastWindow); notifyTopWindowChanged(m_lastMouseTargetWindow);
} }
} }
@ -268,7 +266,7 @@ int QWasmCompositor::windowCount() const
return m_windowStack.count(); return m_windowStack.count();
} }
QWindow *QWasmCompositor::windowAt(QPoint globalPoint, int padding) const QWindow *QWasmCompositor::windowAt(QPoint targetPointInScreenCoords, int padding) const
{ {
int index = m_windowStack.count() - 1; int index = m_windowStack.count() - 1;
// qDebug() << "window at" << "point" << p << "window count" << index; // qDebug() << "window at" << "point" << p << "window count" << index;
@ -280,7 +278,7 @@ QWindow *QWasmCompositor::windowAt(QPoint globalPoint, int padding) const
QRect geometry = compositedWindow.window->windowFrameGeometry() QRect geometry = compositedWindow.window->windowFrameGeometry()
.adjusted(-padding, -padding, padding, padding); .adjusted(-padding, -padding, padding, padding);
if (compositedWindow.visible && geometry.contains(globalPoint)) if (compositedWindow.visible && geometry.contains(targetPointInScreenCoords))
return m_windowStack.at(index)->window(); return m_windowStack.at(index)->window();
--index; --index;
} }
@ -920,11 +918,11 @@ void QWasmCompositor::resizeWindow(QWindow *window, QWasmCompositor::ResizeMode
void QWasmCompositor::notifyTopWindowChanged(QWasmWindow *window) void QWasmCompositor::notifyTopWindowChanged(QWasmWindow *window)
{ {
QWindow *modalWindow; QWindow *modalWindow;
bool blocked = QGuiApplicationPrivate::instance()->isWindowBlocked(window->window(), &modalWindow); bool isTargetWindowBlocked = QGuiApplicationPrivate::instance()->isWindowBlocked(window->window(), &modalWindow);
if (blocked) { if (isTargetWindowBlocked) {
modalWindow->requestActivate(); modalWindow->requestActivate();
raise(static_cast<QWasmWindow*>(modalWindow->handle())); raise(AsWasmWindow(modalWindow));
return; return;
} }
@ -976,162 +974,146 @@ int QWasmCompositor::touchCallback(int eventType, const EmscriptenTouchEvent *to
bool QWasmCompositor::processMouse(int eventType, const EmscriptenMouseEvent *mouseEvent) bool QWasmCompositor::processMouse(int eventType, const EmscriptenMouseEvent *mouseEvent)
{ {
QPoint targetPoint(mouseEvent->targetX, mouseEvent->targetY); const Qt::MouseButton button = QWasmEventTranslator::translateMouseButton(mouseEvent->button);
QPoint globalPoint = screen()->geometry().topLeft() + targetPoint;
const QPoint targetPointInCanvasCoords(mouseEvent->targetX, mouseEvent->targetY);
const QPoint targetPointInScreenCoords = screen()->geometry().topLeft() + targetPointInCanvasCoords;
QEvent::Type buttonEventType = QEvent::None; QEvent::Type buttonEventType = QEvent::None;
Qt::MouseButton button = Qt::NoButton; Qt::KeyboardModifiers modifiers = m_eventTranslator->translateMouseEventModifier(mouseEvent);
Qt::KeyboardModifiers modifiers = eventTranslator->translateMouseEventModifier(mouseEvent);
QWindow *window2 = nullptr; QWindow *const targetWindow = ([this, &targetPointInScreenCoords]() -> QWindow * {
if (resizeMode == QWasmCompositor::ResizeNone) auto *targetWindow =
window2 = screen()->compositor()->windowAt(globalPoint, 5); m_resizeMode == QWasmCompositor::ResizeNone ?
screen()->compositor()->windowAt(targetPointInScreenCoords, 5) : nullptr;
if (window2 == nullptr) { return targetWindow ? targetWindow : m_lastMouseTargetWindow.get();
window2 = lastWindow; })();
} else { if (targetWindow)
lastWindow = window2; m_lastMouseTargetWindow = targetWindow;
}
QPoint localPoint = window2->mapFromGlobal(globalPoint); const QPoint pointInTargetWindowCoords = targetWindow->mapFromGlobal(targetPointInScreenCoords);
bool interior = window2->geometry().contains(globalPoint); const bool pointerIsWithinTargetWindowBounds = targetWindow->geometry().contains(targetPointInScreenCoords);
bool blocked = QGuiApplicationPrivate::instance()->isWindowBlocked(window2); const bool isTargetWindowBlocked = QGuiApplicationPrivate::instance()->isWindowBlocked(targetWindow);
if (mouseInCanvas) { if (m_mouseInCanvas && m_windowUnderMouse != targetWindow && pointerIsWithinTargetWindowBounds) {
if (windowUnderMouse != window2 && interior) {
// delayed mouse enter // delayed mouse enter
enterWindow(window2, localPoint, globalPoint); enterWindow(targetWindow, pointInTargetWindowCoords, targetPointInScreenCoords);
windowUnderMouse = window2; m_windowUnderMouse = targetWindow;
}
} }
QWasmWindow *htmlWindow = static_cast<QWasmWindow*>(window2->handle()); QWasmWindow *wasmTargetWindow = AsWasmWindow(targetWindow);
Qt::WindowStates windowState = htmlWindow->window()->windowState(); Qt::WindowStates windowState = targetWindow->windowState();
bool isResizable = !(windowState.testFlag(Qt::WindowMaximized) || const bool isTargetWindowResizable = !windowState.testFlag(Qt::WindowMaximized) && !windowState.testFlag(Qt::WindowFullScreen);
windowState.testFlag(Qt::WindowFullScreen));
switch (eventType) { switch (eventType) {
case EMSCRIPTEN_EVENT_MOUSEDOWN: case EMSCRIPTEN_EVENT_MOUSEDOWN:
{ {
button = QWasmEventTranslator::translateMouseButton(mouseEvent->button);
if (window2)
window2->requestActivate();
pressedButtons.setFlag(button);
pressedWindow = window2;
buttonEventType = QEvent::MouseButtonPress; buttonEventType = QEvent::MouseButtonPress;
m_pressedButtons.setFlag(button);
// button overview: if (targetWindow)
// 0 = primary mouse button, usually left click targetWindow->requestActivate();
// 1 = middle mouse button, usually mouse wheel
// 2 = right mouse button, usually right click m_pressedWindow = targetWindow;
// from: https://w3c.github.io/uievents/#dom-mouseevent-button
if (mouseEvent->button == 0) { if (isTargetWindowResizable && button == Qt::MouseButton::LeftButton && !isTargetWindowBlocked) {
if (!blocked && !(htmlWindow->m_windowState & Qt::WindowFullScreen) if (wasmTargetWindow->isPointOnTitle(targetPointInScreenCoords)) {
&& !(htmlWindow->m_windowState & Qt::WindowMaximized)) { m_windowBeingManipulated = targetWindow;
if (htmlWindow && window2->flags().testFlag(Qt::WindowTitleHint) } else if (wasmTargetWindow->isPointOnResizeRegion(targetPointInScreenCoords)) {
&& htmlWindow->isPointOnTitle(globalPoint)) m_windowBeingManipulated = targetWindow;
draggedWindow = window2; m_resizeMode = wasmTargetWindow->resizeModeAtPoint(targetPointInScreenCoords);
else if (htmlWindow && htmlWindow->isPointOnResizeRegion(globalPoint)) { m_resizePoint = targetPointInScreenCoords;
draggedWindow = window2; m_resizeStartRect = targetWindow->geometry();
resizeMode = htmlWindow->resizeModeAtPoint(globalPoint);
resizePoint = globalPoint;
resizeStartRect = window2->geometry();
}
} }
} }
htmlWindow->injectMousePressed(localPoint, globalPoint, button, modifiers); wasmTargetWindow->injectMousePressed(pointInTargetWindowCoords, targetPointInScreenCoords, button, modifiers);
break; break;
} }
case EMSCRIPTEN_EVENT_MOUSEUP: case EMSCRIPTEN_EVENT_MOUSEUP:
{ {
button = QWasmEventTranslator::translateMouseButton(mouseEvent->button);
pressedButtons.setFlag(button, false);
buttonEventType = QEvent::MouseButtonRelease; buttonEventType = QEvent::MouseButtonRelease;
QWasmWindow *oldWindow = nullptr;
if (mouseEvent->button == 0 && pressedWindow) { m_pressedButtons.setFlag(button, false);
oldWindow = static_cast<QWasmWindow*>(pressedWindow->handle());
pressedWindow = nullptr; if (m_windowBeingManipulated && m_pressedButtons.testFlag(Qt::NoButton)) {
m_windowBeingManipulated = nullptr;
m_resizeMode = QWasmCompositor::ResizeNone;
} }
if (draggedWindow && pressedButtons.testFlag(Qt::NoButton)) { if (m_pressedWindow) {
draggedWindow = nullptr; // Always deliver the released event to the same window that was pressed
resizeMode = QWasmCompositor::ResizeNone; AsWasmWindow(m_pressedWindow)->injectMouseReleased(pointInTargetWindowCoords, targetPointInScreenCoords, button, modifiers);
if (button == Qt::MouseButton::LeftButton)
m_pressedWindow = nullptr;
} else {
wasmTargetWindow->injectMouseReleased(pointInTargetWindowCoords, targetPointInScreenCoords, button, modifiers);
} }
if (oldWindow)
oldWindow->injectMouseReleased(localPoint, globalPoint, button, modifiers);
else
htmlWindow->injectMouseReleased(localPoint, globalPoint, button, modifiers);
break; break;
} }
case EMSCRIPTEN_EVENT_MOUSEMOVE: // drag event case EMSCRIPTEN_EVENT_MOUSEMOVE:
{ {
buttonEventType = QEvent::MouseMove; buttonEventType = QEvent::MouseMove;
if (htmlWindow && pressedButtons.testFlag(Qt::NoButton)) { if (wasmTargetWindow && m_pressedButtons.testFlag(Qt::NoButton)) {
const bool isOnResizeRegion = wasmTargetWindow->isPointOnResizeRegion(targetPointInScreenCoords);
bool isOnResizeRegion = htmlWindow->isPointOnResizeRegion(globalPoint); if (isTargetWindowResizable && isOnResizeRegion && !isTargetWindowBlocked) {
const QCursor resizingCursor = QWasmEventTranslator::cursorForMode(
wasmTargetWindow->resizeModeAtPoint(targetPointInScreenCoords));
if (isResizable && isOnResizeRegion && !blocked) { if (resizingCursor != targetWindow->cursor()) {
QCursor resizingCursor = eventTranslator->cursorForMode(htmlWindow->resizeModeAtPoint(globalPoint)); m_isResizeCursorDisplayed = true;
QWasmCursor::setOverrideWasmCursor(resizingCursor, targetWindow->screen());
if (resizingCursor != window2->cursor()) {
isCursorOverridden = true;
QWasmCursor::setOverrideWasmCursor(&resizingCursor, window2->screen());
}
} else { // off resizing area
if (isCursorOverridden) {
isCursorOverridden = false;
QWasmCursor::clearOverrideWasmCursor(window2->screen());
} }
} else if (m_isResizeCursorDisplayed) { // off resizing area
m_isResizeCursorDisplayed = false;
QWasmCursor::clearOverrideWasmCursor(targetWindow->screen());
} }
} }
if (!(htmlWindow->m_windowState & Qt::WindowFullScreen) && !(htmlWindow->m_windowState & Qt::WindowMaximized)) { if (m_windowBeingManipulated && isTargetWindowResizable) {
if (resizeMode == QWasmCompositor::ResizeNone && draggedWindow) { if (m_resizeMode == QWasmCompositor::ResizeNone) {
draggedWindow->setX(draggedWindow->x() + mouseEvent->movementX); m_windowBeingManipulated->setPosition(
draggedWindow->setY(draggedWindow->y() + mouseEvent->movementY); m_windowBeingManipulated->position() + QPoint(mouseEvent->movementX, mouseEvent->movementY));
} } else {
const QPoint delta = targetPointInCanvasCoords - m_resizePoint;
if (resizeMode != QWasmCompositor::ResizeNone && !(htmlWindow->m_windowState & Qt::WindowFullScreen)) { resizeWindow(m_windowBeingManipulated, m_resizeMode, m_resizeStartRect, delta);
QPoint delta = QPoint(mouseEvent->targetX, mouseEvent->targetY) - resizePoint;
resizeWindow(draggedWindow, resizeMode, resizeStartRect, delta);
} }
} }
break; break;
} }
case EMSCRIPTEN_EVENT_MOUSEENTER: case EMSCRIPTEN_EVENT_MOUSEENTER:
processMouseEnter(mouseEvent); processMouseEnter(mouseEvent);
break; break;
case EMSCRIPTEN_EVENT_MOUSELEAVE: case EMSCRIPTEN_EVENT_MOUSELEAVE:
processMouseLeave(); processMouseLeave();
break;
default:
break; break;
default: break;
}; };
if (!interior && pressedButtons.testFlag(Qt::NoButton)) { if (!pointerIsWithinTargetWindowBounds && m_pressedButtons.testFlag(Qt::NoButton)) {
leaveWindow(lastWindow); leaveWindow(m_lastMouseTargetWindow);
} }
if (!window2 && buttonEventType == QEvent::MouseButtonRelease) { bool shouldDeliverEvent = pointerIsWithinTargetWindowBounds;
window2 = lastWindow; QWindow *eventTarget = targetWindow;
lastWindow = nullptr; if (!eventTarget && buttonEventType == QEvent::MouseButtonRelease) {
interior = true; eventTarget = m_lastMouseTargetWindow;
} m_lastMouseTargetWindow = nullptr;
bool accepted = false; shouldDeliverEvent = true;
if (window2 && interior) {
accepted = QWindowSystemInterface::handleMouseEvent<QWindowSystemInterface::SynchronousDelivery>(
window2, QWasmIntegration::getTimestamp(), localPoint, globalPoint, pressedButtons, button, buttonEventType, modifiers);
} }
const bool eventAccepted =
eventTarget != nullptr && shouldDeliverEvent &&
QWindowSystemInterface::handleMouseEvent<QWindowSystemInterface::SynchronousDelivery>(
eventTarget, QWasmIntegration::getTimestamp(), pointInTargetWindowCoords, targetPointInScreenCoords,
m_pressedButtons, button, buttonEventType, modifiers);
if (eventType == EMSCRIPTEN_EVENT_MOUSEDOWN && !accepted) if (!eventAccepted && buttonEventType == QEvent::MouseButtonPress)
QGuiApplicationPrivate::instance()->closeAllPopups(); QGuiApplicationPrivate::instance()->closeAllPopups();
return accepted; return eventAccepted;
} }
bool QWasmCompositor::processKeyboard(int eventType, const EmscriptenKeyboardEvent *keyEvent) bool QWasmCompositor::processKeyboard(int eventType, const EmscriptenKeyboardEvent *keyEvent)
@ -1143,12 +1125,12 @@ bool QWasmCompositor::processKeyboard(int eventType, const EmscriptenKeyboardEve
case EMSCRIPTEN_EVENT_KEYPRESS: case EMSCRIPTEN_EVENT_KEYPRESS:
case EMSCRIPTEN_EVENT_KEYDOWN: // down case EMSCRIPTEN_EVENT_KEYDOWN: // down
keyType = QEvent::KeyPress; keyType = QEvent::KeyPress;
qtKey = this->eventTranslator->getKey(keyEvent); qtKey = m_eventTranslator->getKey(keyEvent);
keyText = this->eventTranslator->getKeyText(keyEvent, qtKey); keyText = m_eventTranslator->getKeyText(keyEvent, qtKey);
break; break;
case EMSCRIPTEN_EVENT_KEYUP: // up case EMSCRIPTEN_EVENT_KEYUP: // up
keyType = QEvent::KeyRelease; keyType = QEvent::KeyRelease;
this->eventTranslator->setStickyDeadKey(keyEvent); m_eventTranslator->setStickyDeadKey(keyEvent);
break; break;
default: default:
break; break;
@ -1157,7 +1139,7 @@ bool QWasmCompositor::processKeyboard(int eventType, const EmscriptenKeyboardEve
if (keyType == QEvent::None) if (keyType == QEvent::None)
return 0; return 0;
QFlags<Qt::KeyboardModifier> modifiers = eventTranslator->translateKeyboardEventModifier(keyEvent); QFlags<Qt::KeyboardModifier> modifiers = m_eventTranslator->translateKeyboardEventModifier(keyEvent);
// Clipboard fallback path: cut/copy/paste are handled by clipboard event // Clipboard fallback path: cut/copy/paste are handled by clipboard event
// handlers if direct clipboard access is not available. // handlers if direct clipboard access is not available.
@ -1215,14 +1197,14 @@ bool QWasmCompositor::processWheel(int eventType, const EmscriptenWheelEvent *wh
scrollFactor = -scrollFactor; // Web scroll deltas are inverted from Qt deltas. scrollFactor = -scrollFactor; // Web scroll deltas are inverted from Qt deltas.
Qt::KeyboardModifiers modifiers = eventTranslator->translateMouseEventModifier(&mouseEvent); Qt::KeyboardModifiers modifiers = m_eventTranslator->translateMouseEventModifier(&mouseEvent);
QPoint targetPoint(mouseEvent.targetX, mouseEvent.targetY); QPoint targetPointInCanvasCoords(mouseEvent.targetX, mouseEvent.targetY);
QPoint globalPoint = screen()->geometry().topLeft() + targetPoint; QPoint targetPointInScreenCoords = screen()->geometry().topLeft() + targetPointInCanvasCoords;
QWindow *window2 = screen()->compositor()->windowAt(globalPoint, 5); QWindow *targetWindow = screen()->compositor()->windowAt(targetPointInScreenCoords, 5);
if (!window2) if (!targetWindow)
return 0; return 0;
QPoint localPoint = window2->mapFromGlobal(globalPoint); QPoint pointInTargetWindowCoords = targetWindow->mapFromGlobal(targetPointInScreenCoords);
QPoint pixelDelta; QPoint pixelDelta;
@ -1232,8 +1214,8 @@ bool QWasmCompositor::processWheel(int eventType, const EmscriptenWheelEvent *wh
QPoint angleDelta = pixelDelta; // FIXME: convert from pixels? QPoint angleDelta = pixelDelta; // FIXME: convert from pixels?
bool accepted = QWindowSystemInterface::handleWheelEvent( bool accepted = QWindowSystemInterface::handleWheelEvent(
window2, QWasmIntegration::getTimestamp(), localPoint, targetWindow, QWasmIntegration::getTimestamp(), pointInTargetWindowCoords,
globalPoint, pixelDelta, angleDelta, modifiers, targetPointInScreenCoords, pixelDelta, angleDelta, modifiers,
Qt::NoScrollPhase, Qt::MouseEventNotSynthesized, Qt::NoScrollPhase, Qt::MouseEventNotSynthesized,
g_scrollingInvertedFromDevice); g_scrollingInvertedFromDevice);
return accepted; return accepted;
@ -1243,17 +1225,17 @@ int QWasmCompositor::handleTouch(int eventType, const EmscriptenTouchEvent *touc
{ {
QList<QWindowSystemInterface::TouchPoint> touchPointList; QList<QWindowSystemInterface::TouchPoint> touchPointList;
touchPointList.reserve(touchEvent->numTouches); touchPointList.reserve(touchEvent->numTouches);
QWindow *window2; QWindow *targetWindow;
for (int i = 0; i < touchEvent->numTouches; i++) { for (int i = 0; i < touchEvent->numTouches; i++) {
const EmscriptenTouchPoint *touches = &touchEvent->touches[i]; const EmscriptenTouchPoint *touches = &touchEvent->touches[i];
QPoint targetPoint(touches->targetX, touches->targetY); QPoint targetPointInCanvasCoords(touches->targetX, touches->targetY);
QPoint globalPoint = screen()->geometry().topLeft() + targetPoint; QPoint targetPointInScreenCoords = screen()->geometry().topLeft() + targetPointInCanvasCoords;
window2 = this->screen()->compositor()->windowAt(globalPoint, 5); targetWindow = screen()->compositor()->windowAt(targetPointInScreenCoords, 5);
if (window2 == nullptr) if (targetWindow == nullptr)
continue; continue;
QWindowSystemInterface::TouchPoint touchPoint; QWindowSystemInterface::TouchPoint touchPoint;
@ -1262,41 +1244,41 @@ int QWasmCompositor::handleTouch(int eventType, const EmscriptenTouchEvent *touc
touchPoint.id = touches->identifier; touchPoint.id = touches->identifier;
touchPoint.pressure = 1.0; touchPoint.pressure = 1.0;
touchPoint.area.moveCenter(globalPoint); touchPoint.area.moveCenter(targetPointInScreenCoords);
const auto tp = pressedTouchIds.constFind(touchPoint.id); const auto tp = m_pressedTouchIds.constFind(touchPoint.id);
if (tp != pressedTouchIds.constEnd()) if (tp != m_pressedTouchIds.constEnd())
touchPoint.normalPosition = tp.value(); touchPoint.normalPosition = tp.value();
QPointF localPoint = QPointF(window2->mapFromGlobal(globalPoint)); QPointF pointInTargetWindowCoords = QPointF(targetWindow->mapFromGlobal(targetPointInScreenCoords));
QPointF normalPosition(localPoint.x() / window2->width(), QPointF normalPosition(pointInTargetWindowCoords.x() / targetWindow->width(),
localPoint.y() / window2->height()); pointInTargetWindowCoords.y() / targetWindow->height());
const bool stationaryTouchPoint = (normalPosition == touchPoint.normalPosition); const bool stationaryTouchPoint = (normalPosition == touchPoint.normalPosition);
touchPoint.normalPosition = normalPosition; touchPoint.normalPosition = normalPosition;
switch (eventType) { switch (eventType) {
case EMSCRIPTEN_EVENT_TOUCHSTART: case EMSCRIPTEN_EVENT_TOUCHSTART:
if (tp != pressedTouchIds.constEnd()) { if (tp != m_pressedTouchIds.constEnd()) {
touchPoint.state = (stationaryTouchPoint touchPoint.state = (stationaryTouchPoint
? QEventPoint::State::Stationary ? QEventPoint::State::Stationary
: QEventPoint::State::Updated); : QEventPoint::State::Updated);
} else { } else {
touchPoint.state = QEventPoint::State::Pressed; touchPoint.state = QEventPoint::State::Pressed;
} }
pressedTouchIds.insert(touchPoint.id, touchPoint.normalPosition); m_pressedTouchIds.insert(touchPoint.id, touchPoint.normalPosition);
break; break;
case EMSCRIPTEN_EVENT_TOUCHEND: case EMSCRIPTEN_EVENT_TOUCHEND:
touchPoint.state = QEventPoint::State::Released; touchPoint.state = QEventPoint::State::Released;
pressedTouchIds.remove(touchPoint.id); m_pressedTouchIds.remove(touchPoint.id);
break; break;
case EMSCRIPTEN_EVENT_TOUCHMOVE: case EMSCRIPTEN_EVENT_TOUCHMOVE:
touchPoint.state = (stationaryTouchPoint touchPoint.state = (stationaryTouchPoint
? QEventPoint::State::Stationary ? QEventPoint::State::Stationary
: QEventPoint::State::Updated); : QEventPoint::State::Updated);
pressedTouchIds.insert(touchPoint.id, touchPoint.normalPosition); m_pressedTouchIds.insert(touchPoint.id, touchPoint.normalPosition);
break; break;
default: default:
break; break;
@ -1305,40 +1287,40 @@ int QWasmCompositor::handleTouch(int eventType, const EmscriptenTouchEvent *touc
touchPointList.append(touchPoint); touchPointList.append(touchPoint);
} }
QFlags<Qt::KeyboardModifier> keyModifier = eventTranslator->translateTouchEventModifier(touchEvent); QFlags<Qt::KeyboardModifier> keyModifier = m_eventTranslator->translateTouchEventModifier(touchEvent);
bool accepted = false; bool accepted = false;
if (eventType == EMSCRIPTEN_EVENT_TOUCHCANCEL) if (eventType == EMSCRIPTEN_EVENT_TOUCHCANCEL)
accepted = QWindowSystemInterface::handleTouchCancelEvent(window2, QWasmIntegration::getTimestamp(), touchDevice, keyModifier); accepted = QWindowSystemInterface::handleTouchCancelEvent(targetWindow, QWasmIntegration::getTimestamp(), m_touchDevice.get(), keyModifier);
else else
accepted = QWindowSystemInterface::handleTouchEvent<QWindowSystemInterface::SynchronousDelivery>( accepted = QWindowSystemInterface::handleTouchEvent<QWindowSystemInterface::SynchronousDelivery>(
window2, QWasmIntegration::getTimestamp(), touchDevice, touchPointList, keyModifier); targetWindow, QWasmIntegration::getTimestamp(), m_touchDevice.get(), touchPointList, keyModifier);
return static_cast<int>(accepted); return static_cast<int>(accepted);
} }
void QWasmCompositor::leaveWindow(QWindow *window) void QWasmCompositor::leaveWindow(QWindow *window)
{ {
windowUnderMouse = nullptr; m_windowUnderMouse = nullptr;
QWindowSystemInterface::handleLeaveEvent<QWindowSystemInterface::SynchronousDelivery>(window); QWindowSystemInterface::handleLeaveEvent<QWindowSystemInterface::SynchronousDelivery>(window);
} }
void QWasmCompositor::enterWindow(QWindow *window, const QPoint &localPoint, const QPoint &globalPoint) void QWasmCompositor::enterWindow(QWindow *window, const QPoint &pointInTargetWindowCoords, const QPoint &targetPointInScreenCoords)
{ {
QWindowSystemInterface::handleEnterEvent<QWindowSystemInterface::SynchronousDelivery>(window, localPoint, globalPoint); QWindowSystemInterface::handleEnterEvent<QWindowSystemInterface::SynchronousDelivery>(window, pointInTargetWindowCoords, targetPointInScreenCoords);
} }
bool QWasmCompositor::processMouseEnter(const EmscriptenMouseEvent *mouseEvent) bool QWasmCompositor::processMouseEnter(const EmscriptenMouseEvent *mouseEvent)
{ {
Q_UNUSED(mouseEvent) Q_UNUSED(mouseEvent)
// mouse has entered the canvas area // mouse has entered the canvas area
mouseInCanvas = true; m_mouseInCanvas = true;
return true; return true;
} }
bool QWasmCompositor::processMouseLeave() bool QWasmCompositor::processMouseLeave()
{ {
mouseInCanvas = false; m_mouseInCanvas = false;
return true; return true;
} }

View File

@ -146,39 +146,6 @@ private:
void blit(QOpenGLTextureBlitter *blitter, QWasmScreen *screen, const QOpenGLTexture *texture, QRect targetGeometry); void blit(QOpenGLTextureBlitter *blitter, QWasmScreen *screen, const QOpenGLTexture *texture, QRect targetGeometry);
void drawWindowDecorations(QOpenGLTextureBlitter *blitter, QWasmScreen *screen, QWasmWindow *window); void drawWindowDecorations(QOpenGLTextureBlitter *blitter, QWasmScreen *screen, QWasmWindow *window);
void drwPanelButton();
QScopedPointer<QOpenGLContext> m_context;
QScopedPointer<QOpenGLTextureBlitter> m_blitter;
QHash<QWasmWindow *, QWasmCompositedWindow> m_compositedWindows;
QList<QWasmWindow *> m_windowStack;
QRegion m_globalDamage; // damage caused by expose, window close, etc.
bool m_needComposit;
bool m_inFlush;
bool m_inResize;
bool m_isEnabled;
QSize m_targetSize;
qreal m_targetDevicePixelRatio;
QMap<QWasmWindow *, UpdateRequestDeliveryType> m_requestUpdateWindows;
bool m_requestUpdateAllWindows = false;
int m_requestAnimationFrameId = -1;
bool m_inDeliverUpdateRequest = false;
QPointer<QWindow> draggedWindow;
QPointer<QWindow> pressedWindow;
QPointer<QWindow> lastWindow;
Qt::MouseButtons pressedButtons;
QWasmCompositor::ResizeMode resizeMode;
QPoint resizePoint;
QRect resizeStartRect;
QPointingDevice *touchDevice;
QMap <int, QPointF> pressedTouchIds;
QCursor overriddenCursor;
bool isCursorOverridden = false;
static QPalette makeWindowPalette(); static QPalette makeWindowPalette();
@ -195,10 +162,41 @@ private:
static int touchCallback(int eventType, const EmscriptenTouchEvent *ev, void *userData); static int touchCallback(int eventType, const EmscriptenTouchEvent *ev, void *userData);
QWasmEventTranslator *eventTranslator; QScopedPointer<QOpenGLContext> m_context;
QScopedPointer<QOpenGLTextureBlitter> m_blitter;
bool mouseInCanvas; QHash<QWasmWindow *, QWasmCompositedWindow> m_compositedWindows;
QPointer<QWindow> windowUnderMouse; QList<QWasmWindow *> m_windowStack;
QRegion m_globalDamage; // damage caused by expose, window close, etc.
bool m_needComposit = false;
bool m_inFlush = false;
bool m_inResize = false;
bool m_isEnabled = true;
QSize m_targetSize;
qreal m_targetDevicePixelRatio = 1;
QMap<QWasmWindow *, UpdateRequestDeliveryType> m_requestUpdateWindows;
bool m_requestUpdateAllWindows = false;
int m_requestAnimationFrameId = -1;
bool m_inDeliverUpdateRequest = false;
QPointer<QWindow> m_windowBeingManipulated;
QPointer<QWindow> m_pressedWindow;
QPointer<QWindow> m_lastMouseTargetWindow;
Qt::MouseButtons m_pressedButtons = Qt::NoButton;
ResizeMode m_resizeMode = ResizeNone;
QPoint m_resizePoint;
QRect m_resizeStartRect;
std::unique_ptr<QPointingDevice> m_touchDevice;
QMap <int, QPointF> m_pressedTouchIds;
bool m_isResizeCursorDisplayed = false;
std::unique_ptr<QWasmEventTranslator> m_eventTranslator;
bool m_mouseInCanvas = false;
QPointer<QWindow> m_windowUnderMouse;
}; };
Q_DECLARE_OPERATORS_FOR_FLAGS(QWasmCompositor::SubControls) Q_DECLARE_OPERATORS_FOR_FLAGS(QWasmCompositor::SubControls)

View File

@ -123,10 +123,10 @@ void QWasmCursor::setWasmCursor(QScreen *screen, const QByteArray &name)
canvasStyle.set("cursor", val(name.constData())); canvasStyle.set("cursor", val(name.constData()));
} }
void QWasmCursor::setOverrideWasmCursor(QCursor *windowCursor, QScreen *screen) void QWasmCursor::setOverrideWasmCursor(const QCursor &windowCursor, QScreen *screen)
{ {
QWasmCursor *wCursor = static_cast<QWasmCursor *>(QWasmScreen::get(screen)->cursor()); QWasmCursor *wCursor = static_cast<QWasmCursor *>(QWasmScreen::get(screen)->cursor());
wCursor->setWasmCursor(screen, wCursor->cursorShapeToHtml(windowCursor->shape())); wCursor->setWasmCursor(screen, wCursor->cursorShapeToHtml(windowCursor.shape()));
} }
void QWasmCursor::clearOverrideWasmCursor(QScreen *screen) void QWasmCursor::clearOverrideWasmCursor(QScreen *screen)

View File

@ -13,7 +13,7 @@ public:
void changeCursor(QCursor *windowCursor, QWindow *window) override; void changeCursor(QCursor *windowCursor, QWindow *window) override;
QByteArray cursorShapeToHtml(Qt::CursorShape shape); QByteArray cursorShapeToHtml(Qt::CursorShape shape);
static void setOverrideWasmCursor(QCursor *windowCursor, QScreen *screen); static void setOverrideWasmCursor(const QCursor &windowCursor, QScreen *screen);
static void clearOverrideWasmCursor(QScreen *screen); static void clearOverrideWasmCursor(QScreen *screen);
private: private:
QByteArray htmlCursorName = "default"; QByteArray htmlCursorName = "default";

View File

@ -238,18 +238,6 @@ Qt::Key QWasmEventTranslator::translateEmscriptKey(const EmscriptenKeyboardEvent
return qtKey; return qtKey;
} }
Qt::MouseButton QWasmEventTranslator::translateMouseButton(unsigned short button)
{
if (button == 0)
return Qt::LeftButton;
else if (button == 1)
return Qt::MiddleButton;
else if (button == 2)
return Qt::RightButton;
return Qt::NoButton;
}
struct KeyMapping { Qt::Key from, to; }; struct KeyMapping { Qt::Key from, to; };
constexpr KeyMapping tildeKeyTable[] = { // ~ constexpr KeyMapping tildeKeyTable[] = { // ~

View File

@ -33,7 +33,18 @@ public:
QFlags<Qt::KeyboardModifier> translateKeyboardEventModifier(const EmscriptenKeyboardEvent *keyEvent); QFlags<Qt::KeyboardModifier> translateKeyboardEventModifier(const EmscriptenKeyboardEvent *keyEvent);
QFlags<Qt::KeyboardModifier> translateMouseEventModifier(const EmscriptenMouseEvent *mouseEvent); QFlags<Qt::KeyboardModifier> translateMouseEventModifier(const EmscriptenMouseEvent *mouseEvent);
QFlags<Qt::KeyboardModifier> translateTouchEventModifier(const EmscriptenTouchEvent *touchEvent); QFlags<Qt::KeyboardModifier> translateTouchEventModifier(const EmscriptenTouchEvent *touchEvent);
static Qt::MouseButton translateMouseButton(unsigned short button); static constexpr Qt::MouseButton translateMouseButton(unsigned short button) {
switch (button) {
case 0:
return Qt::LeftButton;
case 1:
return Qt::MiddleButton;
case 2:
return Qt::RightButton;
default:
return Qt::NoButton;
}
}
static QCursor cursorForMode(QWasmCompositor::ResizeMode mode); static QCursor cursorForMode(QWasmCompositor::ResizeMode mode);
QString getKeyText(const EmscriptenKeyboardEvent *keyEvent, Qt::Key key); QString getKeyText(const EmscriptenKeyboardEvent *keyEvent, Qt::Key key);

View File

@ -229,8 +229,7 @@ QRegion QWasmWindow::resizeRegion() const
bool QWasmWindow::isPointOnTitle(QPoint point) const bool QWasmWindow::isPointOnTitle(QPoint point) const
{ {
bool ok = titleGeometry().contains(point); return hasTitleBar() ? titleGeometry().contains(point) : false;
return ok;
} }
bool QWasmWindow::isPointOnResizeRegion(QPoint point) const bool QWasmWindow::isPointOnResizeRegion(QPoint point) const