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 "waylandcompositor.h"
43 #include "waylandsurface.h"
44 #include <QtCompositor/waylandinput.h>
46 #include <QApplication>
50 #include <QMouseEvent>
51 #include <QtCore/QLinkedList>
53 #ifdef QT_COMPOSITOR_WAYLAND_GL
54 #include <QOpenGLContext>
56 #include <QtGui/private/qopengltexturecache_p.h>
57 #include "textureblitter.h"
58 #include <QOpenGLFunctions>
63 #ifdef QT_COMPOSITOR_WAYLAND_GL
64 class QWidgetCompositor : public QGLWidget, public WaylandCompositor
66 class QWidgetCompositor : public QWidget, public WaylandCompositor
72 : WaylandCompositor(windowHandle())
73 #ifdef QT_COMPOSITOR_WAYLAND_GL
74 , m_surfaceCompositorFbo(0)
79 , m_dragSourceSurface(0)
81 enableSubSurfaceExtension();
82 setMouseTracking(true);
83 setRetainedSelectionEnabled(true);
84 m_background = QImage(QLatin1String(":/background.jpg"));
85 //make sure we get the window id and create the glcontext
86 //so that clients can successfully initialize egl
91 void surfaceDestroyed(QObject *object) {
92 WaylandSurface *surface = static_cast<WaylandSurface *>(object);
93 m_surfaces.removeAll(surface);
97 void surfaceMapped() {
98 WaylandSurface *surface = qobject_cast<WaylandSurface *>(sender());
100 if (!m_surfaces.contains(surface)) {
101 uint px = 1 + (qrand() % (width() - surface->size().width() - 2));
102 uint py = 1 + (qrand() % (height() - surface->size().height() - 2));
103 pos = QPoint(px, py);
104 surface->setPos(pos);
105 m_surfaces.append(surface);
108 defaultInputDevice()->setKeyboardFocus(surface);
112 void surfaceDamaged(const QRect &rect) {
113 WaylandSurface *surface = qobject_cast<WaylandSurface *>(sender());
114 surfaceDamaged(surface, rect);
118 void surfaceDamaged(WaylandSurface *surface, const QRect &rect)
120 #ifdef QT_COMPOSITOR_WAYLAND_GL
125 update(rect.translated(surface->geometry().topLeft()));
129 void surfaceCreated(WaylandSurface *surface) {
130 connect(surface, SIGNAL(destroyed(QObject *)), this, SLOT(surfaceDestroyed(QObject *)));
131 connect(surface, SIGNAL(mapped()), this, SLOT(surfaceMapped()));
132 connect(surface, SIGNAL(damaged(const QRect &)), this, SLOT(surfaceDamaged(const QRect &)));
136 #ifdef QT_COMPOSITOR_WAYLAND_GL
137 GLuint composeSurface(WaylandSurface *surface) {
139 QOpenGLFunctions *functions = QOpenGLContext::currentContext()->functions();
141 if (!m_surfaceCompositorFbo)
142 functions->glGenFramebuffers(1,&m_surfaceCompositorFbo);
144 functions->glBindFramebuffer(GL_FRAMEBUFFER, m_surfaceCompositorFbo);
146 if (surface->type() == WaylandSurface::Shm) {
147 texture = m_textureCache->bindTexture(context()->contextHandle(), surface->image());
149 texture = surface->texture(QOpenGLContext::currentContext());
152 functions->glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
153 GL_TEXTURE_2D, texture, 0);
154 paintChildren(surface,surface);
155 functions->glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
156 GL_TEXTURE_2D, 0, 0);
158 functions->glBindFramebuffer(GL_FRAMEBUFFER, 0);
162 void paintChildren(WaylandSurface *surface, WaylandSurface *window) {
164 if (surface->subSurfaces().size() == 0)
167 QLinkedListIterator<WaylandSurface *> i(surface->subSurfaces());
168 while (i.hasNext()) {
169 WaylandSurface *subSurface = i.next();
170 QPointF p = subSurface->mapTo(window,QPoint(0,0));
171 QSize size = subSurface->size();
172 if (size.isValid()) {
174 if (subSurface->type() == WaylandSurface::Texture) {
175 texture = subSurface->texture(QOpenGLContext::currentContext());
176 } else if (surface->type() == WaylandSurface::Shm ) {
177 texture = m_textureCache->bindTexture(context()->contextHandle(), surface->image());
179 m_textureBlitter->drawTexture(texture,QRect(p.toPoint(),size),window->size(),0,window->isYInverted(),subSurface->isYInverted());
181 paintChildren(subSurface,window);
184 #else //hmmm, this is actually untested :(
185 QImage composeSurface(WaylandSurface *surface)
187 Q_ASSER(surface->type() == WaylandSurface::Shm);
188 QImage img = surface->image();
190 paintChildren(surface,p,surface);
195 void paintChildren(WaylandSurface *surface, QPainter *painter, WaylandSurface *window) {
196 if (surface->subSurfaces().size() == 0)
199 QLinkedListIterator<WaylandSurface *> i(surface->subSurfaces());
200 while (i.hasNext()) {
201 WaylandSurface *subSurface = i.next();
202 QPoint p = subSurface->mapTo(window,QPoint(0,0));
203 QRect geo = subSurface->geometry();
206 painter->drawImage(p,subSurface->image());
208 paintChildren(subSurface,painter,window);
211 #endif //QT_COMPOSITOR_WAYLAND_GL
215 void paintEvent(QPaintEvent *) {
218 if (!m_background.isNull())
219 p.drawPixmap(rect(), m_backgroundScaled);
221 #ifdef QT_COMPOSITOR_WAYLAND_GL
222 if (!m_textureCache) {
223 m_textureCache = new QOpenGLTextureCache(context()->contextHandle());
225 if (!m_textureBlitter) {
226 m_textureBlitter = new TextureBlitter();
228 m_textureBlitter->bind();
230 for (int i = 0; i < m_surfaces.size(); ++i) {
231 #ifdef QT_COMPOSITOR_WAYLAND_GL
232 GLuint texture = composeSurface(m_surfaces.at(i));
233 WaylandSurface *surface = m_surfaces.at(i);
234 QRect geo(surface->pos().toPoint(),surface->size());
235 m_textureBlitter->drawTexture(texture,geo,size(),0,false,m_surfaces.at(i)->isYInverted());
237 QImage img = composeSurface(m_surfaces.at(i));
238 p.drawImage(m_surfaces.at(i)->geometry().topLeft(),img);
239 #endif //QT_COMPOSITOR_WAYLAND_GL
242 if (!m_cursor.isNull())
243 p.drawImage(m_cursorPos - m_cursorHotspot, m_cursor);
247 #ifdef QT_COMPOSITOR_WAYLAND_GL
250 m_textureBlitter->release();
254 void resizeEvent(QResizeEvent *)
256 if (!m_background.isNull()) {
257 m_backgroundScaled = QPixmap::fromImage(m_background.scaled(size(),
258 Qt::IgnoreAspectRatio, Qt::SmoothTransformation));
262 void raise(WaylandSurface *surface) {
263 defaultInputDevice()->setKeyboardFocus(surface);
264 surfaceDamaged(surface, QRect(QPoint(), surface->size()));
265 m_surfaces.removeOne(surface);
266 m_surfaces.append(surface);
269 void mousePressEvent(QMouseEvent *e) {
270 m_cursorPos = e->pos();
271 if (!m_cursor.isNull())
274 if (WaylandSurface *surface = surfaceAt(e->pos(), &local)) {
276 if (e->modifiers() & Qt::ControlModifier) {
277 m_moveSurface = surface;
278 m_moveOffset = local;
280 defaultInputDevice()->sendMousePressEvent(e->button(), local.toPoint(),e->pos());
285 void mouseMoveEvent(QMouseEvent *e) {
286 m_cursorPos = e->pos();
287 if (!m_cursor.isNull())
290 QPoint global = e->pos(); // "global" here means the window of the compositor
292 WaylandSurface *surface = surfaceAt(e->pos(), &local);
294 if (!m_dragSourceSurface)
295 m_dragSourceSurface = surface;
296 if (m_dragSourceSurface == surface)
297 m_lastDragSourcePos = local;
300 //this should go away when draggin is reimplemented
301 sendDragMoveEvent(global, local.toPoint(), surface);
305 m_moveSurface->setPos(e->localPos() - m_moveOffset);
310 if (surfaceAt(e->pos(), &local))
311 defaultInputDevice()->sendMouseMoveEvent(local.toPoint(),pos());
314 void mouseReleaseEvent(QMouseEvent *e) {
317 if (m_dragSourceSurface) {
318 // Must send a release event to the source too, no matter where the cursor is now.
319 // This is a hack and should go away when we reimplement draging
320 defaultInputDevice()->sendMouseReleaseEvent(e->button(), m_lastDragSourcePos.toPoint(), e->pos());
321 m_dragSourceSurface = 0;
329 if (surfaceAt(e->pos(), &local))
330 defaultInputDevice()->sendMouseReleaseEvent(e->button(), local.toPoint(), e->pos());
333 void keyPressEvent(QKeyEvent *event)
335 defaultInputDevice()->sendKeyPressEvent(event->nativeScanCode());
338 void keyReleaseEvent(QKeyEvent *event)
340 defaultInputDevice()->sendKeyReleaseEvent(event->nativeScanCode());
343 WaylandSurface *surfaceAt(const QPointF &point, QPointF *local = 0) {
344 for (int i = m_surfaces.size() - 1; i >= 0; --i) {
345 WaylandSurface *surface = m_surfaces.at(i);
346 QRect geo(surface->pos().toPoint(),surface->size());
347 if (geo.contains(point.toPoint())) {
349 *local = point - surface->pos();
356 void changeCursor(const QImage &image, int hotspotX, int hotspotY) {
358 m_cursorHotspot = QPoint(hotspotX, hotspotY);
364 QPixmap m_backgroundScaled;
366 QList<WaylandSurface *> m_surfaces;
368 #ifdef QT_COMPOSITOR_WAYLAND_GL
369 GLuint m_surfaceCompositorFbo;
370 TextureBlitter *m_textureBlitter;
371 QOpenGLTextureCache *m_textureCache;
374 WaylandSurface *m_moveSurface;
375 QPointF m_moveOffset;
376 WaylandSurface *m_dragSourceSurface;
377 QPointF m_lastDragSourcePos;
381 QPoint m_cursorHotspot;
383 friend class TouchObserver;
386 int main(int argc, char *argv[])
388 QApplication app(argc, argv);
390 QWidgetCompositor compositor;
391 compositor.resize(800, 600);
394 // QTouchScreenHandlerThread t(QString(), new TouchObserver(&compositor));