1 /****************************************************************************
3 ** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies).
4 ** Contact: http://www.qt-project.org/legal
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 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.
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 "waylandsurfaceitem.h"
42 #include "waylandsurfacenode.h"
43 #include "waylandsurface.h"
44 #include "waylandcompositor.h"
45 #include "waylandinput.h"
47 #include "wlsurface.h"
48 #include "wlextendedsurface.h"
50 #include <QtGui/QKeyEvent>
51 #include <QtGui/QGuiApplication>
52 #include <QtGui/QScreen>
54 #include <QtQuick/QSGSimpleRectNode>
55 #include <QtQuick/QQuickCanvas>
57 #include <QtCore/QMutexLocker>
58 #include <QtCore/QMutex>
61 class WaylandSurfaceTextureProvider : public QSGTextureProvider
66 WaylandSurfaceTextureProvider() : t(0) { }
67 ~WaylandSurfaceTextureProvider() { delete t; }
69 QSGTexture *texture() const {
71 t->setFiltering(smooth ? QSGTexture::Linear : QSGTexture::Nearest);
86 QMutex *WaylandSurfaceItem::mutex = 0;
88 WaylandSurfaceItem::WaylandSurfaceItem(QQuickItem *parent)
93 , m_paintEnabled(true)
94 , m_useTextureAlpha(false)
95 , m_clientRenderingEnabled(false)
96 , m_touchEventsEnabled(false)
102 WaylandSurfaceItem::WaylandSurfaceItem(WaylandSurface *surface, QQuickItem *parent)
107 , m_paintEnabled(true)
108 , m_useTextureAlpha(false)
109 , m_clientRenderingEnabled(false)
110 , m_touchEventsEnabled(false)
115 void WaylandSurfaceItem::init(WaylandSurface *surface)
121 m_surface->setSurfaceItem(0);
125 m_surface->setSurfaceItem(this);
126 if (m_clientRenderingEnabled) {
127 m_surface->sendOnScreenVisibilityChange(m_clientRenderingEnabled);
130 setWidth(surface->size().width());
131 setHeight(surface->size().height());
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()));
151 m_yInverted = surface ? surface->isYInverted() : true;
154 WaylandSurfaceItem::~WaylandSurfaceItem()
156 QMutexLocker locker(mutex);
160 m_surface->setSurfaceItem(0);
162 m_provider->deleteLater();
165 void WaylandSurfaceItem::setSurface(WaylandSurface *surface)
167 if (surface == m_surface)
171 emit surfaceChanged();
174 bool WaylandSurfaceItem::isYInverted() const
179 QSGTextureProvider *WaylandSurfaceItem::textureProvider() const
181 const_cast<WaylandSurfaceItem *>(this)->ensureProvider();
185 void WaylandSurfaceItem::ensureProvider()
188 m_provider = new WaylandSurfaceTextureProvider();
189 connect(canvas(), SIGNAL(sceneGraphInvalidated()), m_provider, SLOT(invalidate()), Qt::DirectConnection);
193 void WaylandSurfaceItem::mousePressEvent(QMouseEvent *event)
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());
203 void WaylandSurfaceItem::mouseMoveEvent(QMouseEvent *event)
206 WaylandInputDevice *inputDevice = m_surface->compositor()->defaultInputDevice();
207 inputDevice->sendMouseMoveEvent(m_surface, toSurface(event->pos()), event->globalPos());
211 void WaylandSurfaceItem::mouseReleaseEvent(QMouseEvent *event)
214 WaylandInputDevice *inputDevice = m_surface->compositor()->defaultInputDevice();
215 inputDevice->sendMouseReleaseEvent(event->button(), toSurface(event->pos()), event->globalPos());
219 void WaylandSurfaceItem::wheelEvent(QWheelEvent *event)
222 WaylandInputDevice *inputDevice = m_surface->compositor()->defaultInputDevice();
223 inputDevice->sendMouseWheelEvent(event->orientation(), event->delta());
227 void WaylandSurfaceItem::keyPressEvent(QKeyEvent *event)
229 if (m_surface && hasFocus()) {
230 WaylandInputDevice *inputDevice = m_surface->compositor()->defaultInputDevice();
231 inputDevice->sendFullKeyEvent(event);
235 void WaylandSurfaceItem::keyReleaseEvent(QKeyEvent *event)
237 if (m_surface && hasFocus()) {
238 WaylandInputDevice *inputDevice = m_surface->compositor()->defaultInputDevice();
239 inputDevice->sendFullKeyEvent(event);
243 void WaylandSurfaceItem::touchEvent(QTouchEvent *event)
245 if (m_touchEventsEnabled && m_surface) {
246 WaylandInputDevice *inputDevice = m_surface->compositor()->defaultInputDevice();
248 if (inputDevice->mouseFocus() != m_surface) {
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);
255 inputDevice->sendFullTouchEvent(event);
261 void WaylandSurfaceItem::takeFocus()
266 WaylandInputDevice *inputDevice = m_surface->compositor()->defaultInputDevice();
267 inputDevice->setKeyboardFocus(m_surface);
271 QPoint WaylandSurfaceItem::toSurface(const QPointF &pos) const
273 return pos.toPoint();
276 void WaylandSurfaceItem::surfaceMapped()
278 setPaintEnabled(true);
281 void WaylandSurfaceItem::surfaceUnmapped()
283 setPaintEnabled(false);
286 void WaylandSurfaceItem::surfaceDestroyed(QObject *)
291 void WaylandSurfaceItem::setDamagedFlag(bool on)
297 void WaylandSurfaceItem::surfaceDamaged(const QRect &)
301 bool inverted = m_surface->isYInverted();
302 if (inverted != m_yInverted) {
303 m_yInverted = inverted;
304 emit yInvertedChanged();
307 emit textureChanged();
311 void WaylandSurfaceItem::parentChanged(WaylandSurface *newParent, WaylandSurface *oldParent)
315 WaylandSurfaceItem *item = newParent? newParent->surfaceItem():0;
319 setPaintEnabled(true);
326 void WaylandSurfaceItem::updateSize()
328 setSize(m_surface->size());
331 void WaylandSurfaceItem::updatePosition()
333 setPos(m_surface->pos());
336 bool WaylandSurfaceItem::paintEnabled() const
338 return m_paintEnabled;
341 void WaylandSurfaceItem::setPaintEnabled(bool enabled)
343 m_paintEnabled = enabled;
347 void WaylandSurfaceItem::updateTexture()
350 QSGTexture *texture = m_provider->t;
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;
360 texture = canvas()->createTextureFromId(m_surface->texture(context), m_surface->size(), opt);
362 texture = canvas()->createTextureFromImage(m_surface->image());
368 m_provider->t = texture;
369 m_provider->smooth = smooth();
372 QSGNode *WaylandSurfaceItem::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData *)
380 if (!m_provider->t || !m_paintEnabled) {
385 WaylandSurfaceNode *node = static_cast<WaylandSurfaceNode *>(oldNode);
388 node = new WaylandSurfaceNode(this);
391 node->updateTexture();
393 if (surface()->isYInverted()) {
394 node->setRect(0, height(), width(), -height());
396 node->setRect(0, 0, width(), height());
399 node->setTextureUpdated(true);
404 void WaylandSurfaceItem::setUseTextureAlpha(bool useTextureAlpha)
406 m_useTextureAlpha = useTextureAlpha;
408 if ((flags() & ItemHasContents) != 0) {
413 void WaylandSurfaceItem::setClientRenderingEnabled(bool enabled)
415 if (m_clientRenderingEnabled != enabled) {
416 m_clientRenderingEnabled = enabled;
419 m_surface->sendOnScreenVisibilityChange(enabled);
422 emit clientRenderingEnabledChanged();
426 void WaylandSurfaceItem::setTouchEventsEnabled(bool enabled)
428 if (m_touchEventsEnabled != enabled) {
429 m_touchEventsEnabled = enabled;
430 emit touchEventsEnabledChanged();
434 #include "waylandsurfaceitem.moc"