From d5ea033df8cf0a2dec49fce639d84e7dd0a2fced Mon Sep 17 00:00:00 2001 From: =?utf8?q?J=C3=B8rgen=20Lind?= Date: Wed, 4 Jan 2012 08:33:28 +0100 Subject: [PATCH] Implement subsurfaces extension MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit This allows you to have subwindows in the compositor. We tried to experiment with composing subsurfaces client side, but the architecture did not feel very lean. This however, requires the compositor to compose each surface before drawing the surface. The example compositors render the subsurfaces into the wl_surfaces texture. This might not be a good idea. Change-Id: I6e186b62d7b490de7f4e6c6f22fcf6c1e0a70df3 Reviewed-by: Samuel Rødal --- examples/qml-compositor/main.cpp | 43 +++-- examples/qml-compositor/qml-compositor.pro | 2 + examples/qwidget-compositor/main.cpp | 190 ++++++++++++--------- examples/qwidget-compositor/qwidget-compositor.pro | 16 +- examples/qwidget-compositor/textureblitter.cpp | 118 +++++++++++++ examples/qwidget-compositor/textureblitter.h | 28 +++ examples/qwindow-compositor/qwindow-compositor.pro | 16 +- examples/qwindow-compositor/qwindowcompositor.cpp | 98 ++++++++--- examples/qwindow-compositor/qwindowcompositor.h | 14 +- examples/qwindow-compositor/surfacerenderer.cpp | 146 ---------------- examples/qwindow-compositor/surfacerenderer.h | 29 ---- examples/qwindow-compositor/textureblitter.cpp | 118 +++++++++++++ examples/qwindow-compositor/textureblitter.h | 26 +++ extensions/sub-surface-extension.xml | 80 +++++++++ extensions/surface-extension.xml | 1 - .../compositor_api/waylandcompositor.cpp | 5 + src/compositor/compositor_api/waylandcompositor.h | 2 + src/compositor/compositor_api/waylandsurface.cpp | 78 ++++++++- src/compositor/compositor_api/waylandsurface.h | 21 +++ .../compositor_api/waylandsurfaceitem.cpp | 67 ++++++-- src/compositor/compositor_api/waylandsurfaceitem.h | 3 + src/compositor/wayland_wrapper/wayland_wrapper.pri | 7 +- src/compositor/wayland_wrapper/wlcompositor.cpp | 9 + src/compositor/wayland_wrapper/wlcompositor.h | 3 + .../wayland_wrapper/wlextendedsurface.cpp | 6 + src/compositor/wayland_wrapper/wlextendedsurface.h | 24 ++- src/compositor/wayland_wrapper/wlsubsurface.cpp | 168 ++++++++++++++++++ src/compositor/wayland_wrapper/wlsubsurface.h | 129 ++++++++++++++ src/compositor/wayland_wrapper/wlsurface.cpp | 56 +++++- src/compositor/wayland_wrapper/wlsurface.h | 7 + src/plugins/platforms/wayland/qwaylanddisplay.cpp | 3 + src/plugins/platforms/wayland/qwaylanddisplay.h | 3 + .../platforms/wayland/qwaylandextendedsurface.h | 1 + .../platforms/wayland/qwaylandshmbackingstore.cpp | 1 - .../platforms/wayland/qwaylandsubsurface.cpp | 79 +++++++++ src/plugins/platforms/wayland/qwaylandsubsurface.h | 73 ++++++++ src/plugins/platforms/wayland/qwaylandwindow.cpp | 24 ++- src/plugins/platforms/wayland/qwaylandwindow.h | 4 + src/plugins/platforms/wayland/wayland.pro | 7 +- 39 files changed, 1356 insertions(+), 349 deletions(-) create mode 100644 examples/qwidget-compositor/textureblitter.cpp create mode 100644 examples/qwidget-compositor/textureblitter.h delete mode 100644 examples/qwindow-compositor/surfacerenderer.cpp delete mode 100644 examples/qwindow-compositor/surfacerenderer.h create mode 100644 examples/qwindow-compositor/textureblitter.cpp create mode 100644 examples/qwindow-compositor/textureblitter.h create mode 100644 extensions/sub-surface-extension.xml create mode 100644 src/compositor/wayland_wrapper/wlsubsurface.cpp create mode 100644 src/compositor/wayland_wrapper/wlsubsurface.h create mode 100644 src/plugins/platforms/wayland/qwaylandsubsurface.cpp create mode 100644 src/plugins/platforms/wayland/qwaylandsubsurface.h diff --git a/examples/qml-compositor/main.cpp b/examples/qml-compositor/main.cpp index fc6a461..466533b 100644 --- a/examples/qml-compositor/main.cpp +++ b/examples/qml-compositor/main.cpp @@ -56,8 +56,10 @@ class QmlCompositor : public QQuickView, public WaylandCompositor { Q_OBJECT public: - QmlCompositor() : WaylandCompositor(this) { - //setMouseTracking(true); + QmlCompositor() + : WaylandCompositor(this) + { + enableSubSurfaceExtension(); setSource(QUrl(QLatin1String("qrc:qml/QmlCompositor/main.qml"))); setResizeMode(QQuickView::SizeRootObjectToView); winId(); @@ -78,27 +80,20 @@ public slots: private slots: void surfaceMapped() { WaylandSurface *surface = qobject_cast(sender()); - surface->setGeometry(QRect(surface->geometry().topLeft(),size)); - - if (m_windowMap.contains(surface)) { - WaylandSurfaceItem *item = m_windowMap.value(surface); - item->setWidth(size.width()); - item->setHeight(size.height()); - emit windowResized(QVariant::fromValue(static_cast(item))); - } else { - WaylandSurfaceItem *item = new WaylandSurfaceItem(surface, rootObject()); - item->setTouchEventsEnabled(true); - connect(surface, SIGNAL(destroyed(QObject *)), this, SLOT(surfaceDestroyed(QObject *))); - emit windowAdded(QVariant::fromValue(static_cast(item))); - m_windowMap[surface] = item; - - item->takeFocus(); - } + WaylandSurfaceItem *item = surface->surfaceItem(); + item->takeFocus(); + emit windowAdded(QVariant::fromValue(static_cast(item))); + } + void surfaceUnmapped() { + WaylandSurface *surface = qobject_cast(sender()); + QQuickItem *item = surface->surfaceItem(); + emit windowDestroyed(QVariant::fromValue(item)); } void surfaceDestroyed(QObject *object) { - WaylandSurfaceItem *item = m_windowMap.take(object); - emit windowDestroyed(QVariant::fromValue(static_cast(item))); + WaylandSurface *surface = static_cast(object); + QQuickItem *item = surface->surfaceItem(); + emit windowDestroyed(QVariant::fromValue(item)); } void frameSwappedSlot() { @@ -107,11 +102,13 @@ private slots: protected: void surfaceCreated(WaylandSurface *surface) { + WaylandSurfaceItem *item = new WaylandSurfaceItem(surface, rootObject()); + item->setTouchEventsEnabled(true); + connect(surface, SIGNAL(destroyed(QObject *)), this, SLOT(surfaceDestroyed(QObject *))); + connect(surface, SIGNAL(mapped()), this, SLOT(surfaceMapped())); + connect(surface,SIGNAL(unmapped()), this,SLOT(surfaceUnmapped())); } - -private: - QMap m_windowMap; }; int main(int argc, char *argv[]) diff --git a/examples/qml-compositor/qml-compositor.pro b/examples/qml-compositor/qml-compositor.pro index 88c4ca0..1414cef 100644 --- a/examples/qml-compositor/qml-compositor.pro +++ b/examples/qml-compositor/qml-compositor.pro @@ -3,6 +3,8 @@ TARGET = qml-compositor DEPENDPATH += . INCLUDEPATH += . +DEFINES += QT_COMPOSITOR_QUICK + # comment out the following to not use pkg-config in the pri files CONFIG += use_pkgconfig diff --git a/examples/qwidget-compositor/main.cpp b/examples/qwidget-compositor/main.cpp index b074735..a95eda6 100644 --- a/examples/qwidget-compositor/main.cpp +++ b/examples/qwidget-compositor/main.cpp @@ -47,32 +47,17 @@ #include #include #include +#include #ifdef QT_COMPOSITOR_WAYLAND_GL #include #include +#include +#include "textureblitter.h" #endif #include -//#include "qtouchscreen.h" -// -//static int touch_x_min, touch_x_max, touch_y_min, touch_y_max; -// -//class QWidgetCompositor; -// -//class TouchObserver : public QTouchScreenObserver -//{ -//public: -// TouchObserver(QWidgetCompositor *compositor) -// : m_compositor(compositor) { } -// void touch_configure(int x_min, int x_max, int y_min, int y_max); -// void touch_point(QEvent::Type state, const QList &points); -// -//private: -// QWidgetCompositor *m_compositor; -//}; - #ifdef QT_COMPOSITOR_WAYLAND_GL class QWidgetCompositor : public QGLWidget, public WaylandCompositor #else @@ -85,18 +70,19 @@ public: : WaylandCompositor(windowHandle()) , m_moveSurface(0) , m_dragSourceSurface(0) +#ifdef QT_COMPOSITOR_WAYLAND_GL + , m_surfaceCompositorFbo(0) + , m_textureBlitter(0) + , m_textureCache(0) +#endif { + enableSubSurfaceExtension(); setMouseTracking(true); setRetainedSelectionEnabled(true); m_background = QImage(QLatin1String("background.jpg")); //make sure we get the window id and create the glcontext //so that clients can successfully initialize egl winId(); -#ifdef QT_COMPOSITOR_WAYLAND_GL - if (windowHandle()) { -// windowHandle()->surfaceHandle(); - } -#endif } private slots: @@ -115,9 +101,8 @@ private slots: pos = QPoint(px, py); surface->setGeometry(QRect(pos, surface->geometry().size())); m_surfaces.append(surface); - } else { - surface->setGeometry(QRect(geometry().topLeft(),size)); } + setInputFocus(surface); update(); } @@ -140,29 +125,113 @@ protected: } void surfaceCreated(WaylandSurface *surface) { - qDebug() << "surface created"; connect(surface, SIGNAL(destroyed(QObject *)), this, SLOT(surfaceDestroyed(QObject *))); connect(surface, SIGNAL(mapped()), this, SLOT(surfaceMapped())); connect(surface, SIGNAL(damaged(const QRect &)), this, SLOT(surfaceDamaged(const QRect &))); update(); } +#ifdef QT_COMPOSITOR_WAYLAND_GL + GLuint composeSurface(WaylandSurface *surface) { + GLuint texture = 0; + + if (!m_surfaceCompositorFbo) { + glGenFramebuffers(1,&m_surfaceCompositorFbo); + } + glBindFramebuffer(GL_FRAMEBUFFER, m_surfaceCompositorFbo); + + if (surface->type() == WaylandSurface::Shm) { + texture = m_textureCache->bindTexture(context()->contextHandle(), surface->image()); + } else { + texture = surface->texture(QOpenGLContext::currentContext()); + } + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, + GL_TEXTURE_2D, texture, 0); + paintChildren(surface,surface); + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, + GL_TEXTURE_2D, 0, 0); + + glBindFramebuffer(GL_FRAMEBUFFER, 0); + return texture; + } + + void paintChildren(WaylandSurface *surface, WaylandSurface *window) { + + if (surface->subSurfaces().size() == 0) + return; + + QLinkedListIterator i(surface->subSurfaces()); + while (i.hasNext()) { + WaylandSurface *subSurface = i.next(); + QPoint p = subSurface->mapTo(window,QPoint(0,0)); + QRect geo = subSurface->geometry(); + geo.moveTo(p); + if (geo.isValid()) { + GLuint texture = 0; + if (subSurface->type() == WaylandSurface::Texture) { + texture = subSurface->texture(QOpenGLContext::currentContext()); + } else if (surface->type() == WaylandSurface::Shm ) { + texture = m_textureCache->bindTexture(context()->contextHandle(), surface->image()); + } + m_textureBlitter->drawTexture(texture,geo,window->geometry().size(),0,window->isYInverted(),subSurface->isYInverted()); + } + paintChildren(subSurface,window); + } + } +#else //hmmm, this is actually untested :( + QImage composeSurface(WaylandSurface *surface) + { + Q_ASSER(surface->type() == WaylandSurface::Shm); + QImage img = surface->image(); + QPainter p(&img); + paintChildren(surface,p,surface); + + return img; + } + + void paintChildren(WaylandSurface *surface, QPainter *painter, WaylandSurface *window) { + if (surface->subSurfaces().size() == 0) + return; + + QLinkedListIterator i(surface->subSurfaces()); + while (i.hasNext()) { + WaylandSurface *subSurface = i.next(); + QPoint p = subSurface->mapTo(window,QPoint(0,0)); + QRect geo = subSurface->geometry(); + geo.moveTo(p); + if (geo.isValid()) { + painter->drawImage(p,subSurface->image()); + } + paintChildren(subSurface,painter,window); + } + } +#endif //QT_COMPOSITOR_WAYLAND_GL + + + void paintEvent(QPaintEvent *) { QPainter p(this); if (!m_background.isNull()) p.drawPixmap(rect(), m_backgroundScaled); +#ifdef QT_COMPOSITOR_WAYLAND_GL + if (!m_textureCache) { + m_textureCache = new QOpenGLTextureCache(context()->contextHandle()); + } + if (!m_textureBlitter) { + m_textureBlitter = new TextureBlitter(); + } + m_textureBlitter->bind(); +#endif for (int i = 0; i < m_surfaces.size(); ++i) { - if (m_surfaces.at(i)->type() == WaylandSurface::Texture) { #ifdef QT_COMPOSITOR_WAYLAND_GL - drawTexture(m_surfaces.at(i)->geometry(), m_surfaces.at(i)->texture(QOpenGLContext::currentContext())); - break; + GLuint texture = composeSurface(m_surfaces.at(i)); + m_textureBlitter->drawTexture(texture,m_surfaces.at(i)->geometry(),size(),0,false,m_surfaces.at(i)->isYInverted()); +#else + QImage img = composeSurface(m_surfaces.at(i)); + p.drawImage(m_surfaces.at(i)->geometry().topLeft(),img); #endif //QT_COMPOSITOR_WAYLAND_GL - } else if (m_surfaces.at(i)->type() == WaylandSurface::Shm) { - QImage img = m_surfaces.at(i)->image(); - p.drawImage(m_surfaces.at(i)->geometry(), img); - } } if (!m_cursor.isNull()) @@ -173,7 +242,7 @@ protected: #ifdef QT_COMPOSITOR_WAYLAND_GL //jl:FIX FIX FIX:) // update(); - glFinish(); + m_textureBlitter->release(); #endif } @@ -293,6 +362,12 @@ private: QList m_surfaces; +#ifdef QT_COMPOSITOR_WAYLAND_GL + GLuint m_surfaceCompositorFbo; + TextureBlitter *m_textureBlitter; + QOpenGLTextureCache *m_textureCache; +#endif + WaylandSurface *m_moveSurface; QPoint m_moveOffset; WaylandSurface *m_dragSourceSurface; @@ -305,53 +380,6 @@ private: friend class TouchObserver; }; -//void TouchObserver::touch_configure(int x_min, int x_max, int y_min, int y_max) -//{ -// touch_x_min = x_min; -// touch_x_max = x_max; -// touch_y_min = y_min; -// touch_y_max = y_max; -//} - -//void TouchObserver::touch_point(QEvent::Type state, const QList &points) -//{ -// Q_UNUSED(state); -// WaylandSurface *focusSurface = m_compositor->inputFocus(); -// if (focusSurface) { -// if (points.isEmpty()) -// return; -// for (int i = 0; i < points.count(); ++i) { -// const QWindowSystemInterface::TouchPoint &point(points.at(i)); - -// // These are hw coordinates. -// int x = int(point.area.left()); -// int y = int(point.area.top()); - -// // Wayland expects surface-relative coordinates. - -// // Translate so that (0, 0) is the top-left corner. -// x = qBound(touch_x_min, x, touch_x_max) - touch_x_min; -// y = qBound(touch_y_min, y, touch_y_max) - touch_y_min; - -// // Get a normalized position in range 0..1. -// const int hw_w = touch_x_max - touch_x_min; -// const int hw_h = touch_y_max - touch_y_min; -// const qreal nx = x / qreal(hw_w); -// const qreal ny = y / qreal(hw_h); - -// // Map to surface. -// QRect winRect(focusSurface->geometry()); -// x = int(nx * winRect.width()); -// y = int(ny * winRect.height()); - -// focusSurface->sendTouchPointEvent(point.id, -// x, y, -// point.state); -// } -// focusSurface->sendTouchFrameEvent(); -// } -//} - int main(int argc, char *argv[]) { QApplication app(argc, argv); diff --git a/examples/qwidget-compositor/qwidget-compositor.pro b/examples/qwidget-compositor/qwidget-compositor.pro index 5637989..b681fb8 100644 --- a/examples/qwidget-compositor/qwidget-compositor.pro +++ b/examples/qwidget-compositor/qwidget-compositor.pro @@ -11,8 +11,6 @@ CONFIG += use_pkgconfig # the following line #include (../../src/qt-compositor/qt-compositor.pri) -# Input -SOURCES += main.cpp CONFIG += qt warn_on debug create_prl link_prl OBJECTS_DIR = .obj/release-shared @@ -25,13 +23,15 @@ isEmpty(QT_SOURCE_TREE) { QTBASE = $$QT_SOURCE_TREE } -#TOUCHSCREEN_BASE = $$QTBASE/src/plugins/generic/touchscreen -#SOURCES += $$TOUCHSCREEN_BASE/qtouchscreen.cpp -#HEADERS += $$TOUCHSCREEN_BASE/qtouchscreen.h -#INCLUDEPATH += $$TOUCHSCREEN_BASE -#LIBS += -ludev -lmtdev +# Input +HEADERS += \ + textureblitter.h + +SOURCES += \ + main.cpp \ + textureblitter.cpp -QT += gui-private widgets widgets-private opengl opengl-private compositor +QT += core-private gui-private widgets widgets-private opengl opengl-private compositor # install target.path = $$[QT_INSTALL_EXAMPLES]/qtwayland/qwidget-compositor diff --git a/examples/qwidget-compositor/textureblitter.cpp b/examples/qwidget-compositor/textureblitter.cpp new file mode 100644 index 0000000..8fefe48 --- /dev/null +++ b/examples/qwidget-compositor/textureblitter.cpp @@ -0,0 +1,118 @@ +#include "textureblitter.h" + +#include +#include +#include + +TextureBlitter::TextureBlitter() + : m_shaderProgram(new QOpenGLShaderProgram()) +{ + static const char *textureVertexProgram = + "uniform highp mat4 matrix;\n" + "attribute highp vec3 vertexCoordEntry;\n" + "attribute highp vec2 textureCoordEntry;\n" + "varying highp vec2 textureCoord;\n" + "void main() {\n" + " textureCoord = textureCoordEntry;\n" + " gl_Position = matrix * vec4(vertexCoordEntry, 1);\n" + "}\n"; + + static const char *textureFragmentProgram = + "uniform sampler2D texture;\n" + "varying highp vec2 textureCoord;\n" + "void main() {\n" + " gl_FragColor = texture2D(texture, textureCoord);\n" + "}\n"; + + //Enable transparent windows + glEnable(GL_BLEND); + glBlendFunc (GL_ONE,GL_ONE_MINUS_SRC_ALPHA); + + m_shaderProgram->addShaderFromSourceCode(QOpenGLShader::Vertex, textureVertexProgram); + m_shaderProgram->addShaderFromSourceCode(QOpenGLShader::Fragment, textureFragmentProgram); + m_shaderProgram->link(); +} + + +void TextureBlitter::bind() +{ + + m_shaderProgram->bind(); + + m_vertexCoordEntry = m_shaderProgram->attributeLocation("vertexCoordEntry"); + m_textureCoordEntry = m_shaderProgram->attributeLocation("textureCoordEntry"); + m_matrixLocation = m_shaderProgram->uniformLocation("matrix"); +} + +void TextureBlitter::release() +{ + m_shaderProgram->release(); +} + +void TextureBlitter::drawTexture(int textureId, const QRectF &targetRect, const QSize &targetSize, int depth, bool targethasInvertedY, bool sourceHasInvertedY) +{ + + glViewport(0,0,targetSize.width(),targetSize.height()); + GLfloat zValue = depth / 1000.0f; + //Set Texture and Vertex coordinates + const GLfloat textureCoordinates[] = { + 0, 0, + 1, 0, + 1, 1, + 0, 1 + }; + + int x1 = targetRect.left(); + int x2 = targetRect.right(); + int y1, y2; + if (targethasInvertedY) { + if (sourceHasInvertedY) { + y1 = targetRect.top(); + y2 = targetRect.bottom(); + } else { + y1 = targetRect.bottom(); + y2 = targetRect.top(); + } + } else { + if (sourceHasInvertedY) { + y1 = targetSize.height() - targetRect.top(); + y2 = targetSize.height() - targetRect.bottom(); + } else { + y1 = targetSize.height() - targetRect.bottom(); + y2 = targetSize.height() - targetRect.top(); + } + } + + const GLfloat vertexCoordinates[] = { + x1, y1, zValue, + x2, y1, zValue, + x2, y2, zValue, + x1, y2, zValue + }; + + //Set matrix to transfrom geometry values into gl coordinate space. + m_transformMatrix.setToIdentity(); + m_transformMatrix.scale( 2.0f / targetSize.width(), 2.0f / targetSize.height() ); + m_transformMatrix.translate(-targetSize.width() / 2.0f, -targetSize.height() / 2.0f); + + //attach the data! + QOpenGLContext *currentContext = QOpenGLContext::currentContext(); + currentContext->functions()->glEnableVertexAttribArray(m_vertexCoordEntry); + currentContext->functions()->glEnableVertexAttribArray(m_textureCoordEntry); + + currentContext->functions()->glVertexAttribPointer(m_vertexCoordEntry, 3, GL_FLOAT, GL_FALSE, 0, vertexCoordinates); + currentContext->functions()->glVertexAttribPointer(m_textureCoordEntry, 2, GL_FLOAT, GL_FALSE, 0, textureCoordinates); + m_shaderProgram->setUniformValue(m_matrixLocation, m_transformMatrix); + + glBindTexture(GL_TEXTURE_2D, textureId); + + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + + glDrawArrays(GL_TRIANGLE_FAN, 0, 4); + + glBindTexture(GL_TEXTURE_2D, 0); + + currentContext->functions()->glDisableVertexAttribArray(m_vertexCoordEntry); + currentContext->functions()->glDisableVertexAttribArray(m_textureCoordEntry); +} diff --git a/examples/qwidget-compositor/textureblitter.h b/examples/qwidget-compositor/textureblitter.h new file mode 100644 index 0000000..35d5cff --- /dev/null +++ b/examples/qwidget-compositor/textureblitter.h @@ -0,0 +1,28 @@ +#ifndef TEXTUREBLITTER_H +#define TEXTUREBLITTER_H + +#include + +#include + +class QOpenGLShaderProgram; +class TextureBlitter +{ +public: + TextureBlitter(); + void bind(); + void release(); + void drawTexture(int textureId, const QRectF &sourceGeometry, + const QSize &targetRect, int depth, + bool targethasInvertedY, bool sourceHasInvertedY); + +private: + QOpenGLShaderProgram *m_shaderProgram; + QMatrix4x4 m_transformMatrix; + + int m_matrixLocation; + int m_vertexCoordEntry; + int m_textureCoordEntry; +}; + +#endif // TEXTUREBLITTER_H diff --git a/examples/qwindow-compositor/qwindow-compositor.pro b/examples/qwindow-compositor/qwindow-compositor.pro index b3e7ffb..3bae92d 100644 --- a/examples/qwindow-compositor/qwindow-compositor.pro +++ b/examples/qwindow-compositor/qwindow-compositor.pro @@ -9,17 +9,22 @@ CONFIG += use_pkgconfig LIBS += -L ../../lib #include (../../src/qt-compositor/qt-compositor.pri) +HEADERS += \ + qopenglwindow.h \ + qwindowcompositor.h \ + textureblitter.h + # Input SOURCES += main.cpp \ qopenglwindow.cpp \ - surfacerenderer.cpp \ - qwindowcompositor.cpp + qwindowcompositor.cpp \ + textureblitter.cpp CONFIG += qt warn_on debug create_prl link_prl OBJECTS_DIR = .obj/release-shared MOC_DIR = .moc/release-shared -QT += gui +QT += gui gui-private core-private QT += compositor @@ -28,11 +33,6 @@ QT += compositor # the following line #include(../../src/compositor/compositor.pri) -HEADERS += \ - qopenglwindow.h \ - surfacerenderer.h \ - qwindowcompositor.h - RESOURCES += qwindow-compositor.qrc # install diff --git a/examples/qwindow-compositor/qwindowcompositor.cpp b/examples/qwindow-compositor/qwindowcompositor.cpp index 59e181a..d194a48 100644 --- a/examples/qwindow-compositor/qwindowcompositor.cpp +++ b/examples/qwindow-compositor/qwindowcompositor.cpp @@ -6,16 +6,27 @@ QWindowCompositor::QWindowCompositor(QOpenGLWindow *window) : WaylandCompositor(window) , m_window(window) + , m_textureBlitter(0) + , m_renderScheduler(this) { + enableSubSurfaceExtension(); + m_window->makeCurrent(); + + m_textureCache = new QOpenGLTextureCache(m_window->context()); + m_textureBlitter = new TextureBlitter(); m_backgroundImage = QImage(QLatin1String(":/background.jpg")); - m_renderer = new SurfaceRenderer(m_window->context(), m_window); - m_backgroundTexture = m_renderer->textureFromImage(m_backgroundImage); + m_renderScheduler.setSingleShot(true); + connect(&m_renderScheduler,SIGNAL(timeout()),this,SLOT(render())); + + + + glGenFramebuffers(1,&m_surface_fbo); window->installEventFilter(this); setRetainedSelectionEnabled(true); - render(); + m_renderScheduler.start(0); } void QWindowCompositor::surfaceDestroyed(QObject *object) @@ -24,7 +35,7 @@ void QWindowCompositor::surfaceDestroyed(QObject *object) m_surfaces.removeOne(surface); if (inputFocus() == surface || !inputFocus()) // typically reset to 0 already in Compositor::surfaceDestroyed() setInputFocus(m_surfaces.isEmpty() ? 0 : m_surfaces.last()); - render(); + m_renderScheduler.start(0); } void QWindowCompositor::surfaceMapped() @@ -42,7 +53,7 @@ void QWindowCompositor::surfaceMapped() } m_surfaces.append(surface); setInputFocus(surface); - render(); + m_renderScheduler.start(0); } void QWindowCompositor::surfaceDamaged(const QRect &rect) @@ -55,7 +66,7 @@ void QWindowCompositor::surfaceDamaged(WaylandSurface *surface, const QRect &rec { Q_UNUSED(surface) Q_UNUSED(rect) - render(); + m_renderScheduler.start(0); } void QWindowCompositor::surfaceCreated(WaylandSurface *surface) @@ -63,7 +74,7 @@ void QWindowCompositor::surfaceCreated(WaylandSurface *surface) connect(surface, SIGNAL(destroyed(QObject *)), this, SLOT(surfaceDestroyed(QObject *))); connect(surface, SIGNAL(mapped()), this, SLOT(surfaceMapped())); connect(surface, SIGNAL(damaged(const QRect &)), this, SLOT(surfaceDamaged(const QRect &))); - render(); + m_renderScheduler.start(0); } QPointF QWindowCompositor::toSurface(WaylandSurface *surface, const QPointF &pos) const @@ -83,33 +94,78 @@ WaylandSurface *QWindowCompositor::surfaceAt(const QPoint &point, QPoint *local) return 0; } +GLuint QWindowCompositor::composeSurface(WaylandSurface *surface) { + GLuint texture = 0; + + glBindFramebuffer(GL_FRAMEBUFFER, m_surface_fbo); + + if (surface->type() == WaylandSurface::Shm) { + texture = m_textureCache->bindTexture(QOpenGLContext::currentContext(),surface->image()); + } else { + texture = surface->texture(QOpenGLContext::currentContext()); + } + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, + GL_TEXTURE_2D, texture, 0); + paintChildren(surface,surface); + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, + GL_TEXTURE_2D,0, 0); + + glBindFramebuffer(GL_FRAMEBUFFER,0); + return texture; +} + +void QWindowCompositor::paintChildren(WaylandSurface *surface, WaylandSurface *window) { + + if (surface->subSurfaces().size() == 0) + return; + + QLinkedListIterator i(surface->subSurfaces()); + while (i.hasNext()) { + WaylandSurface *subSurface = i.next(); + QPoint p = subSurface->mapTo(window,QPoint(0,0)); + QRect geo = subSurface->geometry(); + geo.moveTo(p); + if (geo.isValid()) { + GLuint texture = 0; + if (subSurface->type() == WaylandSurface::Texture) { + texture = subSurface->texture(QOpenGLContext::currentContext()); + } else if (surface->type() == WaylandSurface::Shm ) { + texture = m_textureCache->bindTexture(QOpenGLContext::currentContext(),surface->image()); + } + qDebug() << "window geo is" << window->geometry().size(); + m_textureBlitter->drawTexture(texture,geo,window->geometry().size(),0,window->isYInverted(),subSurface->isYInverted()); + } + paintChildren(subSurface,window); + } +} + + void QWindowCompositor::render() { m_window->makeCurrent(); + m_backgroundTexture = m_textureCache->bindTexture(QOpenGLContext::currentContext(),m_backgroundImage); + m_textureBlitter->bind(); //Draw the background Image texture int w = m_window->width(); int h = m_window->height(); - int iw = m_backgroundImage.width(); - int ih = m_backgroundImage.height(); - for (int y = 0; y < h; y += ih) { - for (int x = 0; x < w; x += iw) { - m_renderer->drawTexture(m_backgroundTexture, QRect(QPoint(x, y), QSize(iw, ih)), 0); + QSize imageSize = m_backgroundImage.size(); + for (int y = 0; y < h; y += imageSize.height()) { + for (int x = 0; x < w; x += imageSize.width()) { + m_textureBlitter->drawTexture(m_backgroundTexture,QRect(QPoint(x, y),imageSize),window()->size(), 0,true,true); } } - //Iterate all surfaces in m_surfaces - //If type == WaylandSurface::Texture draw textureId at geometry foreach (WaylandSurface *surface, m_surfaces) { - if (surface->type() == WaylandSurface::Texture) - m_renderer->drawTexture(surface->texture(QOpenGLContext::currentContext()), surface->geometry(), 1); //depth argument should be dynamic (focused should be top). - else if (surface->type() == WaylandSurface::Shm) - m_renderer->drawImage(surface->image(), surface->geometry()); + GLuint texture = composeSurface(surface); + m_textureBlitter->drawTexture(texture,surface->geometry(),m_window->size(),0,false,surface->isYInverted()); } + + m_textureBlitter->release(); frameFinished(); glFinish(); + m_window->swapBuffers(); - m_window->context()->doneCurrent(); } bool QWindowCompositor::eventFilter(QObject *obj, QEvent *event) @@ -119,7 +175,7 @@ bool QWindowCompositor::eventFilter(QObject *obj, QEvent *event) switch (event->type()) { case QEvent::Expose: - render(); + m_renderScheduler.start(0); break; case QEvent::MouseButtonPress: { QPoint local; @@ -130,7 +186,7 @@ bool QWindowCompositor::eventFilter(QObject *obj, QEvent *event) setInputFocus(targetSurface); m_surfaces.removeOne(targetSurface); m_surfaces.append(targetSurface); - render(); + m_renderScheduler.start(0); } targetSurface->sendMousePressEvent(local, me->button()); } diff --git a/examples/qwindow-compositor/qwindowcompositor.h b/examples/qwindow-compositor/qwindowcompositor.h index 2472604..558451e 100644 --- a/examples/qwindow-compositor/qwindowcompositor.h +++ b/examples/qwindow-compositor/qwindowcompositor.h @@ -3,9 +3,11 @@ #include "waylandcompositor.h" #include "waylandsurface.h" -#include "surfacerenderer.h" +#include "textureblitter.h" #include "qopenglwindow.h" +#include + #include class QWindowCompositor : public QObject, public WaylandCompositor @@ -18,13 +20,16 @@ private slots: void surfaceMapped(); void surfaceDamaged(const QRect &rect); + void render(); protected: void surfaceDamaged(WaylandSurface *surface, const QRect &rect); void surfaceCreated(WaylandSurface *surface); WaylandSurface* surfaceAt(const QPoint &point, QPoint *local = 0); - void render(); + GLuint composeSurface(WaylandSurface *surface); + void paintChildren(WaylandSurface *surface, WaylandSurface *window); + bool eventFilter(QObject *obj, QEvent *event); QPointF toSurface(WaylandSurface *surface, const QPointF &pos) const; @@ -34,7 +39,10 @@ private: QImage m_backgroundImage; GLuint m_backgroundTexture; QList m_surfaces; - SurfaceRenderer *m_renderer; + TextureBlitter *m_textureBlitter; + QOpenGLTextureCache *m_textureCache; + GLuint m_surface_fbo; + QTimer m_renderScheduler; }; #endif // QWINDOWCOMPOSITOR_H diff --git a/examples/qwindow-compositor/surfacerenderer.cpp b/examples/qwindow-compositor/surfacerenderer.cpp deleted file mode 100644 index 31f3141..0000000 --- a/examples/qwindow-compositor/surfacerenderer.cpp +++ /dev/null @@ -1,146 +0,0 @@ -#include "surfacerenderer.h" - -#include -#include - -SurfaceRenderer::SurfaceRenderer(QOpenGLContext *context, QWindow *surface) - : m_context(context) - , m_surface(surface) -{ - const char *textureVertexProgram = - "uniform highp mat4 matrix;\n" - "attribute highp vec3 vertexCoordEntry;\n" - "attribute highp vec2 textureCoordEntry;\n" - "varying highp vec2 textureCoord;\n" - "void main() {\n" - " textureCoord = textureCoordEntry;\n" - " gl_Position = matrix * vec4(vertexCoordEntry, 1);\n" - "}\n"; - - const char *textureFragmentProgram = - "uniform sampler2D texture;\n" - "varying highp vec2 textureCoord;\n" - "void main() {\n" - " gl_FragColor = texture2D(texture, textureCoord);\n" - "}\n"; - - m_context->makeCurrent(m_surface); - - //Enable transparent windows - glEnable(GL_BLEND); - glBlendFunc (GL_ONE,GL_ONE_MINUS_SRC_ALPHA); - - //May need to manually set context here - m_shaderProgram = new QOpenGLShaderProgram(); - - m_shaderProgram->addShaderFromSourceCode(QOpenGLShader::Vertex, textureVertexProgram); - m_shaderProgram->addShaderFromSourceCode(QOpenGLShader::Fragment, textureFragmentProgram); - m_shaderProgram->link(); - m_shaderProgram->bind(); - - m_vertexCoordEntry = m_shaderProgram->attributeLocation("vertexCoordEntry"); - m_textureCoordEntry = m_shaderProgram->attributeLocation("textureCoordEntry"); - m_matrixLocation = m_shaderProgram->uniformLocation("matrix"); - -} - -void SurfaceRenderer::drawImage(const QImage &image, const QRectF &geometry) -{ - if (image.isNull()) - return; - GLuint textureId = textureFromImage(image); - drawTexture(textureId, geometry); - glDeleteTextures(1, &textureId); -} - -void SurfaceRenderer::drawTexture(int textureId, const QRectF &geometry, int depth) -{ - GLfloat zValue = depth / 1000.0f; - //Set Texture and Vertex coordinates - GLfloat textureCoordinates[] = { 0, 1, - 1, 1, - 1, 0, - 0, 0 - }; - - GLfloat vertexCoordinates[] = { geometry.left(), geometry.top(), zValue, - geometry.right(), geometry.top(), zValue, - geometry.right(), geometry.bottom(), zValue, - geometry.left(), geometry.bottom(), zValue - }; - - //Set matrix to transfrom geometry values into gl coordinate space. - m_transformMatrix.setToIdentity(); - m_transformMatrix.scale( 2.0f / m_surface->geometry().width(), -2.0f / m_surface->geometry().height()); - m_transformMatrix.translate(-m_surface->geometry().width() / 2.0f, -m_surface->geometry().height() / 2.0f); - - m_shaderProgram->bind(); - - //attach the data! - m_context->functions()->glEnableVertexAttribArray(m_vertexCoordEntry); - m_context->functions()->glEnableVertexAttribArray(m_textureCoordEntry); - - m_context->functions()->glVertexAttribPointer(m_vertexCoordEntry, 3, GL_FLOAT, GL_FALSE, 0, vertexCoordinates); - m_context->functions()->glVertexAttribPointer(m_textureCoordEntry, 2, GL_FLOAT, GL_FALSE, 0, textureCoordinates); - m_shaderProgram->setUniformValue(m_matrixLocation, m_transformMatrix); - - glBindTexture(GL_TEXTURE_2D, textureId); - - glDrawArrays(GL_TRIANGLE_FAN, 0, 4); - - glBindTexture(GL_TEXTURE_2D, 0); - - m_context->functions()->glDisableVertexAttribArray(m_vertexCoordEntry); - m_context->functions()->glDisableVertexAttribArray(m_textureCoordEntry); - m_shaderProgram->release(); -} - -static inline QImage convertToGLFormat(const QImage &img) -{ - QImage dst(img.width(), img.height(), QImage::Format_ARGB32); - const int width = img.width(); - const int height = img.height(); - const uint *p = (const uint*) img.scanLine(img.height() - 1); - uint *q = (uint*) dst.scanLine(0); - - if (QSysInfo::ByteOrder == QSysInfo::BigEndian) { - for (int i=0; i < height; ++i) { - const uint *end = p + width; - while (p < end) { - *q = (*p << 8) | ((*p >> 24) & 0xff); - p++; - q++; - } - p -= 2 * width; - } - } else { - for (int i=0; i < height; ++i) { - const uint *end = p + width; - while (p < end) { - *q = ((*p << 16) & 0xff0000) | ((*p >> 16) & 0xff) | (*p & 0xff00ff00); - p++; - q++; - } - p -= 2 * width; - } - } - - return dst; -} - -GLuint SurfaceRenderer::textureFromImage(const QImage &image) -{ - QImage convertedImage = convertToGLFormat(image); - GLuint textureId; - //Copy QImage data to Texture - glGenTextures(1, &textureId); - glBindTexture(GL_TEXTURE_2D, textureId); - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, convertedImage.width(), convertedImage.height(), 0, GL_RGBA, GL_UNSIGNED_BYTE, convertedImage.constBits()); - - glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); - glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - - return textureId; -} diff --git a/examples/qwindow-compositor/surfacerenderer.h b/examples/qwindow-compositor/surfacerenderer.h deleted file mode 100644 index abfb554..0000000 --- a/examples/qwindow-compositor/surfacerenderer.h +++ /dev/null @@ -1,29 +0,0 @@ -#ifndef SURFACERENDERER_H -#define SURFACERENDERER_H - -#include -#include -#include - -class SurfaceRenderer -{ -public: - SurfaceRenderer(QOpenGLContext *context, QWindow *surface); - - void drawImage(const QImage &image, const QRectF &geometry); - void drawTexture(int textureId, const QRectF &geometry, int depth = 0); - GLuint textureFromImage(const QImage &image); - -private: - - QOpenGLContext *m_context; - QWindow *m_surface; - QOpenGLShaderProgram *m_shaderProgram; - QMatrix4x4 m_transformMatrix; - - int m_matrixLocation; - int m_vertexCoordEntry; - int m_textureCoordEntry; -}; - -#endif // SURFACERENDERER_H diff --git a/examples/qwindow-compositor/textureblitter.cpp b/examples/qwindow-compositor/textureblitter.cpp new file mode 100644 index 0000000..8fefe48 --- /dev/null +++ b/examples/qwindow-compositor/textureblitter.cpp @@ -0,0 +1,118 @@ +#include "textureblitter.h" + +#include +#include +#include + +TextureBlitter::TextureBlitter() + : m_shaderProgram(new QOpenGLShaderProgram()) +{ + static const char *textureVertexProgram = + "uniform highp mat4 matrix;\n" + "attribute highp vec3 vertexCoordEntry;\n" + "attribute highp vec2 textureCoordEntry;\n" + "varying highp vec2 textureCoord;\n" + "void main() {\n" + " textureCoord = textureCoordEntry;\n" + " gl_Position = matrix * vec4(vertexCoordEntry, 1);\n" + "}\n"; + + static const char *textureFragmentProgram = + "uniform sampler2D texture;\n" + "varying highp vec2 textureCoord;\n" + "void main() {\n" + " gl_FragColor = texture2D(texture, textureCoord);\n" + "}\n"; + + //Enable transparent windows + glEnable(GL_BLEND); + glBlendFunc (GL_ONE,GL_ONE_MINUS_SRC_ALPHA); + + m_shaderProgram->addShaderFromSourceCode(QOpenGLShader::Vertex, textureVertexProgram); + m_shaderProgram->addShaderFromSourceCode(QOpenGLShader::Fragment, textureFragmentProgram); + m_shaderProgram->link(); +} + + +void TextureBlitter::bind() +{ + + m_shaderProgram->bind(); + + m_vertexCoordEntry = m_shaderProgram->attributeLocation("vertexCoordEntry"); + m_textureCoordEntry = m_shaderProgram->attributeLocation("textureCoordEntry"); + m_matrixLocation = m_shaderProgram->uniformLocation("matrix"); +} + +void TextureBlitter::release() +{ + m_shaderProgram->release(); +} + +void TextureBlitter::drawTexture(int textureId, const QRectF &targetRect, const QSize &targetSize, int depth, bool targethasInvertedY, bool sourceHasInvertedY) +{ + + glViewport(0,0,targetSize.width(),targetSize.height()); + GLfloat zValue = depth / 1000.0f; + //Set Texture and Vertex coordinates + const GLfloat textureCoordinates[] = { + 0, 0, + 1, 0, + 1, 1, + 0, 1 + }; + + int x1 = targetRect.left(); + int x2 = targetRect.right(); + int y1, y2; + if (targethasInvertedY) { + if (sourceHasInvertedY) { + y1 = targetRect.top(); + y2 = targetRect.bottom(); + } else { + y1 = targetRect.bottom(); + y2 = targetRect.top(); + } + } else { + if (sourceHasInvertedY) { + y1 = targetSize.height() - targetRect.top(); + y2 = targetSize.height() - targetRect.bottom(); + } else { + y1 = targetSize.height() - targetRect.bottom(); + y2 = targetSize.height() - targetRect.top(); + } + } + + const GLfloat vertexCoordinates[] = { + x1, y1, zValue, + x2, y1, zValue, + x2, y2, zValue, + x1, y2, zValue + }; + + //Set matrix to transfrom geometry values into gl coordinate space. + m_transformMatrix.setToIdentity(); + m_transformMatrix.scale( 2.0f / targetSize.width(), 2.0f / targetSize.height() ); + m_transformMatrix.translate(-targetSize.width() / 2.0f, -targetSize.height() / 2.0f); + + //attach the data! + QOpenGLContext *currentContext = QOpenGLContext::currentContext(); + currentContext->functions()->glEnableVertexAttribArray(m_vertexCoordEntry); + currentContext->functions()->glEnableVertexAttribArray(m_textureCoordEntry); + + currentContext->functions()->glVertexAttribPointer(m_vertexCoordEntry, 3, GL_FLOAT, GL_FALSE, 0, vertexCoordinates); + currentContext->functions()->glVertexAttribPointer(m_textureCoordEntry, 2, GL_FLOAT, GL_FALSE, 0, textureCoordinates); + m_shaderProgram->setUniformValue(m_matrixLocation, m_transformMatrix); + + glBindTexture(GL_TEXTURE_2D, textureId); + + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + + glDrawArrays(GL_TRIANGLE_FAN, 0, 4); + + glBindTexture(GL_TEXTURE_2D, 0); + + currentContext->functions()->glDisableVertexAttribArray(m_vertexCoordEntry); + currentContext->functions()->glDisableVertexAttribArray(m_textureCoordEntry); +} diff --git a/examples/qwindow-compositor/textureblitter.h b/examples/qwindow-compositor/textureblitter.h new file mode 100644 index 0000000..13b2c6a --- /dev/null +++ b/examples/qwindow-compositor/textureblitter.h @@ -0,0 +1,26 @@ +#ifndef TEXTUREBLITTER_H +#define TEXTUREBLITTER_H + +#include + +class QOpenGLShaderProgram; +class TextureBlitter +{ +public: + TextureBlitter(); + void bind(); + void release(); + void drawTexture(int textureId, const QRectF &sourceGeometry, + const QSize &targetRect, int depth, + bool targethasInvertedY, bool sourceHasInvertedY); + +private: + QOpenGLShaderProgram *m_shaderProgram; + QMatrix4x4 m_transformMatrix; + + int m_matrixLocation; + int m_vertexCoordEntry; + int m_textureCoordEntry; +}; + +#endif // TEXTUREBLITTER_H diff --git a/extensions/sub-surface-extension.xml b/extensions/sub-surface-extension.xml new file mode 100644 index 0000000..6f9ca07 --- /dev/null +++ b/extensions/sub-surface-extension.xml @@ -0,0 +1,80 @@ + + + + + Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). + All rights reserved. + Contact: Nokia Corporation (qt-info@nokia.com) + + This file is part of the plugins of the Qt Toolkit. + + $QT_BEGIN_LICENSE:LGPL$ + GNU Lesser General Public License Usage + This file may be used under the terms of the GNU Lesser General Public + License version 2.1 as published by the Free Software Foundation and + appearing in the file LICENSE.LGPL included in the packaging of this + file. Please review the following information to ensure the GNU Lesser + General Public License version 2.1 requirements will be met: + http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. + + In addition, as a special exception, Nokia gives you certain additional + rights. These rights are described in the Nokia Qt LGPL Exception + version 1.1, included in the file LGPL_EXCEPTION.txt in this package. + + GNU General Public License Usage + Alternatively, this file may be used under the terms of the GNU General + Public License version 3.0 as published by the Free Software Foundation + and appearing in the file LICENSE.GPL included in the packaging of this + file. Please review the following information to ensure the GNU General + Public License version 3.0 requirements will be met: + http://www.gnu.org/copyleft/gpl.html. + + Other Usage + Alternatively, this file may be used in accordance with the terms and + conditions contained in a signed written agreement between you and Nokia. + + + + + + $QT_END_LICENSE$ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/extensions/surface-extension.xml b/extensions/surface-extension.xml index db150ae..51850f8 100644 --- a/extensions/surface-extension.xml +++ b/extensions/surface-extension.xml @@ -66,7 +66,6 @@ - diff --git a/src/compositor/compositor_api/waylandcompositor.cpp b/src/compositor/compositor_api/waylandcompositor.cpp index 3f84f7c..73ddf23 100644 --- a/src/compositor/compositor_api/waylandcompositor.cpp +++ b/src/compositor/compositor_api/waylandcompositor.cpp @@ -186,3 +186,8 @@ void WaylandCompositor::changeCursor(const QImage &image, int hotspotX, int hots Q_UNUSED(hotspotY); qDebug() << "changeCursor" << image.size() << hotspotX << hotspotY; } + +void WaylandCompositor::enableSubSurfaceExtension() +{ + m_compositor->enableSubSurfaceExtension(); +} diff --git a/src/compositor/compositor_api/waylandcompositor.h b/src/compositor/compositor_api/waylandcompositor.h index a38c3df..b384585 100644 --- a/src/compositor/compositor_api/waylandcompositor.h +++ b/src/compositor/compositor_api/waylandcompositor.h @@ -91,6 +91,8 @@ public: virtual void changeCursor(const QImage &image, int hotspotX, int hotspotY); + void enableSubSurfaceExtension(); + private: static void retainedSelectionChanged(QMimeData *mimeData, void *param); diff --git a/src/compositor/compositor_api/waylandsurface.cpp b/src/compositor/compositor_api/waylandsurface.cpp index 003a6d4..60d2684 100644 --- a/src/compositor/compositor_api/waylandsurface.cpp +++ b/src/compositor/compositor_api/waylandsurface.cpp @@ -3,16 +3,35 @@ #include #include "wayland_wrapper/wlsurface.h" +#include "wayland_wrapper/wlextendedsurface.h" +#include "wayland_wrapper/wlsubsurface.h" + +#ifdef QT_COMPOSITOR_QUICK +#include "waylandsurfaceitem.h" +#endif class WaylandSurfacePrivate : public QObjectPrivate { public: WaylandSurfacePrivate(Wayland::Surface *srfc) : surface(srfc) +#ifdef QT_COMPOSITOR_QUICK + , surface_item(0) +#endif {} + ~WaylandSurfacePrivate() + { +#ifdef QT_COMPOSITOR_QUICK + if (surface_item) + surface_item->setSurface(0); +#endif + } + Wayland::Surface *surface; - QRect geometry; +#ifdef QT_COMPOSITOR_QUICK + WaylandSurfaceItem *surface_item; +#endif }; WaylandSurface::WaylandSurface(Wayland::Surface *surface) @@ -21,6 +40,24 @@ WaylandSurface::WaylandSurface(Wayland::Surface *surface) } +WaylandSurface *WaylandSurface::parentSurface() const +{ + Q_D(const WaylandSurface); + if (d->surface->subSurface()) { + return d->surface->subSurface()->parent()->waylandSurface(); + } + return 0; +} + +QLinkedList WaylandSurface::subSurfaces() const +{ + Q_D(const WaylandSurface); + if (d->surface->subSurface()) { + return d->surface->subSurface()->subSurfaces(); + } + return QLinkedList(); +} + WaylandSurface::Type WaylandSurface::type() const { Q_D(const WaylandSurface); @@ -42,13 +79,13 @@ bool WaylandSurface::visible() const QRect WaylandSurface::geometry() const { Q_D(const WaylandSurface); - return d->geometry; + return d->surface->geometry(); } void WaylandSurface::setGeometry(const QRect &geometry) { Q_D(WaylandSurface); - d->geometry = geometry; + d->surface->setGeometry(geometry); } QImage WaylandSurface::image() const @@ -76,6 +113,20 @@ Wayland::Surface * WaylandSurface::handle() const return d->surface; } +#ifdef QT_COMPOSITOR_QUICK +WaylandSurfaceItem *WaylandSurface::surfaceItem() const +{ + Q_D(const WaylandSurface); + return d->surface_item; +} + +void WaylandSurface::setSurfaceItem(WaylandSurfaceItem *surfaceItem) +{ + Q_D(WaylandSurface); + d->surface_item = surfaceItem; +} +#endif //QT_COMPOSITOR_QUICK + qint64 WaylandSurface::processId() const { Q_D(const WaylandSurface); @@ -100,6 +151,27 @@ void WaylandSurface::setWindowProperty(const QString &name, const QVariant &valu d->surface->setWindowProperty(name, value); } +QPoint WaylandSurface::mapToParent(const QPoint &pos) const +{ + return pos + geometry().topLeft(); +} + +QPoint WaylandSurface::mapTo(WaylandSurface *parent, const QPoint &pos) const +{ + QPoint p = pos; + if (parent) { + const WaylandSurface * surface = this; + while (surface != parent) { + Q_ASSERT_X(surface, "WaylandSurface::mapTo(WaylandSurface *parent, const QPoint &pos)", + "parent must be in parent hierarchy"); + p = surface->mapToParent(p); + surface = surface->parentSurface(); + } + } + return p; + +} + void WaylandSurface::sendMousePressEvent(const QPoint &pos, Qt::MouseButton button) { Q_D(WaylandSurface); diff --git a/src/compositor/compositor_api/waylandsurface.h b/src/compositor/compositor_api/waylandsurface.h index 45c308a..89befea 100644 --- a/src/compositor/compositor_api/waylandsurface.h +++ b/src/compositor/compositor_api/waylandsurface.h @@ -54,15 +54,21 @@ class WaylandSurfacePrivate; +#ifdef QT_COMPOSITOR_QUICK +class WaylandSurfaceItem; +#endif + namespace Wayland { class Surface; class SurfacePrivate; +class ExtendedSurface; } class Q_COMPOSITOR_EXPORT WaylandSurface : public QObject { Q_OBJECT Q_DECLARE_PRIVATE(WaylandSurface) + Q_PROPERTY(QRect geometry READ geometry WRITE setGeometry NOTIFY geometryChanged) public: enum Type { Invalid, @@ -73,6 +79,9 @@ public: WaylandSurface(Wayland::Surface *surface); + WaylandSurface *parentSurface() const; + QLinkedList subSurfaces() const; + Type type() const; bool isYInverted() const; @@ -105,19 +114,31 @@ public: void setInputFocus(); Wayland::Surface *handle() const; + +#ifdef QT_COMPOSITOR_QUICK + WaylandSurfaceItem *surfaceItem() const; + void setSurfaceItem(WaylandSurfaceItem *surfaceItem); +#endif + qint64 processId() const; QByteArray authenticationToken() const; QVariantMap windowProperties() const; void setWindowProperty(const QString &name, const QVariant &value); + QPoint mapToParent(const QPoint &) const; + QPoint mapTo(WaylandSurface *, const QPoint &) const; + signals: void mapped(); void unmapped(); void damaged(const QRect &rect); + void parentChanged(WaylandSurface *newParent, WaylandSurface *oldParent); + void geometryChanged(); void windowPropertyChanged(const QString &name, const QVariant &value); friend class Wayland::Surface; friend class Wayland::SurfacePrivate; + friend class Wayland::ExtendedSurface; }; #endif // WAYLANDSURFACE_H diff --git a/src/compositor/compositor_api/waylandsurfaceitem.cpp b/src/compositor/compositor_api/waylandsurfaceitem.cpp index 67d4784..4d3687c 100644 --- a/src/compositor/compositor_api/waylandsurfaceitem.cpp +++ b/src/compositor/compositor_api/waylandsurfaceitem.cpp @@ -41,6 +41,9 @@ #include "waylandsurfaceitem.h" #include "waylandsurface.h" +#include "wlsurface.h" +#include "wlextendedsurface.h" + #include #include @@ -62,13 +65,6 @@ public: bool smooth; }; -void WaylandSurfaceItem::surfaceDamaged(const QRect &) -{ - m_damaged = true; - emit textureChanged(); - update(); -} - WaylandSurfaceItem::WaylandSurfaceItem(QQuickItem *parent) : QQuickItem(parent) , m_surface(0) @@ -95,7 +91,12 @@ void WaylandSurfaceItem::init(WaylandSurface *surface) if (!surface) return; + if (m_surface) { + m_surface->setSurfaceItem(0); + } + m_surface = surface; + m_surface->setSurfaceItem(this); setWidth(surface->geometry().width()); setHeight(surface->geometry().height()); @@ -104,8 +105,12 @@ void WaylandSurfaceItem::init(WaylandSurface *surface) setFlag(ItemHasContents); setAcceptedMouseButtons(Qt::LeftButton | Qt::RightButton); connect(surface, SIGNAL(mapped(const QSize &)), this, SLOT(surfaceMapped(const QSize &))); + connect(surface, SIGNAL(unmapped()), this, SLOT(surfaceUnmapped())); connect(surface, SIGNAL(destroyed(QObject *)), this, SLOT(surfaceDestroyed(QObject *))); connect(surface, SIGNAL(damaged(const QRect &)), this, SLOT(surfaceDamaged(const QRect &))); + connect(surface, SIGNAL(parentChanged(WaylandSurface*,WaylandSurface*)), + this, SLOT(parentChanged(WaylandSurface*,WaylandSurface*))); + connect(surface, SIGNAL(geometryChanged()), this, SLOT(updateGeometry())); m_damaged = false; @@ -113,6 +118,9 @@ void WaylandSurfaceItem::init(WaylandSurface *surface) WaylandSurfaceItem::~WaylandSurfaceItem() { + if (m_surface) { + m_surface->setSurfaceItem(0); + } m_texture->deleteLater(); } @@ -194,10 +202,14 @@ QPoint WaylandSurfaceItem::toSurface(const QPointF &pos) const return pos.toPoint(); } -void WaylandSurfaceItem::surfaceMapped(const QSize &size) +void WaylandSurfaceItem::surfaceMapped(const QSize &) +{ + setPaintEnabled(true); +} + +void WaylandSurfaceItem::surfaceUnmapped() { - setWidth(size.width()); - setHeight(size.height()); + setPaintEnabled(false); } void WaylandSurfaceItem::surfaceDestroyed(QObject *) @@ -205,6 +217,34 @@ void WaylandSurfaceItem::surfaceDestroyed(QObject *) m_surface = 0; } +void WaylandSurfaceItem::surfaceDamaged(const QRect &) +{ + m_damaged = true; + emit textureChanged(); + update(); +} + +void WaylandSurfaceItem::parentChanged(WaylandSurface *newParent, WaylandSurface *oldParent) +{ + Q_UNUSED(oldParent); + + WaylandSurfaceItem *item = newParent? newParent->surfaceItem():0; + setParentItem(item); + + if (newParent) { + setPaintEnabled(true); + setVisible(true); + setOpacity(1); + setEnabled(true); + } +} + +void WaylandSurfaceItem::updateGeometry() +{ + setPos(m_surface->geometry().topLeft()); + setSize(m_surface->geometry().size()); +} + bool WaylandSurfaceItem::paintEnabled() const { return m_paintEnabled; @@ -218,9 +258,10 @@ void WaylandSurfaceItem::setPaintEnabled(bool enabled) QSGNode *WaylandSurfaceItem::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData *) { - if (!m_surface) + if (!m_surface) { + delete oldNode; return 0; - QSGSimpleTextureNode *node = static_cast(oldNode); + } if (m_damaged) { QSGTexture *oldTexture = m_texture; @@ -234,6 +275,7 @@ QSGNode *WaylandSurfaceItem::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeDa } else { m_texture = canvas()->createTextureFromImage(m_surface->image()); } + delete oldTexture; m_damaged = false; } @@ -243,6 +285,7 @@ QSGNode *WaylandSurfaceItem::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeDa m_provider->smooth = smooth(); } + QSGSimpleTextureNode *node = static_cast(oldNode); if (!m_texture || !m_paintEnabled) { delete oldNode; return 0; diff --git a/src/compositor/compositor_api/waylandsurfaceitem.h b/src/compositor/compositor_api/waylandsurfaceitem.h index a66a2ce..e08cda3 100644 --- a/src/compositor/compositor_api/waylandsurfaceitem.h +++ b/src/compositor/compositor_api/waylandsurfaceitem.h @@ -100,8 +100,11 @@ public slots: private slots: void surfaceMapped(const QSize &size); + void surfaceUnmapped(); void surfaceDestroyed(QObject *object); void surfaceDamaged(const QRect &); + void parentChanged(WaylandSurface *newParent, WaylandSurface *oldParent); + void updateGeometry(); signals: void textureChanged(); diff --git a/src/compositor/wayland_wrapper/wayland_wrapper.pri b/src/compositor/wayland_wrapper/wayland_wrapper.pri index cf841f9..6340f5c 100644 --- a/src/compositor/wayland_wrapper/wayland_wrapper.pri +++ b/src/compositor/wayland_wrapper/wayland_wrapper.pri @@ -1,5 +1,6 @@ WAYLANDSOURCES += \ $$PWD/../../../extensions/surface-extension.xml \ + $$PWD/../../../extensions/sub-surface-extension.xml \ $$PWD/../../../extensions/output-extension.xml @@ -16,7 +17,8 @@ HEADERS += \ $$PWD/wldataoffer.h \ $$PWD/wldatasource.h \ $$PWD/wlextendedsurface.h \ - $$PWD/wlextendedoutput.h + $$PWD/wlextendedoutput.h \ + $$PWD/wlsubsurface.h SOURCES += \ $$PWD/wlcompositor.cpp \ @@ -31,5 +33,6 @@ SOURCES += \ $$PWD/wldataoffer.cpp \ $$PWD/wldatasource.cpp \ $$PWD/wlextendedsurface.cpp \ - $$PWD/wlextendedoutput.cpp + $$PWD/wlextendedoutput.cpp \ + $$PWD/wlsubsurface.cpp diff --git a/src/compositor/wayland_wrapper/wlcompositor.cpp b/src/compositor/wayland_wrapper/wlcompositor.cpp index abfcac6..b998c91 100644 --- a/src/compositor/wayland_wrapper/wlcompositor.cpp +++ b/src/compositor/wayland_wrapper/wlcompositor.cpp @@ -49,6 +49,7 @@ #include "wldatadevice.h" #include "wlextendedoutput.h" #include "wlextendedsurface.h" +#include "wlsubsurface.h" #include #include @@ -120,6 +121,7 @@ Compositor::Compositor(WaylandCompositor *qt_compositor) , m_retainNotify(0) , m_outputExtension(0) , m_surfaceExtension(0) + , m_subSurfaceExtension(0) { compositor = this; qDebug() << "Compositor instance is" << this; @@ -339,6 +341,13 @@ void Compositor::initializeWindowManagerProtocol() m_windowManagerIntegration->initialize(m_display); } +void Compositor::enableSubSurfaceExtension() +{ + if (!m_subSurfaceExtension) { + m_subSurfaceExtension = new SubSurfaceExtensionGlobal(this); + } +} + bool Compositor::setDirectRenderSurface(Surface *surface) { #ifdef QT_COMPOSITOR_WAYLAND_GL diff --git a/src/compositor/wayland_wrapper/wlcompositor.h b/src/compositor/wayland_wrapper/wlcompositor.h index 4404ff8..a26e23a 100644 --- a/src/compositor/wayland_wrapper/wlcompositor.h +++ b/src/compositor/wayland_wrapper/wlcompositor.h @@ -64,6 +64,7 @@ class InputDevice; class DataDeviceManager; class OutputExtensionGlobal; class SurfaceExtensionGlobal; +class SubSurfaceExtensionGlobal; class Q_COMPOSITOR_EXPORT Compositor : public QObject { @@ -100,6 +101,7 @@ public: GraphicsHardwareIntegration *graphicsHWIntegration() const; void initializeHardwareIntegration(); void initializeWindowManagerProtocol(); + void enableSubSurfaceExtension(); bool setDirectRenderSurface(Surface *surface); Surface *directRenderSurface() const {return m_directRenderSurface;} @@ -181,6 +183,7 @@ private: OutputExtensionGlobal *m_outputExtension; SurfaceExtensionGlobal *m_surfaceExtension; + SubSurfaceExtensionGlobal *m_subSurfaceExtension; static void bind_func(struct wl_client *client, void *data, uint32_t version, uint32_t id); diff --git a/src/compositor/wayland_wrapper/wlextendedsurface.cpp b/src/compositor/wayland_wrapper/wlextendedsurface.cpp index 85bdd8e..68f6d05 100644 --- a/src/compositor/wayland_wrapper/wlextendedsurface.cpp +++ b/src/compositor/wayland_wrapper/wlextendedsurface.cpp @@ -87,6 +87,11 @@ ExtendedSurface::ExtendedSurface(struct wl_client *client, uint32_t id, Surface this); } +ExtendedSurface::~ExtendedSurface() +{ + +} + void ExtendedSurface::sendGenericProperty(const char *name, const QVariant &variant) { QByteArray byteValue; @@ -106,6 +111,7 @@ void ExtendedSurface::sendOnScreenVisibllity(bool visible) wl_resource_post_event(m_extended_surface_resource,WL_EXTENDED_SURFACE_ONSCREEN_VISIBILITY,visibleInt); } + void ExtendedSurface::update_generic_property(wl_client *client, wl_resource *extended_surface_resource, const char *name, wl_array *value) { Q_UNUSED(client); diff --git a/src/compositor/wayland_wrapper/wlextendedsurface.h b/src/compositor/wayland_wrapper/wlextendedsurface.h index d322896..46dc03c 100644 --- a/src/compositor/wayland_wrapper/wlextendedsurface.h +++ b/src/compositor/wayland_wrapper/wlextendedsurface.h @@ -43,12 +43,16 @@ #include "wayland-surface-extension-server-protocol.h" +#include "wlsurface.h" + #include +#include + +class WaylandSurface; namespace Wayland { class Compositor; -class Surface; class SurfaceExtensionGlobal { @@ -72,10 +76,17 @@ class ExtendedSurface { public: ExtendedSurface(struct wl_client *client, uint32_t id, Surface *surface); + ~ExtendedSurface(); void sendGenericProperty(const char *name, const QVariant &variant); void sendOnScreenVisibllity(bool visible); + void setSubSurface(ExtendedSurface *subSurface,int x, int y); + void removeSubSurface(ExtendedSurface *subSurfaces); + ExtendedSurface *parent() const; + void setParent(ExtendedSurface *parent); + QLinkedList subSurfaces() const; + private: struct wl_resource *m_extended_surface_resource; Surface *m_surface; @@ -84,6 +95,17 @@ private: struct wl_resource *resource, const char *name, struct wl_array *value); + static void map_sub_surface(struct wl_client *client, + struct wl_resource *extended_surface_resource, + struct wl_resource *sub_surface_resource, + int32_t x, + int32_t y); + static void move_sub_surface(struct wl_client *client, + struct wl_resource *extended_surface_resource, + struct wl_resource *sub_surface_resource, + int32_t x, + int32_t y); + static const struct wl_extended_surface_interface extended_surface_interface; }; diff --git a/src/compositor/wayland_wrapper/wlsubsurface.cpp b/src/compositor/wayland_wrapper/wlsubsurface.cpp new file mode 100644 index 0000000..e8b8ab6 --- /dev/null +++ b/src/compositor/wayland_wrapper/wlsubsurface.cpp @@ -0,0 +1,168 @@ +/**************************************************************************** +** +** This file is part of QtCompositor** +** +** Copyright © 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** +** Contact: Nokia Corporation qt-info@nokia.com +** +** You may use this file under the terms of the BSD license as follows: +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** +** Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** +** Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in the +** documentation and/or other materials provided with the distribution. +** +** Neither the name of Nokia Corporation and its Subsidiary(-ies) nor the +** names of its contributors may be used to endorse or promote products +** derived from this software without specific prior written permission. +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +** +****************************************************************************/ + +#include "wlsubsurface.h" + +#include "wlcompositor.h" + +namespace Wayland { + +SubSurfaceExtensionGlobal::SubSurfaceExtensionGlobal(Compositor *compositor) + : m_compositor(compositor) +{ + wl_display_add_global(m_compositor->wl_display(), + &wl_sub_surface_extension_interface, + this, + SubSurfaceExtensionGlobal::bind_func); +} + +void SubSurfaceExtensionGlobal::bind_func(wl_client *client, void *data, uint32_t version, uint32_t id) +{ + Q_UNUSED(version); + wl_client_add_object(client, &wl_sub_surface_extension_interface,&sub_surface_extension_interface,id,data); +} + +void SubSurfaceExtensionGlobal::get_sub_surface_aware_surface(wl_client *client, wl_resource *sub_surface_extension_resource, uint32_t id, wl_resource *surface_resource) +{ + Q_UNUSED(sub_surface_extension_resource); + Surface *surface = reinterpret_cast(surface_resource); + new SubSurface(client,id,surface); +} + +const struct wl_sub_surface_extension_interface SubSurfaceExtensionGlobal::sub_surface_extension_interface = { + SubSurfaceExtensionGlobal::get_sub_surface_aware_surface +}; + +SubSurface::SubSurface(wl_client *client, uint32_t id, Surface *surface) + : m_surface(surface) + , m_parent(0) +{ + surface->setSubSurface(this); + m_sub_surface_resource = wl_client_add_object(client, + &wl_sub_surface_interface, + &sub_surface_interface, + id, + this); +} + +SubSurface::~SubSurface() +{ + if (m_parent) { + m_parent->removeSubSurface(this); + } +} + +void SubSurface::setSubSurface(SubSurface *subSurface, int x, int y) +{ +// Q_ASSERT(!m_sub_surfaces.contains(subSurface->m_surface->handle())); + m_sub_surfaces.append(subSurface->m_surface->handle()); + subSurface->setParent(this); + QRect rect = m_surface->geometry(); + rect.moveTo(x,y); + subSurface->m_surface->setGeometry(rect); +} + +void SubSurface::removeSubSurface(SubSurface *subSurfaces) +{ + Q_ASSERT(m_sub_surfaces.contains(subSurfaces->m_surface->handle())); + m_sub_surfaces.removeOne(subSurfaces->m_surface->handle()); +} + +SubSurface *SubSurface::parent() const +{ + return m_parent; +} + +void SubSurface::setParent(SubSurface *parent) +{ + if (m_parent == parent) + return; + + WaylandSurface *oldParent = 0; + WaylandSurface *newParent = 0; + + if (m_parent) { + oldParent = m_parent->m_surface->handle(); + m_parent->removeSubSurface(this); + } + if (parent) { + newParent = parent->m_surface->handle(); + } + m_parent = parent; + + m_surface->handle()->parentChanged(newParent,oldParent); +} + +QLinkedList SubSurface::subSurfaces() const +{ + return m_sub_surfaces; +} + +void SubSurface::attach_sub_surface(wl_client *client, wl_resource *sub_surface_parent_resource, wl_resource *sub_surface_child_resource, int32_t x, int32_t y) +{ + Q_UNUSED(client); + SubSurface *parent_sub_surface = static_cast(sub_surface_parent_resource->data); + SubSurface *child_sub_surface = static_cast(sub_surface_child_resource->data); + parent_sub_surface->setSubSurface(child_sub_surface,x,y); +} + +void SubSurface::move_sub_surface(wl_client *client, wl_resource *sub_surface_parent_resource, wl_resource *sub_surface_child_resource, int32_t x, int32_t y) +{ + Q_UNUSED(client); + SubSurface *parent_sub_surface = static_cast(sub_surface_parent_resource->data); + SubSurface *child_sub_surface = static_cast(sub_surface_child_resource->data); +} + +void SubSurface::raise(wl_client *client, wl_resource *sub_surface_parent_resource, wl_resource *sub_surface_child_resource) +{ +} + +void SubSurface::lower(wl_client *client, wl_resource *sub_surface_parent_resource, wl_resource *sub_surface_child_resource) +{ +} + +const struct wl_sub_surface_interface SubSurface::sub_surface_interface = { + SubSurface::attach_sub_surface, + SubSurface::move_sub_surface, + SubSurface::raise, + SubSurface::lower +}; + +} diff --git a/src/compositor/wayland_wrapper/wlsubsurface.h b/src/compositor/wayland_wrapper/wlsubsurface.h new file mode 100644 index 0000000..947cd02 --- /dev/null +++ b/src/compositor/wayland_wrapper/wlsubsurface.h @@ -0,0 +1,129 @@ +/**************************************************************************** +** +** This file is part of QtCompositor** +** +** Copyright © 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** +** Contact: Nokia Corporation qt-info@nokia.com +** +** You may use this file under the terms of the BSD license as follows: +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** +** Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** +** Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in the +** documentation and/or other materials provided with the distribution. +** +** Neither the name of Nokia Corporation and its Subsidiary(-ies) nor the +** names of its contributors may be used to endorse or promote products +** derived from this software without specific prior written permission. +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +** +****************************************************************************/ + +#ifndef WLSUBSURFACE_H +#define WLSUBSURFACE_H + +#include "wlsurface.h" + +#include "wayland-sub-surface-extension-server-protocol.h" + +#include + +class Compositor; +class WaylandSurface; + +namespace Wayland { + +class SubSurfaceExtensionGlobal +{ +public: + SubSurfaceExtensionGlobal(Compositor *compositor); + +private: + Compositor *m_compositor; + + static void bind_func(struct wl_client *client, void *data, + uint32_t version, uint32_t id); + static void get_sub_surface_aware_surface(struct wl_client *client, + struct wl_resource *sub_surface_extension_resource, + uint32_t id, + struct wl_resource *surface_resource); + + static const struct wl_sub_surface_extension_interface sub_surface_extension_interface; +}; + +class SubSurface +{ +public: + SubSurface(struct wl_client *client, uint32_t id, Surface *surface); + ~SubSurface(); + + void setSubSurface(SubSurface *subSurface, int x, int y); + void removeSubSurface(SubSurface *subSurfaces); + + SubSurface *parent() const; + void setParent(SubSurface *parent); + + QLinkedList subSurfaces() const; + + Surface *surface() const; + WaylandSurface *waylandSurface() const; + +private: + struct wl_resource *m_sub_surface_resource; + Surface *m_surface; + + SubSurface *m_parent; + QLinkedList m_sub_surfaces; + + static void attach_sub_surface(struct wl_client *client, + struct wl_resource *sub_surface_parent_resource, + struct wl_resource *sub_surface_child_resource, + int32_t x, + int32_t y); + static void move_sub_surface(struct wl_client *client, + struct wl_resource *sub_surface_parent_resource, + struct wl_resource *sub_surface_child_resource, + int32_t x, + int32_t y); + static void raise(struct wl_client *client, + struct wl_resource *sub_surface_parent_resource, + struct wl_resource *sub_surface_child_resource); + static void lower(struct wl_client *client, + struct wl_resource *sub_surface_parent_resource, + struct wl_resource *sub_surface_child_resource); + static const struct wl_sub_surface_interface sub_surface_interface; +}; + +inline Surface *SubSurface::surface() const +{ + return m_surface; +} + +inline WaylandSurface *SubSurface::waylandSurface() const +{ + return m_surface->handle(); +} + + +} + +#endif // WLSUBSURFACE_H diff --git a/src/compositor/wayland_wrapper/wlsurface.cpp b/src/compositor/wayland_wrapper/wlsurface.cpp index 21f2d31..30b0bd0 100644 --- a/src/compositor/wayland_wrapper/wlsurface.cpp +++ b/src/compositor/wayland_wrapper/wlsurface.cpp @@ -46,6 +46,7 @@ #include "wlshmbuffer.h" #include "wlinputdevice.h" #include "wlextendedsurface.h" +#include "wlsubsurface.h" #include @@ -203,11 +204,13 @@ public: : q_ptr(surface) , client(client) , compositor(compositor) + , qtSurface(new WaylandSurface(surface)) , directRenderBuffer(0) , processId(0) , textureBuffer(0) , surfaceBuffer(0) , extendedSurface(0) + , subSurface(0) { @@ -236,8 +239,11 @@ public: struct wl_list frame_callback_list; ExtendedSurface *extendedSurface; + SubSurface *subSurface; SurfaceBuffer bufferPool[buffer_pool_size]; + + QRect geometry; private: Surface *q_ptr; }; @@ -278,7 +284,7 @@ Surface::Surface(struct wl_client *client, Compositor *compositor) : d_ptr(new SurfacePrivate(this,client,compositor)) { base()->resource.client = client; - d_ptr->qtSurface = new WaylandSurface(this); + } Surface::~Surface() @@ -309,6 +315,9 @@ bool Surface::isYInverted() const #ifdef QT_COMPOSITOR_WAYLAND_GL Q_D(const Surface); + if (!d->surfaceBuffer) + return false; + if (d->compositor->graphicsHWIntegration() && !d->surfaceBuffer->bufferIsDestroyed()) { if (type() == WaylandSurface::Texture) { return d->compositor->graphicsHWIntegration()->isYInverted(d->surfaceBuffer->handle()); @@ -368,11 +377,31 @@ QImage Surface::image() const return QImage(); } +QRect Surface::geometry() const +{ + Q_D(const Surface); + return d->geometry; +} + +void Surface::setGeometry(const QRect &rect) +{ + Q_D(Surface); + bool emitChange = false; + if (rect != d->geometry) + emitChange = true; + d->geometry = rect; + if (emitChange) + d->qtSurface->geometryChanged(); +} + #ifdef QT_COMPOSITOR_WAYLAND_GL GLuint Surface::textureId(QOpenGLContext *context) const { Q_D(const Surface); + if (!d->surfaceBuffer) { + return 0; + } if (d->compositor->graphicsHWIntegration() && type() == WaylandSurface::Texture && !d->surfaceBuffer->textureCreated()) { Surface *that = const_cast(this); @@ -408,7 +437,7 @@ void Surface::attach(struct wl_buffer *buffer) Q_ASSERT(newBuffer); } - bool emitMap = !d->surfaceBuffer && buffer; + bool emitMap = !d->surfaceBuffer && buffer && (!d->subSurface || !d->subSurface->parent()); bool emitUnmap = d->surfaceBuffer && !buffer; if (d->surfaceBuffer && d->surfaceBuffer != d->directRenderBuffer) { @@ -418,6 +447,17 @@ void Surface::attach(struct wl_buffer *buffer) d->surfaceBuffer = 0; } d->surfaceBuffer = newBuffer; + int width = 0; + int height = 0; + if (d->surfaceBuffer) { + width = d->surfaceBuffer->width(); + height = d->surfaceBuffer->height(); + } + QRect geo = geometry(); + geo.setWidth(width); + geo.setHeight(height); + setGeometry(geo); + if (emitMap) { d->qtSurface->mapped(); } else if (emitUnmap) { @@ -515,6 +555,18 @@ ExtendedSurface *Surface::extendedSurface() const return d->extendedSurface; } +void Surface::setSubSurface(SubSurface *subSurface) +{ + Q_D(Surface); + d->subSurface = subSurface; +} + +SubSurface *Surface::subSurface() const +{ + Q_D(const Surface); + return d->subSurface; +} + void Surface::sendMousePressEvent(int x, int y, Qt::MouseButton button) { Q_D(Surface); diff --git a/src/compositor/wayland_wrapper/wlsurface.h b/src/compositor/wayland_wrapper/wlsurface.h index 425e3ce..905ee53 100644 --- a/src/compositor/wayland_wrapper/wlsurface.h +++ b/src/compositor/wayland_wrapper/wlsurface.h @@ -64,6 +64,7 @@ namespace Wayland { class Compositor; class Buffer; class ExtendedSurface; +class SubSurface; class SurfacePrivate; @@ -83,6 +84,9 @@ public: QImage image() const; + QRect geometry() const; + void setGeometry(const QRect &rect); + #ifdef QT_COMPOSITOR_WAYLAND_GL GLuint textureId(QOpenGLContext *context) const; #endif @@ -121,6 +125,9 @@ public: void setExtendedSurface(ExtendedSurface *extendedSurface); ExtendedSurface *extendedSurface() const; + void setSubSurface(SubSurface *subSurface); + SubSurface *subSurface() const; + static const struct wl_surface_interface surface_interface; protected: QScopedPointer d_ptr; diff --git a/src/plugins/platforms/wayland/qwaylanddisplay.cpp b/src/plugins/platforms/wayland/qwaylanddisplay.cpp index 0d62877..3f160b7 100644 --- a/src/plugins/platforms/wayland/qwaylanddisplay.cpp +++ b/src/plugins/platforms/wayland/qwaylanddisplay.cpp @@ -59,6 +59,7 @@ #include "qwaylandextendedoutput.h" #include "qwaylandextendedsurface.h" +#include "qwaylandsubsurface.h" #include #include @@ -306,6 +307,8 @@ void QWaylandDisplay::displayHandleGlobal(uint32_t id, mOutputExtension = new QWaylandOutputExtension(this,id); } else if (interface == "wl_surface_extension") { mWindowExtension = new QWaylandSurfaceExtension(this,id); + } else if (interface == "wl_sub_surface_extension") { + mSubSurfaceExtension = new QWaylandSubSurfaceExtension(this,id); } } diff --git a/src/plugins/platforms/wayland/qwaylanddisplay.h b/src/plugins/platforms/wayland/qwaylanddisplay.h index cce0486..4163799 100644 --- a/src/plugins/platforms/wayland/qwaylanddisplay.h +++ b/src/plugins/platforms/wayland/qwaylanddisplay.h @@ -60,6 +60,7 @@ class QWaylandWindowManagerIntegration; class QWaylandDataDeviceManager; class QWaylandShell; class QWaylandSurfaceExtension; +class QWaylandSubSurfaceExtension; class QWaylandOutputExtension; class QWaylandDisplay : public QObject { @@ -97,6 +98,7 @@ public: QWaylandDataDeviceManager *dndSelectionHandler() const { return mDndSelectionHandler; } QWaylandSurfaceExtension *windowExtension() const { return mWindowExtension; } + QWaylandSubSurfaceExtension *subSurfaceExtension() const { return mSubSurfaceExtension; } QWaylandOutputExtension *outputExtension() const { return mOutputExtension; } struct wl_shm *shm() const { return mShm; } @@ -125,6 +127,7 @@ private: QWaylandInputDevice *mLastKeyboardFocusInputDevice; QWaylandDataDeviceManager *mDndSelectionHandler; QWaylandSurfaceExtension *mWindowExtension; + QWaylandSubSurfaceExtension *mSubSurfaceExtension; QWaylandOutputExtension *mOutputExtension; QSocketNotifier *mReadNotifier; diff --git a/src/plugins/platforms/wayland/qwaylandextendedsurface.h b/src/plugins/platforms/wayland/qwaylandextendedsurface.h index 10d17b9..c17df84 100644 --- a/src/plugins/platforms/wayland/qwaylandextendedsurface.h +++ b/src/plugins/platforms/wayland/qwaylandextendedsurface.h @@ -70,6 +70,7 @@ public: QVariantMap properties() const; QVariant property(const QString &name); QVariant property(const QString &name, const QVariant &defaultValue); + private: QWaylandWindow *m_window; struct wl_extended_surface *m_extended_surface; diff --git a/src/plugins/platforms/wayland/qwaylandshmbackingstore.cpp b/src/plugins/platforms/wayland/qwaylandshmbackingstore.cpp index 42e0416..da9031b 100644 --- a/src/plugins/platforms/wayland/qwaylandshmbackingstore.cpp +++ b/src/plugins/platforms/wayland/qwaylandshmbackingstore.cpp @@ -130,7 +130,6 @@ void QWaylandShmBackingStore::flush(QWindow *window, const QRegion ®ion, cons void QWaylandShmBackingStore::resize(const QSize &size, const QRegion &) { QWaylandShmWindow *waylandWindow = static_cast(window()->handle()); - Q_ASSERT(waylandWindow->windowType() == QWaylandWindow::Shm); QImage::Format format = QPlatformScreen::platformScreenForWindow(window())->format(); diff --git a/src/plugins/platforms/wayland/qwaylandsubsurface.cpp b/src/plugins/platforms/wayland/qwaylandsubsurface.cpp new file mode 100644 index 0000000..13d8c99 --- /dev/null +++ b/src/plugins/platforms/wayland/qwaylandsubsurface.cpp @@ -0,0 +1,79 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the plugins of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qwaylandsubsurface.h" + +#include "qwaylandwindow.h" + +#include "wayland-sub-surface-extension-client-protocol.h" + +QWaylandSubSurfaceExtension::QWaylandSubSurfaceExtension(QWaylandDisplay *display, uint32_t id) +{ + m_sub_surface_extension = static_cast( + wl_display_bind(display->wl_display(),id, &wl_sub_surface_extension_interface)); +} + +QWaylandSubSurface *QWaylandSubSurfaceExtension::getSubSurfaceAwareWindow(QWaylandWindow *window) +{ + struct wl_surface *surface = window->wl_surface(); + Q_ASSERT(surface); + struct wl_sub_surface *sub_surface = + wl_sub_surface_extension_get_sub_surface_aware_surface(m_sub_surface_extension,surface); + + return new QWaylandSubSurface(window,sub_surface); + +} + +QWaylandSubSurface::QWaylandSubSurface(QWaylandWindow *window, struct wl_sub_surface *sub_surface) + : m_window(window) + , m_sub_surface(sub_surface) +{ +} + +void QWaylandSubSurface::setParent(const QWaylandWindow *parent) +{ + QWaylandSubSurface *parentSurface = parent? parent->subSurfaceWindow():0; + if (parentSurface) { + int x = m_window->geometry().x(); + int y = m_window->geometry().y(); + wl_sub_surface_attach_sub_surface(parentSurface->m_sub_surface,m_sub_surface,x,y); + } +} diff --git a/src/plugins/platforms/wayland/qwaylandsubsurface.h b/src/plugins/platforms/wayland/qwaylandsubsurface.h new file mode 100644 index 0000000..5c8b2b2 --- /dev/null +++ b/src/plugins/platforms/wayland/qwaylandsubsurface.h @@ -0,0 +1,73 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the plugins of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QWAYLANDSUBSURFACE_H +#define QWAYLANDSUBSURFACE_H + +class QWaylandDisplay; +class QWaylandWindow; +class QWaylandSubSurface; + +#include + +class QWaylandSubSurfaceExtension +{ +public: + QWaylandSubSurfaceExtension(QWaylandDisplay *display, uint32_t id); + + QWaylandSubSurface *getSubSurfaceAwareWindow(QWaylandWindow *window); +private: + struct wl_sub_surface_extension *m_sub_surface_extension; +}; + +class QWaylandSubSurface +{ +public: + QWaylandSubSurface(QWaylandWindow *window, struct wl_sub_surface *sub_surface); + + void setParent(const QWaylandWindow *parent); + +private: + QWaylandWindow *m_window; + struct wl_sub_surface *m_sub_surface; +}; + +#endif // QWAYLANDSUBSURFACE_H diff --git a/src/plugins/platforms/wayland/qwaylandwindow.cpp b/src/plugins/platforms/wayland/qwaylandwindow.cpp index 73ed850..9e45831 100644 --- a/src/plugins/platforms/wayland/qwaylandwindow.cpp +++ b/src/plugins/platforms/wayland/qwaylandwindow.cpp @@ -55,18 +55,18 @@ #endif #include "qwaylandextendedsurface.h" +#include "qwaylandsubsurface.h" #include #include -#include - QWaylandWindow::QWaylandWindow(QWindow *window) : QPlatformWindow(window) , mDisplay(QWaylandScreen::waylandScreenFromWindow(window)->display()) , mSurface(mDisplay->createSurface(this)) , mShellSurface(mDisplay->shell()->createShellSurface(this)) , mExtendedWindow(0) + , mSubSurfaceWindow(0) , mBuffer(0) , mWaitingForFrameSync(false) , mFrameCallback(0) @@ -76,14 +76,19 @@ QWaylandWindow::QWaylandWindow(QWindow *window) if (mDisplay->windowExtension()) mExtendedWindow = mDisplay->windowExtension()->getExtendedWindow(this); + if (mDisplay->subSurfaceExtension()) + mSubSurfaceWindow = mDisplay->subSurfaceExtension()->getSubSurfaceAwareWindow(this); #ifdef QT_WAYLAND_WINDOWMANAGER_SUPPORT mDisplay->windowManagerIntegration()->mapClientToProcess(qApp->applicationPid()); mDisplay->windowManagerIntegration()->authenticateWithToken(); #endif - //all surfaces are toplevel surfaces for now - wl_shell_surface_set_toplevel(mShellSurface->handle()); + if (parent() && mSubSurfaceWindow) { + mSubSurfaceWindow->setParent(static_cast(parent())); + } else { + wl_shell_surface_set_toplevel(mShellSurface->handle()); + } } QWaylandWindow::~QWaylandWindow() @@ -106,8 +111,10 @@ WId QWaylandWindow::winId() const void QWaylandWindow::setParent(const QPlatformWindow *parent) { - Q_UNUSED(parent); - qWarning("Sub window is not supported"); + const QWaylandWindow *parentWaylandWindow = static_cast(parent); + if (subSurfaceWindow()) { + subSurfaceWindow()->setParent(parentWaylandWindow); + } } void QWaylandWindow::setVisible(bool visible) @@ -192,3 +199,8 @@ QWaylandExtendedSurface *QWaylandWindow::extendedWindow() const { return mExtendedWindow; } + +QWaylandSubSurface *QWaylandWindow::subSurfaceWindow() const +{ + return mSubSurfaceWindow; +} diff --git a/src/plugins/platforms/wayland/qwaylandwindow.h b/src/plugins/platforms/wayland/qwaylandwindow.h index fb4ac74..282454b 100644 --- a/src/plugins/platforms/wayland/qwaylandwindow.h +++ b/src/plugins/platforms/wayland/qwaylandwindow.h @@ -51,6 +51,8 @@ class QWaylandDisplay; class QWaylandBuffer; class QWaylandShellSurface; class QWaylandExtendedSurface; +class QWaylandSubSurface; + struct wl_egl_window; class QWaylandWindow : public QPlatformWindow @@ -81,12 +83,14 @@ public: QWaylandShellSurface *shellSurface() const; QWaylandExtendedSurface *extendedWindow() const; + QWaylandSubSurface *subSurfaceWindow() const; protected: QWaylandDisplay *mDisplay; struct wl_surface *mSurface; QWaylandShellSurface *mShellSurface; QWaylandExtendedSurface *mExtendedWindow; + QWaylandSubSurface *mSubSurfaceWindow; QWaylandBuffer *mBuffer; WId mWindowId; diff --git a/src/plugins/platforms/wayland/wayland.pro b/src/plugins/platforms/wayland/wayland.pro index aeef608..51ad95a 100644 --- a/src/plugins/platforms/wayland/wayland.pro +++ b/src/plugins/platforms/wayland/wayland.pro @@ -17,6 +17,7 @@ QT += core-private gui-private platformsupport-private WAYLANDSOURCES += \ $$PWD/../../../../extensions/surface-extension.xml \ + $$PWD/../../../../extensions/sub-surface-extension.xml \ $$PWD/../../../../extensions/output-extension.xml SOURCES = main.cpp \ @@ -37,7 +38,8 @@ SOURCES = main.cpp \ qwaylandshell.cpp \ qwaylandshellsurface.cpp \ qwaylandextendedoutput.cpp \ - qwaylandextendedsurface.cpp + qwaylandextendedsurface.cpp \ + qwaylandsubsurface.cpp HEADERS = qwaylandintegration.h \ qwaylandnativeinterface.h \ @@ -56,7 +58,8 @@ HEADERS = qwaylandintegration.h \ qwaylandshell.h \ qwaylandshellsurface.h \ qwaylandextendedoutput.h \ - qwaylandextendedsurface.h + qwaylandextendedsurface.h \ + qwaylandsubsurface.h INCLUDEPATH += $$QMAKE_INCDIR_WAYLAND LIBS += $$QMAKE_LIBS_WAYLAND -- 2.7.4