Move event handling into WaylandInput api
[profile/ivi/qtwayland.git] / src / compositor / compositor_api / waylandsurfaceitem.cpp
1 /****************************************************************************
2 **
3 ** This file is part of QtCompositor**
4 **
5 ** Copyright © 2010 Nokia Corporation and/or its subsidiary(-ies).
6 ** All rights reserved.
7 **
8 ** Contact:  Nokia Corporation qt-info@nokia.com
9 **
10 ** You may use this file under the terms of the BSD license as follows:
11 **
12 ** Redistribution and use in source and binary forms, with or without
13 ** modification, are permitted provided that the following conditions are
14 ** met:
15 **
16 ** Redistributions of source code must retain the above copyright
17 ** notice, this list of conditions and the following disclaimer.
18 **
19 ** Redistributions in binary form must reproduce the above copyright
20 ** notice, this list of conditions and the following disclaimer in the
21 ** documentation and/or other materials provided with the distribution.
22 **
23 ** Neither the name of Nokia Corporation and its Subsidiary(-ies) nor the
24 ** names of its contributors may be used to endorse or promote products
25 ** derived from this software without specific prior written permission.
26 **
27 ** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
28 ** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
29 ** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
30 ** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
31 ** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
32 ** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
33 ** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
34 ** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
35 ** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
36 ** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
37 ** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
38 **
39 ****************************************************************************/
40
41 #include "waylandsurfaceitem.h"
42 #include "waylandsurface.h"
43 #include "waylandcompositor.h"
44 #include "waylandinput.h"
45
46 #include "wlsurface.h"
47 #include "wlextendedsurface.h"
48
49 #include <QtGui/QKeyEvent>
50
51 #include <QtQuick/QSGSimpleTextureNode>
52 #include <QtQuick/QSGSimpleRectNode>
53 #include <QtQuick/QQuickCanvas>
54
55 class WaylandSurfaceTextureProvider : public QSGTextureProvider
56 {
57 public:
58     WaylandSurfaceTextureProvider() : t(0) { }
59
60     QSGTexture *texture() const {
61         if (t)
62             t->setFiltering(smooth ? QSGTexture::Linear : QSGTexture::Nearest);
63         return t;
64     }
65
66     QSGTexture *t;
67     bool smooth;
68 };
69
70 WaylandSurfaceItem::WaylandSurfaceItem(QQuickItem *parent)
71     : QQuickItem(parent)
72     , m_surface(0)
73     , m_texture(0)
74     , m_provider(0)
75     , m_paintEnabled(true)
76     , m_touchEventsEnabled(false)
77 {
78 }
79
80 WaylandSurfaceItem::WaylandSurfaceItem(WaylandSurface *surface, QQuickItem *parent)
81     : QQuickItem(parent)
82     , m_surface(0)
83     , m_texture(0)
84     , m_provider(0)
85     , m_paintEnabled(true)
86     , m_touchEventsEnabled(false)
87 {
88     init(surface);
89 }
90
91 void WaylandSurfaceItem::init(WaylandSurface *surface)
92 {
93     if (!surface)
94         return;
95
96     if (m_surface) {
97         m_surface->setSurfaceItem(0);
98     }
99
100     m_surface = surface;
101     m_surface->setSurfaceItem(this);
102
103     setWidth(surface->size().width());
104     setHeight(surface->size().height());
105
106     setSmooth(true);
107     setFlag(ItemHasContents);
108     setAcceptedMouseButtons(Qt::LeftButton | Qt::RightButton);
109     connect(surface, SIGNAL(mapped()), this, SLOT(surfaceMapped()));
110     connect(surface, SIGNAL(unmapped()), this, SLOT(surfaceUnmapped()));
111     connect(surface, SIGNAL(destroyed(QObject *)), this, SLOT(surfaceDestroyed(QObject *)));
112     connect(surface, SIGNAL(damaged(const QRect &)), this, SLOT(surfaceDamaged(const QRect &)));
113     connect(surface, SIGNAL(parentChanged(WaylandSurface*,WaylandSurface*)),
114             this, SLOT(parentChanged(WaylandSurface*,WaylandSurface*)));
115     connect(surface, SIGNAL(sizeChanged()), this, SLOT(updateSize()));
116     connect(surface, SIGNAL(posChanged()), this, SLOT(updatePosition()));
117
118     m_damaged = false;
119     m_yInverted = surface ? surface->isYInverted() : true;
120 }
121
122 WaylandSurfaceItem::~WaylandSurfaceItem()
123 {
124     if (m_surface) {
125         m_surface->setSurfaceItem(0);
126     }
127     m_texture->deleteLater();
128 }
129
130 void WaylandSurfaceItem::setSurface(WaylandSurface *surface)
131 {
132     init(surface);
133 }
134
135 bool WaylandSurfaceItem::isYInverted() const
136 {
137     return m_yInverted;
138 }
139
140 QSGTextureProvider *WaylandSurfaceItem::textureProvider() const
141 {
142     if (!m_provider)
143         m_provider = new WaylandSurfaceTextureProvider();
144     return m_provider;
145 }
146
147 void WaylandSurfaceItem::mousePressEvent(QMouseEvent *event)
148 {
149     if (m_surface) {
150         WaylandInputDevice *inputDevice = m_surface->compositor()->defaultInputDevice();
151         inputDevice->sendMousePressEvent(event->button(), toSurface(event->pos()));
152     }
153 }
154
155 void WaylandSurfaceItem::mouseMoveEvent(QMouseEvent *event)
156 {
157     if (m_surface){
158         WaylandInputDevice *inputDevice = m_surface->compositor()->defaultInputDevice();
159         inputDevice->sendMouseMoveEvent(m_surface, toSurface(event->pos()));
160     }
161 }
162
163 void WaylandSurfaceItem::mouseReleaseEvent(QMouseEvent *event)
164 {
165     if (m_surface){
166         WaylandInputDevice *inputDevice = m_surface->compositor()->defaultInputDevice();
167         inputDevice->sendMouseReleaseEvent(event->button(), toSurface(event->pos()));
168     }
169 }
170
171 void WaylandSurfaceItem::keyPressEvent(QKeyEvent *event)
172 {
173     if (m_surface && hasFocus()) {
174         WaylandInputDevice *inputDevice = m_surface->compositor()->defaultInputDevice();
175         inputDevice->sendKeyPressEvent(event->nativeScanCode());
176     }
177 }
178
179 void WaylandSurfaceItem::keyReleaseEvent(QKeyEvent *event)
180 {
181     if (m_surface && hasFocus()) {
182         WaylandInputDevice *inputDevice = m_surface->compositor()->defaultInputDevice();
183         inputDevice->sendKeyReleaseEvent(event->nativeScanCode());
184     }
185 }
186
187 void WaylandSurfaceItem::touchEvent(QTouchEvent *event)
188 {
189     if (m_touchEventsEnabled && m_surface) {
190         WaylandInputDevice *inputDevice = m_surface->compositor()->defaultInputDevice();
191         event->accept();
192         QList<QTouchEvent::TouchPoint> points = event->touchPoints();
193         if (!points.isEmpty()) {
194             for (int i = 0; i < points.count(); ++i) {
195                 const QTouchEvent::TouchPoint &point(points.at(i));
196                 // Wayland expects surface-relative coordinates.
197                 inputDevice->sendTouchPointEvent(point.id(), point.pos().x(), point.pos().y(), point.state());
198             }
199             inputDevice->sendTouchFrameEvent();
200         }
201     } else {
202         event->ignore();
203     }
204 }
205
206 void WaylandSurfaceItem::takeFocus()
207 {
208     setFocus(true);
209
210     if (m_surface) {
211         WaylandInputDevice *inputDevice = m_surface->compositor()->defaultInputDevice();
212         inputDevice->setKeyboardFocus(m_surface);
213     }
214 }
215
216 QPoint WaylandSurfaceItem::toSurface(const QPointF &pos) const
217 {
218     return pos.toPoint();
219 }
220
221 void WaylandSurfaceItem::surfaceMapped()
222 {
223     setPaintEnabled(true);
224 }
225
226 void WaylandSurfaceItem::surfaceUnmapped()
227 {
228     setPaintEnabled(false);
229 }
230
231 void WaylandSurfaceItem::surfaceDestroyed(QObject *)
232 {
233     m_surface = 0;
234 }
235
236 void WaylandSurfaceItem::surfaceDamaged(const QRect &)
237 {
238     m_damaged = true;
239     if (m_surface) {
240         bool inverted = m_surface->isYInverted();
241         if (inverted  != m_yInverted) {
242             m_yInverted = inverted;
243             emit yInvertedChanged();
244         }
245     }
246     emit textureChanged();
247     update();
248 }
249
250 void WaylandSurfaceItem::parentChanged(WaylandSurface *newParent, WaylandSurface *oldParent)
251 {
252     Q_UNUSED(oldParent);
253
254     WaylandSurfaceItem *item = newParent? newParent->surfaceItem():0;
255     setParentItem(item);
256
257     if (newParent) {
258         setPaintEnabled(true);
259         setVisible(true);
260         setOpacity(1);
261         setEnabled(true);
262     }
263 }
264
265 void WaylandSurfaceItem::updateSize()
266 {
267     setSize(m_surface->size());
268 }
269
270 void WaylandSurfaceItem::updatePosition()
271 {
272     setPos(m_surface->pos());
273 }
274
275 bool WaylandSurfaceItem::paintEnabled() const
276 {
277     return m_paintEnabled;
278 }
279
280 void WaylandSurfaceItem::setPaintEnabled(bool enabled)
281 {
282     m_paintEnabled = enabled;
283     update();
284 }
285
286 QSGNode *WaylandSurfaceItem::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData *)
287 {
288     if (!m_surface) {
289         delete oldNode;
290         return 0;
291     }
292
293     if (m_damaged) {
294         QSGTexture *oldTexture = m_texture;
295         if (m_surface->type() == WaylandSurface::Texture) {
296             QOpenGLContext *context = QOpenGLContext::currentContext();
297
298             QQuickCanvas::CreateTextureOptions opt = useTextureAlpha() ? QQuickCanvas::TextureHasAlphaChannel : QQuickCanvas::CreateTextureOptions(0);
299             m_texture = canvas()->createTextureFromId(m_surface->texture(context),
300                                                                           m_surface->size(),
301                                                                           opt);
302         } else {
303             m_texture = canvas()->createTextureFromImage(m_surface->image());
304         }
305
306         delete oldTexture;
307         m_damaged = false;
308     }
309
310     if (m_provider) {
311         m_provider->t = m_texture;
312         m_provider->smooth = smooth();
313     }
314
315     QSGSimpleTextureNode *node = static_cast<QSGSimpleTextureNode *>(oldNode);
316     if (!m_texture || !m_paintEnabled) {
317         delete oldNode;
318         return 0;
319     }
320
321     if (!node) {
322         node = new QSGSimpleTextureNode();
323     }
324
325     if (surface()->isYInverted()) {
326         node->setRect(0, height(), width(), -height());
327     } else {
328         node->setRect(0, 0, width(), height());
329     }
330
331     node->setTexture(m_texture);
332     node->setFiltering(smooth() ? QSGTexture::Linear : QSGTexture::Nearest);
333
334     return node;
335 }
336
337 void WaylandSurfaceItem::setUseTextureAlpha(bool useTextureAlpha)
338 {
339     m_useTextureAlpha = useTextureAlpha;
340
341     if ((flags() & ItemHasContents) != 0) {
342         update();
343     }
344 }
345
346 void WaylandSurfaceItem::setClientRenderingEnabled(bool enabled)
347 {
348     if (m_clientRenderingEnabled != enabled) {
349         m_clientRenderingEnabled = enabled;
350
351         if (m_surface) {
352             m_surface->sendOnScreenVisibilityChange(enabled);
353         }
354
355         emit clientRenderingEnabledChanged();
356     }
357 }
358
359 void WaylandSurfaceItem::setTouchEventsEnabled(bool enabled)
360 {
361     if (m_touchEventsEnabled != enabled) {
362         m_touchEventsEnabled = enabled;
363         emit touchEventsEnabledChanged();
364     }
365 }