471e5ca46446b61cfd0bd74fd5e72f5b5d49d23d
[profile/ivi/qtwayland.git] / src / compositor / compositor_api / waylandsurfaceitem.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 "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 #include <QtGui/QGuiApplication>
51 #include <QtGui/QScreen>
52
53 #include <QtQuick/QSGSimpleTextureNode>
54 #include <QtQuick/QSGSimpleRectNode>
55 #include <QtQuick/QQuickCanvas>
56
57 class WaylandSurfaceTextureProvider : public QSGTextureProvider
58 {
59 public:
60     WaylandSurfaceTextureProvider() : t(0) { }
61
62     QSGTexture *texture() const {
63         if (t)
64             t->setFiltering(smooth ? QSGTexture::Linear : QSGTexture::Nearest);
65         return t;
66     }
67
68     QSGTexture *t;
69     bool smooth;
70 };
71
72 WaylandSurfaceItem::WaylandSurfaceItem(QQuickItem *parent)
73     : QQuickItem(parent)
74     , m_surface(0)
75     , m_texture(0)
76     , m_provider(0)
77     , m_paintEnabled(true)
78     , m_useTextureAlpha(false)
79     , m_clientRenderingEnabled(false)
80     , m_touchEventsEnabled(false)
81 {
82 }
83
84 WaylandSurfaceItem::WaylandSurfaceItem(WaylandSurface *surface, QQuickItem *parent)
85     : QQuickItem(parent)
86     , m_surface(0)
87     , m_texture(0)
88     , m_provider(0)
89     , m_paintEnabled(true)
90     , m_useTextureAlpha(false)
91     , m_clientRenderingEnabled(false)
92     , m_touchEventsEnabled(false)
93 {
94     init(surface);
95 }
96
97 void WaylandSurfaceItem::init(WaylandSurface *surface)
98 {
99     if (!surface)
100         return;
101
102     if (m_surface) {
103         m_surface->setSurfaceItem(0);
104     }
105
106     m_surface = surface;
107     m_surface->setSurfaceItem(this);
108     if (m_clientRenderingEnabled) {
109         m_surface->sendOnScreenVisibilityChange(m_clientRenderingEnabled);
110     }
111
112     setWidth(surface->size().width());
113     setHeight(surface->size().height());
114
115     setSmooth(true);
116     setFlag(ItemHasContents);
117     setAcceptedMouseButtons(Qt::LeftButton | Qt::RightButton);
118     setAcceptHoverEvents(true);
119     connect(surface, SIGNAL(mapped()), this, SLOT(surfaceMapped()));
120     connect(surface, SIGNAL(unmapped()), this, SLOT(surfaceUnmapped()));
121     connect(surface, SIGNAL(destroyed(QObject *)), this, SLOT(surfaceDestroyed(QObject *)));
122     connect(surface, SIGNAL(damaged(const QRect &)), this, SLOT(surfaceDamaged(const QRect &)));
123     connect(surface, SIGNAL(parentChanged(WaylandSurface*,WaylandSurface*)),
124             this, SLOT(parentChanged(WaylandSurface*,WaylandSurface*)));
125     connect(surface, SIGNAL(sizeChanged()), this, SLOT(updateSize()));
126     connect(surface, SIGNAL(posChanged()), this, SLOT(updatePosition()));
127
128     m_damaged = false;
129     m_yInverted = surface ? surface->isYInverted() : true;
130 }
131
132 WaylandSurfaceItem::~WaylandSurfaceItem()
133 {
134     if (m_surface) {
135         m_surface->setSurfaceItem(0);
136     }
137     m_texture->deleteLater();
138 }
139
140 void WaylandSurfaceItem::setSurface(WaylandSurface *surface)
141 {
142     if (surface == m_surface)
143         return;
144
145     init(surface);
146     emit surfaceChanged();
147 }
148
149 bool WaylandSurfaceItem::isYInverted() const
150 {
151     return m_yInverted;
152 }
153
154 QSGTextureProvider *WaylandSurfaceItem::textureProvider() const
155 {
156     if (!m_provider)
157         m_provider = new WaylandSurfaceTextureProvider();
158     return m_provider;
159 }
160
161 void WaylandSurfaceItem::mousePressEvent(QMouseEvent *event)
162 {
163     if (m_surface) {
164         WaylandInputDevice *inputDevice = m_surface->compositor()->defaultInputDevice();
165         if (inputDevice->mouseFocus() != m_surface)
166             inputDevice->setMouseFocus(m_surface, event->pos(), event->globalPos());
167         inputDevice->sendMousePressEvent(event->button(), toSurface(event->pos()));
168     }
169 }
170
171 void WaylandSurfaceItem::mouseMoveEvent(QMouseEvent *event)
172 {
173     if (m_surface){
174         WaylandInputDevice *inputDevice = m_surface->compositor()->defaultInputDevice();
175         inputDevice->sendMouseMoveEvent(m_surface, toSurface(event->pos()));
176     }
177 }
178
179 void WaylandSurfaceItem::mouseReleaseEvent(QMouseEvent *event)
180 {
181     if (m_surface){
182         WaylandInputDevice *inputDevice = m_surface->compositor()->defaultInputDevice();
183         inputDevice->sendMouseReleaseEvent(event->button(), toSurface(event->pos()));
184     }
185 }
186
187 void WaylandSurfaceItem::keyPressEvent(QKeyEvent *event)
188 {
189     if (m_surface && hasFocus()) {
190         WaylandInputDevice *inputDevice = m_surface->compositor()->defaultInputDevice();
191         inputDevice->sendKeyPressEvent(event->nativeScanCode());
192     }
193 }
194
195 void WaylandSurfaceItem::keyReleaseEvent(QKeyEvent *event)
196 {
197     if (m_surface && hasFocus()) {
198         WaylandInputDevice *inputDevice = m_surface->compositor()->defaultInputDevice();
199         inputDevice->sendKeyReleaseEvent(event->nativeScanCode());
200     }
201 }
202
203 void WaylandSurfaceItem::touchEvent(QTouchEvent *event)
204 {
205     if (m_touchEventsEnabled && m_surface) {
206         WaylandInputDevice *inputDevice = m_surface->compositor()->defaultInputDevice();
207         event->accept();
208         if (inputDevice->mouseFocus() != m_surface) {
209             QPoint pointPos;
210             QList<QTouchEvent::TouchPoint> points = event->touchPoints();
211             if (!points.isEmpty())
212                 pointPos = points.at(0).pos().toPoint();
213             inputDevice->setMouseFocus(m_surface, pointPos, pointPos);
214         }
215         inputDevice->sendFullTouchEvent(event);
216     } else {
217         event->ignore();
218     }
219 }
220
221 void WaylandSurfaceItem::takeFocus()
222 {
223     setFocus(true);
224
225     if (m_surface) {
226         WaylandInputDevice *inputDevice = m_surface->compositor()->defaultInputDevice();
227         inputDevice->setKeyboardFocus(m_surface);
228     }
229 }
230
231 QPoint WaylandSurfaceItem::toSurface(const QPointF &pos) const
232 {
233     return pos.toPoint();
234 }
235
236 void WaylandSurfaceItem::surfaceMapped()
237 {
238     setPaintEnabled(true);
239 }
240
241 void WaylandSurfaceItem::surfaceUnmapped()
242 {
243     setPaintEnabled(false);
244 }
245
246 void WaylandSurfaceItem::surfaceDestroyed(QObject *)
247 {
248     m_surface = 0;
249 }
250
251 void WaylandSurfaceItem::surfaceDamaged(const QRect &)
252 {
253     m_damaged = true;
254     if (m_surface) {
255         bool inverted = m_surface->isYInverted();
256         if (inverted  != m_yInverted) {
257             m_yInverted = inverted;
258             emit yInvertedChanged();
259         }
260     }
261     emit textureChanged();
262     update();
263 }
264
265 void WaylandSurfaceItem::parentChanged(WaylandSurface *newParent, WaylandSurface *oldParent)
266 {
267     Q_UNUSED(oldParent);
268
269     WaylandSurfaceItem *item = newParent? newParent->surfaceItem():0;
270     setParentItem(item);
271
272     if (newParent) {
273         setPaintEnabled(true);
274         setVisible(true);
275         setOpacity(1);
276         setEnabled(true);
277     }
278 }
279
280 void WaylandSurfaceItem::updateSize()
281 {
282     setSize(m_surface->size());
283 }
284
285 void WaylandSurfaceItem::updatePosition()
286 {
287     setPos(m_surface->pos());
288 }
289
290 bool WaylandSurfaceItem::paintEnabled() const
291 {
292     return m_paintEnabled;
293 }
294
295 void WaylandSurfaceItem::setPaintEnabled(bool enabled)
296 {
297     m_paintEnabled = enabled;
298     update();
299 }
300
301 QSGNode *WaylandSurfaceItem::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData *)
302 {
303     if (!m_surface) {
304         delete oldNode;
305         return 0;
306     }
307
308     if (m_damaged) {
309         QSGTexture *oldTexture = m_texture;
310         if (m_surface->type() == WaylandSurface::Texture) {
311             QOpenGLContext *context = QOpenGLContext::currentContext();
312
313             QQuickCanvas::CreateTextureOptions opt = useTextureAlpha() ? QQuickCanvas::TextureHasAlphaChannel : QQuickCanvas::CreateTextureOptions(0);
314             m_texture = canvas()->createTextureFromId(m_surface->texture(context),
315                                                                           m_surface->size(),
316                                                                           opt);
317         } else {
318             m_texture = canvas()->createTextureFromImage(m_surface->image());
319         }
320
321         delete oldTexture;
322         m_damaged = false;
323     }
324
325     if (m_provider) {
326         m_provider->t = m_texture;
327         m_provider->smooth = smooth();
328     }
329
330     QSGSimpleTextureNode *node = static_cast<QSGSimpleTextureNode *>(oldNode);
331     if (!m_texture || !m_paintEnabled) {
332         delete oldNode;
333         return 0;
334     }
335
336     if (!node) {
337         node = new QSGSimpleTextureNode();
338     }
339
340     if (surface()->isYInverted()) {
341         node->setRect(0, height(), width(), -height());
342     } else {
343         node->setRect(0, 0, width(), height());
344     }
345
346     node->setTexture(m_texture);
347     node->setFiltering(smooth() ? QSGTexture::Linear : QSGTexture::Nearest);
348
349     return node;
350 }
351
352 void WaylandSurfaceItem::setUseTextureAlpha(bool useTextureAlpha)
353 {
354     m_useTextureAlpha = useTextureAlpha;
355
356     if ((flags() & ItemHasContents) != 0) {
357         update();
358     }
359 }
360
361 void WaylandSurfaceItem::setClientRenderingEnabled(bool enabled)
362 {
363     if (m_clientRenderingEnabled != enabled) {
364         m_clientRenderingEnabled = enabled;
365
366         if (m_surface) {
367             m_surface->sendOnScreenVisibilityChange(enabled);
368         }
369
370         emit clientRenderingEnabledChanged();
371     }
372 }
373
374 void WaylandSurfaceItem::setTouchEventsEnabled(bool enabled)
375 {
376     if (m_touchEventsEnabled != enabled) {
377         m_touchEventsEnabled = enabled;
378         emit touchEventsEnabledChanged();
379     }
380 }