diff --git a/examples/qwindow-compositor/qopenglwindow.cpp b/examples/qwindow-compositor/qopenglwindow.cpp index d70c4a9656bc71665c22d733003db501798e075c..473e4c151961f348847bc33247387adb8a5757fe 100644 --- a/examples/qwindow-compositor/qopenglwindow.cpp +++ b/examples/qwindow-compositor/qopenglwindow.cpp @@ -39,6 +39,7 @@ ****************************************************************************/ #include "qopenglwindow.h" +#include <QTouchEvent> QOpenGLWindow::QOpenGLWindow(const QSurfaceFormat &format, const QRect &geometry) : m_format(format) @@ -51,3 +52,10 @@ QOpenGLWindow::QOpenGLWindow(const QSurfaceFormat &format, const QRect &geometry m_context->setFormat(format); m_context->create(); } + +void QOpenGLWindow::touchEvent(QTouchEvent *event) +{ + // Do not want any automatically synthesized mouse events + // so make sure the touch is always accepted. + event->accept(); +} diff --git a/examples/qwindow-compositor/qopenglwindow.h b/examples/qwindow-compositor/qopenglwindow.h index 0d1cfbf7a3c6f77b78338f1b087d1d3d35288d7b..2ba883cf03c23860c58c145b7f62b13420223e89 100644 --- a/examples/qwindow-compositor/qopenglwindow.h +++ b/examples/qwindow-compositor/qopenglwindow.h @@ -53,7 +53,8 @@ public: QOpenGLContext* context() { return m_context; } bool makeCurrent() { return m_context->makeCurrent(this); } void swapBuffers() { m_context->swapBuffers(this); } - +protected: + void touchEvent(QTouchEvent *event); private: QOpenGLContext *m_context; QSurfaceFormat m_format; diff --git a/examples/qwindow-compositor/qwindowcompositor.cpp b/examples/qwindow-compositor/qwindowcompositor.cpp index 90192f98d3148ff8f4171f2387c57423ae468a9b..a7132101e428ee6c40a3cfa9a4a6f38da8679290 100644 --- a/examples/qwindow-compositor/qwindowcompositor.cpp +++ b/examples/qwindow-compositor/qwindowcompositor.cpp @@ -58,6 +58,11 @@ QWindowCompositor::QWindowCompositor(QOpenGLWindow *window) // using a custom protocol extension. // enableTouchExtension(); + // Enable the following to have mouse events generated from touch + // on client side. This is not the same as synthesizing mouse events + // in the compositor because it avoids sending data through the wire. + // configureTouchExtension(WaylandCompositor::TouchExtMouseFromTouch); + enableSubSurfaceExtension(); m_window->makeCurrent(); diff --git a/extensions/touch-extension.xml b/extensions/touch-extension.xml index 268d70a68cca9d67cbaed321633f5ad45a02b5a6..d1baa7ba90f40ae2190d7e0b4873a1a1c70dbfbf 100644 --- a/extensions/touch-extension.xml +++ b/extensions/touch-extension.xml @@ -56,6 +56,14 @@ <arg name="rawdata" type="array" /> </event> + <enum name="flags"> + <entry name="mouse_from_touch" value="0x1" /> + </enum> + + <event name="configure"> + <arg name="flags" type="uint" /> + </event> + <request name="dummy"> </request> diff --git a/src/compositor/compositor_api/waylandcompositor.cpp b/src/compositor/compositor_api/waylandcompositor.cpp index eee6805f07169677fb065225c9613c5a8c78cc65..c86698bd4e14b4451f5f37c066d25653b4ef5440 100644 --- a/src/compositor/compositor_api/waylandcompositor.cpp +++ b/src/compositor/compositor_api/waylandcompositor.cpp @@ -193,3 +193,8 @@ void WaylandCompositor::enableTouchExtension() { m_compositor->enableTouchExtension(); } + +void WaylandCompositor::configureTouchExtension(TouchExtensionFlags flags) +{ + m_compositor->configureTouchExtension(flags); +} diff --git a/src/compositor/compositor_api/waylandcompositor.h b/src/compositor/compositor_api/waylandcompositor.h index f4d64992c0dab6730effb248f12d31d4363f62c8..3cc255a8bd9760d5a012b6377038e53682c8ffc8 100644 --- a/src/compositor/compositor_api/waylandcompositor.h +++ b/src/compositor/compositor_api/waylandcompositor.h @@ -95,6 +95,11 @@ public: void enableSubSurfaceExtension(); void enableTouchExtension(); + enum TouchExtensionFlag { + TouchExtMouseFromTouch = 0x01 + }; + Q_DECLARE_FLAGS(TouchExtensionFlags, TouchExtensionFlag) + void configureTouchExtension(TouchExtensionFlags flags); private: static void retainedSelectionChanged(QMimeData *mimeData, void *param); @@ -104,4 +109,6 @@ private: QByteArray m_socket_name; }; +Q_DECLARE_OPERATORS_FOR_FLAGS(WaylandCompositor::TouchExtensionFlags) + #endif // QTCOMP_H diff --git a/src/compositor/wayland_wrapper/wlcompositor.cpp b/src/compositor/wayland_wrapper/wlcompositor.cpp index b28f8f8bde0e965a97c57c0244d0f8ccde1c97dc..75e5eb954efa2ceb8eaca46daa41c4d9f82c6546 100644 --- a/src/compositor/wayland_wrapper/wlcompositor.cpp +++ b/src/compositor/wayland_wrapper/wlcompositor.cpp @@ -384,6 +384,12 @@ void Compositor::enableTouchExtension() } } +void Compositor::configureTouchExtension(int flags) +{ + if (m_touchExtension) + m_touchExtension->setFlags(flags); +} + void Compositor::setRetainedSelectionWatcher(RetainedSelectionFunc func, void *param) { m_retainNotify = func; diff --git a/src/compositor/wayland_wrapper/wlcompositor.h b/src/compositor/wayland_wrapper/wlcompositor.h index fd0e306177eaa43a1aeca210a804a2171b3c45f8..3d4185f698884789eaada82ad9f683aa981d626f 100644 --- a/src/compositor/wayland_wrapper/wlcompositor.h +++ b/src/compositor/wayland_wrapper/wlcompositor.h @@ -119,6 +119,7 @@ public: void enableTouchExtension(); TouchExtensionGlobal *touchExtension() { return m_touchExtension; } + void configureTouchExtension(int flags); bool isDragging() const; void sendDragMoveEvent(const QPoint &global, const QPoint &local, Surface *surface); diff --git a/src/compositor/wayland_wrapper/wltouch.cpp b/src/compositor/wayland_wrapper/wltouch.cpp index f94c5af0ecd3b691e681ad763af0b04f91544f90..06499b1ae2a4c3388a2612804cd4a2b07d43b60b 100644 --- a/src/compositor/wayland_wrapper/wltouch.cpp +++ b/src/compositor/wayland_wrapper/wltouch.cpp @@ -56,7 +56,8 @@ const struct wl_touch_extension_interface TouchExtensionGlobal::touch_interface static const int maxRawPos = 24; TouchExtensionGlobal::TouchExtensionGlobal(Compositor *compositor) - : m_compositor(compositor) + : m_compositor(compositor), + m_flags(0) { wl_array_init(&m_rawdata_array); m_rawdata_ptr = static_cast<float *>(wl_array_add(&m_rawdata_array, maxRawPos * sizeof(float) * 2)); @@ -86,6 +87,7 @@ void TouchExtensionGlobal::bind_func(wl_client *client, void *data, uint32_t ver resource->destroy = destroy_resource; TouchExtensionGlobal *self = static_cast<TouchExtensionGlobal *>(resource->data); self->m_resources.append(resource); + wl_resource_post_event(resource, WL_TOUCH_EXTENSION_CONFIGURE, self->m_flags); } static inline int toFixed(qreal f) diff --git a/src/compositor/wayland_wrapper/wltouch.h b/src/compositor/wayland_wrapper/wltouch.h index e1a662c59490872e5f704eade1d0ecae02f3d048..0d63defb7e14681362536737489b91a259ee0c21 100644 --- a/src/compositor/wayland_wrapper/wltouch.h +++ b/src/compositor/wayland_wrapper/wltouch.h @@ -59,9 +59,9 @@ public: void postTouchEvent(QTouchEvent *event, Surface *surface); -private: - Compositor *m_compositor; + void setFlags(int flags) { m_flags = flags; } +private: static void bind_func(struct wl_client *client, void *data, uint32_t version, uint32_t id); @@ -69,6 +69,8 @@ private: static const struct wl_touch_extension_interface touch_interface; + Compositor *m_compositor; + int m_flags; QList<wl_resource *> m_resources; wl_array m_rawdata_array; float *m_rawdata_ptr; diff --git a/src/plugins/platforms/wayland/qwaylandtouch.cpp b/src/plugins/platforms/wayland/qwaylandtouch.cpp index 353103630605961c8528a818762433792e3b535c..82e1519b3ba5acc9ca60e4f5f71dd13de3883fbb 100644 --- a/src/plugins/platforms/wayland/qwaylandtouch.cpp +++ b/src/plugins/platforms/wayland/qwaylandtouch.cpp @@ -48,6 +48,8 @@ QWaylandTouchExtension::QWaylandTouchExtension(QWaylandDisplay *display, uint32_ { mDisplay = display; mPointsLeft = 0; + mFlags = 0; + mTouch = static_cast<struct wl_touch_extension *>(wl_display_bind(display->wl_display(), id, &wl_touch_extension_interface)); wl_touch_extension_add_listener(mTouch, &touch_listener, this); @@ -92,6 +94,7 @@ void QWaylandTouchExtension::handle_touch(void *data, wl_touch_extension *ext, u qWarning("wl_touch_extension: handle_touch: No pointer focus"); return; } + self->mTargetWindow = win->window(); QWindowSystemInterface::TouchPoint tp; tp.id = id; @@ -107,7 +110,7 @@ void QWaylandTouchExtension::handle_touch(void *data, wl_touch_extension *ext, u // Got surface-relative coords but need a (virtual) screen position. QPointF relPos = QPointF(fromFixed(x), fromFixed(y)); QPointF delta = relPos - relPos.toPoint(); - tp.area.moveCenter(win->window()->mapToGlobal(relPos.toPoint()) + delta); + tp.area.moveCenter(self->mTargetWindow->mapToGlobal(relPos.toPoint()) + delta); tp.normalPosition.setX(fromFixed(normalized_x)); tp.normalPosition.setY(fromFixed(normalized_y)); @@ -159,20 +162,41 @@ void QWaylandTouchExtension::sendTouchEvent() QWindowSystemInterface::handleTouchEvent(0, mTimestamp, mTouchDevice, mTouchPoints); - bool allReleased = true; + Qt::TouchPointStates states = 0; for (int i = 0; i < mTouchPoints.count(); ++i) - if (mTouchPoints.at(i).state != Qt::TouchPointReleased) { - allReleased = false; - break; + states |= mTouchPoints.at(i).state; + + if (mFlags & WL_TOUCH_EXTENSION_FLAGS_MOUSE_FROM_TOUCH) { + if (states == Qt::TouchPointPressed) + mMouseSourceId = mTouchPoints.first().id; + for (int i = 0; i < mTouchPoints.count(); ++i) { + const QWindowSystemInterface::TouchPoint &tp(mTouchPoints.at(i)); + if (tp.id == mMouseSourceId) { + Qt::MouseButtons buttons = tp.state == Qt::TouchPointReleased ? Qt::NoButton : Qt::LeftButton; + QPointF globalPos = tp.area.center(); + QPointF delta = globalPos - globalPos.toPoint(); + QPointF localPos = mTargetWindow->mapFromGlobal(globalPos.toPoint()) + delta; + QWindowSystemInterface::handleMouseEvent(0, mTimestamp, localPos, globalPos, buttons); + break; + } } + } mPrevTouchPoints = mTouchPoints; mTouchPoints.clear(); - if (allReleased) + if (states == Qt::TouchPointReleased) mPrevTouchPoints.clear(); } +void QWaylandTouchExtension::handle_configure(void *data, wl_touch_extension *ext, uint32_t flags) +{ + Q_UNUSED(ext); + QWaylandTouchExtension *self = static_cast<QWaylandTouchExtension *>(data); + self->mFlags = flags; +} + const struct wl_touch_extension_listener QWaylandTouchExtension::touch_listener = { QWaylandTouchExtension::handle_touch, + QWaylandTouchExtension::handle_configure }; diff --git a/src/plugins/platforms/wayland/qwaylandtouch.h b/src/plugins/platforms/wayland/qwaylandtouch.h index ab24c26fdd8dcdc3926179e7d3c6c35b6521c931..b29d136cb1da6ab60b3224b11ccdc3226e07afca 100644 --- a/src/plugins/platforms/wayland/qwaylandtouch.h +++ b/src/plugins/platforms/wayland/qwaylandtouch.h @@ -73,6 +73,9 @@ private: int32_t velocity_y, uint32_t flags, struct wl_array *rawdata); + static void handle_configure(void *data, + struct wl_touch_extension *ext, + uint32_t flags); void sendTouchEvent(); @@ -81,6 +84,9 @@ private: QTouchDevice *mTouchDevice; uint32_t mTimestamp; int mPointsLeft; + uint32_t mFlags; + int mMouseSourceId; + QWindow *mTargetWindow; }; #endif // QWAYLANDTOUCH_H