From 083ece74feedb93c0ed208017658c85a4bb1e532 Mon Sep 17 00:00:00 2001 From: Laszlo Agocs <laszlo.p.agocs@nokia.com> Date: Tue, 7 Feb 2012 11:39:49 +0200 Subject: [PATCH] Add mouse event synthesizing to the touch extension protocol. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The compositor can now be configured to tell the clients to generate mouse events when receiving touch events. In touchscreen-only systems this can be used to reduce the number of Wayland events. Change-Id: I231a15cd4ed463ee81c510c082a270efa255a1f3 Reviewed-by: Jørgen Lind <jorgen.lind@nokia.com> --- examples/qwindow-compositor/qopenglwindow.cpp | 8 +++++ examples/qwindow-compositor/qopenglwindow.h | 3 +- .../qwindow-compositor/qwindowcompositor.cpp | 5 +++ extensions/touch-extension.xml | 8 +++++ .../compositor_api/waylandcompositor.cpp | 5 +++ .../compositor_api/waylandcompositor.h | 7 ++++ .../wayland_wrapper/wlcompositor.cpp | 6 ++++ src/compositor/wayland_wrapper/wlcompositor.h | 1 + src/compositor/wayland_wrapper/wltouch.cpp | 4 ++- src/compositor/wayland_wrapper/wltouch.h | 6 ++-- .../platforms/wayland/qwaylandtouch.cpp | 36 +++++++++++++++---- src/plugins/platforms/wayland/qwaylandtouch.h | 6 ++++ 12 files changed, 85 insertions(+), 10 deletions(-) diff --git a/examples/qwindow-compositor/qopenglwindow.cpp b/examples/qwindow-compositor/qopenglwindow.cpp index d70c4a96..473e4c15 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 0d1cfbf7..2ba883cf 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 90192f98..a7132101 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 268d70a6..d1baa7ba 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 eee6805f..c86698bd 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 f4d64992..3cc255a8 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 b28f8f8b..75e5eb95 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 fd0e3061..3d4185f6 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 f94c5af0..06499b1a 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 e1a662c5..0d63defb 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 35310363..82e1519b 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 ab24c26f..b29d136c 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 -- GitLab