1 /****************************************************************************
3 ** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
4 ** Contact: http://www.qt-project.org/
6 ** This file is part of the Qt Compositor.
8 ** $QT_BEGIN_LICENSE:BSD$
9 ** You may use this file under the terms of the BSD license as follows:
11 ** "Redistribution and use in source and binary forms, with or without
12 ** modification, are permitted provided that the following conditions are
14 ** * Redistributions of source code must retain the above copyright
15 ** notice, this list of conditions and the following disclaimer.
16 ** * Redistributions in binary form must reproduce the above copyright
17 ** notice, this list of conditions and the following disclaimer in
18 ** the documentation and/or other materials provided with the
20 ** * Neither the name of Nokia Corporation and its Subsidiary(-ies) nor
21 ** the names of its contributors may be used to endorse or promote
22 ** products derived from this software without specific prior written
25 ** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
26 ** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
27 ** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
28 ** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
29 ** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
30 ** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
31 ** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
32 ** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
33 ** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
34 ** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
35 ** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
39 ****************************************************************************/
41 #include "wlinputdevice.h"
43 #include "wlshmbuffer.h"
44 #include "wlcompositor.h"
45 #include "wldatadevice.h"
46 #include "wlsurface.h"
48 #include "waylandcompositor.h"
50 #include <QtGui/QTouchEvent>
54 static ShmBuffer *currentCursor;
56 InputDevice::InputDevice(WaylandInputDevice *handle, Compositor *compositor)
58 , m_compositor(compositor)
60 wl_input_device_init(base());
61 wl_display_add_global(compositor->wl_display(),&wl_input_device_interface,this,InputDevice::bind_func);
64 InputDevice::~InputDevice()
66 qDeleteAll(m_data_devices);
69 void InputDevice::sendMousePressEvent(Qt::MouseButton button, const QPoint &localPos, const QPoint &globalPos)
71 sendMouseMoveEvent(localPos,globalPos);
73 uint32_t time = m_compositor->currentTimeMsecs();
74 struct wl_resource *pointer_focus_resource = base()->pointer_focus_resource;
75 if (pointer_focus_resource) {
76 wl_resource_post_event(pointer_focus_resource,
77 WL_INPUT_DEVICE_BUTTON, time, toWaylandButton(button), 1);
81 void InputDevice::sendMouseReleaseEvent(Qt::MouseButton button, const QPoint &localPos, const QPoint &globalPos)
83 sendMouseMoveEvent(localPos,globalPos);
85 uint32_t time = m_compositor->currentTimeMsecs();
86 struct wl_resource *pointer_focus_resource = base()->pointer_focus_resource;
87 if (pointer_focus_resource) {
88 wl_resource_post_event(pointer_focus_resource,
89 WL_INPUT_DEVICE_BUTTON, time, toWaylandButton(button), 0);
93 void InputDevice::sendMouseMoveEvent(const QPoint &localPos, const QPoint &globalPos)
95 uint32_t time = m_compositor->currentTimeMsecs();
96 struct wl_resource *pointer_focus_resource = base()->pointer_focus_resource;
97 if (pointer_focus_resource) {
98 QPoint validGlobalPos = globalPos.isNull()?localPos:globalPos;
99 wl_resource_post_event(pointer_focus_resource,
100 WL_INPUT_DEVICE_MOTION,
102 validGlobalPos.x(), validGlobalPos.y(), //wayland sends globals before locals
103 localPos.x(), localPos.y());
107 void InputDevice::sendMouseMoveEvent(Surface *surface, const QPoint &localPos, const QPoint &globalPos)
109 if (mouseFocus() != surface) {
110 setMouseFocus(surface,localPos,globalPos);
112 sendMouseMoveEvent(localPos,globalPos);
115 void InputDevice::sendKeyPressEvent(uint code)
117 if (base()->keyboard_focus_resource != NULL) {
118 uint32_t time = m_compositor->currentTimeMsecs();
119 wl_resource_post_event(base()->keyboard_focus_resource,
120 WL_INPUT_DEVICE_KEY, time, code - 8, 1);
124 void InputDevice::sendKeyReleaseEvent(uint code)
126 if (base()->keyboard_focus_resource != NULL) {
127 uint32_t time = m_compositor->currentTimeMsecs();
128 wl_resource_post_event(base()->keyboard_focus_resource,
129 WL_INPUT_DEVICE_KEY, time, code - 8, 0);
133 void InputDevice::sendTouchPointEvent(int id, int x, int y, Qt::TouchPointState state)
135 uint32_t time = m_compositor->currentTimeMsecs();
136 struct wl_resource *resource = base()->pointer_focus_resource;
140 case Qt::TouchPointPressed:
141 wl_resource_post_event(resource, WL_INPUT_DEVICE_TOUCH_DOWN, time, base()->pointer_focus, id, x, y);
143 case Qt::TouchPointMoved:
144 wl_resource_post_event(resource, WL_INPUT_DEVICE_TOUCH_MOTION, time, id, x, y);
146 case Qt::TouchPointReleased:
147 wl_resource_post_event(resource, WL_INPUT_DEVICE_TOUCH_UP, time, id);
149 case Qt::TouchPointStationary:
150 // stationary points are not sent through wayland, the client must cache them
157 void InputDevice::sendTouchFrameEvent()
159 struct wl_resource *resource = base()->pointer_focus_resource;
161 wl_resource_post_event(resource,
162 WL_INPUT_DEVICE_TOUCH_FRAME);
166 void InputDevice::sendTouchCancelEvent()
168 struct wl_resource *resource = base()->pointer_focus_resource;
170 wl_resource_post_event(resource,
171 WL_INPUT_DEVICE_TOUCH_CANCEL);
175 void InputDevice::sendFullTouchEvent(QTouchEvent *event)
178 qWarning("Cannot send touch event, no pointer focus, fix the compositor");
182 if (event->type() == QEvent::TouchCancel) {
183 sendTouchCancelEvent();
187 TouchExtensionGlobal *ext = m_compositor->touchExtension();
189 ext->postTouchEvent(event, mouseFocus());
193 const QList<QTouchEvent::TouchPoint> points = event->touchPoints();
194 if (points.isEmpty())
197 const int pointCount = points.count();
198 QPointF pos = mouseFocus()->pos();
199 for (int i = 0; i < pointCount; ++i) {
200 const QTouchEvent::TouchPoint &tp(points.at(i));
201 // Convert the local pos in the compositor window to surface-relative.
202 QPoint p = (tp.pos() - pos).toPoint();
203 sendTouchPointEvent(tp.id(), p.x(), p.y(), tp.state());
205 sendTouchFrameEvent();
208 Surface *InputDevice::keyboardFocus() const
210 return wayland_cast<Surface *>(base()->keyboard_focus);
213 void InputDevice::setKeyboardFocus(Surface *surface)
215 sendSelectionFocus(surface);
216 wl_input_device_set_keyboard_focus(base(), surface ? surface->base() : 0, m_compositor->currentTimeMsecs());
219 Surface *InputDevice::mouseFocus() const
221 return wayland_cast<Surface *>(base()->pointer_focus);
224 void InputDevice::setMouseFocus(Surface *surface, const QPoint &globalPos, const QPoint &localPos)
226 wl_input_device_set_pointer_focus(base(),
227 surface ? surface->base() : 0,
228 m_compositor->currentTimeMsecs(),
229 globalPos.x(), globalPos.y(),
230 localPos.x(), localPos.y());
233 void InputDevice::cleanupDataDeviceForClient(struct wl_client *client, bool destroyDev)
235 for (int i = 0; i < m_data_devices.size(); i++) {
236 struct wl_resource *data_device_resource =
237 m_data_devices.at(i)->dataDeviceResource();
238 if (data_device_resource->client == client) {
240 delete m_data_devices.at(i);
241 m_data_devices.removeAt(i);
247 void InputDevice::clientRequestedDataDevice(DataDeviceManager *data_device_manager, struct wl_client *client, uint32_t id)
249 cleanupDataDeviceForClient(client, false);
250 DataDevice *dataDevice = new DataDevice(data_device_manager,client,id);
251 m_data_devices.append(dataDevice);
254 void InputDevice::sendSelectionFocus(Surface *surface)
258 DataDevice *device = dataDevice(surface->base()->resource.client);
260 device->sendSelectionFocus();
264 Compositor *InputDevice::compositor() const
269 WaylandInputDevice *InputDevice::handle() const
274 uint32_t InputDevice::toWaylandButton(Qt::MouseButton button)
277 uint32_t BTN_LEFT = 0x110;
278 uint32_t BTN_RIGHT = 0x111;
279 uint32_t BTN_MIDDLE = 0x112;
284 case Qt::RightButton:
291 DataDevice *InputDevice::dataDevice(struct wl_client *client) const
293 for (int i = 0; i < m_data_devices.size();i++) {
294 if (m_data_devices.at(i)->dataDeviceResource()->client == client) {
295 return m_data_devices.at(i);
301 void InputDevice::bind_func(struct wl_client *client, void *data,
302 uint32_t version, uint32_t id)
305 struct wl_resource *resource = wl_client_add_object(client,&wl_input_device_interface ,&input_device_interface,id,data);
307 struct wl_input_device *input_device = static_cast<struct wl_input_device *>(data);
308 resource->destroy = destroy_resource;
309 wl_list_insert(&input_device->resource_list,&resource->link);
312 void InputDevice::input_device_attach(struct wl_client *client,
313 struct wl_resource *device_resource,
315 struct wl_resource *buffer_resource, int32_t x, int32_t y)
320 struct wl_input_device *device_base = reinterpret_cast<struct wl_input_device *>(device_resource->data);
321 struct wl_buffer *buffer = reinterpret_cast<struct wl_buffer *>(buffer_resource);
323 InputDevice *inputDevice = wayland_cast<InputDevice *>(device_base);
324 if (wl_buffer_is_shm(buffer)) {
325 ShmBuffer *shmBuffer = static_cast<ShmBuffer *>(buffer->user_data);
327 inputDevice->m_compositor->waylandCompositor()->changeCursor(shmBuffer->image(), x, y);
328 currentCursor = shmBuffer;
333 const struct wl_input_device_interface InputDevice::input_device_interface = {
334 InputDevice::input_device_attach,
337 void InputDevice::destroy_resource(wl_resource *resource)
339 InputDevice *input_device = static_cast<InputDevice *>(resource->data);
340 if (input_device->base()->keyboard_focus_resource == resource) {
341 input_device->base()->keyboard_focus_resource = 0;
343 if (input_device->base()->pointer_focus_resource == resource) {
344 input_device->base()->pointer_focus_resource = 0;
347 input_device->cleanupDataDeviceForClient(resource->client, true);
349 wl_list_remove(&resource->link);