Compositor memory leak fixes
[profile/ivi/qtwayland.git] / src / compositor / wayland_wrapper / wlinputdevice.cpp
1 /****************************************************************************
2 **
3 ** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
4 ** Contact: http://www.qt-project.org/
5 **
6 ** This file is part of the Qt Compositor.
7 **
8 ** $QT_BEGIN_LICENSE:BSD$
9 ** You may use this file under the terms of the BSD license as follows:
10 **
11 ** "Redistribution and use in source and binary forms, with or without
12 ** modification, are permitted provided that the following conditions are
13 ** met:
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
19 **     distribution.
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
23 **     permission.
24 **
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."
36 **
37 ** $QT_END_LICENSE$
38 **
39 ****************************************************************************/
40
41 #include "wlinputdevice.h"
42
43 #include "wlshmbuffer.h"
44 #include "wlcompositor.h"
45 #include "wldatadevice.h"
46 #include "wlsurface.h"
47 #include "wltouch.h"
48 #include "waylandcompositor.h"
49
50 #include <QtGui/QTouchEvent>
51
52 namespace Wayland {
53
54 static ShmBuffer *currentCursor;
55
56 InputDevice::InputDevice(WaylandInputDevice *handle, Compositor *compositor)
57     : m_handle(handle)
58     , m_compositor(compositor)
59 {
60     wl_input_device_init(base());
61     wl_display_add_global(compositor->wl_display(),&wl_input_device_interface,this,InputDevice::bind_func);
62 }
63
64 InputDevice::~InputDevice()
65 {
66     qDeleteAll(m_data_devices);
67 }
68
69 void InputDevice::sendMousePressEvent(Qt::MouseButton button, const QPoint &localPos, const QPoint &globalPos)
70 {
71     sendMouseMoveEvent(localPos,globalPos);
72
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);
78     }
79 }
80
81 void InputDevice::sendMouseReleaseEvent(Qt::MouseButton button, const QPoint &localPos, const QPoint &globalPos)
82 {
83     sendMouseMoveEvent(localPos,globalPos);
84
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);
90     }
91 }
92
93 void InputDevice::sendMouseMoveEvent(const QPoint &localPos, const QPoint &globalPos)
94 {
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,
101                                time,
102                                validGlobalPos.x(), validGlobalPos.y(), //wayland sends globals before locals
103                                localPos.x(), localPos.y());
104     }
105 }
106
107 void InputDevice::sendMouseMoveEvent(Surface *surface, const QPoint &localPos, const QPoint &globalPos)
108 {
109     if (mouseFocus() != surface) {
110         setMouseFocus(surface,localPos,globalPos);
111     }
112     sendMouseMoveEvent(localPos,globalPos);
113 }
114
115 void InputDevice::sendKeyPressEvent(uint code)
116 {
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);
121     }
122 }
123
124 void InputDevice::sendKeyReleaseEvent(uint code)
125 {
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);
130     }
131 }
132
133 void InputDevice::sendTouchPointEvent(int id, int x, int y, Qt::TouchPointState state)
134 {
135     uint32_t time = m_compositor->currentTimeMsecs();
136     struct wl_resource *resource = base()->pointer_focus_resource;
137     if (!resource)
138         return;
139     switch (state) {
140     case Qt::TouchPointPressed:
141         wl_resource_post_event(resource, WL_INPUT_DEVICE_TOUCH_DOWN, time, base()->pointer_focus, id, x, y);
142         break;
143     case Qt::TouchPointMoved:
144         wl_resource_post_event(resource, WL_INPUT_DEVICE_TOUCH_MOTION, time, id, x, y);
145         break;
146     case Qt::TouchPointReleased:
147         wl_resource_post_event(resource, WL_INPUT_DEVICE_TOUCH_UP, time, id);
148         break;
149     case Qt::TouchPointStationary:
150         // stationary points are not sent through wayland, the client must cache them
151         break;
152     default:
153         break;
154     }
155 }
156
157 void InputDevice::sendTouchFrameEvent()
158 {
159     struct wl_resource *resource = base()->pointer_focus_resource;
160     if (resource) {
161         wl_resource_post_event(resource,
162                                WL_INPUT_DEVICE_TOUCH_FRAME);
163     }
164 }
165
166 void InputDevice::sendTouchCancelEvent()
167 {
168     struct wl_resource *resource = base()->pointer_focus_resource;
169     if (resource) {
170         wl_resource_post_event(resource,
171                                WL_INPUT_DEVICE_TOUCH_CANCEL);
172     }
173 }
174
175 void InputDevice::sendFullTouchEvent(QTouchEvent *event)
176 {
177     if (!mouseFocus()) {
178         qWarning("Cannot send touch event, no pointer focus, fix the compositor");
179         return;
180     }
181
182     if (event->type() == QEvent::TouchCancel) {
183         sendTouchCancelEvent();
184         return;
185     }
186
187     TouchExtensionGlobal *ext = m_compositor->touchExtension();
188     if (ext) {
189         ext->postTouchEvent(event, mouseFocus());
190         return;
191     }
192
193     const QList<QTouchEvent::TouchPoint> points = event->touchPoints();
194     if (points.isEmpty())
195         return;
196
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());
204     }
205     sendTouchFrameEvent();
206 }
207
208 Surface *InputDevice::keyboardFocus() const
209 {
210     return wayland_cast<Surface *>(base()->keyboard_focus);
211 }
212
213 void InputDevice::setKeyboardFocus(Surface *surface)
214 {
215     sendSelectionFocus(surface);
216     wl_input_device_set_keyboard_focus(base(), surface ? surface->base() : 0, m_compositor->currentTimeMsecs());
217 }
218
219 Surface *InputDevice::mouseFocus() const
220 {
221     return wayland_cast<Surface *>(base()->pointer_focus);
222 }
223
224 void InputDevice::setMouseFocus(Surface *surface, const QPoint &globalPos, const QPoint &localPos)
225 {
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());
231 }
232
233 void InputDevice::cleanupDataDeviceForClient(struct wl_client *client, bool destroyDev)
234 {
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) {
239             if (destroyDev)
240                 delete m_data_devices.at(i);
241             m_data_devices.removeAt(i);
242             break;
243         }
244     }
245 }
246
247 void InputDevice::clientRequestedDataDevice(DataDeviceManager *data_device_manager, struct wl_client *client, uint32_t id)
248 {
249     cleanupDataDeviceForClient(client, false);
250     DataDevice *dataDevice = new DataDevice(data_device_manager,client,id);
251     m_data_devices.append(dataDevice);
252 }
253
254 void InputDevice::sendSelectionFocus(Surface *surface)
255 {
256     if (!surface)
257         return;
258     DataDevice *device = dataDevice(surface->base()->resource.client);
259     if (device) {
260         device->sendSelectionFocus();
261     }
262 }
263
264 Compositor *InputDevice::compositor() const
265 {
266     return m_compositor;
267 }
268
269 WaylandInputDevice *InputDevice::handle() const
270 {
271     return m_handle;
272 }
273
274 uint32_t InputDevice::toWaylandButton(Qt::MouseButton button)
275 {
276 #ifndef BTN_LEFT
277     uint32_t BTN_LEFT = 0x110;
278     uint32_t BTN_RIGHT = 0x111;
279     uint32_t BTN_MIDDLE = 0x112;
280 #endif
281     switch (button) {
282     case Qt::LeftButton:
283         return BTN_LEFT;
284     case Qt::RightButton:
285         return BTN_RIGHT;
286     default:
287         return BTN_MIDDLE;
288     }
289 }
290
291 DataDevice *InputDevice::dataDevice(struct wl_client *client) const
292 {
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);
296         }
297     }
298     return 0;
299 }
300
301 void InputDevice::bind_func(struct wl_client *client, void *data,
302                             uint32_t version, uint32_t id)
303 {
304     Q_UNUSED(version);
305     struct wl_resource *resource = wl_client_add_object(client,&wl_input_device_interface ,&input_device_interface,id,data);
306
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);
310 }
311
312 void InputDevice::input_device_attach(struct wl_client *client,
313                          struct wl_resource *device_resource,
314                          uint32_t time,
315                          struct wl_resource *buffer_resource, int32_t x, int32_t y)
316 {
317     Q_UNUSED(client);
318     Q_UNUSED(time);
319
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);
322
323     InputDevice *inputDevice = wayland_cast<InputDevice *>(device_base);
324     if (wl_buffer_is_shm(buffer)) {
325         ShmBuffer *shmBuffer = static_cast<ShmBuffer *>(buffer->user_data);
326         if (shmBuffer) {
327             inputDevice->m_compositor->waylandCompositor()->changeCursor(shmBuffer->image(), x, y);
328             currentCursor = shmBuffer;
329         }
330     }
331 }
332
333 const struct wl_input_device_interface InputDevice::input_device_interface = {
334     InputDevice::input_device_attach,
335 };
336
337 void InputDevice::destroy_resource(wl_resource *resource)
338 {
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;
342     }
343     if (input_device->base()->pointer_focus_resource == resource) {
344         input_device->base()->pointer_focus_resource = 0;
345     }
346
347     input_device->cleanupDataDeviceForClient(resource->client, true);
348
349     wl_list_remove(&resource->link);
350
351     free(resource);
352 }
353
354 }