Change copyrights from Nokia to Digia
[profile/ivi/qtwayland.git] / src / compositor / compositor_api / waylandsurfaceitem.cpp
1 /****************************************************************************
2 **
3 ** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies).
4 ** Contact: http://www.qt-project.org/legal
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 Digia Plc and its Subsidiary(-ies) nor the names
21 **     of its contributors may be used to endorse or promote products derived
22 **     from this software without specific prior written permission.
23 **
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 "waylandsurfacenode.h"
43 #include "waylandsurface.h"
44 #include "waylandcompositor.h"
45 #include "waylandinput.h"
46
47 #include "wlsurface.h"
48 #include "wlextendedsurface.h"
49
50 #include <QtGui/QKeyEvent>
51 #include <QtGui/QGuiApplication>
52 #include <QtGui/QScreen>
53
54 #include <QtQuick/QSGSimpleRectNode>
55 #include <QtQuick/QQuickCanvas>
56
57 #include <QtCore/QMutexLocker>
58 #include <QtCore/QMutex>
59
60
61 class WaylandSurfaceTextureProvider : public QSGTextureProvider
62 {
63     Q_OBJECT
64
65 public:
66     WaylandSurfaceTextureProvider() : t(0) { }
67     ~WaylandSurfaceTextureProvider() { delete t; }
68
69     QSGTexture *texture() const {
70         if (t)
71             t->setFiltering(smooth ? QSGTexture::Linear : QSGTexture::Nearest);
72         return t;
73     }
74
75     bool smooth;
76     QSGTexture *t;
77
78 public slots:
79     void invalidate()
80     {
81         delete t;
82         t = 0;
83     }
84 };
85
86 QMutex *WaylandSurfaceItem::mutex = 0;
87
88 WaylandSurfaceItem::WaylandSurfaceItem(QQuickItem *parent)
89     : QQuickItem(parent)
90     , m_surface(0)
91     , m_provider(0)
92     , m_node(0)
93     , m_paintEnabled(true)
94     , m_useTextureAlpha(false)
95     , m_clientRenderingEnabled(false)
96     , m_touchEventsEnabled(false)
97 {
98     if (!mutex)
99         mutex = new QMutex;
100 }
101
102 WaylandSurfaceItem::WaylandSurfaceItem(WaylandSurface *surface, QQuickItem *parent)
103     : QQuickItem(parent)
104     , m_surface(0)
105     , m_provider(0)
106     , m_node(0)
107     , m_paintEnabled(true)
108     , m_useTextureAlpha(false)
109     , m_clientRenderingEnabled(false)
110     , m_touchEventsEnabled(false)
111 {
112     init(surface);
113 }
114
115 void WaylandSurfaceItem::init(WaylandSurface *surface)
116 {
117     if (!surface)
118         return;
119
120     if (m_surface) {
121         m_surface->setSurfaceItem(0);
122     }
123
124     m_surface = surface;
125     m_surface->setSurfaceItem(this);
126     if (m_clientRenderingEnabled) {
127         m_surface->sendOnScreenVisibilityChange(m_clientRenderingEnabled);
128     }
129
130     setWidth(surface->size().width());
131     setHeight(surface->size().height());
132
133     setSmooth(true);
134     setFlag(ItemHasContents);
135     setAcceptedMouseButtons(Qt::LeftButton | Qt::MiddleButton | Qt::RightButton |
136         Qt::ExtraButton1 | Qt::ExtraButton2 | Qt::ExtraButton3 | Qt::ExtraButton4 |
137         Qt::ExtraButton5 | Qt::ExtraButton6 | Qt::ExtraButton7 | Qt::ExtraButton8 |
138         Qt::ExtraButton9 | Qt::ExtraButton10 | Qt::ExtraButton11 |
139         Qt::ExtraButton12 | Qt::ExtraButton13);
140     setAcceptHoverEvents(true);
141     connect(surface, SIGNAL(mapped()), this, SLOT(surfaceMapped()));
142     connect(surface, SIGNAL(unmapped()), this, SLOT(surfaceUnmapped()));
143     connect(surface, SIGNAL(destroyed(QObject *)), this, SLOT(surfaceDestroyed(QObject *)));
144     connect(surface, SIGNAL(damaged(const QRect &)), this, SLOT(surfaceDamaged(const QRect &)));
145     connect(surface, SIGNAL(parentChanged(WaylandSurface*,WaylandSurface*)),
146             this, SLOT(parentChanged(WaylandSurface*,WaylandSurface*)));
147     connect(surface, SIGNAL(sizeChanged()), this, SLOT(updateSize()));
148     connect(surface, SIGNAL(posChanged()), this, SLOT(updatePosition()));
149
150     m_damaged = false;
151     m_yInverted = surface ? surface->isYInverted() : true;
152 }
153
154 WaylandSurfaceItem::~WaylandSurfaceItem()
155 {
156     QMutexLocker locker(mutex);
157     if (m_node)
158         m_node->setItem(0);
159     if (m_surface)
160         m_surface->setSurfaceItem(0);
161     if (m_provider)
162         m_provider->deleteLater();
163 }
164
165 void WaylandSurfaceItem::setSurface(WaylandSurface *surface)
166 {
167     if (surface == m_surface)
168         return;
169
170     init(surface);
171     emit surfaceChanged();
172 }
173
174 bool WaylandSurfaceItem::isYInverted() const
175 {
176     return m_yInverted;
177 }
178
179 QSGTextureProvider *WaylandSurfaceItem::textureProvider() const
180 {
181     const_cast<WaylandSurfaceItem *>(this)->ensureProvider();
182     return m_provider;
183 }
184
185 void WaylandSurfaceItem::ensureProvider()
186 {
187     if (!m_provider) {
188         m_provider = new WaylandSurfaceTextureProvider();
189         connect(canvas(), SIGNAL(sceneGraphInvalidated()), m_provider, SLOT(invalidate()), Qt::DirectConnection);
190     }
191 }
192
193 void WaylandSurfaceItem::mousePressEvent(QMouseEvent *event)
194 {
195     if (m_surface) {
196         WaylandInputDevice *inputDevice = m_surface->compositor()->defaultInputDevice();
197         if (inputDevice->mouseFocus() != m_surface)
198             inputDevice->setMouseFocus(m_surface, event->pos(), event->globalPos());
199         inputDevice->sendMousePressEvent(event->button(), toSurface(event->pos()), event->globalPos());
200     }
201 }
202
203 void WaylandSurfaceItem::mouseMoveEvent(QMouseEvent *event)
204 {
205     if (m_surface){
206         WaylandInputDevice *inputDevice = m_surface->compositor()->defaultInputDevice();
207         inputDevice->sendMouseMoveEvent(m_surface, toSurface(event->pos()), event->globalPos());
208     }
209 }
210
211 void WaylandSurfaceItem::mouseReleaseEvent(QMouseEvent *event)
212 {
213     if (m_surface){
214         WaylandInputDevice *inputDevice = m_surface->compositor()->defaultInputDevice();
215         inputDevice->sendMouseReleaseEvent(event->button(), toSurface(event->pos()), event->globalPos());
216     }
217 }
218
219 void WaylandSurfaceItem::wheelEvent(QWheelEvent *event)
220 {
221     if (m_surface) {
222         WaylandInputDevice *inputDevice = m_surface->compositor()->defaultInputDevice();
223         inputDevice->sendMouseWheelEvent(event->orientation(), event->delta());
224     }
225 }
226
227 void WaylandSurfaceItem::keyPressEvent(QKeyEvent *event)
228 {
229     if (m_surface && hasFocus()) {
230         WaylandInputDevice *inputDevice = m_surface->compositor()->defaultInputDevice();
231         inputDevice->sendFullKeyEvent(event);
232     }
233 }
234
235 void WaylandSurfaceItem::keyReleaseEvent(QKeyEvent *event)
236 {
237     if (m_surface && hasFocus()) {
238         WaylandInputDevice *inputDevice = m_surface->compositor()->defaultInputDevice();
239         inputDevice->sendFullKeyEvent(event);
240     }
241 }
242
243 void WaylandSurfaceItem::touchEvent(QTouchEvent *event)
244 {
245     if (m_touchEventsEnabled && m_surface) {
246         WaylandInputDevice *inputDevice = m_surface->compositor()->defaultInputDevice();
247         event->accept();
248         if (inputDevice->mouseFocus() != m_surface) {
249             QPoint pointPos;
250             QList<QTouchEvent::TouchPoint> points = event->touchPoints();
251             if (!points.isEmpty())
252                 pointPos = points.at(0).pos().toPoint();
253             inputDevice->setMouseFocus(m_surface, pointPos, pointPos);
254         }
255         inputDevice->sendFullTouchEvent(event);
256     } else {
257         event->ignore();
258     }
259 }
260
261 void WaylandSurfaceItem::takeFocus()
262 {
263     setFocus(true);
264
265     if (m_surface) {
266         WaylandInputDevice *inputDevice = m_surface->compositor()->defaultInputDevice();
267         inputDevice->setKeyboardFocus(m_surface);
268     }
269 }
270
271 QPoint WaylandSurfaceItem::toSurface(const QPointF &pos) const
272 {
273     return pos.toPoint();
274 }
275
276 void WaylandSurfaceItem::surfaceMapped()
277 {
278     setPaintEnabled(true);
279 }
280
281 void WaylandSurfaceItem::surfaceUnmapped()
282 {
283     setPaintEnabled(false);
284 }
285
286 void WaylandSurfaceItem::surfaceDestroyed(QObject *)
287 {
288     m_surface = 0;
289 }
290
291 void WaylandSurfaceItem::setDamagedFlag(bool on)
292 {
293     m_damaged = on;
294 }
295
296
297 void WaylandSurfaceItem::surfaceDamaged(const QRect &)
298 {
299     m_damaged = true;
300     if (m_surface) {
301         bool inverted = m_surface->isYInverted();
302         if (inverted  != m_yInverted) {
303             m_yInverted = inverted;
304             emit yInvertedChanged();
305         }
306     }
307     emit textureChanged();
308     update();
309 }
310
311 void WaylandSurfaceItem::parentChanged(WaylandSurface *newParent, WaylandSurface *oldParent)
312 {
313     Q_UNUSED(oldParent);
314
315     WaylandSurfaceItem *item = newParent? newParent->surfaceItem():0;
316     setParentItem(item);
317
318     if (newParent) {
319         setPaintEnabled(true);
320         setVisible(true);
321         setOpacity(1);
322         setEnabled(true);
323     }
324 }
325
326 void WaylandSurfaceItem::updateSize()
327 {
328     setSize(m_surface->size());
329 }
330
331 void WaylandSurfaceItem::updatePosition()
332 {
333     setPos(m_surface->pos());
334 }
335
336 bool WaylandSurfaceItem::paintEnabled() const
337 {
338     return m_paintEnabled;
339 }
340
341 void WaylandSurfaceItem::setPaintEnabled(bool enabled)
342 {
343     m_paintEnabled = enabled;
344     update();
345 }
346
347 void WaylandSurfaceItem::updateTexture()
348 {
349     ensureProvider();
350     QSGTexture *texture = m_provider->t;
351     if (m_damaged) {
352         m_damaged = false;
353         QSGTexture *oldTexture = texture;
354         if (m_surface->type() == WaylandSurface::Texture) {
355             QOpenGLContext *context = QOpenGLContext::currentContext();
356             QQuickCanvas::CreateTextureOptions opt = 0;
357             if (useTextureAlpha()) {
358                 opt |= QQuickCanvas::TextureHasAlphaChannel;
359             }
360             texture = canvas()->createTextureFromId(m_surface->texture(context), m_surface->size(), opt);
361         } else {
362             texture = canvas()->createTextureFromImage(m_surface->image());
363         }
364         texture->bind();
365         delete oldTexture;
366     }
367
368     m_provider->t = texture;
369     m_provider->smooth = smooth();
370 }
371
372 QSGNode *WaylandSurfaceItem::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData *)
373 {
374     if (!m_surface) {
375         delete oldNode;
376         return 0;
377     }
378
379     updateTexture();
380     if (!m_provider->t || !m_paintEnabled) {
381         delete oldNode;
382         return 0;
383     }
384
385     WaylandSurfaceNode *node = static_cast<WaylandSurfaceNode *>(oldNode);
386
387     if (!node) {
388         node = new WaylandSurfaceNode(this);
389     }
390
391     node->updateTexture();
392
393     if (surface()->isYInverted()) {
394         node->setRect(0, height(), width(), -height());
395     } else {
396         node->setRect(0, 0, width(), height());
397     }
398
399     node->setTextureUpdated(true);
400
401     return node;
402 }
403
404 void WaylandSurfaceItem::setUseTextureAlpha(bool useTextureAlpha)
405 {
406     m_useTextureAlpha = useTextureAlpha;
407
408     if ((flags() & ItemHasContents) != 0) {
409         update();
410     }
411 }
412
413 void WaylandSurfaceItem::setClientRenderingEnabled(bool enabled)
414 {
415     if (m_clientRenderingEnabled != enabled) {
416         m_clientRenderingEnabled = enabled;
417
418         if (m_surface) {
419             m_surface->sendOnScreenVisibilityChange(enabled);
420         }
421
422         emit clientRenderingEnabledChanged();
423     }
424 }
425
426 void WaylandSurfaceItem::setTouchEventsEnabled(bool enabled)
427 {
428     if (m_touchEventsEnabled != enabled) {
429         m_touchEventsEnabled = enabled;
430         emit touchEventsEnabledChanged();
431     }
432 }
433
434 #include "waylandsurfaceitem.moc"