Handle the mouse events in the window itself

It is now not the screen that handles all of the events and relays
them to individual windows, but the window elements themselves.

This allows us to get rid of manual window targeting logic and let
the browser do its job.

Fixes: QTBUG-107217
Pick-to: 6.5
Change-Id: I4dc5a74b1343f027f72c1da4623b99cd28bfbb38
Reviewed-by: Morten Johan Sørvig <morten.sorvig@qt.io>
This commit is contained in:
Mikolaj Boc 2022-12-20 15:56:49 +01:00
parent cf2651ae80
commit c15a8750bc
12 changed files with 215 additions and 241 deletions

View File

@ -35,6 +35,7 @@ qt_internal_add_plugin(QWasmIntegrationPlugin
qwasmstylepixmaps_p.h qwasmstylepixmaps_p.h
qwasmtheme.cpp qwasmtheme.h qwasmtheme.cpp qwasmtheme.h
qwasmwindow.cpp qwasmwindow.h qwasmwindow.cpp qwasmwindow.h
qwasmwindowclientarea.cpp qwasmwindowclientarea.h
qwasmwindownonclientarea.cpp qwasmwindownonclientarea.h qwasmwindownonclientarea.cpp qwasmwindownonclientarea.h
qwasminputcontext.cpp qwasminputcontext.h qwasminputcontext.cpp qwasminputcontext.h
qwasmdrag.cpp qwasmdrag.h qwasmdrag.cpp qwasmdrag.h

View File

@ -60,8 +60,6 @@ QWasmCompositor::QWasmCompositor(QWasmScreen *screen)
QWasmCompositor::~QWasmCompositor() QWasmCompositor::~QWasmCompositor()
{ {
m_windowUnderMouse.clear();
if (m_requestAnimationFrameId != -1) if (m_requestAnimationFrameId != -1)
emscripten_cancel_animation_frame(m_requestAnimationFrameId); emscripten_cancel_animation_frame(m_requestAnimationFrameId);
@ -75,8 +73,6 @@ void QWasmCompositor::deregisterEventHandlers()
emscripten_set_keydown_callback(screenElementSelector.constData(), 0, 0, NULL); emscripten_set_keydown_callback(screenElementSelector.constData(), 0, 0, NULL);
emscripten_set_keyup_callback(screenElementSelector.constData(), 0, 0, NULL); emscripten_set_keyup_callback(screenElementSelector.constData(), 0, 0, NULL);
emscripten_set_focus_callback(screenElementSelector.constData(), 0, 0, NULL);
emscripten_set_wheel_callback(screenElementSelector.constData(), 0, 0, NULL); emscripten_set_wheel_callback(screenElementSelector.constData(), 0, 0, NULL);
emscripten_set_touchstart_callback(screenElementSelector.constData(), 0, 0, NULL); emscripten_set_touchstart_callback(screenElementSelector.constData(), 0, 0, NULL);
@ -112,26 +108,6 @@ void QWasmCompositor::initEventHandlers()
emscripten_set_keyup_callback(screenElementSelector.constData(), (void *)this, UseCapture, emscripten_set_keyup_callback(screenElementSelector.constData(), (void *)this, UseCapture,
&keyboard_cb); &keyboard_cb);
val screenElement = screen()->element();
const auto callback = std::function([this](emscripten::val event) {
if (processPointer(*PointerEvent::fromWeb(event)))
event.call<void>("preventDefault");
});
m_pointerDownCallback =
std::make_unique<qstdweb::EventCallback>(screenElement, "pointerdown", callback);
m_pointerMoveCallback =
std::make_unique<qstdweb::EventCallback>(screenElement, "pointermove", callback);
m_pointerUpCallback =
std::make_unique<qstdweb::EventCallback>(screenElement, "pointerup", callback);
m_pointerEnterCallback =
std::make_unique<qstdweb::EventCallback>(screenElement, "pointerenter", callback);
m_pointerLeaveCallback =
std::make_unique<qstdweb::EventCallback>(screenElement, "pointerleave", callback);
emscripten_set_focus_callback(screenElementSelector.constData(), (void *)this, UseCapture,
&focus_cb);
emscripten_set_wheel_callback(screenElementSelector.constData(), (void *)this, UseCapture, emscripten_set_wheel_callback(screenElementSelector.constData(), (void *)this, UseCapture,
&wheel_cb); &wheel_cb);
@ -144,9 +120,9 @@ void QWasmCompositor::initEventHandlers()
emscripten_set_touchcancel_callback(screenElementSelector.constData(), (void *)this, UseCapture, emscripten_set_touchcancel_callback(screenElementSelector.constData(), (void *)this, UseCapture,
&touchCallback); &touchCallback);
screenElement.call<void>("addEventListener", std::string("drop"), screen()->element().call<void>("addEventListener", std::string("drop"),
val::module_property("qtDrop"), val(true)); val::module_property("qtDrop"), val(true));
screenElement.set("data-qtdropcontext", // ? unique screen()->element().set("data-qtdropcontext", // ? unique
emscripten::val(quintptr(reinterpret_cast<void *>(screen())))); emscripten::val(quintptr(reinterpret_cast<void *>(screen()))));
} }
@ -162,8 +138,6 @@ void QWasmCompositor::removeWindow(QWasmWindow *window)
{ {
m_requestUpdateWindows.remove(window); m_requestUpdateWindows.remove(window);
m_windowStack.removeWindow(window); m_windowStack.removeWindow(window);
if (m_lastMouseTargetWindow == window->window())
m_lastMouseTargetWindow = nullptr;
if (m_windowStack.topWindow()) if (m_windowStack.topWindow())
m_windowStack.topWindow()->requestActivateWindow(); m_windowStack.topWindow()->requestActivateWindow();
@ -344,15 +318,6 @@ int QWasmCompositor::keyboard_cb(int eventType, const EmscriptenKeyboardEvent *k
return static_cast<int>(wasmCompositor->processKeyboard(eventType, keyEvent)); return static_cast<int>(wasmCompositor->processKeyboard(eventType, keyEvent));
} }
int QWasmCompositor::focus_cb(int eventType, const EmscriptenFocusEvent *focusEvent, void *userData)
{
Q_UNUSED(eventType)
Q_UNUSED(focusEvent)
Q_UNUSED(userData)
return 0;
}
int QWasmCompositor::wheel_cb(int eventType, const EmscriptenWheelEvent *wheelEvent, void *userData) int QWasmCompositor::wheel_cb(int eventType, const EmscriptenWheelEvent *wheelEvent, void *userData)
{ {
QWasmCompositor *compositor = (QWasmCompositor *) userData; QWasmCompositor *compositor = (QWasmCompositor *) userData;
@ -365,112 +330,6 @@ int QWasmCompositor::touchCallback(int eventType, const EmscriptenTouchEvent *to
return static_cast<int>(compositor->processTouch(eventType, touchEvent)); return static_cast<int>(compositor->processTouch(eventType, touchEvent));
} }
bool QWasmCompositor::processPointer(const PointerEvent& event)
{
if (event.pointerType != PointerType::Mouse)
return false;
const auto pointInScreen = screen()->mapFromLocal(event.localPoint);
QWindow *const targetWindow = ([this, pointInScreen]() -> QWindow * {
auto *targetWindow = m_mouseCaptureWindow != nullptr
? m_mouseCaptureWindow.get()
: windowAt(pointInScreen, 5);
return targetWindow ? targetWindow : m_lastMouseTargetWindow.get();
})();
if (!targetWindow)
return false;
m_lastMouseTargetWindow = targetWindow;
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, pointInScreen);
m_windowUnderMouse = targetWindow;
}
switch (event.type) {
case EventType::PointerDown:
{
screen()->element().call<void>("setPointerCapture", event.pointerId);
if (targetWindow)
targetWindow->requestActivate();
break;
}
case EventType::PointerUp:
{
screen()->element().call<void>("releasePointerCapture", event.pointerId);
break;
}
case EventType::PointerEnter:
processMouseEnter(nullptr);
break;
case EventType::PointerLeave:
processMouseLeave();
break;
default:
break;
};
if (!pointerIsWithinTargetWindowBounds && event.mouseButtons.testFlag(Qt::NoButton)) {
leaveWindow(m_lastMouseTargetWindow);
}
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)
{
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(), pointInScreen.x())),
std::max(screen()->geometry().top(),
std::min(screen()->geometry().bottom(), pointInScreen.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 (!deliveringToPreviouslyClickedWindow && !m_mouseCaptureWindow
&& !eventTarget->geometry().contains(targetPointClippedToScreen)) {
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(
eventTarget, QWasmIntegration::getTimestamp(),
eventTarget->mapFromGlobal(targetPointClippedToScreen),
targetPointClippedToScreen, event.mouseButtons, event.mouseButton,
eventType, event.modifiers);
}
bool QWasmCompositor::processKeyboard(int eventType, const EmscriptenKeyboardEvent *emKeyEvent) bool QWasmCompositor::processKeyboard(int eventType, const EmscriptenKeyboardEvent *emKeyEvent)
{ {
constexpr bool ProceedToNativeEvent = false; constexpr bool ProceedToNativeEvent = false;
@ -521,9 +380,8 @@ 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 = KeyboardModifier::getForEvent(*mouseEvent); Qt::KeyboardModifiers modifiers = KeyboardModifier::getForEvent(*mouseEvent);
QPoint targetPointInScreenElementCoords(mouseEvent->targetX, mouseEvent->targetY);
QPoint targetPointInScreenCoords = QPoint targetPointInScreenCoords =
screen()->geometry().topLeft() + targetPointInScreenElementCoords; screen()->mapFromLocal(QPoint(mouseEvent->targetX, mouseEvent->targetY));
QWindow *targetWindow = screen()->compositor()->windowAt(targetPointInScreenCoords, 5); QWindow *targetWindow = screen()->compositor()->windowAt(targetPointInScreenCoords, 5);
if (!targetWindow) if (!targetWindow)
@ -555,9 +413,8 @@ bool QWasmCompositor::processTouch(int eventType, const EmscriptenTouchEvent *to
const EmscriptenTouchPoint *touches = &touchEvent->touches[i]; const EmscriptenTouchPoint *touches = &touchEvent->touches[i];
QPoint targetPointInScreenElementCoords(touches->targetX, touches->targetY);
QPoint targetPointInScreenCoords = QPoint targetPointInScreenCoords =
screen()->geometry().topLeft() + targetPointInScreenElementCoords; screen()->mapFromLocal(QPoint(touches->targetX, touches->targetY));
targetWindow = screen()->compositor()->windowAt(targetPointInScreenCoords, 5); targetWindow = screen()->compositor()->windowAt(targetPointInScreenCoords, 5);
if (targetWindow == nullptr) if (targetWindow == nullptr)
@ -624,39 +481,3 @@ bool QWasmCompositor::processTouch(int eventType, const EmscriptenTouchEvent *to
return static_cast<int>(accepted); return static_cast<int>(accepted);
} }
void QWasmCompositor::setCapture(QWasmWindow *window)
{
Q_ASSERT(std::find(m_windowStack.begin(), m_windowStack.end(), window) != m_windowStack.end());
m_mouseCaptureWindow = window->window();
}
void QWasmCompositor::releaseCapture()
{
m_mouseCaptureWindow = nullptr;
}
void QWasmCompositor::leaveWindow(QWindow *window)
{
m_windowUnderMouse = nullptr;
QWindowSystemInterface::handleLeaveEvent(window);
}
void QWasmCompositor::enterWindow(QWindow *window, const QPoint &pointInTargetWindowCoords, const QPoint &targetPointInScreenCoords)
{
QWindowSystemInterface::handleEnterEvent(window, pointInTargetWindowCoords, targetPointInScreenCoords);
}
bool QWasmCompositor::processMouseEnter(const EmscriptenMouseEvent *mouseEvent)
{
Q_UNUSED(mouseEvent)
// mouse has entered the screen area
m_mouseInScreen = true;
return true;
}
bool QWasmCompositor::processMouseLeave()
{
m_mouseInScreen = false;
return true;
}

View File

@ -80,15 +80,10 @@ private:
static int focus_cb(int eventType, const EmscriptenFocusEvent *focusEvent, void *userData); static int focus_cb(int eventType, const EmscriptenFocusEvent *focusEvent, void *userData);
static int wheel_cb(int eventType, const EmscriptenWheelEvent *wheelEvent, void *userData); 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); static int touchCallback(int eventType, const EmscriptenTouchEvent *ev, void *userData);
bool processKeyboard(int eventType, const EmscriptenKeyboardEvent *keyEvent); bool processKeyboard(int eventType, const EmscriptenKeyboardEvent *keyEvent);
bool processWheel(int eventType, const EmscriptenWheelEvent *wheelEvent); bool processWheel(int eventType, const EmscriptenWheelEvent *wheelEvent);
bool processMouseEnter(const EmscriptenMouseEvent *mouseEvent);
bool processMouseLeave();
bool processTouch(int eventType, const EmscriptenTouchEvent *touchEvent); bool processTouch(int eventType, const EmscriptenTouchEvent *touchEvent);
void enterWindow(QWindow *window, const QPoint &localPoint, const QPoint &globalPoint); void enterWindow(QWindow *window, const QPoint &localPoint, const QPoint &globalPoint);
@ -106,25 +101,11 @@ private:
int m_requestAnimationFrameId = -1; int m_requestAnimationFrameId = -1;
bool m_inDeliverUpdateRequest = false; bool m_inDeliverUpdateRequest = false;
QPointer<QWindow> m_lastMouseTargetWindow;
QPointer<QWindow> m_mouseCaptureWindow;
std::unique_ptr<qstdweb::EventCallback> m_pointerDownCallback;
std::unique_ptr<qstdweb::EventCallback> m_pointerMoveCallback;
std::unique_ptr<qstdweb::EventCallback> m_pointerUpCallback;
std::unique_ptr<qstdweb::EventCallback> m_pointerLeaveCallback;
std::unique_ptr<qstdweb::EventCallback> m_pointerEnterCallback;
std::unique_ptr<QPointingDevice> m_touchDevice; std::unique_ptr<QPointingDevice> m_touchDevice;
QMap <int, QPointF> m_pressedTouchIds; QMap <int, QPointF> m_pressedTouchIds;
bool m_isResizeCursorDisplayed = false;
std::unique_ptr<QWasmEventTranslator> m_eventTranslator; std::unique_ptr<QWasmEventTranslator> m_eventTranslator;
bool m_mouseInScreen = false;
QPointer<QWindow> m_windowUnderMouse;
}; };
QT_END_NAMESPACE QT_END_NAMESPACE

View File

@ -29,7 +29,6 @@ const char *Style = R"css(
.qt-window { .qt-window {
box-shadow: rgb(0 0 0 / 20%) 0px 10px 16px 0px, rgb(0 0 0 / 19%) 0px 6px 20px 0px; box-shadow: rgb(0 0 0 / 20%) 0px 10px 16px 0px, rgb(0 0 0 / 19%) 0px 6px 20px 0px;
pointer-events: none;
position: absolute; position: absolute;
background-color: lightgray; background-color: lightgray;
} }
@ -41,7 +40,6 @@ const char *Style = R"css(
.resize-outline { .resize-outline {
position: absolute; position: absolute;
pointer-events: all;
display: none; display: none;
} }
@ -119,7 +117,6 @@ const char *Style = R"css(
overflow: hidden; overflow: hidden;
height: 18px; height: 18px;
padding-bottom: 4px; padding-bottom: 4px;
pointer-events: all;
} }
.qt-window.has-title-bar .title-bar { .qt-window.has-title-bar .title-bar {
@ -184,7 +181,6 @@ const char *Style = R"css(
} }
.title-bar .action-button { .title-bar .action-button {
pointer-events: all; pointer-events: all;
align-self: end;
} }
.qt-window.blocked div { .qt-window.blocked div {

View File

@ -39,7 +39,7 @@ std::optional<PointerEvent> PointerEvent::fromWeb(emscripten::val event)
return std::nullopt; return std::nullopt;
ret.type = *eventType; ret.type = *eventType;
ret.currentTarget = event["currentTarget"]; ret.target = event["target"];
ret.pointerType = event["pointerType"].as<std::string>() == "mouse" ? ret.pointerType = event["pointerType"].as<std::string>() == "mouse" ?
PointerType::Mouse : PointerType::Other; PointerType::Mouse : PointerType::Other;
ret.mouseButton = MouseEvent::buttonFromWeb(event["button"].as<int>()); ret.mouseButton = MouseEvent::buttonFromWeb(event["button"].as<int>());

View File

@ -110,7 +110,7 @@ QFlags<Qt::KeyboardModifier> getForEvent<EmscriptenKeyboardEvent>(
struct Q_CORE_EXPORT Event struct Q_CORE_EXPORT Event
{ {
EventType type; EventType type;
emscripten::val currentTarget = emscripten::val::undefined(); emscripten::val target = emscripten::val::undefined();
}; };
struct Q_CORE_EXPORT MouseEvent : public Event struct Q_CORE_EXPORT MouseEvent : public Event

View File

@ -12,6 +12,7 @@
#include "qwasmbase64iconstore.h" #include "qwasmbase64iconstore.h"
#include "qwasmdom.h" #include "qwasmdom.h"
#include "qwasmwindow.h" #include "qwasmwindow.h"
#include "qwasmwindowclientarea.h"
#include "qwasmscreen.h" #include "qwasmscreen.h"
#include "qwasmstylepixmaps_p.h" #include "qwasmstylepixmaps_p.h"
#include "qwasmcompositor.h" #include "qwasmcompositor.h"
@ -24,6 +25,8 @@
#include <GL/gl.h> #include <GL/gl.h>
#include <QtCore/private/qstdweb_p.h>
QT_BEGIN_NAMESPACE QT_BEGIN_NAMESPACE
Q_GUI_EXPORT int qt_defaultDpiX(); Q_GUI_EXPORT int qt_defaultDpiX();
@ -45,6 +48,8 @@ QWasmWindow::QWasmWindow(QWindow *w, QWasmCompositor *compositor, QWasmBackingSt
m_nonClientArea = std::make_unique<NonClientArea>(this, m_qtWindow); m_nonClientArea = std::make_unique<NonClientArea>(this, m_qtWindow);
m_nonClientArea->titleBar()->setTitle(window()->title()); m_nonClientArea->titleBar()->setTitle(window()->title());
m_clientArea = std::make_unique<ClientArea>(this, compositor->screen(), m_canvas);
m_qtWindow.call<void>("appendChild", m_windowContents); m_qtWindow.call<void>("appendChild", m_windowContents);
m_canvas["classList"].call<void>("add", emscripten::val("qt-window-content")); m_canvas["classList"].call<void>("add", emscripten::val("qt-window-content"));
@ -65,6 +70,16 @@ QWasmWindow::QWasmWindow(QWindow *w, QWasmCompositor *compositor, QWasmBackingSt
emscripten::val::module_property("specialHTMLTargets").set(canvasSelector(), m_canvas); emscripten::val::module_property("specialHTMLTargets").set(canvasSelector(), m_canvas);
m_compositor->addWindow(this); m_compositor->addWindow(this);
const auto callback = std::function([this](emscripten::val event) {
if (processPointer(*PointerEvent::fromWeb(event)))
event.call<void>("preventDefault");
});
m_pointerEnterCallback =
std::make_unique<qstdweb::EventCallback>(m_qtWindow, "pointerenter", callback);
m_pointerLeaveCallback =
std::make_unique<qstdweb::EventCallback>(m_qtWindow, "pointerleave", callback);
} }
QWasmWindow::~QWasmWindow() QWasmWindow::~QWasmWindow()
@ -106,8 +121,8 @@ void QWasmWindow::onNonClientAreaInteraction()
bool QWasmWindow::onNonClientEvent(const PointerEvent &event) bool QWasmWindow::onNonClientEvent(const PointerEvent &event)
{ {
QPoint pointInScreen = platformScreen()->mapFromLocal( QPoint pointInScreen = platformScreen()->mapFromLocal(
dom::mapPoint(event.currentTarget, platformScreen()->element(), event.localPoint)); dom::mapPoint(event.target, platformScreen()->element(), event.localPoint));
return QWindowSystemInterface::handleMouseEvent<QWindowSystemInterface::SynchronousDelivery>( return QWindowSystemInterface::handleMouseEvent(
window(), QWasmIntegration::getTimestamp(), window()->mapFromGlobal(pointInScreen), window(), QWasmIntegration::getTimestamp(), window()->mapFromGlobal(pointInScreen),
pointInScreen, event.mouseButtons, event.mouseButton, ([event]() { pointInScreen, event.mouseButtons, event.mouseButton, ([event]() {
switch (event.type) { switch (event.type) {
@ -287,12 +302,6 @@ void QWasmWindow::propagateSizeHints()
} }
} }
bool QWasmWindow::startSystemResize(Qt::Edges)
{
// TODO(mikolajboc): This can only be implemented if per-window events are up and running
return false;
}
void QWasmWindow::invalidate() void QWasmWindow::invalidate()
{ {
m_compositor->requestUpdateWindow(this); m_compositor->requestUpdateWindow(this);
@ -374,6 +383,29 @@ void QWasmWindow::applyWindowState()
setGeometry(newGeom); setGeometry(newGeom);
} }
bool QWasmWindow::processPointer(const PointerEvent &event)
{
if (event.pointerType != PointerType::Mouse)
return false;
switch (event.type) {
case EventType::PointerEnter: {
const auto pointInScreen = platformScreen()->mapFromLocal(
dom::mapPoint(event.target, platformScreen()->element(), event.localPoint));
QWindowSystemInterface::handleEnterEvent(
window(), m_window->mapFromGlobal(pointInScreen), pointInScreen);
break;
}
case EventType::PointerLeave:
QWindowSystemInterface::handleLeaveEvent(window());
break;
default:
break;
}
return false;
}
QRect QWasmWindow::normalGeometry() const QRect QWasmWindow::normalGeometry() const
{ {
return m_normalGeometry; return m_normalGeometry;
@ -418,11 +450,8 @@ void QWasmWindow::requestActivateWindow()
bool QWasmWindow::setMouseGrabEnabled(bool grab) bool QWasmWindow::setMouseGrabEnabled(bool grab)
{ {
if (grab) Q_UNUSED(grab);
m_compositor->setCapture(this); return false;
else
m_compositor->releaseCapture();
return true;
} }
bool QWasmWindow::windowEvent(QEvent *event) bool QWasmWindow::windowEvent(QEvent *event)

View File

@ -20,6 +20,12 @@
QT_BEGIN_NAMESPACE QT_BEGIN_NAMESPACE
namespace qstdweb {
class EventCallback;
}
class ClientArea;
class QWasmWindow final : public QPlatformWindow class QWasmWindow final : public QPlatformWindow
{ {
public: public:
@ -59,7 +65,6 @@ public:
bool setKeyboardGrabEnabled(bool) override { return false; } bool setKeyboardGrabEnabled(bool) override { return false; }
bool setMouseGrabEnabled(bool grab) final; bool setMouseGrabEnabled(bool grab) final;
bool windowEvent(QEvent *event) final; bool windowEvent(QEvent *event) final;
bool startSystemResize(Qt::Edges edges) final;
QWasmScreen *platformScreen() const; QWasmScreen *platformScreen() const;
void setBackingStore(QWasmBackingStore *store) { m_backingStore = store; } void setBackingStore(QWasmBackingStore *store) { m_backingStore = store; }
@ -76,6 +81,8 @@ private:
bool hasTitleBar() const; bool hasTitleBar() const;
void applyWindowState(); void applyWindowState();
bool processPointer(const PointerEvent &event);
QWindow *m_window = nullptr; QWindow *m_window = nullptr;
QWasmCompositor *m_compositor = nullptr; QWasmCompositor *m_compositor = nullptr;
QWasmBackingStore *m_backingStore = nullptr; QWasmBackingStore *m_backingStore = nullptr;
@ -89,13 +96,21 @@ private:
emscripten::val m_context2d = emscripten::val::undefined(); emscripten::val m_context2d = emscripten::val::undefined();
std::unique_ptr<NonClientArea> m_nonClientArea; std::unique_ptr<NonClientArea> m_nonClientArea;
std::unique_ptr<ClientArea> m_clientArea;
std::unique_ptr<qstdweb::EventCallback> m_pointerLeaveCallback;
std::unique_ptr<qstdweb::EventCallback> m_pointerEnterCallback;
std::unique_ptr<qstdweb::EventCallback> m_pointerMoveCallback;
Qt::WindowStates m_state = Qt::WindowNoState; Qt::WindowStates m_state = Qt::WindowNoState;
Qt::WindowStates m_previousWindowState = Qt::WindowNoState; Qt::WindowStates m_previousWindowState = Qt::WindowNoState;
Qt::WindowFlags m_flags = Qt::Widget; Qt::WindowFlags m_flags = Qt::Widget;
QPoint m_lastPointerMovePoint;
WId m_winId = 0; WId m_winId = 0;
bool m_wantCapture = false;
bool m_hasTitle = false; bool m_hasTitle = false;
bool m_needsCompositor = false; bool m_needsCompositor = false;
long m_requestAnimationFrameId = -1; long m_requestAnimationFrameId = -1;

View File

@ -0,0 +1,93 @@
// Copyright (C) 2022 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
#include "qwasmwindowclientarea.h"
#include "qwasmdom.h"
#include "qwasmevent.h"
#include "qwasmscreen.h"
#include "qwasmwindow.h"
#include <QtGui/private/qguiapplication_p.h>
#include <qpa/qwindowsysteminterface.h>
#include <QtCore/qassert.h>
QT_BEGIN_NAMESPACE
ClientArea::ClientArea(QWasmWindow *window, QWasmScreen *screen, emscripten::val element)
: m_screen(screen), m_window(window), m_element(element)
{
const auto callback = std::function([this](emscripten::val event) {
if (processPointer(*PointerEvent::fromWeb(event)))
event.call<void>("preventDefault");
});
m_pointerDownCallback =
std::make_unique<qstdweb::EventCallback>(element, "pointerdown", callback);
m_pointerMoveCallback =
std::make_unique<qstdweb::EventCallback>(element, "pointermove", callback);
m_pointerUpCallback = std::make_unique<qstdweb::EventCallback>(element, "pointerup", callback);
}
bool ClientArea::processPointer(const PointerEvent &event)
{
if (event.pointerType != PointerType::Mouse)
return false;
const auto localScreenPoint =
dom::mapPoint(event.target, m_screen->element(), event.localPoint);
const auto pointInScreen = m_screen->mapFromLocal(localScreenPoint);
const QPoint pointInTargetWindowCoords = m_window->mapFromGlobal(pointInScreen);
switch (event.type) {
case EventType::PointerDown: {
m_element.call<void>("setPointerCapture", event.pointerId);
m_window->window()->requestActivate();
break;
}
case EventType::PointerUp: {
m_element.call<void>("releasePointerCapture", event.pointerId);
break;
}
case EventType::PointerEnter:;
QWindowSystemInterface::handleEnterEvent(
m_window->window(), pointInTargetWindowCoords, pointInScreen);
break;
case EventType::PointerLeave:
QWindowSystemInterface::handleLeaveEvent(m_window->window());
break;
default:
break;
};
const bool eventAccepted = deliverEvent(event);
if (!eventAccepted && event.type == EventType::PointerDown)
QGuiApplicationPrivate::instance()->closeAllPopups();
return eventAccepted;
}
bool ClientArea::deliverEvent(const PointerEvent &event)
{
const auto pointInScreen = m_screen->mapFromLocal(
dom::mapPoint(event.target, m_screen->element(), event.localPoint));
const QPoint targetPointClippedToScreen(
std::max(m_screen->geometry().left(),
std::min(m_screen->geometry().right(), pointInScreen.x())),
std::max(m_screen->geometry().top(),
std::min(m_screen->geometry().bottom(), pointInScreen.y())));
const QEvent::Type eventType =
MouseEvent::mouseEventTypeFromEventType(event.type, WindowArea::Client);
return eventType != QEvent::None
&& QWindowSystemInterface::handleMouseEvent(
m_window->window(), QWasmIntegration::getTimestamp(),
m_window->window()->mapFromGlobal(targetPointClippedToScreen),
targetPointClippedToScreen, event.mouseButtons, event.mouseButton, eventType,
event.modifiers);
}
QT_END_NAMESPACE

View File

@ -0,0 +1,42 @@
// Copyright (C) 2022 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
#ifndef QWASMWINDOWCLIENTAREA_H
#define QWASMWINDOWCLIENTAREA_H
#include <QtCore/qnamespace.h>
#include <emscripten/val.h>
#include <memory>
QT_BEGIN_NAMESPACE
namespace qstdweb {
class EventCallback;
}
struct PointerEvent;
class QWasmScreen;
class QWasmWindow;
class ClientArea
{
public:
ClientArea(QWasmWindow *window, QWasmScreen *screen, emscripten::val element);
private:
bool processPointer(const PointerEvent &event);
bool deliverEvent(const PointerEvent &event);
std::unique_ptr<qstdweb::EventCallback> m_pointerDownCallback;
std::unique_ptr<qstdweb::EventCallback> m_pointerMoveCallback;
std::unique_ptr<qstdweb::EventCallback> m_pointerUpCallback;
QWasmScreen *m_screen;
QWasmWindow *m_window;
emscripten::val m_element;
};
QT_END_NAMESPACE
#endif // QWASMWINDOWNONCLIENTAREA_H

View File

@ -55,14 +55,16 @@ void WebImageButton::setCallbacks(Callbacks callbacks)
if (callbacks) { if (callbacks) {
if (!m_webClickEventCallback) { if (!m_webClickEventCallback) {
m_webMouseDownEventCallback = std::make_unique<qstdweb::EventCallback>( m_webMouseDownEventCallback = std::make_unique<qstdweb::EventCallback>(
m_containerElement, "mousedown", [this](emscripten::val event) { m_containerElement, "pointerdown", [this](emscripten::val event) {
event.call<void>("preventDefault"); event.call<void>("preventDefault");
event.call<void>("stopPropagation"); event.call<void>("stopPropagation");
m_callbacks.onInteraction(); m_callbacks.onInteraction();
}); });
m_webClickEventCallback = std::make_unique<qstdweb::EventCallback>( m_webClickEventCallback = std::make_unique<qstdweb::EventCallback>(
m_containerElement, "click", m_containerElement, "click", [this](emscripten::val event) {
[this](emscripten::val) { m_callbacks.onClick(); }); m_callbacks.onClick();
event.call<void>("stopPropagation");
});
} }
} else { } else {
m_webMouseDownEventCallback.reset(); m_webMouseDownEventCallback.reset();
@ -104,12 +106,10 @@ Resizer::ResizerElement::ResizerElement(emscripten::val parentElement, Qt::Edges
event.call<void>("preventDefault"); event.call<void>("preventDefault");
event.call<void>("stopPropagation"); event.call<void>("stopPropagation");
}); });
m_mouseDragEvent = std::make_unique<qstdweb::EventCallback>( m_mouseMoveEvent = std::make_unique<qstdweb::EventCallback>(
m_element, "pointermove", [this](emscripten::val event) { m_element, "pointermove", [this](emscripten::val event) {
if (onPointerMove(*PointerEvent::fromWeb(event))) { if (onPointerMove(*PointerEvent::fromWeb(event)))
event.call<void>("preventDefault"); event.call<void>("preventDefault");
event.call<void>("stopPropagation");
}
}); });
m_mouseUpEvent = std::make_unique<qstdweb::EventCallback>( m_mouseUpEvent = std::make_unique<qstdweb::EventCallback>(
m_element, "pointerup", [this](emscripten::val event) { m_element, "pointerup", [this](emscripten::val event) {
@ -193,7 +193,7 @@ void Resizer::startResize(Qt::Edges resizeEdges, const PointerEvent &event)
m_currentResizeData.reset(new ResizeData{ m_currentResizeData.reset(new ResizeData{
.edges = resizeEdges, .edges = resizeEdges,
.originInScreenCoords = dom::mapPoint( .originInScreenCoords = dom::mapPoint(
event.currentTarget, m_window->platformScreen()->element(), event.localPoint), event.target, m_window->platformScreen()->element(), event.localPoint),
}); });
const auto *window = m_window->window(); const auto *window = m_window->window();
@ -213,15 +213,12 @@ void Resizer::startResize(Qt::Edges resizeEdges, const PointerEvent &event)
window->maximumHeight() - window->geometry().height())); window->maximumHeight() - window->geometry().height()));
m_currentResizeData->initialBounds = window->geometry(); m_currentResizeData->initialBounds = window->geometry();
// TODO(mikolajboc): Implement system resize
// .m_originInScreenCoords = m_systemDragInitData.lastMouseMovePoint,
} }
void Resizer::continueResize(const PointerEvent &event) void Resizer::continueResize(const PointerEvent &event)
{ {
const auto pointInScreen = dom::mapPoint( const auto pointInScreen =
event.currentTarget, m_window->platformScreen()->element(), event.localPoint); dom::mapPoint(event.target, m_window->platformScreen()->element(), event.localPoint);
const auto amount = pointInScreen - m_currentResizeData->originInScreenCoords; const auto amount = pointInScreen - m_currentResizeData->originInScreenCoords;
const QPoint cappedGrowVector( const QPoint cappedGrowVector(
std::min(m_currentResizeData->maxGrow.x(), std::min(m_currentResizeData->maxGrow.x(),
@ -310,11 +307,10 @@ TitleBar::TitleBar(QWasmWindow *window, emscripten::val parentElement)
event.call<void>("preventDefault"); event.call<void>("preventDefault");
event.call<void>("stopPropagation"); event.call<void>("stopPropagation");
}); });
m_mouseDragEvent = std::make_unique<qstdweb::EventCallback>( m_mouseMoveEvent = std::make_unique<qstdweb::EventCallback>(
m_element, "pointermove", [this](emscripten::val event) { m_element, "pointermove", [this](emscripten::val event) {
if (onPointerMove(*PointerEvent::fromWeb(event))) { if (onPointerMove(*PointerEvent::fromWeb(event))) {
event.call<void>("preventDefault"); event.call<void>("preventDefault");
event.call<void>("stopPropagation");
} }
}); });
m_mouseUpEvent = std::make_unique<qstdweb::EventCallback>( m_mouseUpEvent = std::make_unique<qstdweb::EventCallback>(

View File

@ -137,7 +137,7 @@ public:
Resizer *m_resizer; Resizer *m_resizer;
std::unique_ptr<qstdweb::EventCallback> m_mouseDownEvent; std::unique_ptr<qstdweb::EventCallback> m_mouseDownEvent;
std::unique_ptr<qstdweb::EventCallback> m_mouseDragEvent; std::unique_ptr<qstdweb::EventCallback> m_mouseMoveEvent;
std::unique_ptr<qstdweb::EventCallback> m_mouseUpEvent; std::unique_ptr<qstdweb::EventCallback> m_mouseUpEvent;
}; };
@ -203,7 +203,7 @@ private:
QPoint m_lastMovePoint; QPoint m_lastMovePoint;
std::unique_ptr<qstdweb::EventCallback> m_mouseDownEvent; std::unique_ptr<qstdweb::EventCallback> m_mouseDownEvent;
std::unique_ptr<qstdweb::EventCallback> m_mouseDragEvent; std::unique_ptr<qstdweb::EventCallback> m_mouseMoveEvent;
std::unique_ptr<qstdweb::EventCallback> m_mouseUpEvent; std::unique_ptr<qstdweb::EventCallback> m_mouseUpEvent;
std::unique_ptr<qstdweb::EventCallback> m_doubleClickEvent; std::unique_ptr<qstdweb::EventCallback> m_doubleClickEvent;
}; };