diff options
39 files changed, 1356 insertions, 349 deletions
diff --git a/examples/qml-compositor/main.cpp b/examples/qml-compositor/main.cpp index fc6a4618e..466533b52 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<WaylandSurface *>(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<QQuickItem *>(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<QQuickItem *>(item))); - m_windowMap[surface] = item; - - item->takeFocus(); - } + WaylandSurfaceItem *item = surface->surfaceItem(); + item->takeFocus(); + emit windowAdded(QVariant::fromValue(static_cast<QQuickItem *>(item))); + } + void surfaceUnmapped() { + WaylandSurface *surface = qobject_cast<WaylandSurface *>(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<QQuickItem *>(item))); + WaylandSurface *surface = static_cast<WaylandSurface *>(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<QObject *, WaylandSurfaceItem *> 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 88c4ca021..1414cef3d 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 b074735b0..a95eda67f 100644 --- a/examples/qwidget-compositor/main.cpp +++ b/examples/qwidget-compositor/main.cpp @@ -47,32 +47,17 @@ #include <QTimer> #include <QPainter> #include <QMouseEvent> +#include <QtCore/QLinkedList> #ifdef QT_COMPOSITOR_WAYLAND_GL #include <QOpenGLContext> #include <QGLWidget> +#include <QtGui/private/qopengltexturecache_p.h> +#include "textureblitter.h" #endif #include <QDebug> -//#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<QWindowSystemInterface::TouchPoint> &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<WaylandSurface *> 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<WaylandSurface *> 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<WaylandSurface *> 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<QWindowSystemInterface::TouchPoint> &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 56379891e..b681fb88b 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 000000000..8fefe48f6 --- /dev/null +++ b/examples/qwidget-compositor/textureblitter.cpp @@ -0,0 +1,118 @@ +#include "textureblitter.h" + +#include <QtGui/QOpenGLShaderProgram> +#include <QtGui/QOpenGLContext> +#include <QtGui/QOpenGLFunctions> + +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 000000000..35d5cffc0 --- /dev/null +++ b/examples/qwidget-compositor/textureblitter.h @@ -0,0 +1,28 @@ +#ifndef TEXTUREBLITTER_H +#define TEXTUREBLITTER_H + +#include <QtGui/QMatrix4x4> + +#include <QtGui/qopengl.h> + +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 b3e7ffbc2..3bae92dd6 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 59e181a21..d194a4832 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<WaylandSurface *> 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 247260406..558451eb9 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 <QtGui/private/qopengltexturecache_p.h> + #include <QObject> 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<WaylandSurface *> 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 31f31419d..000000000 --- a/examples/qwindow-compositor/surfacerenderer.cpp +++ /dev/null @@ -1,146 +0,0 @@ -#include "surfacerenderer.h" - -#include <QOpenGLFunctions> -#include <QImage> - -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 abfb554b0..000000000 --- a/examples/qwindow-compositor/surfacerenderer.h +++ /dev/null @@ -1,29 +0,0 @@ -#ifndef SURFACERENDERER_H -#define SURFACERENDERER_H - -#include <QOpenGLContext> -#include <QOpenGLShaderProgram> -#include <QWindow> - -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 000000000..8fefe48f6 --- /dev/null +++ b/examples/qwindow-compositor/textureblitter.cpp @@ -0,0 +1,118 @@ +#include "textureblitter.h" + +#include <QtGui/QOpenGLShaderProgram> +#include <QtGui/QOpenGLContext> +#include <QtGui/QOpenGLFunctions> + +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 000000000..13b2c6af8 --- /dev/null +++ b/examples/qwindow-compositor/textureblitter.h @@ -0,0 +1,26 @@ +#ifndef TEXTUREBLITTER_H +#define TEXTUREBLITTER_H + +#include <QtGui/QMatrix4x4> + +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 000000000..6f9ca07d9 --- /dev/null +++ b/extensions/sub-surface-extension.xml @@ -0,0 +1,80 @@ +<!-- +# /**************************************************************************** +# ** +# ** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +# ** Contact: Nokia Corporation (qt-info@nokia.com) +# ** +# ** This file is part of qt-compositor. +# ** +# ****************************************************************************/ +--> +<protocol name="sub_surface_extension"> + + <copyright> + 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$ + </copyright> + + <interface name="wl_sub_surface_extension" version="1"> + <request name="get_sub_surface_aware_surface"> + <arg name="id" type="new_id" interface="wl_sub_surface"/> + <arg name="surface" type="object" interface="wl_surface"/> + </request> + </interface> + + <interface name="wl_sub_surface" version="1"> + <request name="attach_sub_surface"> + <arg name="sub_surface" type="object" interface="wl_sub_surface"/> + <arg name="x" type="int"/> + <arg name="y" type="int"/> + </request> + + <request name="move_sub_surface"> + <arg name="sub_surface" type="object" interface="wl_sub_surface"/> + <arg name="x" type="int"/> + <arg name="y" type="int"/> + </request> + + <request name="raise"> + <arg name="sub_surface" type="object" interface="wl_sub_surface"/> + </request> + + <request name="lower"> + <arg name="sub_surface" type="object" interface="wl_sub_surface"/> + </request> + </interface> +</protocol> diff --git a/extensions/surface-extension.xml b/extensions/surface-extension.xml index db150aee4..51850f8bf 100644 --- a/extensions/surface-extension.xml +++ b/extensions/surface-extension.xml @@ -66,7 +66,6 @@ <arg name="value" type="array"/> </event> - <!-- update generic property from client to server --> <request name="update_generic_property"> <arg name="name" type="string"/> <arg name="value" type="array"/> diff --git a/src/compositor/compositor_api/waylandcompositor.cpp b/src/compositor/compositor_api/waylandcompositor.cpp index 3f84f7c84..73ddf236f 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 a38c3df47..b38458577 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 003a6d451..60d2684ea 100644 --- a/src/compositor/compositor_api/waylandsurface.cpp +++ b/src/compositor/compositor_api/waylandsurface.cpp @@ -3,16 +3,35 @@ #include <private/qobject_p.h> #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 *> WaylandSurface::subSurfaces() const +{ + Q_D(const WaylandSurface); + if (d->surface->subSurface()) { + return d->surface->subSurface()->subSurfaces(); + } + return QLinkedList<WaylandSurface *>(); +} + 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 45c308a6b..89befeafc 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<WaylandSurface *> 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 67d478432..4d3687ceb 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 <QtGui/QKeyEvent> #include <QtQuick/QSGSimpleTextureNode> @@ -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<QSGSimpleTextureNode *>(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<QSGSimpleTextureNode *>(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 a66a2cead..e08cda3ba 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 cf841f914..6340f5c3f 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 abfcac63f..b998c9120 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 <QWindow> #include <QSocketNotifier> @@ -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 4404ff81e..a26e23aab 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 85bdd8e33..68f6d0573 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 d32289615..46dc03c18 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 <QtCore/QVariant> +#include <QtCore/QLinkedList> + +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<WaylandSurface *> 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 000000000..e8b8ab6e3 --- /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 *>(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<WaylandSurface *> 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<SubSurface *>(sub_surface_parent_resource->data); + SubSurface *child_sub_surface = static_cast<SubSurface *>(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<SubSurface *>(sub_surface_parent_resource->data); + SubSurface *child_sub_surface = static_cast<SubSurface *>(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 000000000..947cd02ca --- /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 <QtCore/QLinkedList> + +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<WaylandSurface *> subSurfaces() const; + + Surface *surface() const; + WaylandSurface *waylandSurface() const; + +private: + struct wl_resource *m_sub_surface_resource; + Surface *m_surface; + + SubSurface *m_parent; + QLinkedList<WaylandSurface *> 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 21f2d3167..30b0bd09c 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 <QtCore/QDebug> @@ -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<Surface *>(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 425e3ce88..905ee535e 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<SurfacePrivate> d_ptr; diff --git a/src/plugins/platforms/wayland/qwaylanddisplay.cpp b/src/plugins/platforms/wayland/qwaylanddisplay.cpp index 0d6287722..3f160b794 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 <QtCore/QAbstractEventDispatcher> #include <QtGui/private/qguiapplication_p.h> @@ -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 cce0486c9..416379921 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 10d17b9bf..c17df8492 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 42e0416e0..da9031b5d 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<QWaylandShmWindow *>(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 000000000..13d8c99b6 --- /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<struct wl_sub_surface_extension *>( + 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 000000000..5c8b2b254 --- /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 <wayland-client.h> + +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 73ed85096..9e45831b2 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 <QCoreApplication> #include <QtGui/QWindowSystemInterface> -#include <QDebug> - 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<const QWaylandWindow *>(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<const QWaylandWindow *>(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 fb4ac7484..282454baf 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 aeef60839..51ad95a9f 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 |