diff options
author | Giulio Camuffo <giulio.camuffo@jollamobile.com> | 2014-03-25 14:19:55 +0200 |
---|---|---|
committer | The Qt Project <gerrit-noreply@qt-project.org> | 2014-04-29 10:09:31 +0200 |
commit | fc439e40e37f9c0b3108225f951fb19bb3abee80 (patch) | |
tree | 851bf52ee2004b3b201b5e86df7a4d4db7f79a2c | |
parent | c551e6df6c77f65a0db62b3ad4db539e86b75a30 (diff) |
Rework the way buffers are used and rendered
The current way buffers are handled is sub-optimal. They are hidden
inside QtWayland::Surface and the actual renderer, be it QtQuick or
anything else, cannot get a direct hold of them, nor it can directly
control when the underlying textures are created or deleted.
The main additions in this commit are the splitting of the QtQuick
code path and the new QWaylandBufferRef and QWaylandBufferAttacher
classes.
QWaylandBufferRef allows a renderer to retain a reference
to a wl_buffer even after the underlying Surface discarded it.
That allows the renderer to directly decide when to destroy the texture
of the buffer.
QWaylandBufferAttacher is a pure virtual class which must be implemented
by the renderer. Instances of it will be assigned to the QWaylandSurfaces,
created. Its attach() virtual method will then be called when a new buffer
is committed to the surface. The renderer can then choose to immediately
create a texture or wait for some later time. It is its responsibility to
create and destroy the GL texture, it will not happen automatically.
This functionality is implemented for QtQuick in the new QWaylandQuickCompositor
and QWaylandQuickSurface classes.
Change-Id: I674b4e5fb8c65c3b1c582e33ff3a0b0e45f2acc9
Reviewed-by: Gunnar Sletta <gunnar.sletta@jollamobile.com>
38 files changed, 1474 insertions, 655 deletions
diff --git a/examples/qml-compositor/WindowContainer.qml b/examples/qml-compositor/WindowContainer.qml index 701b46d24..77dd1d4dc 100644 --- a/examples/qml-compositor/WindowContainer.qml +++ b/examples/qml-compositor/WindowContainer.qml @@ -40,6 +40,7 @@ import QtQuick 2.0 import QtQuick.Window 2.0 +import QtCompositor 1.0 Item { id: container @@ -52,10 +53,20 @@ Item { visible: isFullscreen || !root.hasFullscreenWindow onVisibleChanged: { - child.clientRenderingEnabled = visible + child.surface.clientRenderingEnabled = visible console.log("visibility changed: " + visible); } + WaylandSurfaceItem { + id: surfaceItem + anchors.fill: parent + touchEventsEnabled: true + + onSurfaceDestroyed: { + destroyAnimation.start(); + } + } + opacity: 0 property real targetX @@ -64,7 +75,7 @@ Item { property real targetHeight property real targetScale - property variant child: null + property variant child: surfaceItem property variant chrome: null property bool animationsEnabled: false property bool isFullscreen: state === "fullscreen" @@ -168,11 +179,17 @@ Item { NumberAnimation { target: scaleTransform; property: "yScale"; easing.type: Easing.Linear; to: 0.01; duration: 200; } NumberAnimation { target: scaleTransform; property: "xScale"; easing.type: Easing.Linear; to: 0.01; duration: 150; } NumberAnimation { target: container; property: "opacity"; easing.type: Easing.Linear; to: 0.0; duration: 150; } - ScriptAction { script: container.parent.removeWindow(child); } + ScriptAction { script: container.parent.removeWindow(container) } + } + SequentialAnimation { + id: unmapAnimation + NumberAnimation { target: container; property: "opacity"; easing.type: Easing.Linear; to: 0.0; duration: 150; } + ScriptAction { script: container.parent.removeWindow(container) } } - function runDestroyAnimation() { - destroyAnimation.start(); + Connections { + target: container.child.surface + onUnmapped: unmapAnimation.start() } Image { diff --git a/examples/qml-compositor/main.cpp b/examples/qml-compositor/main.cpp index 93b23c0e3..7ebcb6c29 100644 --- a/examples/qml-compositor/main.cpp +++ b/examples/qml-compositor/main.cpp @@ -38,9 +38,8 @@ ** ****************************************************************************/ -#include "qwaylandcompositor.h" -#include "qwaylandsurface.h" -#include "qwaylandsurfaceitem.h" +#include "qwaylandquickcompositor.h" +#include "qwaylandquicksurface.h" #include <QGuiApplication> #include <QTimer> @@ -52,14 +51,14 @@ #include <QQuickItem> #include <QQuickView> -class QmlCompositor : public QQuickView, public QWaylandCompositor +class QmlCompositor : public QQuickView, public QWaylandQuickCompositor { Q_OBJECT - Q_PROPERTY(QWaylandSurface* fullscreenSurface READ fullscreenSurface WRITE setFullscreenSurface NOTIFY fullscreenSurfaceChanged) + Q_PROPERTY(QWaylandQuickSurface* fullscreenSurface READ fullscreenSurface WRITE setFullscreenSurface NOTIFY fullscreenSurfaceChanged) public: QmlCompositor() - : QWaylandCompositor(this, 0, DefaultExtensions | SubSurfaceExtension) + : QWaylandQuickCompositor(this, 0, DefaultExtensions | SubSurfaceExtension) , m_fullscreenSurface(0) { setSource(QUrl("main.qml")); @@ -67,11 +66,10 @@ public: setColor(Qt::black); winId(); - connect(this, SIGNAL(beforeSynchronizing()), this, SLOT(startFrame()), Qt::DirectConnection); connect(this, SIGNAL(afterRendering()), this, SLOT(sendCallbacks())); } - QWaylandSurface *fullscreenSurface() const + QWaylandQuickSurface *fullscreenSurface() const { return m_fullscreenSurface; } @@ -87,12 +85,7 @@ public slots: qvariant_cast<QObject *>(window)->deleteLater(); } - void destroyClientForWindow(QVariant window) { - QWaylandSurface *surface = qobject_cast<QWaylandSurfaceItem *>(qvariant_cast<QObject *>(window))->surface(); - destroyClientForSurface(surface); - } - - void setFullscreenSurface(QWaylandSurface *surface) { + void setFullscreenSurface(QWaylandQuickSurface *surface) { if (surface == m_fullscreenSurface) return; m_fullscreenSurface = surface; @@ -101,34 +94,25 @@ public slots: private slots: void surfaceMapped() { - QWaylandSurface *surface = qobject_cast<QWaylandSurface *>(sender()); + QWaylandQuickSurface *surface = qobject_cast<QWaylandQuickSurface *>(sender()); //Ignore surface if it's not a window surface if (!surface->hasShellSurface()) return; - QWaylandSurfaceItem *item = surface->surfaceItem(); - //Create a WaylandSurfaceItem if we have not yet - if (!item) - item = new QWaylandSurfaceItem(surface, rootObject()); - - item->setTouchEventsEnabled(true); - //item->takeFocus(); - emit windowAdded(QVariant::fromValue(static_cast<QQuickItem *>(item))); + emit windowAdded(QVariant::fromValue(surface)); } void surfaceUnmapped() { - QWaylandSurface *surface = qobject_cast<QWaylandSurface *>(sender()); + QWaylandQuickSurface *surface = qobject_cast<QWaylandQuickSurface *>(sender()); if (surface == m_fullscreenSurface) m_fullscreenSurface = 0; - QQuickItem *item = surface->surfaceItem(); - emit windowDestroyed(QVariant::fromValue(item)); + emit windowDestroyed(QVariant::fromValue(surface)); } void surfaceDestroyed(QObject *object) { - QWaylandSurface *surface = static_cast<QWaylandSurface *>(object); + QWaylandQuickSurface *surface = static_cast<QWaylandQuickSurface *>(object); if (surface == m_fullscreenSurface) m_fullscreenSurface = 0; - QQuickItem *item = surface->surfaceItem(); - emit windowDestroyed(QVariant::fromValue(item)); + emit windowDestroyed(QVariant::fromValue(surface)); } void sendCallbacks() { @@ -137,9 +121,6 @@ private slots: else sendFrameCallbacks(surfaces()); } - void startFrame() { - frameStarted(); - } protected: void resizeEvent(QResizeEvent *event) @@ -155,7 +136,7 @@ protected: } private: - QWaylandSurface *m_fullscreenSurface; + QWaylandQuickSurface *m_fullscreenSurface; }; int main(int argc, char *argv[]) @@ -170,7 +151,6 @@ int main(int argc, char *argv[]) compositor.rootContext()->setContextProperty("compositor", &compositor); QObject::connect(&compositor, SIGNAL(windowAdded(QVariant)), compositor.rootObject(), SLOT(windowAdded(QVariant))); - QObject::connect(&compositor, SIGNAL(windowDestroyed(QVariant)), compositor.rootObject(), SLOT(windowDestroyed(QVariant))); QObject::connect(&compositor, SIGNAL(windowResized(QVariant)), compositor.rootObject(), SLOT(windowResized(QVariant))); return app.exec(); diff --git a/examples/qml-compositor/main.qml b/examples/qml-compositor/main.qml index 7b152280e..120c92bdb 100644 --- a/examples/qml-compositor/main.qml +++ b/examples/qml-compositor/main.qml @@ -39,6 +39,7 @@ ****************************************************************************/ import QtQuick 2.0 +import QtCompositor 1.0 import "compositor.js" as CompositorLogic Item { @@ -84,15 +85,15 @@ Item { function windowAdded(window) { var windowContainerComponent = Qt.createComponent("WindowContainer.qml"); var windowContainer = windowContainerComponent.createObject(root); + console.log(windowContainerComponent.errorString()); - window.parent = windowContainer; + windowContainer.child.surface = window; - windowContainer.targetWidth = window.width; - windowContainer.targetHeight = window.height; - windowContainer.child = window; + windowContainer.targetWidth = window.size.width; + windowContainer.targetHeight = window.size.height; var windowChromeComponent = Qt.createComponent("WindowChrome.qml"); - var windowChrome = windowChromeComponent.createObject(window); + var windowChrome = windowChromeComponent.createObject(windowContainer.child); CompositorLogic.addWindow(windowContainer); @@ -102,25 +103,16 @@ Item { } function windowResized(window) { - var windowContainer = window.parent; - windowContainer.width = window.width; - windowContainer.height = window.height; + window.width = window.surface.size.width; + window.height = window.surface.size.height; CompositorLogic.relayout(); } - function windowDestroyed(window) { - var windowContainer = window.parent; - if (windowContainer.runDestroyAnimation) - windowContainer.runDestroyAnimation(); - } - function removeWindow(window) { - var windowContainer = window.parent; - CompositorLogic.removeWindow(windowContainer); - windowContainer.chrome.destroy(); - windowContainer.destroy(); - compositor.destroyWindow(window); + CompositorLogic.removeWindow(window); + window.chrome.destroy(); + window.destroy(); } onHeightChanged: CompositorLogic.relayout(); diff --git a/examples/qwindow-compositor/qwindowcompositor.cpp b/examples/qwindow-compositor/qwindowcompositor.cpp index e0f213aa4..aa6afd7aa 100644 --- a/examples/qwindow-compositor/qwindowcompositor.cpp +++ b/examples/qwindow-compositor/qwindowcompositor.cpp @@ -52,6 +52,55 @@ #include <QPainter> #include <QtCompositor/qwaylandinput.h> +#include <QtCompositor/qwaylandbufferref.h> + +static GLuint textureFromImage(const QImage &image) +{ + GLuint texture = 0; + glGenTextures(1, &texture); + glBindTexture(GL_TEXTURE_2D, texture); + QImage tx = image.convertToFormat(QImage::Format_RGBA8888_Premultiplied); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, tx.width(), tx.height(), 0, GL_RGBA, GL_UNSIGNED_BYTE, tx.constBits()); + glBindTexture(GL_TEXTURE_2D, 0); + return texture; +} + +class BufferAttacher : public QWaylandBufferAttacher +{ +public: + void attach(const QWaylandBufferRef &ref) Q_DECL_OVERRIDE + { + if (bufferRef) { + if (ownTexture) + glDeleteTextures(1, &texture); + else + bufferRef.destroyTexture(); + } + + bufferRef = ref; + + if (bufferRef) { + if (bufferRef.isShm()) { + texture = textureFromImage(bufferRef.image()); + ownTexture = true; + } else { + texture = bufferRef.createTexture(); + ownTexture = false; + } + } + } + + QImage image() const + { + if (!bufferRef || !bufferRef.isShm()) + return QImage(); + return bufferRef.image(); + } + + QWaylandBufferRef bufferRef; + GLuint texture; + bool ownTexture; +}; QWindowCompositor::QWindowCompositor(QOpenGLWindow *window) : QWaylandCompositor(window, 0, DefaultExtensions | SubSurfaceExtension) @@ -118,9 +167,9 @@ void QWindowCompositor::ensureKeyboardFocusSurface(QWaylandSurface *oldSurface) defaultInputDevice()->setKeyboardFocus(m_surfaces.isEmpty() ? 0 : m_surfaces.last()); } -void QWindowCompositor::surfaceDestroyed(QObject *object) +void QWindowCompositor::surfaceDestroyed() { - QWaylandSurface *surface = static_cast<QWaylandSurface *>(object); + QWaylandSurface *surface = static_cast<QWaylandSurface *>(sender()); m_surfaces.removeOne(surface); ensureKeyboardFocusSurface(surface); m_renderScheduler.start(0); @@ -157,6 +206,7 @@ void QWindowCompositor::surfaceUnmapped() m_surfaces.insert(0, surface); ensureKeyboardFocusSurface(surface); + m_renderScheduler.start(0); } void QWindowCompositor::surfaceCommitted() @@ -178,13 +228,15 @@ void QWindowCompositor::surfaceCommitted(QWaylandSurface *surface) void QWindowCompositor::surfaceCreated(QWaylandSurface *surface) { - connect(surface, SIGNAL(destroyed(QObject *)), this, SLOT(surfaceDestroyed(QObject *))); + connect(surface, SIGNAL(surfaceDestroyed()), this, SLOT(surfaceDestroyed())); connect(surface, SIGNAL(mapped()), this, SLOT(surfaceMapped())); connect(surface, SIGNAL(unmapped()), this, SLOT(surfaceUnmapped())); - connect(surface, SIGNAL(committed()), this, SLOT(surfaceCommitted())); + connect(surface, SIGNAL(redraw()), this, SLOT(surfaceCommitted())); connect(surface, SIGNAL(extendedSurfaceReady()), this, SLOT(sendExpose())); connect(surface, SIGNAL(posChanged()), this, SLOT(surfacePosChanged())); m_renderScheduler.start(0); + + surface->setBufferAttacher(new BufferAttacher); } void QWindowCompositor::sendExpose() @@ -197,7 +249,10 @@ void QWindowCompositor::updateCursor() { if (!m_cursorSurface) return; - QCursor cursor(QPixmap::fromImage(m_cursorSurface->image()), m_cursorHotspotX, m_cursorHotspotY); + + QImage image = static_cast<BufferAttacher *>(m_cursorSurface->bufferAttacher())->image(); + + QCursor cursor(QPixmap::fromImage(image), m_cursorHotspotX, m_cursorHotspotY); static bool cursorIsSet = false; if (cursorIsSet) { QGuiApplication::changeOverrideCursor(cursor); @@ -215,11 +270,13 @@ QPointF QWindowCompositor::toSurface(QWaylandSurface *surface, const QPointF &po void QWindowCompositor::setCursorSurface(QWaylandSurface *surface, int hotspotX, int hotspotY) { if ((m_cursorSurface != surface) && surface) - connect(surface, SIGNAL(damaged(QRect)), this, SLOT(updateCursor())); + connect(surface, SIGNAL(configure()), this, SLOT(updateCursor())); m_cursorSurface = surface; m_cursorHotspotX = hotspotX; m_cursorHotspotY = hotspotY; + if (!m_cursorSurface->bufferAttacher()) + m_cursorSurface->setBufferAttacher(new BufferAttacher); } QWaylandSurface *QWindowCompositor::surfaceAt(const QPointF &point, QPointF *local) @@ -236,34 +293,14 @@ QWaylandSurface *QWindowCompositor::surfaceAt(const QPointF &point, QPointF *loc return 0; } -static GLuint textureFromImage(const QImage &image) -{ - GLuint texture = 0; - glGenTextures(1, &texture); - glBindTexture(GL_TEXTURE_2D, texture); - QImage tx = image.convertToFormat(QImage::Format_RGBA8888_Premultiplied); - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, tx.width(), tx.height(), 0, GL_RGBA, GL_UNSIGNED_BYTE, tx.constBits()); - glBindTexture(GL_TEXTURE_2D, 0); - return texture; -} - -GLuint QWindowCompositor::composeSurface(QWaylandSurface *surface, bool *textureOwned) +GLuint QWindowCompositor::composeSurface(QWaylandSurface *surface) { - GLuint texture = 0; - QSize windowSize = surface->size(); - surface->swapBuffers(); QOpenGLFunctions *functions = QOpenGLContext::currentContext()->functions(); functions->glBindFramebuffer(GL_FRAMEBUFFER, m_surface_fbo); - if (surface->type() == QWaylandSurface::Shm) { - texture = textureFromImage(surface->image()); - *textureOwned = true; - } else if (surface->type() == QWaylandSurface::Texture) { - texture = surface->texture(); - *textureOwned = false; - } + GLuint texture = static_cast<BufferAttacher *>(surface->bufferAttacher())->texture; functions->glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture, 0); @@ -287,19 +324,11 @@ void QWindowCompositor::paintChildren(QWaylandSurface *surface, QWaylandSurface QWaylandSurface *subSurface = i.next(); QPointF p = subSurface->mapTo(window,QPointF(0,0)); QSize subSize = subSurface->size(); - subSurface->swapBuffers(); if (subSize.isValid()) { - GLuint texture = 0; - if (subSurface->type() == QWaylandSurface::Texture) { - texture = subSurface->texture(); - } else if (surface->type() == QWaylandSurface::Shm) { - texture = textureFromImage(subSurface->image()); - } + GLuint texture = static_cast<BufferAttacher *>(subSurface->bufferAttacher())->texture; QRect geo(p.toPoint(),subSize); if (texture > 0) m_textureBlitter->drawTexture(texture,geo,windowSize,0,window->isYInverted(),subSurface->isYInverted()); - if (surface->type() == QWaylandSurface::Shm) - glDeleteTextures(1, &texture); } paintChildren(subSurface,window,windowSize); } @@ -326,12 +355,9 @@ void QWindowCompositor::render() foreach (QWaylandSurface *surface, m_surfaces) { if (!surface->visible()) continue; - bool ownsTexture; - GLuint texture = composeSurface(surface, &ownsTexture); + GLuint texture = composeSurface(surface); QRect geo(surface->pos().toPoint(),surface->size()); m_textureBlitter->drawTexture(texture,geo,m_window->size(),0,false,surface->isYInverted()); - if (ownsTexture) - glDeleteTextures(1, &texture); } m_textureBlitter->release(); diff --git a/examples/qwindow-compositor/qwindowcompositor.h b/examples/qwindow-compositor/qwindowcompositor.h index e26a09ebc..3ecbdbc1a 100644 --- a/examples/qwindow-compositor/qwindowcompositor.h +++ b/examples/qwindow-compositor/qwindowcompositor.h @@ -58,7 +58,7 @@ public: ~QWindowCompositor(); private slots: - void surfaceDestroyed(QObject *object); + void surfaceDestroyed(); void surfaceMapped(); void surfaceUnmapped(); void surfaceCommitted(); @@ -71,7 +71,7 @@ protected: QWaylandSurface* surfaceAt(const QPointF &point, QPointF *local = 0); - GLuint composeSurface(QWaylandSurface *surface, bool *textureOwned); + GLuint composeSurface(QWaylandSurface *surface); void paintChildren(QWaylandSurface *surface, QWaylandSurface *window, const QSize &windowSize); diff --git a/examples/server-buffer/compositor/main.cpp b/examples/server-buffer/compositor/main.cpp index ff375a8c6..a30ea0895 100644 --- a/examples/server-buffer/compositor/main.cpp +++ b/examples/server-buffer/compositor/main.cpp @@ -38,9 +38,8 @@ ** ****************************************************************************/ -#include "qwaylandcompositor.h" +#include "qwaylandquickcompositor.h" #include "qwaylandsurface.h" -#include "qwaylandsurfaceitem.h" #include <QGuiApplication> #include <QTimer> @@ -63,14 +62,14 @@ class QmlCompositor : public QQuickView - , public QWaylandCompositor + , public QWaylandQuickCompositor , public QtWaylandServer::qt_share_buffer { Q_OBJECT public: QmlCompositor() - : QWaylandCompositor(this, 0, DefaultExtensions | SubSurfaceExtension) + : QWaylandQuickCompositor(this, 0, DefaultExtensions | SubSurfaceExtension) , QtWaylandServer::qt_share_buffer(QWaylandCompositor::handle()->wl_display()) , m_server_buffer_32_bit(0) , m_server_buffer_item_32_bit(0) @@ -83,7 +82,6 @@ public: create(); grabWindow(); - connect(this, SIGNAL(beforeSynchronizing()), this, SLOT(startFrame()), Qt::DirectConnection); connect(this, SIGNAL(afterRendering()), this, SLOT(sendCallbacks())); connect(this, SIGNAL(sceneGraphInitialized()), this, SLOT(initiateServerBuffer()),Qt::DirectConnection); @@ -98,38 +96,26 @@ signals: void serverBuffersCreated(); public slots: - void destroyWindow(QVariant window) - { - qvariant_cast<QObject *>(window)->deleteLater(); - } - void destroyClientForWindow(QVariant window) { - QWaylandSurface *surface = qobject_cast<QWaylandSurfaceItem *>(qvariant_cast<QObject *>(window))->surface(); + QWaylandSurface *surface = qobject_cast<QWaylandSurface *>(qvariant_cast<QObject *>(window)); destroyClientForSurface(surface); } private slots: void surfaceMapped() { QWaylandSurface *surface = qobject_cast<QWaylandSurface *>(sender()); - QQuickItem *item = surface->surfaceItem(); - emit windowAdded(QVariant::fromValue(static_cast<QQuickItem *>(item))); + emit windowAdded(QVariant::fromValue(surface)); } void surfaceUnmapped() { QWaylandSurface *surface = qobject_cast<QWaylandSurface *>(sender()); - QQuickItem *item = surface->surfaceItem(); - emit windowDestroyed(QVariant::fromValue(item)); + emit windowDestroyed(QVariant::fromValue(surface)); } void surfaceDestroyed(QObject *object) { QWaylandSurface *surface = static_cast<QWaylandSurface *>(object); - QQuickItem *item = surface->surfaceItem(); - emit windowDestroyed(QVariant::fromValue(item)); - } - - void startFrame() { - frameStarted(); + emit windowDestroyed(QVariant::fromValue(surface)); } void sendCallbacks() { @@ -219,11 +205,6 @@ protected: } void surfaceCreated(QWaylandSurface *surface) { - QWaylandSurfaceItem *item = new QWaylandSurfaceItem(surface, rootObject()); - item->setUseTextureAlpha(true); - 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())); } @@ -270,7 +251,6 @@ int main(int argc, char *argv[]) compositor.rootContext()->setContextProperty("compositor", &compositor); QObject::connect(&compositor, SIGNAL(windowAdded(QVariant)), compositor.rootObject(), SLOT(windowAdded(QVariant))); - QObject::connect(&compositor, SIGNAL(windowDestroyed(QVariant)), compositor.rootObject(), SLOT(windowDestroyed(QVariant))); QObject::connect(&compositor, SIGNAL(windowResized(QVariant)), compositor.rootObject(), SLOT(windowResized(QVariant))); QObject::connect(&compositor, SIGNAL(serverBufferItemCreated(QVariant)), compositor.rootObject(), SLOT(serverBufferItemCreated(QVariant))); diff --git a/examples/server-buffer/compositor/qml/main.qml b/examples/server-buffer/compositor/qml/main.qml index 231fb5169..1beddbf1d 100644 --- a/examples/server-buffer/compositor/qml/main.qml +++ b/examples/server-buffer/compositor/qml/main.qml @@ -39,6 +39,7 @@ ****************************************************************************/ import QtQuick 2.0 +import QtCompositor 1.0 Item { id: root @@ -58,15 +59,21 @@ Item { anchors.fill: parent } - function windowAdded(window) { - window.parent = root; + Component { + id: windowItem + WaylandSurfaceItem { + onSurfaceDestroyed: { + destroy(); + } + } } - function windowResized(window) { + function windowAdded(window) { + var item = windowItem.createObject(root); + item.surface = window; } - function windowDestroyed(window) { - compositor.destroyWindow(window); + function windowResized(window) { } function removeWindow(window) { diff --git a/src/compositor/compositor_api/compositor_api.pri b/src/compositor/compositor_api/compositor_api.pri index 87d28003c..8e7fd3ace 100644 --- a/src/compositor/compositor_api/compositor_api.pri +++ b/src/compositor/compositor_api/compositor_api.pri @@ -2,29 +2,34 @@ INCLUDEPATH += compositor_api HEADERS += \ compositor_api/qwaylandcompositor.h \ + compositor_api/qwaylandcompositor_p.h \ compositor_api/qwaylandsurface.h \ + compositor_api/qwaylandsurface_p.h \ compositor_api/qwaylandinput.h \ compositor_api/qwaylandinputpanel.h \ - compositor_api/qwaylanddrag.h + compositor_api/qwaylanddrag.h \ + compositor_api/qwaylandbufferref.h SOURCES += \ compositor_api/qwaylandcompositor.cpp \ compositor_api/qwaylandsurface.cpp \ compositor_api/qwaylandinput.cpp \ compositor_api/qwaylandinputpanel.cpp \ - compositor_api/qwaylanddrag.cpp + compositor_api/qwaylanddrag.cpp \ + compositor_api/qwaylandbufferref.cpp QT += core-private qtHaveModule(quick) { SOURCES += \ + compositor_api/qwaylandquickcompositor.cpp \ + compositor_api/qwaylandquicksurface.cpp \ compositor_api/qwaylandsurfaceitem.cpp HEADERS += \ + compositor_api/qwaylandquickcompositor.h \ + compositor_api/qwaylandquicksurface.h \ compositor_api/qwaylandsurfaceitem.h - DEFINES += QT_COMPOSITOR_QUICK - QT += qml quick - QT += quick-private gui-private } diff --git a/src/compositor/compositor_api/qwaylandbufferref.cpp b/src/compositor/compositor_api/qwaylandbufferref.cpp new file mode 100644 index 000000000..67554c7cb --- /dev/null +++ b/src/compositor/compositor_api/qwaylandbufferref.cpp @@ -0,0 +1,131 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Jolla Ltd, author: <giulio.camuffo@jollamobile.com> +** Contact: http://www.qt-project.org/legal +** +** This file is part of the plugins of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, 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, Digia gives you certain additional +** rights. These rights are described in the Digia 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. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include <QDebug> +#include <QAtomicInt> + +#include "qwaylandbufferref.h" +#include "wayland_wrapper/qwlsurfacebuffer_p.h" + +QT_BEGIN_NAMESPACE + +class QWaylandBufferRefPrivate +{ +public: + QtWayland::SurfaceBuffer *buffer; +}; + +QWaylandBufferRef::QWaylandBufferRef() + : d(new QWaylandBufferRefPrivate) +{ + d->buffer = 0; +} + +QWaylandBufferRef::QWaylandBufferRef(QtWayland::SurfaceBuffer *buffer) + : d(new QWaylandBufferRefPrivate) +{ + d->buffer = buffer; + if (buffer) + buffer->m_refCount.ref(); +} + +QWaylandBufferRef::QWaylandBufferRef(const QWaylandBufferRef &ref) + : d(new QWaylandBufferRefPrivate) +{ + d->buffer = 0; + *this = ref; +} + +QWaylandBufferRef::~QWaylandBufferRef() +{ + if (d->buffer && !d->buffer->m_refCount.deref()) + d->buffer->disown(); + delete d; +} + +QWaylandBufferRef &QWaylandBufferRef::operator=(const QWaylandBufferRef &ref) +{ + if (d->buffer && !d->buffer->m_refCount.deref()) + d->buffer->disown(); + + d->buffer = ref.d->buffer; + if (d->buffer) + d->buffer->m_refCount.ref(); + + return *this; +} + +QWaylandBufferRef::operator bool() const +{ + return d->buffer && d->buffer->waylandBufferHandle(); +} + +bool QWaylandBufferRef::isShm() const +{ + return d->buffer->isShmBuffer(); +} + +QImage QWaylandBufferRef::image() const +{ + if (d->buffer->isShmBuffer()) + return d->buffer->image(); + return QImage(); +} + +#ifdef QT_COMPOSITOR_WAYLAND_GL + +GLuint QWaylandBufferRef::createTexture() +{ + if (!d->buffer->isShmBuffer() && !d->buffer->textureCreated()) { + d->buffer->createTexture(); + } + return d->buffer->texture(); +} + +void QWaylandBufferRef::destroyTexture() +{ + if (!d->buffer->isShmBuffer() && d->buffer->textureCreated()) { + d->buffer->destroyTexture(); + } +} +#endif + +QT_END_NAMESPACE diff --git a/src/compositor/compositor_api/qwaylandbufferref.h b/src/compositor/compositor_api/qwaylandbufferref.h new file mode 100644 index 000000000..0d1573bbb --- /dev/null +++ b/src/compositor/compositor_api/qwaylandbufferref.h @@ -0,0 +1,87 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Jolla Ltd, author: <giulio.camuffo@jollamobile.com> +** Contact: http://www.qt-project.org/legal +** +** This file is part of the plugins of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, 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, Digia gives you certain additional +** rights. These rights are described in the Digia 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. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QWAYLANDBUFFERREF_H +#define QWAYLANDBUFFERREF_H + +#ifdef QT_COMPOSITOR_WAYLAND_GL +#include <QtGui/qopengl.h> +#endif + +#include <QtCompositor/qwaylandexport.h> + +QT_BEGIN_NAMESPACE + +namespace QtWayland +{ + class SurfaceBuffer; +} + +class Q_COMPOSITOR_EXPORT QWaylandBufferRef +{ +public: + QWaylandBufferRef(); + explicit QWaylandBufferRef(QtWayland::SurfaceBuffer *buffer); + QWaylandBufferRef(const QWaylandBufferRef &ref); + ~QWaylandBufferRef(); + + QWaylandBufferRef &operator=(const QWaylandBufferRef &ref); + operator bool() const; + bool isShm() const; + + QImage image() const; +#ifdef QT_COMPOSITOR_WAYLAND_GL + /** + * There must be a GL context bound when calling this function. + * It is responsibility of the caller to call destroyTexture() later. + */ + GLuint createTexture(); + void destroyTexture(); +#endif + +private: + class QWaylandBufferRefPrivate *const d; + friend class QWaylandBufferRefPrivate; +}; + +QT_END_NAMESPACE + +#endif diff --git a/src/compositor/compositor_api/qwaylandcompositor.cpp b/src/compositor/compositor_api/qwaylandcompositor.cpp index 342dce510..2135a0e94 100644 --- a/src/compositor/compositor_api/qwaylandcompositor.cpp +++ b/src/compositor/compositor_api/qwaylandcompositor.cpp @@ -55,33 +55,26 @@ #include <QDebug> -#ifdef QT_COMPOSITOR_QUICK -#include "qwaylandsurfaceitem.h" -#endif - QT_BEGIN_NAMESPACE QWaylandCompositor::QWaylandCompositor(QWindow *window, const char *socketName, ExtensionFlags extensions) - : m_compositor(0) + : m_compositor(new QtWayland::Compositor(this, extensions)) , m_toplevel_window(window) - , m_socket_name(socketName) { - QStringList arguments = QCoreApplication::instance()->arguments(); + m_compositor->m_socket_name = socketName; + m_compositor->init(); - int socketArg = arguments.indexOf(QLatin1String("--wayland-socket-name")); - if (socketArg != -1 && socketArg + 1 < arguments.size()) - m_socket_name = arguments.at(socketArg + 1).toLocal8Bit(); - - m_compositor = new QtWayland::Compositor(this, extensions); -#ifdef QT_COMPOSITOR_QUICK - qmlRegisterType<QWaylandSurfaceItem>("WaylandCompositor", 1, 0, "WaylandSurfaceItem"); - qmlRegisterType<QWaylandSurface>("WaylandCompositor", 1, 0, "WaylandSurface"); -#else - qRegisterMetaType<QWaylandSurface*>("WaylandSurface*"); +#if !defined(QT_NO_DEBUG) && !defined(QT_WAYLAND_NO_CLEANUP_WARNING) + qWarning("QWaylandCompositor::cleanupGraphicsResources() must be called manually"); #endif - m_compositor->initializeHardwareIntegration(); - m_compositor->initializeExtensions(); - m_compositor->initializeDefaultInputDevice(); +} + +QWaylandCompositor::QWaylandCompositor(QWindow *window, const char *socketName, QtWayland::Compositor *dptr) + : m_compositor(dptr) + , m_toplevel_window(window) +{ + m_compositor->m_socket_name = socketName; + m_compositor->init(); } QWaylandCompositor::~QWaylandCompositor() @@ -213,9 +206,9 @@ void QWaylandCompositor::setClientFullScreenHint(bool value) const char *QWaylandCompositor::socketName() const { - if (m_socket_name.isEmpty()) + if (m_compositor->m_socket_name.isEmpty()) return 0; - return m_socket_name.constData(); + return m_compositor->m_socket_name.constData(); } /*! diff --git a/src/compositor/compositor_api/qwaylandcompositor.h b/src/compositor/compositor_api/qwaylandcompositor.h index 9009f4caa..85f10b281 100644 --- a/src/compositor/compositor_api/qwaylandcompositor.h +++ b/src/compositor/compositor_api/qwaylandcompositor.h @@ -141,13 +141,14 @@ public: void configureTouchExtension(TouchExtensionFlags flags); protected: + QWaylandCompositor(QWindow *window, const char *socketName, QtWayland::Compositor *dptr); virtual void retainedSelectionReceived(QMimeData *mimeData); -private: friend class QtWayland::Compositor; QtWayland::Compositor *m_compositor; + +private: QWindow *m_toplevel_window; - QByteArray m_socket_name; }; Q_DECLARE_OPERATORS_FOR_FLAGS(QWaylandCompositor::ExtensionFlags) diff --git a/src/compositor/compositor_api/qwaylandquickcompositor.cpp b/src/compositor/compositor_api/qwaylandquickcompositor.cpp new file mode 100644 index 000000000..bc475f1c5 --- /dev/null +++ b/src/compositor/compositor_api/qwaylandquickcompositor.cpp @@ -0,0 +1,102 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Jolla Ltd, author: <giulio.camuffo@jollamobile.com> +** Contact: http://www.qt-project.org/legal +** +** This file is part of the plugins of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, 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, Digia gives you certain additional +** rights. These rights are described in the Digia 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. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include <QQuickWindow> + +#include <QtCompositor/private/qwlcompositor_p.h> + +#include "qwaylandquickcompositor.h" +#include "qwaylandquicksurface.h" +#include "qwaylandsurfaceitem.h" + +QT_BEGIN_NAMESPACE + +class QWaylandQuickCompositorPrivate : public QtWayland::Compositor +{ +public: + QWaylandQuickCompositorPrivate(QWaylandQuickCompositor *compositor, QWaylandCompositor::ExtensionFlags extensions) + : QtWayland::Compositor(compositor, extensions) + , updateScheduled(false) + { + } + + void compositor_create_surface(Resource *resource, uint32_t id) Q_DECL_OVERRIDE + { + QWaylandQuickSurface *surface = new QWaylandQuickSurface(resource->client(), id, static_cast<QWaylandQuickCompositor *>(m_qt_compositor)); + m_surfaces << surface->handle(); + //BUG: This may not be an on-screen window surface though + m_qt_compositor->surfaceCreated(surface); + } + + void updateStarted() + { + updateScheduled = false; + m_qt_compositor->frameStarted(); + m_qt_compositor->cleanupGraphicsResources(); + } + + bool updateScheduled; +}; + + +QWaylandQuickCompositor::QWaylandQuickCompositor(QQuickWindow *window, const char *socketName, ExtensionFlags extensions) + : QWaylandCompositor(window, socketName, new QWaylandQuickCompositorPrivate(this, extensions)) +{ + window->connect(window, &QQuickWindow::beforeSynchronizing, d_ptr(), &QWaylandQuickCompositorPrivate::updateStarted, Qt::DirectConnection); + + qmlRegisterType<QWaylandSurfaceItem>("QtCompositor", 1, 0, "WaylandSurfaceItem"); + qmlRegisterUncreatableType<QWaylandQuickSurface>("QtCompositor", 1, 0, "WaylandQuickSurface", QObject::tr("Cannot create instance of WaylandQuickSurface")); +} + +QWaylandQuickCompositorPrivate *QWaylandQuickCompositor::d_ptr() +{ + return static_cast<QWaylandQuickCompositorPrivate *>(m_compositor); +} + +void QWaylandQuickCompositor::update() +{ + if (!d_ptr()->updateScheduled) { + static_cast<QQuickWindow *>(window())->update(); + d_ptr()->updateScheduled = true; + } +} + +QT_END_NAMESPACE diff --git a/src/compositor/compositor_api/qwaylandquickcompositor.h b/src/compositor/compositor_api/qwaylandquickcompositor.h new file mode 100644 index 000000000..c87585221 --- /dev/null +++ b/src/compositor/compositor_api/qwaylandquickcompositor.h @@ -0,0 +1,64 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Jolla Ltd, author: <giulio.camuffo@jollamobile.com> +** Contact: http://www.qt-project.org/legal +** +** This file is part of the plugins of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, 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, Digia gives you certain additional +** rights. These rights are described in the Digia 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. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QWAYLANDQUICKCOMPOSITOR_H +#define QWAYLANDQUICKCOMPOSITOR_H + +#include <QtCompositor/qwaylandcompositor.h> + +QT_BEGIN_NAMESPACE + +class QQuickWindow; +class QWaylandQuickCompositorPrivate; + +class Q_COMPOSITOR_EXPORT QWaylandQuickCompositor : public QWaylandCompositor +{ +public: + QWaylandQuickCompositor(QQuickWindow *window = 0, const char *socketName = 0, QWaylandCompositor::ExtensionFlags extensions = DefaultExtensions); + + void update(); + +private: + friend class QWaylandQuickCompositorPrivate; + QWaylandQuickCompositorPrivate *d_ptr(); +}; + +#endif diff --git a/src/compositor/compositor_api/qwaylandquicksurface.cpp b/src/compositor/compositor_api/qwaylandquicksurface.cpp new file mode 100644 index 000000000..e4a5f7732 --- /dev/null +++ b/src/compositor/compositor_api/qwaylandquicksurface.cpp @@ -0,0 +1,241 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Jolla Ltd, author: <giulio.camuffo@jollamobile.com> +** Contact: http://www.qt-project.org/legal +** +** This file is part of the plugins of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, 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, Digia gives you certain additional +** rights. These rights are described in the Digia 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. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include <QSGTexture> +#include <QOpenGLTexture> +#include <QQuickWindow> +#include <QDebug> +#include <QQmlPropertyMap> + +#include "qwaylandquicksurface.h" +#include "qwaylandquickcompositor.h" +#include "qwaylandsurfaceitem.h" +#include <QtCompositor/qwaylandbufferref.h> +#include <QtCompositor/private/qwaylandsurface_p.h> + +QT_BEGIN_NAMESPACE + +class BufferAttacher : public QWaylandBufferAttacher +{ +public: + BufferAttacher() + : surface(0) + , texture(0) + , update(false) + { + + } + + ~BufferAttacher() + { + if (texture) + texture->deleteLater(); + bufferRef = QWaylandBufferRef(); + nextBuffer = QWaylandBufferRef(); + } + + void attach(const QWaylandBufferRef &ref) Q_DECL_OVERRIDE + { + nextBuffer = ref; + update = true; + } + + void createTexture() + { + if (bufferRef) + bufferRef.destroyTexture(); + bufferRef = nextBuffer; + + QQuickWindow *window = static_cast<QQuickWindow *>(surface->compositor()->window()); + // If the next buffer is NULL do not delete the current texture. If the client called + // attach(0) the surface is going to be unmapped anyway, if instead the client attached + // a valid buffer but died before we got here we want to keep the old buffer around + // in case some destroy animation is run. + if (bufferRef) { + delete texture; + + if (bufferRef.isShm()) { + texture = window->createTextureFromImage(bufferRef.image()); + } else { + QQuickWindow::CreateTextureOptions opt = 0; + if (surface->useTextureAlpha()) { + opt |= QQuickWindow::TextureHasAlphaChannel; + } + texture = window->createTextureFromId(bufferRef.createTexture(), surface->size(), opt); + } + texture->bind(); + } + + update = false; + } + + void invalidateTexture() + { + delete texture; + texture = 0; + } + + QWaylandQuickSurface *surface; + QWaylandBufferRef bufferRef; + QWaylandBufferRef nextBuffer; + QSGTexture *texture; + bool update; +}; + + +class QWaylandQuickSurfacePrivate : public QWaylandSurfacePrivate +{ +public: + QWaylandQuickSurfacePrivate(wl_client *client, quint32 id, QWaylandQuickCompositor *c, QWaylandQuickSurface *surf) + : QWaylandSurfacePrivate(client, id, c, surf) + , buffer(new BufferAttacher) + , compositor(c) + , useTextureAlpha(true) + , windowPropertyMap(new QQmlPropertyMap) + , clientRenderingEnabled(true) + { + + } + + ~QWaylandQuickSurfacePrivate() + { + windowPropertyMap->deleteLater(); + // buffer is deleted automatically by ~Surface(), since it is the assigned attacher + } + + void surface_commit(Resource *resource) Q_DECL_OVERRIDE + { + if (m_pending.newlyAttached) { + buffer->update = true; + } + QWaylandSurfacePrivate::surface_commit(resource); + + compositor->update(); + } + + BufferAttacher *buffer; + QWaylandQuickCompositor *compositor; + bool useTextureAlpha; + QQmlPropertyMap *windowPropertyMap; + bool clientRenderingEnabled; +}; + +QWaylandQuickSurface::QWaylandQuickSurface(wl_client *client, quint32 id, QWaylandQuickCompositor *compositor) + : QWaylandSurface(new QWaylandQuickSurfacePrivate(client, id, compositor, this)) +{ + Q_D(QWaylandQuickSurface); + d->buffer->surface = this; + setBufferAttacher(d->buffer); + + QQuickWindow *window = static_cast<QQuickWindow *>(compositor->window()); + connect(window, &QQuickWindow::beforeSynchronizing, this, &QWaylandQuickSurface::updateTexture, Qt::DirectConnection); + connect(window, &QQuickWindow::sceneGraphInvalidated, this, &QWaylandQuickSurface::invalidateTexture, Qt::DirectConnection); + connect(this, &QWaylandSurface::windowPropertyChanged, d->windowPropertyMap, &QQmlPropertyMap::insert); + connect(d->windowPropertyMap, &QQmlPropertyMap::valueChanged, this, &QWaylandSurface::setWindowProperty); + +} + +QWaylandQuickSurface::~QWaylandQuickSurface() +{ + +} + +QSGTexture *QWaylandQuickSurface::texture() const +{ + Q_D(const QWaylandQuickSurface); + return d->buffer->texture; +} + +bool QWaylandQuickSurface::useTextureAlpha() const +{ + Q_D(const QWaylandQuickSurface); + return d->useTextureAlpha; +} + +void QWaylandQuickSurface::setUseTextureAlpha(bool useTextureAlpha) +{ + Q_D(QWaylandQuickSurface); + if (d->useTextureAlpha != useTextureAlpha) { + d->useTextureAlpha = useTextureAlpha; + emit useTextureAlphaChanged(); + emit configure(); + } +} + +QObject *QWaylandQuickSurface::windowPropertyMap() const +{ + Q_D(const QWaylandQuickSurface); + return d->windowPropertyMap; +} + + +void QWaylandQuickSurface::updateTexture() +{ + Q_D(QWaylandQuickSurface); + if (d->buffer->update) + d->buffer->createTexture(); +} + +void QWaylandQuickSurface::invalidateTexture() +{ + Q_D(QWaylandQuickSurface); + d->buffer->invalidateTexture(); +} + +bool QWaylandQuickSurface::clientRenderingEnabled() const +{ + Q_D(const QWaylandQuickSurface); + return d->clientRenderingEnabled; +} + +void QWaylandQuickSurface::setClientRenderingEnabled(bool enabled) +{ + Q_D(QWaylandQuickSurface); + if (d->clientRenderingEnabled != enabled) { + d->clientRenderingEnabled = enabled; + + sendOnScreenVisibilityChange(enabled); + + emit clientRenderingEnabledChanged(); + } +} + +QT_END_NAMESPACE diff --git a/src/compositor/compositor_api/qwaylandquicksurface.h b/src/compositor/compositor_api/qwaylandquicksurface.h new file mode 100644 index 000000000..6c464ecd7 --- /dev/null +++ b/src/compositor/compositor_api/qwaylandquicksurface.h @@ -0,0 +1,91 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Jolla Ltd, author: <giulio.camuffo@jollamobile.com> +** Contact: http://www.qt-project.org/legal +** +** This file is part of the plugins of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, 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, Digia gives you certain additional +** rights. These rights are described in the Digia 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. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QQUICKWAYLANDSURFACE_H +#define QQUICKWAYLANDSURFACE_H + +#include <QSGTexture> +#include <QSGTextureProvider> + +#include "qwaylandsurface.h" + +struct wl_client; + +QT_BEGIN_NAMESPACE + +class QWaylandSurfaceItem; +class QWaylandQuickSurfacePrivate; +class QWaylandQuickCompositor; + +class Q_COMPOSITOR_EXPORT QWaylandQuickSurface : public QWaylandSurface +{ + Q_OBJECT + Q_DECLARE_PRIVATE(QWaylandQuickSurface) + Q_PROPERTY(bool useTextureAlpha READ useTextureAlpha WRITE setUseTextureAlpha NOTIFY useTextureAlphaChanged) + Q_PROPERTY(bool clientRenderingEnabled READ clientRenderingEnabled WRITE setClientRenderingEnabled NOTIFY clientRenderingEnabledChanged) + Q_PROPERTY(QObject *windowProperties READ windowPropertyMap CONSTANT) +public: + QWaylandQuickSurface(wl_client *client, quint32 id, QWaylandQuickCompositor *compositor); + ~QWaylandQuickSurface(); + + QSGTexture *texture() const; + + bool useTextureAlpha() const; + void setUseTextureAlpha(bool useTextureAlpha); + + bool clientRenderingEnabled() const; + void setClientRenderingEnabled(bool enabled); + + QObject *windowPropertyMap() const; + +signals: + void useTextureAlphaChanged(); + void clientRenderingEnabledChanged(); + +private: + void updateTexture(); + void invalidateTexture(); + +}; + +QT_END_NAMESPACE + +#endif diff --git a/src/compositor/compositor_api/qwaylandsurface.cpp b/src/compositor/compositor_api/qwaylandsurface.cpp index 2b7d713c8..5fd7fabe9 100644 --- a/src/compositor/compositor_api/qwaylandsurface.cpp +++ b/src/compositor/compositor_api/qwaylandsurface.cpp @@ -53,74 +53,51 @@ #include "qwaylandcompositor.h" #include "waylandwindowmanagerintegration.h" +#include "qwaylandsurface_p.h" +#include "qwaylandbufferref.h" #include <QtGui/QGuiApplication> #include <QtGui/QScreen> -#ifdef QT_COMPOSITOR_QUICK -#include "qwaylandsurfaceitem.h" -#include <QtQml/QQmlPropertyMap> -#endif - QT_BEGIN_NAMESPACE -class QWaylandSurfacePrivate : public QObjectPrivate -{ -public: - QWaylandSurfacePrivate(QtWayland::Surface *srfc) - : surface(srfc) -#ifdef QT_COMPOSITOR_QUICK - , surface_item(0) - , windowPropertyMap(new QQmlPropertyMap) -#endif - {} - - ~QWaylandSurfacePrivate() - { -#ifdef QT_COMPOSITOR_QUICK - if (surface_item) - surface_item->setSurface(0); - if (windowPropertyMap) - windowPropertyMap->deleteLater(); -#endif - } +QWaylandSurfacePrivate::QWaylandSurfacePrivate(wl_client *client, quint32 id, QWaylandCompositor *compositor, QWaylandSurface *surface) + : QtWayland::Surface(client, id, compositor, surface) + , closing(false) + , refCount(1) +{} - QtWayland::Surface *surface; -#ifdef QT_COMPOSITOR_QUICK - QWaylandSurfaceItem *surface_item; - QQmlPropertyMap *windowPropertyMap; -#endif -}; -QWaylandSurface::QWaylandSurface(QtWayland::Surface *surface) - : QObject(*new QWaylandSurfacePrivate(surface)) + +QWaylandSurface::QWaylandSurface(wl_client *client, quint32 id, QWaylandCompositor *compositor) + : QObject(*new QWaylandSurfacePrivate(client, id, compositor, this)) { -#ifdef QT_COMPOSITOR_QUICK - Q_D(QWaylandSurface); - connect(this, &QWaylandSurface::windowPropertyChanged, - d->windowPropertyMap, &QQmlPropertyMap::insert); - connect(d->windowPropertyMap, &QQmlPropertyMap::valueChanged, - this, &QWaylandSurface::setWindowProperty); -#endif + } -void QWaylandSurface::swapBuffers() +QWaylandSurface::QWaylandSurface(QWaylandSurfacePrivate *dptr) + : QObject(*dptr) { - Q_D(const QWaylandSurface); - d->surface->swapBuffers(); + +} + +QWaylandSurface::~QWaylandSurface() +{ + Q_D(QWaylandSurface); + delete d->m_attacher; } WaylandClient *QWaylandSurface::client() const { Q_D(const QWaylandSurface); - return d->surface->resource()->client(); + return d->resource()->client(); } QWaylandSurface *QWaylandSurface::parentSurface() const { Q_D(const QWaylandSurface); - if (d->surface->subSurface() && d->surface->subSurface()->parent()) { - return d->surface->subSurface()->parent()->waylandSurface(); + if (d->subSurface() && d->subSurface()->parent()) { + return d->subSurface()->parent()->waylandSurface(); } return 0; } @@ -128,8 +105,8 @@ QWaylandSurface *QWaylandSurface::parentSurface() const QLinkedList<QWaylandSurface *> QWaylandSurface::subSurfaces() const { Q_D(const QWaylandSurface); - if (d->surface->subSurface()) { - return d->surface->subSurface()->subSurfaces(); + if (d->subSurface()) { + return d->subSurface()->subSurfaces(); } return QLinkedList<QWaylandSurface *>(); } @@ -137,13 +114,13 @@ QLinkedList<QWaylandSurface *> QWaylandSurface::subSurfaces() const QWaylandSurface::Type QWaylandSurface::type() const { Q_D(const QWaylandSurface); - return d->surface->type(); + return d->type(); } bool QWaylandSurface::isYInverted() const { Q_D(const QWaylandSurface); - return d->surface->isYInverted(); + return d->isYInverted(); } bool QWaylandSurface::visible() const @@ -154,110 +131,70 @@ bool QWaylandSurface::visible() const bool QWaylandSurface::isMapped() const { Q_D(const QWaylandSurface); - return d->surface->mapped(); + return d->mapped(); } QPointF QWaylandSurface::pos() const { Q_D(const QWaylandSurface); - return d->surface->pos(); + return d->pos(); } void QWaylandSurface::setPos(const QPointF &pos) { Q_D(QWaylandSurface); - d->surface->setPos(pos); + d->setPos(pos); } QSize QWaylandSurface::size() const { Q_D(const QWaylandSurface); - return d->surface->size(); + return d->size(); } void QWaylandSurface::requestSize(const QSize &size) { Q_D(QWaylandSurface); - if (d->surface->shellSurface()) - d->surface->shellSurface()->sendConfigure(WL_SHELL_SURFACE_RESIZE_BOTTOM_RIGHT, size.width(), size.height()); + if (d->shellSurface()) + d->shellSurface()->sendConfigure(WL_SHELL_SURFACE_RESIZE_BOTTOM_RIGHT, size.width(), size.height()); } Qt::ScreenOrientations QWaylandSurface::orientationUpdateMask() const { Q_D(const QWaylandSurface); - return d->surface->compositor()->orientationUpdateMaskForClient(static_cast<wl_client *>(client())); + return d->compositor()->orientationUpdateMaskForClient(static_cast<wl_client *>(client())); } Qt::ScreenOrientation QWaylandSurface::contentOrientation() const { Q_D(const QWaylandSurface); - if (!d->surface->extendedSurface()) + if (!d->extendedSurface()) return Qt::PrimaryOrientation; - return d->surface->extendedSurface()->contentOrientation(); + return d->extendedSurface()->contentOrientation(); } QWaylandSurface::WindowFlags QWaylandSurface::windowFlags() const { Q_D(const QWaylandSurface); - if (!d->surface->extendedSurface()) + if (!d->extendedSurface()) return QWaylandSurface::WindowFlags(0); - return d->surface->extendedSurface()->windowFlags(); + return d->extendedSurface()->windowFlags(); } QWaylandSurface::WindowType QWaylandSurface::windowType() const { Q_D(const QWaylandSurface); - if (d->surface->shellSurface()) - return d->surface->shellSurface()->windowType(); + if (d->shellSurface()) + return d->shellSurface()->windowType(); return QWaylandSurface::None; } -QImage QWaylandSurface::image() const -{ - Q_D(const QWaylandSurface); - return d->surface->image(); -} - -#ifdef QT_COMPOSITOR_WAYLAND_GL -GLuint QWaylandSurface::texture() const -{ - Q_D(const QWaylandSurface); - return d->surface->textureId(); -} -#else //QT_COMPOSITOR_WAYLAND_GL -uint QWaylandSurface::texture() const -{ - return 0; -} -#endif - -QtWayland::Surface * QWaylandSurface::handle() const -{ - Q_D(const QWaylandSurface); - return d->surface; -} - -#ifdef QT_COMPOSITOR_QUICK -QWaylandSurfaceItem *QWaylandSurface::surfaceItem() const -{ - Q_D(const QWaylandSurface); - return d->surface_item; -} - -void QWaylandSurface::setSurfaceItem(QWaylandSurfaceItem *surfaceItem) +QtWayland::Surface * QWaylandSurface::handle() { Q_D(QWaylandSurface); - d->surface_item = surfaceItem; + return d; } -QObject *QWaylandSurface::windowPropertyMap() const -{ - Q_D(const QWaylandSurface); - return d->windowPropertyMap; -} - -#endif //QT_COMPOSITOR_QUICK - qint64 QWaylandSurface::processId() const { struct wl_client *client = static_cast<struct wl_client *>(this->client()); @@ -269,19 +206,19 @@ qint64 QWaylandSurface::processId() const QVariantMap QWaylandSurface::windowProperties() const { Q_D(const QWaylandSurface); - if (!d->surface->extendedSurface()) + if (!d->extendedSurface()) return QVariantMap(); - return d->surface->extendedSurface()->windowProperties(); + return d->extendedSurface()->windowProperties(); } void QWaylandSurface::setWindowProperty(const QString &name, const QVariant &value) { Q_D(QWaylandSurface); - if (!d->surface->extendedSurface()) + if (!d->extendedSurface()) return; - d->surface->extendedSurface()->setWindowProperty(name, value); + d->extendedSurface()->setWindowProperty(name, value); } QPointF QWaylandSurface::mapToParent(const QPointF &pos) const @@ -307,22 +244,22 @@ QPointF QWaylandSurface::mapTo(QWaylandSurface *parent, const QPointF &pos) cons QWaylandCompositor *QWaylandSurface::compositor() const { Q_D(const QWaylandSurface); - return d->surface->compositor()->waylandCompositor(); + return d->compositor()->waylandCompositor(); } QWaylandSurface *QWaylandSurface::transientParent() const { Q_D(const QWaylandSurface); - if (d->surface->shellSurface() && d->surface->shellSurface()->transientParent()) - return d->surface->shellSurface()->transientParent()->surface()->waylandSurface(); + if (d->shellSurface() && d->shellSurface()->transientParent()) + return d->shellSurface()->transientParent()->surface()->waylandSurface(); return 0; } QWindow::Visibility QWaylandSurface::visibility() const { Q_D(const QWaylandSurface); - if (d->surface->extendedSurface()) - return d->surface->extendedSurface()->visibility(); + if (d->extendedSurface()) + return d->extendedSurface()->visibility(); return QWindow::AutomaticVisibility; } @@ -330,8 +267,8 @@ QWindow::Visibility QWaylandSurface::visibility() const void QWaylandSurface::setVisibility(QWindow::Visibility visibility) { Q_D(QWaylandSurface); - if (d->surface->extendedSurface()) - d->surface->extendedSurface()->setVisibility(visibility); + if (d->extendedSurface()) + d->extendedSurface()->setVisibility(visibility); } void QWaylandSurface::sendOnScreenVisibilityChange(bool visible) @@ -342,19 +279,19 @@ void QWaylandSurface::sendOnScreenVisibilityChange(bool visible) QString QWaylandSurface::className() const { Q_D(const QWaylandSurface); - return d->surface->className(); + return d->className(); } QString QWaylandSurface::title() const { Q_D(const QWaylandSurface); - return d->surface->title(); + return d->title(); } bool QWaylandSurface::hasShellSurface() const { Q_D(const QWaylandSurface); - if (d->surface->shellSurface()) + if (d->shellSurface()) return true; return false; @@ -364,7 +301,7 @@ bool QWaylandSurface::hasInputPanelSurface() const { Q_D(const QWaylandSurface); - return d->surface->inputPanelSurface() != 0; + return d->inputPanelSurface() != 0; } /*! @@ -373,14 +310,21 @@ bool QWaylandSurface::hasInputPanelSurface() const bool QWaylandSurface::transientInactive() const { Q_D(const QWaylandSurface); - return d->surface->transientInactive(); + return d->transientInactive(); +} + +void QWaylandSurface::destroy() +{ + Q_D(QWaylandSurface); + if (--d->refCount == 0) + compositor()->handle()->destroySurface(d); } void QWaylandSurface::destroySurface() { Q_D(QWaylandSurface); - if (d->surface->extendedSurface()) { - d->surface->extendedSurface()->send_close(); + if (d->extendedSurface()) { + d->extendedSurface()->send_close(); } else { destroySurfaceByForce(); } @@ -389,15 +333,15 @@ void QWaylandSurface::destroySurface() void QWaylandSurface::destroySurfaceByForce() { Q_D(QWaylandSurface); - wl_resource *surface_resource = d->surface->resource()->handle; + wl_resource *surface_resource = d->resource()->handle; wl_resource_destroy(surface_resource); } void QWaylandSurface::ping() { Q_D(QWaylandSurface); - if (d->surface->shellSurface()) - d->surface->shellSurface()->ping(); + if (d->shellSurface()) + d->shellSurface()->ping(); } /*! @@ -408,14 +352,32 @@ void QWaylandSurface::ping() void QWaylandSurface::updateSelection() { Q_D(QWaylandSurface); - const QtWayland::InputDevice *inputDevice = d->surface->compositor()->defaultInputDevice(); + const QtWayland::InputDevice *inputDevice = d->compositor()->defaultInputDevice(); if (inputDevice) { const QtWayland::DataDevice *dataDevice = inputDevice->dataDevice(); if (dataDevice) { - d->surface->compositor()->dataDeviceManager()->offerRetainedSelection( - dataDevice->resourceMap().value(d->surface->resource()->client())->handle); + d->compositor()->dataDeviceManager()->offerRetainedSelection( + dataDevice->resourceMap().value(d->resource()->client())->handle); } } } +void QWaylandSurface::ref() +{ + Q_D(QWaylandSurface); + ++d->refCount; +} + +void QWaylandSurface::setBufferAttacher(QWaylandBufferAttacher *attacher) +{ + Q_D(QWaylandSurface); + d->m_attacher = attacher; +} + +QWaylandBufferAttacher *QWaylandSurface::bufferAttacher() const +{ + Q_D(const QWaylandSurface); + return d->m_attacher; +} + QT_END_NAMESPACE diff --git a/src/compositor/compositor_api/qwaylandsurface.h b/src/compositor/compositor_api/qwaylandsurface.h index 2f7b70ce8..22deee5ae 100644 --- a/src/compositor/compositor_api/qwaylandsurface.h +++ b/src/compositor/compositor_api/qwaylandsurface.h @@ -48,19 +48,14 @@ #include <QtGui/QWindow> #include <QtCore/QVariantMap> -#ifdef QT_COMPOSITOR_WAYLAND_GL -#include <QtGui/qopengl.h> -#endif +struct wl_client; QT_BEGIN_NAMESPACE class QTouchEvent; class QWaylandSurfacePrivate; class QWaylandCompositor; - -#ifdef QT_COMPOSITOR_QUICK -class QWaylandSurfaceItem; -#endif +class QWaylandBufferRef; namespace QtWayland { class Surface; @@ -68,6 +63,17 @@ class SurfacePrivate; class ExtendedSurface; } +class Q_COMPOSITOR_EXPORT QWaylandBufferAttacher +{ +public: + virtual ~QWaylandBufferAttacher() {} + +protected: + virtual void attach(const QWaylandBufferRef &ref) = 0; + + friend class QtWayland::Surface; +}; + class Q_COMPOSITOR_EXPORT QWaylandSurface : public QObject { Q_OBJECT @@ -81,9 +87,7 @@ class Q_COMPOSITOR_EXPORT QWaylandSurface : public QObject Q_PROPERTY(QString title READ title NOTIFY titleChanged) Q_PROPERTY(Qt::ScreenOrientations orientationUpdateMask READ orientationUpdateMask NOTIFY orientationUpdateMaskChanged) Q_PROPERTY(QWindow::Visibility visibility READ visibility WRITE setVisibility NOTIFY visibilityChanged) -#ifdef QT_COMPOSITOR_QUICK - Q_PROPERTY(QObject * windowProperties READ windowPropertyMap CONSTANT) -#endif + Q_PROPERTY(QSize size READ size NOTIFY sizeChanged) Q_ENUMS(WindowFlag WindowType) Q_FLAGS(WindowFlag WindowFlags) @@ -109,7 +113,8 @@ public: Texture }; - QWaylandSurface(QtWayland::Surface *surface = 0); + QWaylandSurface(wl_client *client, quint32 id, QWaylandCompositor *compositor); + virtual ~QWaylandSurface(); WaylandClient *client() const; @@ -134,27 +139,13 @@ public: WindowType windowType() const; - QImage image() const; -#ifdef QT_COMPOSITOR_WAYLAND_GL - GLuint texture() const; -#else - uint texture() const; -#endif - QWindow::Visibility visibility() const; void setVisibility(QWindow::Visibility visibility); Q_INVOKABLE void sendOnScreenVisibilityChange(bool visible); // Compat QWaylandSurface *transientParent() const; - QtWayland::Surface *handle() const; - -#ifdef QT_COMPOSITOR_QUICK - QWaylandSurfaceItem *surfaceItem() const; - void setSurfaceItem(QWaylandSurfaceItem *surfaceItem); - - QObject *windowPropertyMap() const; -#endif + QtWayland::Surface *handle(); qint64 processId() const; QByteArray authenticationToken() const; @@ -175,20 +166,26 @@ public: bool transientInactive() const; + Q_INVOKABLE void destroy(); Q_INVOKABLE void destroySurface(); Q_INVOKABLE void destroySurfaceByForce(); Q_INVOKABLE void ping(); - void swapBuffers(); + void ref(); + + void setBufferAttacher(QWaylandBufferAttacher *attacher); + QWaylandBufferAttacher *bufferAttacher() const; public slots: void updateSelection(); +protected: + QWaylandSurface(QWaylandSurfacePrivate *dptr); + signals: void mapped(); void unmapped(); void damaged(const QRegion &rect); - void committed(); void parentChanged(QWaylandSurface *newParent, QWaylandSurface *oldParent); void sizeChanged(); void posChanged(); @@ -204,6 +201,10 @@ signals: void lowerRequested(); void visibilityChanged(); void pong(); + void surfaceDestroyed(); + + void configure(); + void redraw(); }; QT_END_NAMESPACE diff --git a/src/compositor/compositor_api/qwaylandsurface_p.h b/src/compositor/compositor_api/qwaylandsurface_p.h new file mode 100644 index 000000000..aff0a8758 --- /dev/null +++ b/src/compositor/compositor_api/qwaylandsurface_p.h @@ -0,0 +1,68 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Jolla Ltd, author: <giulio.camuffo@jollamobile.com> +** Contact: http://www.qt-project.org/legal +** +** This file is part of the plugins of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, 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, Digia gives you certain additional +** rights. These rights are described in the Digia 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. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QWAYLANDSURFACE_P_H +#define QWAYLANDSURFACE_P_H + +#include <QtCompositor/qwaylandexport.h> +#include <private/qobject_p.h> + +#include <QtCompositor/private/qwlsurface_p.h> + +QT_BEGIN_NAMESPACE + +class QWaylandCompositor; +class QWaylandSurface; + +class Q_COMPOSITOR_EXPORT QWaylandSurfacePrivate : public QObjectPrivate, public QtWayland::Surface +{ +public: + QWaylandSurfacePrivate(wl_client *client, quint32 id, QWaylandCompositor *compositor, QWaylandSurface *surface); + + bool closing; + int refCount; + + friend class QWaylandSurface; +}; + +QT_END_NAMESPACE + +#endif diff --git a/src/compositor/compositor_api/qwaylandsurfaceitem.cpp b/src/compositor/compositor_api/qwaylandsurfaceitem.cpp index 57e5c2906..1a1dc7cdb 100644 --- a/src/compositor/compositor_api/qwaylandsurfaceitem.cpp +++ b/src/compositor/compositor_api/qwaylandsurfaceitem.cpp @@ -39,12 +39,9 @@ ****************************************************************************/ #include "qwaylandsurfaceitem.h" -#include "qwaylandsurface.h" -#include "qwaylandcompositor.h" -#include "qwaylandinput.h" - -#include "qwlsurface_p.h" -#include "qwlextendedsurface_p.h" +#include "qwaylandquicksurface.h" +#include <QtCompositor/qwaylandcompositor.h> +#include <QtCompositor/qwaylandinput.h> #include <QtGui/QKeyEvent> #include <QtGui/QGuiApplication> @@ -58,15 +55,15 @@ QT_BEGIN_NAMESPACE +QMutex *QWaylandSurfaceItem::mutex = 0; + class QWaylandSurfaceTextureProvider : public QSGTextureProvider { - Q_OBJECT - public: QWaylandSurfaceTextureProvider() : t(0) { } - ~QWaylandSurfaceTextureProvider() { delete t; } - QSGTexture *texture() const { + QSGTexture *texture() const Q_DECL_OVERRIDE + { if (t) t->setFiltering(smooth ? QSGTexture::Linear : QSGTexture::Nearest); return t; @@ -74,55 +71,45 @@ public: bool smooth; QSGTexture *t; - -public slots: - void invalidate() - { - delete t; - t = 0; - } }; -QMutex *QWaylandSurfaceItem::mutex = 0; - QWaylandSurfaceItem::QWaylandSurfaceItem(QQuickItem *parent) : QQuickItem(parent) , m_surface(0) , m_provider(0) , m_paintEnabled(true) - , m_useTextureAlpha(false) - , m_clientRenderingEnabled(true) , m_touchEventsEnabled(false) , m_resizeSurfaceToItem(false) + , m_newTexture(false) { if (!mutex) mutex = new QMutex; + + setFlag(ItemHasContents); } -QWaylandSurfaceItem::QWaylandSurfaceItem(QWaylandSurface *surface, QQuickItem *parent) +QWaylandSurfaceItem::QWaylandSurfaceItem(QWaylandQuickSurface *surface, QQuickItem *parent) : QQuickItem(parent) , m_surface(0) , m_provider(0) , m_paintEnabled(true) - , m_useTextureAlpha(false) - , m_clientRenderingEnabled(true) , m_touchEventsEnabled(false) , m_resizeSurfaceToItem(false) { init(surface); } -void QWaylandSurfaceItem::init(QWaylandSurface *surface) +void QWaylandSurfaceItem::init(QWaylandQuickSurface *surface) { + if (m_surface) + m_surface->destroy(); + if (!surface) return; - if (m_surface) { - m_surface->setSurfaceItem(0); - } - m_surface = surface; - m_surface->setSurfaceItem(this); + surface->ref(); + update(); if (m_resizeSurfaceToItem) { updateSurfaceSize(); @@ -134,7 +121,7 @@ void QWaylandSurfaceItem::init(QWaylandSurface *surface) updatePosition(); setSmooth(true); - setFlag(ItemHasContents); + setAcceptedMouseButtons(Qt::LeftButton | Qt::MiddleButton | Qt::RightButton | Qt::ExtraButton1 | Qt::ExtraButton2 | Qt::ExtraButton3 | Qt::ExtraButton4 | Qt::ExtraButton5 | Qt::ExtraButton6 | Qt::ExtraButton7 | Qt::ExtraButton8 | @@ -143,29 +130,29 @@ void QWaylandSurfaceItem::init(QWaylandSurface *surface) setAcceptHoverEvents(true); connect(surface, &QWaylandSurface::mapped, this, &QWaylandSurfaceItem::surfaceMapped); connect(surface, &QWaylandSurface::unmapped, this, &QWaylandSurfaceItem::surfaceUnmapped); - connect(surface, &QWaylandSurface::destroyed, this, &QWaylandSurfaceItem::surfaceDestroyed); - connect(surface, &QWaylandSurface::damaged, this, &QWaylandSurfaceItem::surfaceDamaged); - connect(surface, &QWaylandSurface::committed, this, &QQuickItem::update); + connect(surface, &QWaylandSurface::surfaceDestroyed, this, &QWaylandSurfaceItem::surfaceDestroyed); connect(surface, &QWaylandSurface::parentChanged, this, &QWaylandSurfaceItem::parentChanged); connect(surface, &QWaylandSurface::sizeChanged, this, &QWaylandSurfaceItem::updateSize); connect(surface, &QWaylandSurface::posChanged, this, &QWaylandSurfaceItem::updatePosition); + connect(surface, &QWaylandSurface::configure, this, &QWaylandSurfaceItem::updateBuffer); + connect(surface, &QWaylandSurface::redraw, this, &QQuickItem::update); connect(this, &QWaylandSurfaceItem::widthChanged, this, &QWaylandSurfaceItem::updateSurfaceSize); connect(this, &QWaylandSurfaceItem::heightChanged, this, &QWaylandSurfaceItem::updateSurfaceSize); - m_damaged = false; m_yInverted = surface ? surface->isYInverted() : true; + emit yInvertedChanged(); } QWaylandSurfaceItem::~QWaylandSurfaceItem() { QMutexLocker locker(mutex); if (m_surface) - m_surface->setSurfaceItem(0); + m_surface->destroy(); if (m_provider) m_provider->deleteLater(); } -void QWaylandSurfaceItem::setSurface(QWaylandSurface *surface) +void QWaylandSurfaceItem::setSurface(QWaylandQuickSurface *surface) { if (surface == m_surface) return; @@ -181,16 +168,9 @@ bool QWaylandSurfaceItem::isYInverted() const QSGTextureProvider *QWaylandSurfaceItem::textureProvider() const { - const_cast<QWaylandSurfaceItem *>(this)->ensureProvider(); - return m_provider; -} - -void QWaylandSurfaceItem::ensureProvider() -{ - if (!m_provider) { + if (!m_provider) m_provider = new QWaylandSurfaceTextureProvider(); - connect(window(), &QQuickWindow::sceneGraphInvalidated, m_provider, &QWaylandSurfaceTextureProvider::invalidate, Qt::DirectConnection); - } + return m_provider; } void QWaylandSurfaceItem::mousePressEvent(QMouseEvent *event) @@ -281,40 +261,10 @@ void QWaylandSurfaceItem::surfaceUnmapped() update(); } -void QWaylandSurfaceItem::surfaceDestroyed(QObject *) -{ - if (m_surface) - m_surface->setSurfaceItem(0); - - m_surface = 0; -} - -void QWaylandSurfaceItem::setDamagedFlag(bool on) -{ - m_damaged = on; -} - - -void QWaylandSurfaceItem::surfaceDamaged(const QRegion &) -{ - m_damaged = true; - if (m_surface) { - bool inverted = m_surface->isYInverted(); - if (inverted != m_yInverted) { - m_yInverted = inverted; - emit yInvertedChanged(); - } - } - emit textureChanged(); -} - void QWaylandSurfaceItem::parentChanged(QWaylandSurface *newParent, QWaylandSurface *oldParent) { Q_UNUSED(oldParent); - QWaylandSurfaceItem *item = newParent? newParent->surfaceItem():0; - setParentItem(item); - if (newParent) { setPaintEnabled(true); setVisible(true); @@ -340,6 +290,14 @@ void QWaylandSurfaceItem::updatePosition() setPosition(m_surface->pos()); } +/*! + \qmlproperty bool QtWayland::QWaylandSurfaceItem::paintEnabled + + If this property is true, the \l item is hidden, though the texture + will still be updated. As opposed to hiding the \l item by + setting \l{Item::visible}{visible} to false, setting this property to true + will not prevent mouse or keyboard input from reaching \l item. +*/ bool QWaylandSurfaceItem::paintEnabled() const { return m_paintEnabled; @@ -351,29 +309,14 @@ void QWaylandSurfaceItem::setPaintEnabled(bool enabled) update(); } -void QWaylandSurfaceItem::updateTexture() +void QWaylandSurfaceItem::updateBuffer() { - ensureProvider(); - QSGTexture *texture = m_provider->t; - if (m_damaged) { - m_damaged = false; - QSGTexture *oldTexture = texture; - if (m_surface->type() == QWaylandSurface::Texture) { - QQuickWindow::CreateTextureOptions opt = 0; - if (useTextureAlpha()) { - opt |= QQuickWindow::TextureHasAlphaChannel; - } - texture = window()->createTextureFromId(m_surface->texture(), m_surface->size(), opt); - } else { - texture = window()->createTextureFromImage(m_surface->image()); - } - texture->bind(); - delete oldTexture; - } + bool inv = m_yInverted; + m_yInverted = surface()->isYInverted(); + if (inv != m_yInverted) + emit yInvertedChanged(); - m_provider->t = texture; - emit m_provider->textureChanged(); - m_provider->smooth = smooth(); + m_newTexture = true; } QSGNode *QWaylandSurfaceItem::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData *) @@ -383,14 +326,20 @@ QSGNode *QWaylandSurfaceItem::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeD return 0; } + if (!m_provider) + m_provider = new QWaylandSurfaceTextureProvider(); + // Order here is important, as the state of visible is that of the pending // buffer but will be replaced after we advance the buffer queue. bool mapped = m_surface->isMapped(); - surface()->swapBuffers(); if (mapped) - updateTexture(); + m_provider->t = surface()->texture(); + m_provider->smooth = smooth(); + if (m_newTexture) + emit m_provider->textureChanged(); + m_newTexture = false; - if (!mapped|| !m_provider || !m_provider->t || !m_paintEnabled) { + if (!mapped || !m_provider->t || !m_paintEnabled) { delete oldNode; return 0; } @@ -409,28 +358,6 @@ QSGNode *QWaylandSurfaceItem::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeD return node; } -void QWaylandSurfaceItem::setUseTextureAlpha(bool useTextureAlpha) -{ - m_useTextureAlpha = useTextureAlpha; - - if ((flags() & ItemHasContents) != 0) { - update(); - } -} - -void QWaylandSurfaceItem::setClientRenderingEnabled(bool enabled) -{ - if (m_clientRenderingEnabled != enabled) { - m_clientRenderingEnabled = enabled; - - if (m_surface) { - m_surface->sendOnScreenVisibilityChange(enabled); - } - - emit clientRenderingEnabledChanged(); - } -} - void QWaylandSurfaceItem::setTouchEventsEnabled(bool enabled) { if (m_touchEventsEnabled != enabled) { @@ -448,5 +375,3 @@ void QWaylandSurfaceItem::setResizeSurfaceToItem(bool enabled) } QT_END_NAMESPACE - -#include "qwaylandsurfaceitem.moc" diff --git a/src/compositor/compositor_api/qwaylandsurfaceitem.h b/src/compositor/compositor_api/qwaylandsurfaceitem.h index 8abd4bf2d..f1da27995 100644 --- a/src/compositor/compositor_api/qwaylandsurfaceitem.h +++ b/src/compositor/compositor_api/qwaylandsurfaceitem.h @@ -42,38 +42,37 @@ #define QWAYLANDSURFACEITEM_H #include <QtCompositor/qwaylandexport.h> -#include <QtCompositor/qwaylandsurface.h> #include <QtQuick/QQuickItem> #include <QtQuick/qsgtexture.h> #include <QtQuick/qsgtextureprovider.h> +#include "qwaylandquicksurface.h" + QT_BEGIN_NAMESPACE class QWaylandSurfaceTextureProvider; class QMutex; -Q_DECLARE_METATYPE(QWaylandSurface*) +Q_DECLARE_METATYPE(QWaylandQuickSurface*) -class Q_COMPOSITOR_EXPORT QWaylandSurfaceItem : public QQuickItem +class QWaylandSurfaceItem : public QQuickItem { Q_OBJECT - Q_PROPERTY(QWaylandSurface* surface READ surface WRITE setSurface NOTIFY surfaceChanged) + Q_PROPERTY(QWaylandQuickSurface* surface READ surface WRITE setSurface NOTIFY surfaceChanged) Q_PROPERTY(bool paintEnabled READ paintEnabled WRITE setPaintEnabled) - Q_PROPERTY(bool useTextureAlpha READ useTextureAlpha WRITE setUseTextureAlpha NOTIFY useTextureAlphaChanged) - Q_PROPERTY(bool clientRenderingEnabled READ clientRenderingEnabled WRITE setClientRenderingEnabled NOTIFY clientRenderingEnabledChanged) Q_PROPERTY(bool touchEventsEnabled READ touchEventsEnabled WRITE setTouchEventsEnabled NOTIFY touchEventsEnabledChanged) Q_PROPERTY(bool isYInverted READ isYInverted NOTIFY yInvertedChanged) Q_PROPERTY(bool resizeSurfaceToItem READ resizeSurfaceToItem WRITE setResizeSurfaceToItem NOTIFY resizeSurfaceToItemChanged) public: QWaylandSurfaceItem(QQuickItem *parent = 0); - QWaylandSurfaceItem(QWaylandSurface *surface, QQuickItem *parent = 0); + QWaylandSurfaceItem(QWaylandQuickSurface *surface, QQuickItem *parent = 0); ~QWaylandSurfaceItem(); - void setSurface(QWaylandSurface *surface); - QWaylandSurface *surface() const {return m_surface; } + void setSurface(QWaylandQuickSurface *surface); + QWaylandQuickSurface *surface() const {return m_surface; } Q_INVOKABLE bool isYInverted() const; @@ -81,18 +80,12 @@ public: QSGTextureProvider *textureProvider() const; bool paintEnabled() const; - bool useTextureAlpha() const { return m_useTextureAlpha; } - bool clientRenderingEnabled() const { return m_clientRenderingEnabled; } bool touchEventsEnabled() const { return m_touchEventsEnabled; } bool resizeSurfaceToItem() const { return m_resizeSurfaceToItem; } - void setUseTextureAlpha(bool useTextureAlpha); - void setClientRenderingEnabled(bool enabled); void setTouchEventsEnabled(bool enabled); void setResizeSurfaceToItem(bool enabled); - void setDamagedFlag(bool on); - protected: void mousePressEvent(QMouseEvent *event); void mouseMoveEvent(QMouseEvent *event); @@ -111,21 +104,18 @@ public slots: private slots: void surfaceMapped(); void surfaceUnmapped(); - void surfaceDestroyed(QObject *object); - void surfaceDamaged(const QRegion &); void parentChanged(QWaylandSurface *newParent, QWaylandSurface *oldParent); void updateSize(); void updateSurfaceSize(); void updatePosition(); + void updateBuffer(); signals: - void textureChanged(); - void useTextureAlphaChanged(); - void clientRenderingEnabledChanged(); void touchEventsEnabledChanged(); void yInvertedChanged(); void surfaceChanged(); void resizeSurfaceToItemChanged(); + void surfaceDestroyed(); protected: QSGNode *updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData *); @@ -133,20 +123,17 @@ protected: private: friend class QWaylandSurfaceNode; void updateTexture(); - void init(QWaylandSurface *); - void ensureProvider(); + void init(QWaylandQuickSurface *); static QMutex *mutex; - QWaylandSurface *m_surface; - QWaylandSurfaceTextureProvider *m_provider; + QWaylandQuickSurface *m_surface; + mutable QWaylandSurfaceTextureProvider *m_provider; bool m_paintEnabled; - bool m_useTextureAlpha; - bool m_clientRenderingEnabled; bool m_touchEventsEnabled; - bool m_damaged; bool m_yInverted; bool m_resizeSurfaceToItem; + bool m_newTexture; }; QT_END_NAMESPACE diff --git a/src/compositor/wayland_wrapper/qwlcompositor.cpp b/src/compositor/wayland_wrapper/qwlcompositor.cpp index da67c3cd2..a6ec62caa 100644 --- a/src/compositor/wayland_wrapper/qwlcompositor.cpp +++ b/src/compositor/wayland_wrapper/qwlcompositor.cpp @@ -69,10 +69,6 @@ #include <QtCore/QAbstractEventDispatcher> #include <QtGui/private/qguiapplication_p.h> -#ifdef QT_COMPOSITOR_QUICK -#include <QtQuick/QQuickWindow> -#endif - #include <stdio.h> #include <stdlib.h> #include <string.h> @@ -131,6 +127,15 @@ Compositor::Compositor(QWaylandCompositor *qt_compositor, QWaylandCompositor::Ex { m_timer.start(); compositor = this; +} + +void Compositor::init() +{ + QStringList arguments = QCoreApplication::instance()->arguments(); + + int socketArg = arguments.indexOf(QLatin1String("--wayland-socket-name")); + if (socketArg != -1 && socketArg + 1 < arguments.size()) + m_socket_name = arguments.at(socketArg + 1).toLocal8Bit(); wl_compositor::init(m_display->handle()); @@ -147,7 +152,7 @@ Compositor::Compositor(QWaylandCompositor *qt_compositor, QWaylandCompositor::Ex m_shell, Shell::bind_func); - if (wl_display_add_socket(m_display->handle(), qt_compositor->socketName())) { + if (wl_display_add_socket(m_display->handle(), m_qt_compositor->socketName())) { fprintf(stderr, "Fatal: Failed to open server socket\n"); exit(EXIT_FAILURE); } @@ -163,18 +168,12 @@ Compositor::Compositor(QWaylandCompositor *qt_compositor, QWaylandCompositor::Ex connect(dispatcher, SIGNAL(aboutToBlock()), this, SLOT(processWaylandEvents())); qRegisterMetaType<SurfaceBuffer*>("SurfaceBuffer*"); + qRegisterMetaType<QWaylandSurface*>("WaylandSurface*"); //initialize distancefieldglyphcache here -#ifdef QT_COMPOSITOR_QUICK - if (QQuickWindow *w = qobject_cast<QQuickWindow *>(qt_compositor->window())) { - connect(w, SIGNAL(beforeSynchronizing()), this, SLOT(cleanupGraphicsResources()), Qt::DirectConnection); - } else -#endif - { -#if !defined(QT_NO_DEBUG) && !defined(QT_WAYLAND_NO_CLEANUP_WARNING) - qWarning("QWaylandCompositor::cleanupGraphicsResources() must be called manually"); -#endif - } + initializeHardwareIntegration(); + initializeExtensions(); + initializeDefaultInputDevice(); } Compositor::~Compositor() @@ -216,44 +215,26 @@ void Compositor::processWaylandEvents() void Compositor::destroySurface(Surface *surface) { - InputDevice *dev = defaultInputDevice(); - if (dev->mouseFocus() == surface) { - dev->setMouseFocus(0, QPointF(), QPointF()); - // Make sure the surface is reset regardless of what the grabber - // interface's focus() does. (e.g. the default implementation does - // nothing when a button is down which would be disastrous here) - dev->pointerDevice()->setFocus(0, QPointF()); - } - if (dev->pointerDevice()->current() == surface) { - dev->pointerDevice()->setCurrent(0, QPointF()); - } - if (dev->keyboardFocus() == surface) - dev->setKeyboardFocus(0); - m_surfaces.removeOne(surface); waylandCompositor()->surfaceAboutToBeDestroyed(surface->waylandSurface()); surface->releaseSurfaces(); - m_destroyed_surfaces << surface; + m_destroyed_surfaces << surface->waylandSurface(); } void Compositor::cleanupGraphicsResources() { - foreach (SurfaceBuffer *s, m_destroyed_buffers) - s->bufferWasDestroyed(); - m_destroyed_buffers.clear(); - qDeleteAll(m_destroyed_surfaces); m_destroyed_surfaces.clear(); } void Compositor::compositor_create_surface(Resource *resource, uint32_t id) { - Surface *surface = new Surface(resource->client(), id, this); - m_surfaces << surface; + QWaylandSurface *surface = new QWaylandSurface(resource->client(), id, m_qt_compositor); + m_surfaces << surface->handle(); //BUG: This may not be an on-screen window surface though - m_qt_compositor->surfaceCreated(surface->waylandSurface()); + m_qt_compositor->surfaceCreated(surface); } void Compositor::compositor_create_region(Resource *resource, uint32_t id) diff --git a/src/compositor/wayland_wrapper/qwlcompositor_p.h b/src/compositor/wayland_wrapper/qwlcompositor_p.h index 450ee23ed..835fa1fd8 100644 --- a/src/compositor/wayland_wrapper/qwlcompositor_p.h +++ b/src/compositor/wayland_wrapper/qwlcompositor_p.h @@ -90,7 +90,9 @@ public: Compositor(QWaylandCompositor *qt_compositor, QWaylandCompositor::ExtensionFlags extensions); ~Compositor(); + void init(); void sendFrameCallbacks(QList<QWaylandSurface *> visibleSurfaces); + void frameFinished(Surface *surface = 0); InputDevice *defaultInputDevice(); //we just have 1 default device for now (since QPA doesn't give us anything else) @@ -155,8 +157,6 @@ public: bool retainedSelectionEnabled() const; void overrideSelection(const QMimeData *data); void feedRetainedSelectionData(QMimeData *data); - - void bufferWasDestroyed(SurfaceBuffer *buffer) { m_destroyed_buffers << buffer; } public slots: void cleanupGraphicsResources(); @@ -166,13 +166,14 @@ protected: private slots: void processWaylandEvents(); -private: +protected: void loadClientBufferIntegration(); void loadServerBufferIntegration(); QWaylandCompositor::ExtensionFlags m_extensions; Display *m_display; + QByteArray m_socket_name; /* Input */ QWaylandInputDevice *m_default_wayland_input_device; @@ -186,8 +187,7 @@ private: QElapsedTimer m_timer; QList<Surface *> m_surfaces; - QSet<Surface *> m_destroyed_surfaces; - QSet<SurfaceBuffer *> m_destroyed_buffers; + QSet<QWaylandSurface *> m_destroyed_surfaces; /* Render state */ uint32_t m_current_frame; @@ -220,6 +220,8 @@ private: uint32_t version, uint32_t id); bool m_retainSelection; + + friend class ::QWaylandCompositor; }; } diff --git a/src/compositor/wayland_wrapper/qwlinputdevice.cpp b/src/compositor/wayland_wrapper/qwlinputdevice.cpp index 50ed377a6..0f3fce94f 100644 --- a/src/compositor/wayland_wrapper/qwlinputdevice.cpp +++ b/src/compositor/wayland_wrapper/qwlinputdevice.cpp @@ -260,7 +260,7 @@ Surface *InputDevice::keyboardFocus() const */ bool InputDevice::setKeyboardFocus(Surface *surface) { - if (surface && surface->transientInactive()) + if (surface && (surface->transientInactive() || surface->isDestroyed())) return false; m_keyboard->setFocus(surface); @@ -276,6 +276,9 @@ Surface *InputDevice::mouseFocus() const void InputDevice::setMouseFocus(Surface *surface, const QPointF &localPos, const QPointF &globalPos) { + if (surface && surface->isDestroyed()) + return; + m_pointer->setMouseFocus(surface, localPos, globalPos); // We have no separate touch focus management so make it match the pointer focus always. diff --git a/src/compositor/wayland_wrapper/qwlkeyboard.cpp b/src/compositor/wayland_wrapper/qwlkeyboard.cpp index 4c3aa8920..25e7155b0 100644 --- a/src/compositor/wayland_wrapper/qwlkeyboard.cpp +++ b/src/compositor/wayland_wrapper/qwlkeyboard.cpp @@ -75,6 +75,7 @@ Keyboard::Keyboard(Compositor *compositor, InputDevice *seat) #ifndef QT_NO_WAYLAND_XKB initXKB(); #endif + connect(&m_focusDestroyListener, &WlListener::fired, this, &Keyboard::focusDestroyed); } Keyboard::~Keyboard() @@ -93,6 +94,7 @@ void Keyboard::setFocus(Surface *surface) if (m_focusResource && m_focus != surface) { uint32_t serial = wl_display_next_serial(m_compositor->wl_display()); send_leave(m_focusResource->handle, serial, m_focus->resource()->handle); + m_focusDestroyListener.reset(); } Resource *resource = surface ? resourceMap().value(surface->resource()->client()) : 0; @@ -101,6 +103,7 @@ void Keyboard::setFocus(Surface *surface) uint32_t serial = wl_display_next_serial(m_compositor->wl_display()); send_modifiers(resource->handle, serial, m_modsDepressed, m_modsLatched, m_modsLocked, m_group); send_enter(resource->handle, serial, surface->resource()->handle, QByteArray::fromRawData((char *)m_keys.data(), m_keys.size() * sizeof(uint32_t))); + m_focusDestroyListener.listenForDestruction(surface->resource()->handle); } m_focusResource = resource; @@ -114,6 +117,15 @@ void Keyboard::setKeymap(const QWaylandKeymap &keymap) m_pendingKeymap = true; } +void Keyboard::focusDestroyed(void *data) +{ + Q_UNUSED(data) + m_focusDestroyListener.reset(); + + m_focus = 0; + m_focusResource = 0; +} + void Keyboard::sendKeyModifiers(wl_keyboard::Resource *resource, uint32_t serial) { send_modifiers(resource->handle, serial, m_modsDepressed, m_modsLatched, m_modsLocked, m_group); diff --git a/src/compositor/wayland_wrapper/qwlkeyboard_p.h b/src/compositor/wayland_wrapper/qwlkeyboard_p.h index b20fa97f7..6faf6ace2 100644 --- a/src/compositor/wayland_wrapper/qwlkeyboard_p.h +++ b/src/compositor/wayland_wrapper/qwlkeyboard_p.h @@ -54,6 +54,8 @@ #include <xkbcommon/xkbcommon.h> #endif +#include "qwllistener_p.h" + QT_BEGIN_NAMESPACE namespace QtWayland { @@ -91,6 +93,7 @@ private: void sendKeyEvent(uint code, uint32_t state); void updateModifierState(uint code, uint32_t state); void updateKeymap(); + void focusDestroyed(void *data); #ifndef QT_NO_WAYLAND_XKB void initXKB(); @@ -102,6 +105,7 @@ private: Surface *m_focus; Resource *m_focusResource; + WlListener m_focusDestroyListener; QVector<uint32_t> m_keys; uint32_t m_modsDepressed; diff --git a/src/compositor/wayland_wrapper/qwllistener.cpp b/src/compositor/wayland_wrapper/qwllistener.cpp new file mode 100644 index 000000000..a754981bf --- /dev/null +++ b/src/compositor/wayland_wrapper/qwllistener.cpp @@ -0,0 +1,70 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Jolla Ltd, author: <giulio.camuffo@jollamobile.com> +** Contact: http://www.qt-project.org/legal +** +** This file is part of the plugins of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, 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, Digia gives you certain additional +** rights. These rights are described in the Digia 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. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qwllistener_p.h" + +QT_BEGIN_NAMESPACE + +WlListener::WlListener() +{ + m_listener.parent = this; + m_listener.listener.notify = handler; + wl_list_init(&m_listener.listener.link); +} + +void WlListener::listenForDestruction(::wl_resource *resource) +{ + wl_resource_add_destroy_listener(resource, &m_listener.listener); +} + +void WlListener::reset() +{ + wl_list_remove(&m_listener.listener.link); + wl_list_init(&m_listener.listener.link); +} + +void WlListener::handler(wl_listener *listener, void *data) +{ + WlListener *that = reinterpret_cast<Listener *>(listener)->parent; + emit that->fired(data); +} + +QT_END_NAMESPACE diff --git a/src/compositor/wayland_wrapper/qwllistener_p.h b/src/compositor/wayland_wrapper/qwllistener_p.h new file mode 100644 index 000000000..4c49b1433 --- /dev/null +++ b/src/compositor/wayland_wrapper/qwllistener_p.h @@ -0,0 +1,75 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Jolla Ltd, author: <giulio.camuffo@jollamobile.com> +** Contact: http://www.qt-project.org/legal +** +** This file is part of the plugins of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, 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, Digia gives you certain additional +** rights. These rights are described in the Digia 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. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QTWAYLAND_QWLLISTENER_H +#define QTWAYLAND_QWLLISTENER_H + +#include <QObject> + +#include <wayland-server.h> + +QT_BEGIN_NAMESPACE + +class WlListener : public QObject +{ + Q_OBJECT +public: + WlListener(); + + void listenForDestruction(::wl_resource *resource); + void reset(); + +signals: + void fired(void *data); + +private: + static void handler(wl_listener *listener, void *data); + + struct Listener { + wl_listener listener; + WlListener *parent; + }; + Listener m_listener; +}; + +QT_END_NAMESPACE + +#endif diff --git a/src/compositor/wayland_wrapper/qwlpointer.cpp b/src/compositor/wayland_wrapper/qwlpointer.cpp index b459472a2..60082e325 100644 --- a/src/compositor/wayland_wrapper/qwlpointer.cpp +++ b/src/compositor/wayland_wrapper/qwlpointer.cpp @@ -96,6 +96,7 @@ Pointer::Pointer(Compositor *compositor, InputDevice *seat) , m_currentPoint() , m_buttonCount() { + connect(&m_focusDestroyListener, &WlListener::fired, this, &Pointer::focusDestroyed); } void Pointer::setFocus(Surface *surface, const QPointF &position) @@ -103,6 +104,7 @@ void Pointer::setFocus(Surface *surface, const QPointF &position) if (m_focusResource && m_focus != surface) { uint32_t serial = wl_display_next_serial(m_compositor->wl_display()); send_leave(m_focusResource->handle, serial, m_focus->resource()->handle); + m_focusDestroyListener.reset(); } Resource *resource = surface ? resourceMap().value(surface->resource()->client()) : 0; @@ -117,12 +119,24 @@ void Pointer::setFocus(Surface *surface, const QPointF &position) } send_enter(resource->handle, serial, surface->resource()->handle, wl_fixed_from_double(position.x()), wl_fixed_from_double(position.y())); + + m_focusDestroyListener.listenForDestruction(surface->resource()->handle); } m_focusResource = resource; m_focus = surface; } +void Pointer::focusDestroyed(void *data) +{ + Q_UNUSED(data) + m_focusDestroyListener.reset(); + + m_focus = 0; + m_focusResource = 0; + setMouseFocus(0, QPointF(), QPointF()); +} + void Pointer::startGrab(PointerGrabber *grab) { m_grab = grab; diff --git a/src/compositor/wayland_wrapper/qwlpointer_p.h b/src/compositor/wayland_wrapper/qwlpointer_p.h index ed53b048c..e125ab323 100644 --- a/src/compositor/wayland_wrapper/qwlpointer_p.h +++ b/src/compositor/wayland_wrapper/qwlpointer_p.h @@ -46,11 +46,14 @@ #include <QtCore/QList> #include <QtCore/QPoint> +#include <QtCore/QObject> #include <QtCompositor/private/qwayland-server-wayland.h> #include <stdint.h> +#include "qwllistener_p.h" + QT_BEGIN_NAMESPACE namespace QtWayland { @@ -71,7 +74,7 @@ public: Pointer *m_pointer; }; -class Q_COMPOSITOR_EXPORT Pointer : public QtWaylandServer::wl_pointer, public PointerGrabber +class Q_COMPOSITOR_EXPORT Pointer : public QObject, public QtWaylandServer::wl_pointer, public PointerGrabber { public: Pointer(Compositor *compositor, InputDevice *seat); @@ -112,6 +115,8 @@ protected: void pointer_destroy_resource(Resource *resource) Q_DECL_OVERRIDE; private: + void focusDestroyed(void *data); + Compositor *m_compositor; InputDevice *m_seat; @@ -129,6 +134,8 @@ private: QPointF m_currentPoint; int m_buttonCount; + + WlListener m_focusDestroyListener; }; } // namespace QtWayland diff --git a/src/compositor/wayland_wrapper/qwlsurface.cpp b/src/compositor/wayland_wrapper/qwlsurface.cpp index 5928bbb0f..98d494ac8 100644 --- a/src/compositor/wayland_wrapper/qwlsurface.cpp +++ b/src/compositor/wayland_wrapper/qwlsurface.cpp @@ -41,10 +41,6 @@ #include "qwlsurface_p.h" #include "qwaylandsurface.h" -#ifdef QT_COMPOSITOR_QUICK -#include "qwaylandsurfaceitem.h" -#endif - #include "qwlcompositor_p.h" #include "qwlinputdevice_p.h" #include "qwlextendedsurface_p.h" @@ -58,11 +54,6 @@ #include <wayland-server.h> -#ifdef QT_COMPOSITOR_WAYLAND_GL -#include "hardware_integration/qwlclientbufferintegration_p.h" -#include <qpa/qplatformopenglcontext.h> -#endif - #ifdef QT_WAYLAND_WINDOWMANAGER_SUPPORT #include "waylandwindowmanagerintegration.h" #endif @@ -117,19 +108,20 @@ public: bool canSend; }; -Surface::Surface(struct wl_client *client, uint32_t id, Compositor *compositor) +Surface::Surface(struct wl_client *client, uint32_t id, QWaylandCompositor *compositor, QWaylandSurface *surface) : QtWaylandServer::wl_surface(client, id) - , m_compositor(compositor) - , m_waylandSurface(new QWaylandSurface(this)) - , m_backBuffer(0) - , m_frontBuffer(0) + , m_compositor(compositor->handle()) + , m_waylandSurface(surface) + , m_buffer(0) , m_surfaceMapped(false) + , m_attacher(0) , m_extendedSurface(0) , m_subSurface(0) , m_shellSurface(0) , m_inputPanelSurface(0) , m_transientInactive(false) , m_isCursorSurface(false) + , m_destroyed(false) { m_pending.buffer = 0; m_pending.newlyAttached = false; @@ -137,9 +129,10 @@ Surface::Surface(struct wl_client *client, uint32_t id, Compositor *compositor) Surface::~Surface() { - delete m_waylandSurface; delete m_subSurface; + m_bufferRef = QWaylandBufferRef(); + for (int i = 0; i < m_bufferPool.size(); i++) delete m_bufferPool[i]; @@ -151,10 +144,7 @@ Surface::~Surface() void Surface::releaseSurfaces() { - delete m_waylandSurface; - m_waylandSurface = 0; - delete m_subSurface; - m_subSurface = 0; + } Surface *Surface::fromResource(struct ::wl_resource *resource) @@ -164,9 +154,8 @@ Surface *Surface::fromResource(struct ::wl_resource *resource) QWaylandSurface::Type Surface::type() const { - SurfaceBuffer *surfaceBuffer = currentSurfaceBuffer(); - if (surfaceBuffer && surfaceBuffer->waylandBufferHandle()) { - if (surfaceBuffer->isShmBuffer()) { + if (m_buffer && m_buffer->waylandBufferHandle()) { + if (m_buffer->isShmBuffer()) { return QWaylandSurface::Shm; } else { return QWaylandSurface::Texture; @@ -177,27 +166,14 @@ QWaylandSurface::Type Surface::type() const bool Surface::isYInverted() const { - bool ret = false; - static bool negateReturn = qgetenv("QT_COMPOSITOR_NEGATE_INVERTED_Y").toInt(); - ClientBufferIntegration *clientBufferIntegration = m_compositor->clientBufferIntegration(); - -#ifdef QT_COMPOSITOR_WAYLAND_GL - SurfaceBuffer *surfacebuffer = currentSurfaceBuffer(); - if (!surfacebuffer) { - ret = false; - } else if (clientBufferIntegration && surfacebuffer->waylandBufferHandle() && type() != QWaylandSurface::Shm) { - ret = clientBufferIntegration->isYInverted(surfacebuffer->waylandBufferHandle()); - } else -#endif - ret = true; - - return ret != negateReturn; + if (m_buffer) + return m_buffer->isYInverted(); + return false; } bool Surface::mapped() const { - SurfaceBuffer *surfacebuffer = currentSurfaceBuffer(); - return surfacebuffer ? bool(surfacebuffer->waylandBufferHandle()) : false; + return m_buffer ? bool(m_buffer->waylandBufferHandle()) : false; } QPointF Surface::pos() const @@ -246,28 +222,6 @@ QRegion Surface::opaqueRegion() const return m_opaqueRegion; } -QImage Surface::image() const -{ - SurfaceBuffer *surfacebuffer = currentSurfaceBuffer(); - if (surfacebuffer && !surfacebuffer->isDestroyed() && type() == QWaylandSurface::Shm) { - return surfacebuffer->image(); - } - return QImage(); -} - -#ifdef QT_COMPOSITOR_WAYLAND_GL -GLuint Surface::textureId() const -{ - const SurfaceBuffer *surfacebuffer = m_frontBuffer; - - if (m_compositor->clientBufferIntegration() && type() == QWaylandSurface::Texture - && !surfacebuffer->textureCreated()) { - const_cast<SurfaceBuffer *>(surfacebuffer)->createTexture(); - } - return surfacebuffer->texture(); -} -#endif // QT_COMPOSITOR_WAYLAND_GL - void Surface::sendFrameCallback() { uint time = m_compositor->currentTimeMsecs(); @@ -342,25 +296,6 @@ Compositor *Surface::compositor() const return m_compositor; } -void Surface::swapBuffers() - { - SurfaceBuffer *front = m_frontBuffer; - - // Advance current back buffer to the front buffer. - if (m_backBuffer) { - if (m_backBuffer->isDestroyed()) { - m_backBuffer->disown(); - m_backBuffer = 0; - } - m_frontBuffer = m_backBuffer; - m_backBuffer = 0; - } - - // Release the old front buffer if we changed it. - if (front && front != m_frontBuffer) - front->disown(); -} - /*! * Sets the backbuffer for this surface. The back buffer is not yet on * screen and will become live during the next swapBuffers(). @@ -370,11 +305,11 @@ void Surface::swapBuffers() */ void Surface::setBackBuffer(SurfaceBuffer *buffer) { - m_backBuffer = buffer; + m_buffer = buffer; - if (m_backBuffer) { - bool valid = m_backBuffer->waylandBufferHandle() != 0; - setSize(valid ? m_backBuffer->size() : QSize()); + if (m_buffer) { + bool valid = m_buffer->waylandBufferHandle() != 0; + setSize(valid ? m_buffer->size() : QSize()); if ((!m_subSurface || !m_subSurface->parent()) && !m_surfaceMapped) { m_surfaceMapped = true; @@ -426,7 +361,9 @@ void Surface::surface_destroy_resource(Resource *) m_extendedSurface = 0; } - compositor()->destroySurface(this); + m_destroyed = true; + m_waylandSurface->destroy(); + emit m_waylandSurface->surfaceDestroyed(); } void Surface::surface_destroy(Resource *resource) @@ -469,14 +406,17 @@ void Surface::surface_commit(Resource *) m_damage = m_pending.damage; if (m_pending.buffer || m_pending.newlyAttached) { - if (m_backBuffer && m_backBuffer != m_pending.buffer) - m_backBuffer->disown(); - setBackBuffer(m_pending.buffer); - if (!m_backBuffer && m_surfaceMapped) { + if (!m_buffer && m_surfaceMapped) { m_surfaceMapped = false; emit m_waylandSurface->unmapped(); } + + m_bufferRef = QWaylandBufferRef(m_buffer); + + if (m_attacher) + m_attacher->attach(m_bufferRef); + emit m_waylandSurface->configure(); } m_pending.buffer = 0; @@ -484,13 +424,13 @@ void Surface::surface_commit(Resource *) m_pending.newlyAttached = false; m_pending.damage = QRegion(); - if (m_backBuffer) - m_backBuffer->setCommitted(); + if (m_buffer) + m_buffer->setCommitted(); m_frameCallbacks << m_pendingFrameCallbacks; m_pendingFrameCallbacks.clear(); - emit m_waylandSurface->committed(); + emit m_waylandSurface->redraw(); } void Surface::frameStarted() diff --git a/src/compositor/wayland_wrapper/qwlsurface_p.h b/src/compositor/wayland_wrapper/qwlsurface_p.h index 6d911e915..12984a1f2 100644 --- a/src/compositor/wayland_wrapper/qwlsurface_p.h +++ b/src/compositor/wayland_wrapper/qwlsurface_p.h @@ -45,6 +45,7 @@ #include <private/qwlsurfacebuffer_p.h> #include <QtCompositor/qwaylandsurface.h> +#include <QtCompositor/qwaylandbufferref.h> #include <QtCore/QVector> #include <QtCore/QRect> @@ -54,10 +55,6 @@ #include <QtCore/QTextStream> #include <QtCore/QMetaType> -#ifdef QT_COMPOSITOR_WAYLAND_GL -#include <QtGui/qopengl.h> -#endif - #include <wayland-util.h> #include <QtCompositor/private/qwayland-server-wayland.h> @@ -79,7 +76,7 @@ class FrameCallback; class Q_COMPOSITOR_EXPORT Surface : public QtWaylandServer::wl_surface { public: - Surface(struct wl_client *client, uint32_t id, Compositor *compositor); + Surface(struct wl_client *client, uint32_t id, QWaylandCompositor *compositor, QWaylandSurface *surface); ~Surface(); static Surface *fromResource(struct ::wl_resource *resource); @@ -101,12 +98,6 @@ public: QRegion inputRegion() const; QRegion opaqueRegion() const; - QImage image() const; - -#ifdef QT_COMPOSITOR_WAYLAND_GL - GLuint textureId() const; -#endif - void sendFrameCallback(); void removeFrameCallback(FrameCallback *callback); @@ -140,20 +131,37 @@ public: bool isCursorSurface() const { return m_isCursorSurface; } void setCursorSurface(bool isCursor) { m_isCursorSurface = isCursor; } - void swapBuffers(); void releaseSurfaces(); void frameStarted(); -private: + inline bool isDestroyed() const { return m_destroyed; } + +protected: + void surface_destroy_resource(Resource *resource) Q_DECL_OVERRIDE; + + void surface_destroy(Resource *resource) Q_DECL_OVERRIDE; + void surface_attach(Resource *resource, + struct wl_resource *buffer, int x, int y) Q_DECL_OVERRIDE; + void surface_damage(Resource *resource, + int32_t x, int32_t y, int32_t width, int32_t height) Q_DECL_OVERRIDE; + void surface_frame(Resource *resource, + uint32_t callback) Q_DECL_OVERRIDE; + void surface_set_opaque_region(Resource *resource, + struct wl_resource *region) Q_DECL_OVERRIDE; + void surface_set_input_region(Resource *resource, + struct wl_resource *region) Q_DECL_OVERRIDE; + void surface_commit(Resource *resource) Q_DECL_OVERRIDE; + Q_DISABLE_COPY(Surface) Compositor *m_compositor; QWaylandSurface *m_waylandSurface; - SurfaceBuffer *m_backBuffer; QRegion m_damage; - SurfaceBuffer *m_frontBuffer; + SurfaceBuffer *m_buffer; + QWaylandBufferRef m_bufferRef; bool m_surfaceMapped; + QWaylandBufferAttacher *m_attacher; struct { SurfaceBuffer *buffer; @@ -184,32 +192,12 @@ private: QString m_title; bool m_transientInactive; bool m_isCursorSurface; + bool m_destroyed; - inline SurfaceBuffer *currentSurfaceBuffer() const; void setBackBuffer(SurfaceBuffer *buffer); SurfaceBuffer *createSurfaceBuffer(struct ::wl_resource *buffer); - - void surface_destroy_resource(Resource *resource) Q_DECL_OVERRIDE; - - void surface_destroy(Resource *resource) Q_DECL_OVERRIDE; - void surface_attach(Resource *resource, - struct wl_resource *buffer, int x, int y) Q_DECL_OVERRIDE; - void surface_damage(Resource *resource, - int32_t x, int32_t y, int32_t width, int32_t height) Q_DECL_OVERRIDE; - void surface_frame(Resource *resource, - uint32_t callback) Q_DECL_OVERRIDE; - void surface_set_opaque_region(Resource *resource, - struct wl_resource *region) Q_DECL_OVERRIDE; - void surface_set_input_region(Resource *resource, - struct wl_resource *region) Q_DECL_OVERRIDE; - void surface_commit(Resource *resource) Q_DECL_OVERRIDE; - }; -inline SurfaceBuffer *Surface::currentSurfaceBuffer() const { - return m_backBuffer? m_backBuffer : m_frontBuffer; -} - } QT_END_NAMESPACE diff --git a/src/compositor/wayland_wrapper/qwlsurfacebuffer.cpp b/src/compositor/wayland_wrapper/qwlsurfacebuffer.cpp index b0e67e1fa..3ed469a6c 100644 --- a/src/compositor/wayland_wrapper/qwlsurfacebuffer.cpp +++ b/src/compositor/wayland_wrapper/qwlsurfacebuffer.cpp @@ -100,8 +100,6 @@ void SurfaceBuffer::initialize(struct ::wl_resource *buffer) void SurfaceBuffer::destructBufferState() { - destroyTexture(); - if (m_buffer) { sendRelease(); @@ -239,24 +237,23 @@ QImage SurfaceBuffer::image() return m_image; } -void SurfaceBuffer::bufferWasDestroyed() -{ - destroyTexture(); - m_destroyed = true; - m_buffer = 0; -} - void SurfaceBuffer::destroy_listener_callback(wl_listener *listener, void *data) { Q_UNUSED(data); struct surface_buffer_destroy_listener *destroy_listener = reinterpret_cast<struct surface_buffer_destroy_listener *>(listener); SurfaceBuffer *d = destroy_listener->surfaceBuffer; - d->m_compositor->bufferWasDestroyed(d); + + // Mark the buffer as destroyed and clear m_buffer right away to avoid + // touching it before it is properly cleaned up. + d->m_destroyed = true; + d->m_buffer = 0; } void SurfaceBuffer::createTexture() { + destroyTexture(); + ClientBufferIntegration *hwIntegration = m_compositor->clientBufferIntegration(); #ifdef QT_COMPOSITOR_WAYLAND_GL if (!m_texture) @@ -271,6 +268,22 @@ void SurfaceBuffer::createTexture() #endif } +bool SurfaceBuffer::isYInverted() const +{ + bool ret = false; + static bool negateReturn = qgetenv("QT_COMPOSITOR_NEGATE_INVERTED_Y").toInt(); + ClientBufferIntegration *clientBufferIntegration = m_compositor->clientBufferIntegration(); + +#ifdef QT_COMPOSITOR_WAYLAND_GL + if (clientBufferIntegration && waylandBufferHandle() && isShmBuffer()) { + ret = clientBufferIntegration->isYInverted(waylandBufferHandle()); + } else +#endif + ret = true; + + return ret != negateReturn; +} + } QT_END_NAMESPACE diff --git a/src/compositor/wayland_wrapper/qwlsurfacebuffer_p.h b/src/compositor/wayland_wrapper/qwlsurfacebuffer_p.h index c2c39253a..26993b5d0 100644 --- a/src/compositor/wayland_wrapper/qwlsurfacebuffer_p.h +++ b/src/compositor/wayland_wrapper/qwlsurfacebuffer_p.h @@ -44,12 +44,14 @@ #include <QtCore/QRect> #include <QtGui/qopengl.h> #include <QImage> +#include <QAtomicInt> #include <wayland-server.h> QT_BEGIN_NAMESPACE class QWaylandClientBufferIntegration; +class QWaylandBufferRef; namespace QtWayland { @@ -75,6 +77,7 @@ public: QSize size() const; bool isShmBuffer() const; + bool isYInverted() const; inline bool isRegisteredWithBuffer() const { return m_is_registered_for_buffer; } @@ -131,10 +134,13 @@ private: mutable bool m_isSizeResolved; mutable QSize m_size; + QAtomicInt m_refCount; QImage m_image; static void destroy_listener_callback(wl_listener *listener, void *data); + + friend class ::QWaylandBufferRef; }; GLuint SurfaceBuffer::texture() const diff --git a/src/compositor/wayland_wrapper/qwltouch.cpp b/src/compositor/wayland_wrapper/qwltouch.cpp index 2a4070e5e..d160bc4bf 100644 --- a/src/compositor/wayland_wrapper/qwltouch.cpp +++ b/src/compositor/wayland_wrapper/qwltouch.cpp @@ -54,10 +54,15 @@ Touch::Touch(Compositor *compositor) , m_grab(this) { m_grab->setTouch(this); + connect(&m_focusDestroyListener, &WlListener::fired, this, &Touch::focusDestroyed); } void Touch::setFocus(Surface *surface) { + m_focusDestroyListener.reset(); + if (surface) + m_focusDestroyListener.listenForDestruction(surface->resource()->handle); + m_focus = surface; m_focusResource = surface ? resourceMap().value(surface->resource()->client()) : 0; } @@ -73,6 +78,15 @@ void Touch::endGrab() m_grab = this; } +void Touch::focusDestroyed(void *data) +{ + Q_UNUSED(data) + m_focusDestroyListener.reset(); + + m_focus = 0; + m_focusResource = 0; +} + void Touch::sendCancel() { if (m_focusResource) diff --git a/src/compositor/wayland_wrapper/qwltouch_p.h b/src/compositor/wayland_wrapper/qwltouch_p.h index 695609809..fc6b4d0e3 100644 --- a/src/compositor/wayland_wrapper/qwltouch_p.h +++ b/src/compositor/wayland_wrapper/qwltouch_p.h @@ -45,9 +45,12 @@ #include <QtCompositor/qwaylandexport.h> #include <QtCore/QPoint> +#include <QtCore/QObject> #include <QtCompositor/private/qwayland-server-wayland.h> +#include "qwllistener_p.h" + QT_BEGIN_NAMESPACE namespace QtWayland { @@ -73,7 +76,7 @@ private: Touch *m_touch; }; -class Q_COMPOSITOR_EXPORT Touch : public QtWaylandServer::wl_touch, public TouchGrabber +class Q_COMPOSITOR_EXPORT Touch : public QObject, public QtWaylandServer::wl_touch, public TouchGrabber { public: explicit Touch(Compositor *compositor); @@ -95,10 +98,13 @@ public: void motion(uint32_t time, int touch_id, const QPointF &position); private: + void focusDestroyed(void *data); + Compositor *m_compositor; Surface *m_focus; Resource *m_focusResource; + WlListener m_focusDestroyListener; TouchGrabber *m_grab; }; diff --git a/src/compositor/wayland_wrapper/wayland_wrapper.pri b/src/compositor/wayland_wrapper/wayland_wrapper.pri index 3b695532c..ac34ae283 100644 --- a/src/compositor/wayland_wrapper/wayland_wrapper.pri +++ b/src/compositor/wayland_wrapper/wayland_wrapper.pri @@ -37,6 +37,7 @@ HEADERS += \ wayland_wrapper/qwltextinput_p.h \ wayland_wrapper/qwltextinputmanager_p.h \ wayland_wrapper/qwltouch_p.h \ + wayland_wrapper/qwllistener_p.h \ SOURCES += \ wayland_wrapper/qwlcompositor.cpp \ @@ -65,6 +66,7 @@ SOURCES += \ wayland_wrapper/qwltextinput.cpp \ wayland_wrapper/qwltextinputmanager.cpp \ wayland_wrapper/qwltouch.cpp \ + wayland_wrapper/qwllistener.cpp \ INCLUDEPATH += wayland_wrapper diff --git a/tests/auto/compositor/tst_compositor.cpp b/tests/auto/compositor/tst_compositor.cpp index 44fb2ff96..99f08a4e5 100644 --- a/tests/auto/compositor/tst_compositor.cpp +++ b/tests/auto/compositor/tst_compositor.cpp @@ -42,6 +42,8 @@ #include "mockclient.h" #include "testcompositor.h" +#include "qwaylandbufferref.h" + #include <QtTest/QtTest> class tst_WaylandCompositor : public QObject @@ -186,6 +188,24 @@ static void registerFrameCallback(wl_surface *surface, int *counter) void tst_WaylandCompositor::frameCallback() { + class BufferAttacher : public QWaylandBufferAttacher + { + public: + void attach(const QWaylandBufferRef &ref) Q_DECL_OVERRIDE + { + bufferRef = ref; + } + + QImage image() const + { + if (!bufferRef || !bufferRef.isShm()) + return QImage(); + return bufferRef.image(); + } + + QWaylandBufferRef bufferRef; + }; + TestCompositor compositor; MockClient client; @@ -200,7 +220,9 @@ void tst_WaylandCompositor::frameCallback() QTRY_COMPARE(compositor.surfaces.size(), 1); QWaylandSurface *waylandSurface = compositor.surfaces.at(0); - QSignalSpy damagedSpy(waylandSurface, SIGNAL(damaged(const QRect &))); + BufferAttacher attacher; + waylandSurface->setBufferAttacher(&attacher); + QSignalSpy damagedSpy(waylandSurface, SIGNAL(damaged(const QRegion &))); for (int i = 0; i < 10; ++i) { registerFrameCallback(surface, &frameCounter); @@ -209,7 +231,7 @@ void tst_WaylandCompositor::frameCallback() QTRY_COMPARE(waylandSurface->type(), QWaylandSurface::Shm); QTRY_COMPARE(damagedSpy.count(), i + 1); - QCOMPARE(waylandSurface->image(), buffer.image); + QCOMPARE(static_cast<BufferAttacher *>(waylandSurface->bufferAttacher())->image(), buffer.image); compositor.sendFrameCallbacks(QList<QWaylandSurface *>() << waylandSurface); QTRY_COMPARE(frameCounter, i + 1); |