diff options
author | Paul Olav Tvete <paul.tvete@theqtcompany.com> | 2015-12-09 14:38:30 +0100 |
---|---|---|
committer | Paul Olav Tvete <paul.tvete@theqtcompany.com> | 2016-02-04 12:08:58 +0000 |
commit | 933d69af3061e9fdfe9e9ca1ea61055aac2c0482 (patch) | |
tree | 0fccef825cf65421816d7a4104c01bd735b87495 | |
parent | 93ca929fb9caf34715012dec608afd42e6ccf1e5 (diff) |
Subsurface implementation, with C++ API
This adds support for subsurfaces to QWaylandCompositor and
QWaylandSurface.
Task-number: QTBUG-49809
Change-Id: I2fa9ee4dcd1f48a2a28dab536f9cd6edc716e42b
Reviewed-by: Giulio Camuffo <giuliocamuffo@gmail.com>
10 files changed, 186 insertions, 11 deletions
diff --git a/examples/wayland/qwindow-compositor/compositorwindow.cpp b/examples/wayland/qwindow-compositor/compositorwindow.cpp index a902a7d0d..4b69022f2 100644 --- a/examples/wayland/qwindow-compositor/compositorwindow.cpp +++ b/examples/wayland/qwindow-compositor/compositorwindow.cpp @@ -107,7 +107,8 @@ void CompositorWindow::paintGL() if (surface && surface->isMapped()) { QSize s = surface->size(); if (!s.isEmpty()) { - QRectF surfaceGeometry(view->position(), s); + QPointF pos = view->position() + view->parentPosition(); + QRectF surfaceGeometry(pos, s); QOpenGLTextureBlitter::Origin surfaceOrigin = view->currentBuffer().origin() == QWaylandSurface::OriginTopLeft ? QOpenGLTextureBlitter::OriginTopLeft diff --git a/examples/wayland/qwindow-compositor/windowcompositor.cpp b/examples/wayland/qwindow-compositor/windowcompositor.cpp index f271570de..57d6b382f 100644 --- a/examples/wayland/qwindow-compositor/windowcompositor.cpp +++ b/examples/wayland/qwindow-compositor/windowcompositor.cpp @@ -88,6 +88,8 @@ void WindowCompositor::create() connect(this, &QWaylandCompositor::surfaceCreated, this, &WindowCompositor::onSurfaceCreated); connect(defaultInputDevice(), &QWaylandInputDevice::cursorSurfaceRequest, this, &WindowCompositor::adjustCursorSurface); connect(defaultInputDevice()->drag(), &QWaylandDrag::dragStarted, this, &WindowCompositor::startDrag); + + connect(this, &QWaylandCompositor::subsurfaceChanged, this, &WindowCompositor::onSubsurfaceChanged); } void WindowCompositor::onSurfaceCreated(QWaylandSurface *surface) @@ -96,6 +98,9 @@ void WindowCompositor::onSurfaceCreated(QWaylandSurface *surface) connect(surface, &QWaylandSurface::mappedChanged, this, &WindowCompositor::surfaceMappedChanged); connect(surface, &QWaylandSurface::redraw, this, &WindowCompositor::triggerRender); connect(surface, &QWaylandSurface::offsetForNextFrame, this, &WindowCompositor::frameOffset); + + connect(surface, &QWaylandSurface::subsurfacePositionChanged, this, &WindowCompositor::onSubsurfacePositionChanged); + WindowCompositorView *view = new WindowCompositorView; view->setSurface(surface); view->setOutput(outputFor(m_window)); @@ -167,9 +172,17 @@ void WindowCompositor::onStartResize(QWaylandInputDevice *, QWaylandShellSurface emit startResize(int(edges)); } -void WindowCompositor::onSetTransient(QWaylandSurface *parentSurface, const QPoint &relativeToParent, QWaylandShellSurface::FocusPolicy focusPolicy) +void WindowCompositor::onSetTransient(QWaylandSurface *parent, const QPoint &relativeToParent, QWaylandShellSurface::FocusPolicy focusPolicy) { - qDebug() << "Transient window support not implemented" << parentSurface << relativeToParent << focusPolicy; + QWaylandShellSurface *surface = qobject_cast<QWaylandShellSurface*>(sender()); + WindowCompositorView *view = findView(surface->surface()); + + if (view) { + raise(view); + WindowCompositorView *parentView = findView(parent); + if (parentView) + view->setPosition(parentView->position() + relativeToParent); + } } void WindowCompositor::onSetPopup(QWaylandInputDevice *inputDevice, QWaylandSurface *parent, const QPoint &relativeToParent) @@ -186,6 +199,23 @@ void WindowCompositor::onSetPopup(QWaylandInputDevice *inputDevice, QWaylandSurf } } +void WindowCompositor::onSubsurfaceChanged(QWaylandSurface *child, QWaylandSurface *parent) +{ + WindowCompositorView *view = findView(child); + WindowCompositorView *parentView = findView(parent); + view->setParentView(parentView); +} + +void WindowCompositor::onSubsurfacePositionChanged(const QPoint &position) +{ + QWaylandSurface *surface = qobject_cast<QWaylandSurface*>(sender()); + if (!surface) + return; + WindowCompositorView *view = findView(surface); + view->setPosition(position); + triggerRender(); +} + void WindowCompositor::triggerRender() { m_window->requestUpdate(); @@ -288,8 +318,35 @@ void WindowCompositor::handleDrag(WindowCompositorView *target, QMouseEvent *me) currentDrag->drop(); } +// We only have a flat list of views, plus pointers from child to parent, +// so maintaining a stacking order gets a bit complex. A better data +// structure is left as an exercise for the reader. + +static int findEndOfChildTree(const QList<WindowCompositorView*> &list, int index) +{ + int n = list.count(); + WindowCompositorView *parent = list.at(index); + while (index + 1 < n) { + if (list.at(index+1)->parentView() != parent) + break; + index = findEndOfChildTree(list, index + 1); + } + return index; +} + void WindowCompositor::raise(WindowCompositorView *view) { - m_views.removeOne(view); - m_views.append(view); + int startPos = m_views.indexOf(view); + int endPos = findEndOfChildTree(m_views, startPos); + + int n = m_views.count(); + int tail = n - endPos - 1; + + //bubble sort: move the child tree to the end of the list + for (int i = 0; i < tail; i++) { + int source = endPos + 1 + i; + int dest = startPos + i; + for (int j = source; j > dest; j--) + m_views.swap(j, j-1); + } } diff --git a/examples/wayland/qwindow-compositor/windowcompositor.h b/examples/wayland/qwindow-compositor/windowcompositor.h index 98cc88f6a..7a4f90aad 100644 --- a/examples/wayland/qwindow-compositor/windowcompositor.h +++ b/examples/wayland/qwindow-compositor/windowcompositor.h @@ -56,17 +56,22 @@ class WindowCompositorView : public QWaylandView { Q_OBJECT public: - WindowCompositorView() : m_texture(0), m_shellSurface(0) {} + WindowCompositorView() : m_texture(0), m_shellSurface(0), m_parentView(0) {} GLuint getTexture(); QPointF position() const { return m_position; } void setPosition(const QPointF &pos) { m_position = pos; } bool isCursor() const; bool hasShell() const { return m_shellSurface; } + void setParentView(WindowCompositorView *parent) { m_parentView = parent; } + WindowCompositorView *parentView() const { return m_parentView; } + QPointF parentPosition() const { return m_parentView ? (m_parentView->position() + m_parentView->parentPosition()) : QPointF(); } + private: friend class WindowCompositor; GLuint m_texture; QPointF m_position; QWaylandShellSurface *m_shellSurface; + WindowCompositorView *m_parentView; }; class WindowCompositor : public QWaylandCompositor @@ -114,6 +119,9 @@ private slots: void onSetTransient(QWaylandSurface *parentSurface, const QPoint &relativeToParent, QWaylandShellSurface::FocusPolicy focusPolicy); void onSetPopup(QWaylandInputDevice *inputDevice, QWaylandSurface *parent, const QPoint &relativeToParent); + void onSubsurfaceChanged(QWaylandSurface *child, QWaylandSurface *parent); + void onSubsurfacePositionChanged(const QPoint &position); + void updateCursor(); private: WindowCompositorView *findView(const QWaylandSurface *s) const; diff --git a/examples/wayland/subsurface/main.qml b/examples/wayland/subsurface/main.qml index fa71d4b6b..8d221401b 100644 --- a/examples/wayland/subsurface/main.qml +++ b/examples/wayland/subsurface/main.qml @@ -69,4 +69,22 @@ Rectangle { anchors.horizontalCenter: parent.horizontalCenter text: syncStatus.sync ? "sync mode" : "de-sync mode" } + + // If you can see these rectangles, something's not right + Rectangle { + //Child at (150, 70, 100, 100) + color: "yellow" + x: 150 + y: 70 + width:100 + height:100 + } + Rectangle { + //Shm at (30, 30, 50, 50) + color: "yellow" + x: 30 + y: 30 + width: 50 + height: 50 + } } diff --git a/src/compositor/compositor_api/qwaylandcompositor.cpp b/src/compositor/compositor_api/qwaylandcompositor.cpp index 9aec337bd..5480b1cf1 100644 --- a/src/compositor/compositor_api/qwaylandcompositor.cpp +++ b/src/compositor/compositor_api/qwaylandcompositor.cpp @@ -158,6 +158,7 @@ void QWaylandCompositorPrivate::init() socket_name = arguments.at(socketArg + 1).toLocal8Bit(); wl_compositor::init(display, 3); + wl_subcompositor::init(display, 1); data_device_manager = new QtWayland::DataDeviceManager(q); @@ -270,7 +271,7 @@ void QWaylandCompositorPrivate::addPolishObject(QObject *object) */ -void QWaylandCompositorPrivate::compositor_create_surface(Resource *resource, uint32_t id) +void QWaylandCompositorPrivate::compositor_create_surface(wl_compositor::Resource *resource, uint32_t id) { Q_Q(QWaylandCompositor); QWaylandClient *client = QWaylandClient::fromWlClient(q, resource->client()); @@ -292,11 +293,20 @@ void QWaylandCompositorPrivate::compositor_create_surface(Resource *resource, ui emit q->surfaceCreated(surface); } -void QWaylandCompositorPrivate::compositor_create_region(Resource *resource, uint32_t id) +void QWaylandCompositorPrivate::compositor_create_region(wl_compositor::Resource *resource, uint32_t id) { new QtWayland::Region(resource->client(), id); } +void QWaylandCompositorPrivate::subcompositor_get_subsurface(wl_subcompositor::Resource *resource, uint32_t id, wl_resource *surface, wl_resource *parent) +{ + Q_Q(QWaylandCompositor); + QWaylandSurface *childSurface = QWaylandSurface::fromResource(surface); + QWaylandSurface *parentSurface = QWaylandSurface::fromResource(parent); + QWaylandSurfacePrivate::get(childSurface)->initSubsurface(parentSurface, resource->client(), id, 1); + emit q->subsurfaceChanged(childSurface, parentSurface); +} + /*! \internal Used to create a fallback QWaylandSurface when no surface was diff --git a/src/compositor/compositor_api/qwaylandcompositor.h b/src/compositor/compositor_api/qwaylandcompositor.h index cae7b4582..789832762 100644 --- a/src/compositor/compositor_api/qwaylandcompositor.h +++ b/src/compositor/compositor_api/qwaylandcompositor.h @@ -122,6 +122,7 @@ Q_SIGNALS: void createSurface(QWaylandClient *client, uint id, int version); void surfaceCreated(QWaylandSurface *surface); void surfaceAboutToBeDestroyed(QWaylandSurface *surface); + void subsurfaceChanged(QWaylandSurface *child, QWaylandSurface *parent); void defaultOutputChanged(); void defaultInputDeviceChanged(); diff --git a/src/compositor/compositor_api/qwaylandcompositor_p.h b/src/compositor/compositor_api/qwaylandcompositor_p.h index fb0f803ed..942634af5 100644 --- a/src/compositor/compositor_api/qwaylandcompositor_p.h +++ b/src/compositor/compositor_api/qwaylandcompositor_p.h @@ -69,7 +69,7 @@ namespace QtWayland { class QWindowSystemEventHandler; class QWaylandSurface; -class Q_COMPOSITOR_EXPORT QWaylandCompositorPrivate : public QObjectPrivate, public QtWaylandServer::wl_compositor +class Q_COMPOSITOR_EXPORT QWaylandCompositorPrivate : public QObjectPrivate, public QtWaylandServer::wl_compositor, public QtWaylandServer::wl_subcompositor { public: static QWaylandCompositorPrivate *get(QWaylandCompositor *compositor) { return compositor->d_func(); } @@ -105,8 +105,10 @@ public: inline void addOutput(QWaylandOutput *output); inline void removeOutput(QWaylandOutput *output); protected: - void compositor_create_surface(Resource *resource, uint32_t id) Q_DECL_OVERRIDE; - void compositor_create_region(Resource *resource, uint32_t id) Q_DECL_OVERRIDE; + void compositor_create_surface(wl_compositor::Resource *resource, uint32_t id) Q_DECL_OVERRIDE; + void compositor_create_region(wl_compositor::Resource *resource, uint32_t id) Q_DECL_OVERRIDE; + + void subcompositor_get_subsurface(wl_subcompositor::Resource *resource, uint32_t id, struct ::wl_resource *surface, struct ::wl_resource *parent); virtual QWaylandSurface *createDefaultSurface(); protected: diff --git a/src/compositor/compositor_api/qwaylandsurface.cpp b/src/compositor/compositor_api/qwaylandsurface.cpp index 9391164cf..ed028824f 100644 --- a/src/compositor/compositor_api/qwaylandsurface.cpp +++ b/src/compositor/compositor_api/qwaylandsurface.cpp @@ -130,6 +130,7 @@ QWaylandSurfacePrivate::QWaylandSurfacePrivate() , mapped(false) , isInitialized(false) , contentOrientation(Qt::PrimaryOrientation) + , subsurface(0) { pending.buffer = 0; pending.newlyAttached = false; @@ -777,4 +778,50 @@ void QWaylandSurfacePrivate::derefView(QWaylandView *view) } } +void QWaylandSurfacePrivate::initSubsurface(QWaylandSurface *parent, wl_client *client, int id, int version) +{ + Q_Q(QWaylandSurface); + QWaylandSurface *oldParent = 0; // TODO: implement support for switching parents + + subsurface = new Subsurface(this); + subsurface->init(client, id, version); + subsurface->parentSurface = parent->d_func(); + emit q->parentChanged(parent, oldParent); + emit parent->childAdded(q); +} + +void QWaylandSurfacePrivate::Subsurface::subsurface_set_position(wl_subsurface::Resource *resource, int32_t x, int32_t y) +{ + Q_UNUSED(resource); + position = QPoint(x,y); + emit surface->q_func()->subsurfacePositionChanged(position); + +} + +void QWaylandSurfacePrivate::Subsurface::subsurface_place_above(wl_subsurface::Resource *resource, struct wl_resource *sibling) +{ + Q_UNUSED(resource); + emit surface->q_func()->subsurfacePlaceAbove(QWaylandSurface::fromResource(sibling)); +} + +void QWaylandSurfacePrivate::Subsurface::subsurface_place_below(wl_subsurface::Resource *resource, struct wl_resource *sibling) +{ + Q_UNUSED(resource); + emit surface->q_func()->subsurfacePlaceBelow(QWaylandSurface::fromResource(sibling)); +} + +void QWaylandSurfacePrivate::Subsurface::subsurface_set_sync(wl_subsurface::Resource *resource) +{ + Q_UNUSED(resource); + // TODO: sync/desync implementation + qDebug() << Q_FUNC_INFO; +} + +void QWaylandSurfacePrivate::Subsurface::subsurface_set_desync(wl_subsurface::Resource *resource) +{ + Q_UNUSED(resource); + // TODO: sync/desync implementation + qDebug() << Q_FUNC_INFO; +} + QT_END_NAMESPACE diff --git a/src/compositor/compositor_api/qwaylandsurface.h b/src/compositor/compositor_api/qwaylandsurface.h index d3fe4f15e..bb034080a 100644 --- a/src/compositor/compositor_api/qwaylandsurface.h +++ b/src/compositor/compositor_api/qwaylandsurface.h @@ -129,12 +129,16 @@ Q_SIGNALS: void mappedChanged(); void damaged(const QRegion &rect); void parentChanged(QWaylandSurface *newParent, QWaylandSurface *oldParent); + void childAdded(QWaylandSurface *child); void sizeChanged(); void offsetForNextFrame(const QPoint &offset); void contentOrientationChanged(); void pong(); void surfaceDestroyed(); void originChanged(); + void subsurfacePositionChanged(const QPoint &position); + void subsurfacePlaceAbove(QWaylandSurface *sibling); + void subsurfacePlaceBelow(QWaylandSurface *sibling); void configure(bool hasBuffer); void redraw(); diff --git a/src/compositor/compositor_api/qwaylandsurface_p.h b/src/compositor/compositor_api/qwaylandsurface_p.h index 1f3676bd9..de71b7fe3 100644 --- a/src/compositor/compositor_api/qwaylandsurface_p.h +++ b/src/compositor/compositor_api/qwaylandsurface_p.h @@ -112,6 +112,11 @@ public: static void removeUninitializedSurface(QWaylandSurfacePrivate *surface); static bool hasUninitializedSurface(); #endif + + void initSubsurface(QWaylandSurface *parent, struct ::wl_client *client, int id, int version); + bool isSubsurface() const { return subsurface; } + QWaylandSurfacePrivate *parentSurface() const { return subsurface ? subsurface->parentSurface : nullptr; } + protected: void surface_destroy_resource(Resource *resource) Q_DECL_OVERRIDE; @@ -170,6 +175,28 @@ protected: //member variables Qt::ScreenOrientation contentOrientation; QWindow::Visibility visibility; + class Subsurface : public QtWaylandServer::wl_subsurface + { + public: + Subsurface(QWaylandSurfacePrivate *s) : surface(s) {} + QWaylandSurfacePrivate *surfaceFromResource(); + + protected: + void subsurface_set_position(wl_subsurface::Resource *resource, int32_t x, int32_t y); + void subsurface_place_above(wl_subsurface::Resource *resource, struct wl_resource *sibling); + void subsurface_place_below(wl_subsurface::Resource *resource, struct wl_resource *sibling); + void subsurface_set_sync(wl_subsurface::Resource *resource); + void subsurface_set_desync(wl_subsurface::Resource *resource); + + private: + friend class QWaylandSurfacePrivate; + QWaylandSurfacePrivate *surface; + QWaylandSurfacePrivate *parentSurface; + QPoint position; + }; + + Subsurface *subsurface; + #ifndef QT_NO_DEBUG static QList<QWaylandSurfacePrivate *> uninitializedSurfaces; #endif |