diff --git a/src/wayland/compositor_interface.cpp b/src/wayland/compositor_interface.cpp new file mode 100644 index 0000000000..b6e098d5d3 --- /dev/null +++ b/src/wayland/compositor_interface.cpp @@ -0,0 +1,117 @@ +/******************************************************************** + KWin - the KDE window manager + This file is part of the KDE project. + +Copyright (C) 2014 Martin Gräßlin + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . +*********************************************************************/ +#include "compositor_interface.h" +#include "display.h" +#include "surface_interface.h" + +namespace KWin +{ +namespace WaylandServer +{ + +static const quint32 s_version = 3; + +const struct wl_compositor_interface CompositorInterface::s_interface = { + CompositorInterface::createSurfaceCallback, + CompositorInterface::createRegionCallback +}; + +CompositorInterface::CompositorInterface(Display *display, QObject *parent) + : QObject(parent) + , m_display(display) + , m_compositor(nullptr) +{ +} + +CompositorInterface::~CompositorInterface() +{ + destroy(); +} + +void CompositorInterface::create() +{ + Q_ASSERT(!m_compositor); + m_compositor = wl_global_create(*m_display, &wl_compositor_interface, s_version, this, CompositorInterface::bind); +} + +void CompositorInterface::destroy() +{ + if (!m_compositor) { + return; + } + wl_global_destroy(m_compositor); + m_compositor = nullptr; +} + +void CompositorInterface::bind(wl_client *client, void *data, uint32_t version, uint32_t id) +{ + CompositorInterface *compositor = reinterpret_cast(data); + compositor->bind(client, version, id); +} + +void CompositorInterface::bind(wl_client *client, uint32_t version, uint32_t id) +{ + wl_resource *resource = wl_resource_create(client, &wl_compositor_interface, qMin(version, s_version), id); + if (!resource) { + wl_client_post_no_memory(client); + return; + } + wl_resource_set_implementation(resource, &CompositorInterface::s_interface, this, CompositorInterface::unbind); + // TODO: should we track? +} + +void CompositorInterface::unbind(wl_resource *resource) +{ + Q_UNUSED(resource) + // TODO: implement? +} + +void CompositorInterface::createSurfaceCallback(wl_client *client, wl_resource *resource, uint32_t id) +{ + CompositorInterface::cast(resource)->createSurface(client, resource, id); +} + +void CompositorInterface::createSurface(wl_client *client, wl_resource *resource, uint32_t id) +{ + SurfaceInterface *surface = new SurfaceInterface(this); + surface->create(client, wl_resource_get_version(resource), id); + if (!surface->surface()) { + wl_resource_post_no_memory(resource); + delete surface; + return; + } + emit surfaceCreated(surface); +} + +void CompositorInterface::createRegionCallback(wl_client *client, wl_resource *resource, uint32_t id) +{ + CompositorInterface::cast(resource)->createRegion(client, resource, id); +} + +void CompositorInterface::createRegion(wl_client *client, wl_resource *resource, uint32_t id) +{ + Q_UNUSED(client) + Q_UNUSED(resource) + Q_UNUSED(id) + // TODO: implement +} + +} +} diff --git a/src/wayland/compositor_interface.h b/src/wayland/compositor_interface.h new file mode 100644 index 0000000000..476883c12e --- /dev/null +++ b/src/wayland/compositor_interface.h @@ -0,0 +1,73 @@ +/******************************************************************** + KWin - the KDE window manager + This file is part of the KDE project. + +Copyright (C) 2014 Martin Gräßlin + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . +*********************************************************************/ +#ifndef KWIN_WAYLAND_SERVER_COMPOSITOR_INTERFACE_H +#define KWIN_WAYLAND_SERVER_COMPOSITOR_INTERFACE_H + +#include "surface_interface.h" + +#include + +#include + +namespace KWin +{ +namespace WaylandServer +{ + +class Display; +class SurfaceInterface; + +class CompositorInterface : public QObject +{ + Q_OBJECT +public: + virtual ~CompositorInterface(); + + void create(); + void destroy(); + bool isValid() const { + return m_compositor != nullptr; + } + +Q_SIGNALS: + void surfaceCreated(KWin::WaylandServer::SurfaceInterface*); + +private: + explicit CompositorInterface(Display *display, QObject *parent = nullptr); + friend class Display; + static void bind(wl_client *client, void *data, uint32_t version, uint32_t id); + static void unbind(wl_resource *resource); + static void createSurfaceCallback(wl_client *client, wl_resource *resource, uint32_t id); + static void createRegionCallback(wl_client *client, wl_resource *resource, uint32_t id); + void bind(wl_client *client, uint32_t version, uint32_t id); + void createSurface(wl_client *client, wl_resource *resource, uint32_t id); + void createRegion(wl_client *client, wl_resource *resource, uint32_t id); + static CompositorInterface *cast(wl_resource *r) { + return reinterpret_cast(wl_resource_get_user_data(r)); + } + static const struct wl_compositor_interface s_interface; + Display *m_display; + wl_global *m_compositor; +}; + +} +} + +#endif diff --git a/src/wayland/display.cpp b/src/wayland/display.cpp index af4b410ffe..06210ee33c 100644 --- a/src/wayland/display.cpp +++ b/src/wayland/display.cpp @@ -18,6 +18,7 @@ You should have received a copy of the GNU General Public License along with this program. If not, see . *********************************************************************/ #include "display.h" +#include "compositor_interface.h" #include "output_interface.h" #include @@ -123,6 +124,13 @@ OutputInterface *Display::createOutput(QObject *parent) return output; } +CompositorInterface *Display::createCompositor(QObject *parent) +{ + CompositorInterface *compositor = new CompositorInterface(this, parent); + connect(this, &Display::aboutToTerminate, compositor, [this,compositor] { delete compositor; }); + return compositor; +} + void Display::removeOutput(OutputInterface *output) { m_outputs.removeAll(output); diff --git a/src/wayland/display.h b/src/wayland/display.h index c63dbe2a18..d18d9c09ad 100644 --- a/src/wayland/display.h +++ b/src/wayland/display.h @@ -31,6 +31,7 @@ namespace KWin namespace WaylandServer { +class CompositorInterface; class OutputInterface; class Display : public QObject @@ -64,6 +65,8 @@ public: return m_outputs; } + CompositorInterface *createCompositor(QObject *parent = nullptr); + Q_SIGNALS: void socketNameChanged(const QString&); void runningChanged(bool); diff --git a/src/wayland/surface_interface.cpp b/src/wayland/surface_interface.cpp new file mode 100644 index 0000000000..ea0343c95e --- /dev/null +++ b/src/wayland/surface_interface.cpp @@ -0,0 +1,223 @@ +/******************************************************************** + KWin - the KDE window manager + This file is part of the KDE project. + +Copyright (C) 2014 Martin Gräßlin + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . +*********************************************************************/ +#include "surface_interface.h" +#include "compositor_interface.h" + +namespace KWin +{ +namespace WaylandServer +{ + +const struct wl_surface_interface SurfaceInterface::s_interface = { + SurfaceInterface::destroyCallback, + SurfaceInterface::attachCallback, + SurfaceInterface::damageCallback, + SurfaceInterface::frameCallaback, + SurfaceInterface::opaqueRegionCallback, + SurfaceInterface::inputRegionCallback, + SurfaceInterface::commitCallback, + SurfaceInterface::bufferTransformCallback, + SurfaceInterface::bufferScaleCallback +}; + +SurfaceInterface::SurfaceInterface(CompositorInterface *parent) + : QObject(parent) + , m_compositor(parent) + , m_surface(nullptr) + , m_client(nullptr) +{ +} + +SurfaceInterface::~SurfaceInterface() +{ + destroy(); +} + +void SurfaceInterface::create(wl_client *client, quint32 version, quint32 id) +{ + Q_ASSERT(!m_surface); + Q_ASSERT(!m_client); + m_client = client; + m_surface = wl_resource_create(client, &wl_surface_interface, version, id); + if (!m_surface) { + return; + } + wl_resource_set_implementation(m_surface, &SurfaceInterface::s_interface, this, SurfaceInterface::unbind); +} + +void SurfaceInterface::frameRendered(quint32 msec) +{ + // notify all callbacks + while (!m_current.callbacks.isEmpty()) { + wl_resource *r = m_current.callbacks.takeFirst(); + wl_callback_send_done(r, msec); + wl_resource_destroy(r); + } +} + +void SurfaceInterface::unbind(wl_resource *r) +{ + SurfaceInterface *s = SurfaceInterface::cast(r); + s->m_surface = nullptr; + s->deleteLater(); +} + +void SurfaceInterface::destroy() +{ + for (wl_resource *c : m_current.callbacks) { + wl_resource_destroy(c); + } + for (wl_resource *c : m_pending.callbacks) { + wl_resource_destroy(c); + } + if (m_surface) { + wl_resource_destroy(m_surface); + m_surface = nullptr; + } +} + +void SurfaceInterface::commit() +{ + for (wl_resource *c : m_current.callbacks) { + wl_resource_destroy(c); + } + const bool opaqueRegionChanged = m_current.opaque != m_pending.opaque; + const bool inputRegionChanged = m_current.input != m_pending.input; + const bool scaleFactorChanged = m_current.scale != m_pending.scale; + const bool transformFactorChanged = m_current.transform != m_pending.transform; + // copy values + m_current = m_pending; + m_pending = State{}; + if (opaqueRegionChanged) { + emit opaqueChanged(m_current.opaque); + } + if (inputRegionChanged) { + emit inputChanged(m_current.input); + } + if (scaleFactorChanged) { + emit scaleChanged(m_current.scale); + } + if (transformFactorChanged) { + emit transformChanged(m_current.transform); + } + if (!m_current.damage.isEmpty()) { + emit damaged(m_current.damage); + } +} + +void SurfaceInterface::damage(const QRect &rect) +{ + // TODO: documentation says we need to remove the parts outside of the surface + m_pending.damage = m_pending.damage.united(rect); +} + +void SurfaceInterface::setScale(qint32 scale) +{ + m_pending.scale = scale; +} + +void SurfaceInterface::setTransform(OutputInterface::Transform transform) +{ + m_pending.transform = transform; +} + +void SurfaceInterface::addFrameCallback(uint32_t callback) +{ + wl_resource *r = wl_resource_create(m_client, &wl_callback_interface, 1, callback); + if (!r) { + wl_resource_post_no_memory(m_surface); + return; + } + wl_resource_set_implementation(r, nullptr, this, destroyFrameCallback); + m_pending.callbacks << r; +} + +void SurfaceInterface::destroyFrameCallback(wl_resource *r) +{ + SurfaceInterface *s = SurfaceInterface::cast(r); + s->m_current.callbacks.removeAll(r); + s->m_pending.callbacks.removeAll(r); +} + +void SurfaceInterface::destroyCallback(wl_client *client, wl_resource *resource) +{ + Q_UNUSED(client) + SurfaceInterface::cast(resource)->deleteLater(); +} + +void SurfaceInterface::attachCallback(wl_client *client, wl_resource *resource, wl_resource *buffer, int32_t sx, int32_t sy) +{ + Q_UNUSED(client) + Q_UNUSED(resource) + Q_UNUSED(buffer) + Q_UNUSED(sx) + Q_UNUSED(sy) + // TODO: implement me +} + +void SurfaceInterface::damageCallback(wl_client *client, wl_resource *resource, int32_t x, int32_t y, int32_t width, int32_t height) +{ + Q_UNUSED(client) + SurfaceInterface::cast(resource)->damage(QRect(x, y, width, height)); +} + +void SurfaceInterface::frameCallaback(wl_client *client, wl_resource *resource, uint32_t callback) +{ + SurfaceInterface *s = SurfaceInterface::cast(resource); + Q_ASSERT(client == s->m_client); + s->addFrameCallback(callback); +} + +void SurfaceInterface::opaqueRegionCallback(wl_client *client, wl_resource *resource, wl_resource *region) +{ + Q_UNUSED(client) + Q_UNUSED(resource) + Q_UNUSED(region) + // TODO: implement me +} + +void SurfaceInterface::inputRegionCallback(wl_client *client, wl_resource *resource, wl_resource *region) +{ + Q_UNUSED(client) + Q_UNUSED(resource) + Q_UNUSED(region) + // TODO: implement me +} + +void SurfaceInterface::commitCallback(wl_client *client, wl_resource *resource) +{ + Q_UNUSED(client) + SurfaceInterface::cast(resource)->commit(); +} + +void SurfaceInterface::bufferTransformCallback(wl_client *client, wl_resource *resource, int32_t transform) +{ + Q_UNUSED(client) + SurfaceInterface::cast(resource)->setTransform(OutputInterface::Transform(transform)); +} + +void SurfaceInterface::bufferScaleCallback(wl_client *client, wl_resource *resource, int32_t scale) +{ + Q_UNUSED(client) + SurfaceInterface::cast(resource)->setScale(scale); +} + +} +} diff --git a/src/wayland/surface_interface.h b/src/wayland/surface_interface.h new file mode 100644 index 0000000000..659105e4e7 --- /dev/null +++ b/src/wayland/surface_interface.h @@ -0,0 +1,127 @@ +/******************************************************************** + KWin - the KDE window manager + This file is part of the KDE project. + +Copyright (C) 2014 Martin Gräßlin + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . +*********************************************************************/ +#ifndef KWIN_WAYLAND_SERVER_SURFACE_INTERFACE_H +#define KWIN_WAYLAND_SERVER_SURFACE_INTERFACE_H + +#include "output_interface.h" + +#include +#include + +#include + +namespace KWin +{ +namespace WaylandServer +{ +class CompositorInterface; + +class SurfaceInterface : public QObject +{ + Q_OBJECT + Q_PROPERTY(QRegion damage READ damage NOTIFY damaged) + Q_PROPERTY(QRegion opaque READ opaque NOTIFY opaqueChanged) + Q_PROPERTY(QRegion input READ input NOTIFY inputChanged) + Q_PROPERTY(qint32 scale READ scale NOTIFY scaleChanged) + Q_PROPERTY(KWin::WaylandServer::OutputInterface::Transform transform READ transform NOTIFY transformChanged) +public: + virtual ~SurfaceInterface(); + + void create(wl_client *client, quint32 version, quint32 id); + + void frameRendered(quint32 msec); + + wl_resource *surface() const { + return m_surface; + } + wl_client *client() const { + return m_client; + } + + QRegion damage() const { + return m_current.damage; + } + QRegion opaque() const { + return m_current.opaque; + } + QRegion input() const { + return m_current.input; + } + qint32 scale() const { + return m_current.scale; + } + OutputInterface::Transform transform() const { + return m_current.transform; + } + +Q_SIGNALS: + void damaged(const QRegion&); + void opaqueChanged(const QRegion&); + void inputChanged(const QRegion&); + void scaleChanged(qint32); + void transformChanged(KWin::WaylandServer::OutputInterface::Transform); + +private: + struct State { + QRegion damage = QRegion(); + QRegion opaque = QRegion(); + QRegion input = QRegion(); + qint32 scale = 1; + OutputInterface::Transform transform = OutputInterface::Transform::Normal; + QList callbacks = QList(); + }; + friend class CompositorInterface; + explicit SurfaceInterface(CompositorInterface *parent); + static void unbind(wl_resource *r); + static void destroyFrameCallback(wl_resource *r); + + static const struct wl_surface_interface s_interface; + static void destroyCallback(wl_client *client, wl_resource *resource); + static void attachCallback(wl_client *client, wl_resource *resource, wl_resource *buffer, int32_t sx, int32_t sy); + static void damageCallback(wl_client *client, wl_resource *resource, int32_t x, int32_t y, int32_t width, int32_t height); + static void frameCallaback(wl_client *client, wl_resource *resource, uint32_t callback); + static void opaqueRegionCallback(wl_client *client, wl_resource *resource, wl_resource *region); + static void inputRegionCallback(wl_client *client, wl_resource *resource, wl_resource *region); + static void commitCallback(wl_client *client, wl_resource *resource); + // since version 2 + static void bufferTransformCallback(wl_client *client, wl_resource *resource, int32_t transform); + // since version 3 + static void bufferScaleCallback(wl_client *client, wl_resource *resource, int32_t scale); + + static SurfaceInterface *cast(wl_resource *r) { + return reinterpret_cast(wl_resource_get_user_data(r)); + } + void destroy(); + void commit(); + void damage(const QRect &rect); + void setScale(qint32 scale); + void setTransform(OutputInterface::Transform transform); + void addFrameCallback(uint32_t callback); + CompositorInterface *m_compositor; + wl_resource *m_surface; + wl_client *m_client; + State m_current; + State m_pending; +}; + +} +} + +#endif