diff --git a/src/wayland/buffer_interface.cpp b/src/wayland/buffer_interface.cpp new file mode 100644 index 0000000000..fb8e7501e2 --- /dev/null +++ b/src/wayland/buffer_interface.cpp @@ -0,0 +1,107 @@ +/******************************************************************** + 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 "buffer_interface.h" +#include "surface_interface.h" + +namespace KWin +{ +namespace WaylandServer +{ + +BufferInterface::BufferInterface(wl_resource *resource, SurfaceInterface *parent) + : QObject(parent) + , m_buffer(resource) + , m_shmBuffer(wl_shm_buffer_get(m_buffer)) + , m_surface(parent) + , m_refCount(0) +{ +} + +BufferInterface::~BufferInterface() +{ + Q_ASSERT(m_refCount == 0); + releaseImage(); +} + +void BufferInterface::releaseImage() +{ + if (m_image.isNull()) { + return; + } + // first destroy it + m_image = QImage(); + wl_shm_buffer_end_access(m_shmBuffer); +} + +void BufferInterface::ref() +{ + m_refCount++; +} + +void BufferInterface::unref() +{ + Q_ASSERT(m_refCount > 0); + m_refCount--; + if (m_refCount == 0) { + releaseImage(); + wl_buffer_send_release(m_buffer); + deleteLater(); + } +} + +QImage::Format BufferInterface::format() const +{ + switch (wl_shm_buffer_get_format(m_shmBuffer)) { + case WL_SHM_FORMAT_ARGB8888: + return QImage::Format_ARGB32; + case WL_SHM_FORMAT_XRGB8888: + return QImage::Format_RGB32; + default: + return QImage::Format_Invalid; + } +} + +QImage BufferInterface::data() +{ + if (m_image.isNull()) { + createImage(); + } + return m_image; +} + +void BufferInterface::createImage() +{ + if (!m_shmBuffer) { + return; + } + const QImage::Format imageFormat = format(); + if (imageFormat == QImage::Format_Invalid) { + return; + } + wl_shm_buffer_begin_access(m_shmBuffer); + m_image = QImage((const uchar*)wl_shm_buffer_get_data(m_shmBuffer), + wl_shm_buffer_get_width(m_shmBuffer), + wl_shm_buffer_get_height(m_shmBuffer), + wl_shm_buffer_get_stride(m_shmBuffer), + imageFormat); +} + +} +} diff --git a/src/wayland/buffer_interface.h b/src/wayland/buffer_interface.h new file mode 100644 index 0000000000..41531c4c93 --- /dev/null +++ b/src/wayland/buffer_interface.h @@ -0,0 +1,72 @@ +/******************************************************************** + 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_BUFFER_INTERFACE_H +#define KWIN_WAYLAND_SERVER_BUFFER_INTERFACE_H + +#include +#include + +struct wl_resource; +struct wl_shm_buffer; + +namespace KWin +{ +namespace WaylandServer +{ +class SurfaceInterface; + + +class BufferInterface : public QObject +{ + Q_OBJECT +public: + virtual ~BufferInterface(); + void ref(); + void unref(); + bool isReferenced() const { + return m_refCount > 0; + } + + SurfaceInterface *surface() const { + return m_surface; + } + wl_shm_buffer *shmBuffer() { + return m_shmBuffer; + } + + QImage data(); + +private: + friend class SurfaceInterface; + explicit BufferInterface(wl_resource *resource, SurfaceInterface *parent); + QImage::Format format() const; + void createImage(); + void releaseImage(); + wl_resource *m_buffer; + wl_shm_buffer *m_shmBuffer; + SurfaceInterface *m_surface; + int m_refCount; + QImage m_image; +}; + +} +} + +#endif diff --git a/src/wayland/display.cpp b/src/wayland/display.cpp index 06210ee33c..6778128704 100644 --- a/src/wayland/display.cpp +++ b/src/wayland/display.cpp @@ -131,6 +131,12 @@ CompositorInterface *Display::createCompositor(QObject *parent) return compositor; } +void Display::createShm() +{ + Q_ASSERT(m_running); + wl_display_init_shm(m_display); +} + void Display::removeOutput(OutputInterface *output) { m_outputs.removeAll(output); diff --git a/src/wayland/display.h b/src/wayland/display.h index d18d9c09ad..dc9633c7d0 100644 --- a/src/wayland/display.h +++ b/src/wayland/display.h @@ -66,6 +66,7 @@ public: } CompositorInterface *createCompositor(QObject *parent = nullptr); + void createShm(); Q_SIGNALS: void socketNameChanged(const QString&); diff --git a/src/wayland/surface_interface.cpp b/src/wayland/surface_interface.cpp index ea0343c95e..8ce1d2a93f 100644 --- a/src/wayland/surface_interface.cpp +++ b/src/wayland/surface_interface.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 "surface_interface.h" +#include "buffer_interface.h" #include "compositor_interface.h" namespace KWin @@ -87,6 +88,9 @@ void SurfaceInterface::destroy() for (wl_resource *c : m_pending.callbacks) { wl_resource_destroy(c); } + if (m_current.buffer) { + m_current.buffer->unref(); + } if (m_surface) { wl_resource_destroy(m_surface); m_surface = nullptr; @@ -102,6 +106,12 @@ void SurfaceInterface::commit() 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; + if (m_current.buffer) { + m_current.buffer->unref(); + } + if (m_pending.buffer) { + m_pending.buffer->ref(); + } // copy values m_current = m_pending; m_pending = State{}; @@ -149,6 +159,15 @@ void SurfaceInterface::addFrameCallback(uint32_t callback) m_pending.callbacks << r; } +void SurfaceInterface::attachBuffer(wl_resource *buffer, const QPoint &offset) +{ + m_pending.offset = offset; + if (m_pending.buffer) { + delete m_pending.buffer; + } + m_pending.buffer = new BufferInterface(buffer, this); +} + void SurfaceInterface::destroyFrameCallback(wl_resource *r) { SurfaceInterface *s = SurfaceInterface::cast(r); @@ -165,11 +184,7 @@ void SurfaceInterface::destroyCallback(wl_client *client, wl_resource *resource) 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 + SurfaceInterface::cast(resource)->attachBuffer(buffer, QPoint(sx, sy)); } void SurfaceInterface::damageCallback(wl_client *client, wl_resource *resource, int32_t x, int32_t y, int32_t width, int32_t height) diff --git a/src/wayland/surface_interface.h b/src/wayland/surface_interface.h index 659105e4e7..75e5cdc82c 100644 --- a/src/wayland/surface_interface.h +++ b/src/wayland/surface_interface.h @@ -31,6 +31,7 @@ namespace KWin { namespace WaylandServer { +class BufferInterface; class CompositorInterface; class SurfaceInterface : public QObject @@ -70,6 +71,12 @@ public: OutputInterface::Transform transform() const { return m_current.transform; } + BufferInterface *buffer() { + return m_current.buffer; + } + QPoint offset() const { + return m_current.offset; + } Q_SIGNALS: void damaged(const QRegion&); @@ -86,6 +93,8 @@ private: qint32 scale = 1; OutputInterface::Transform transform = OutputInterface::Transform::Normal; QList callbacks = QList(); + QPoint offset = QPoint(); + BufferInterface *buffer = nullptr; }; friend class CompositorInterface; explicit SurfaceInterface(CompositorInterface *parent); @@ -114,6 +123,7 @@ private: void setScale(qint32 scale); void setTransform(OutputInterface::Transform transform); void addFrameCallback(uint32_t callback); + void attachBuffer(wl_resource *buffer, const QPoint &offset); CompositorInterface *m_compositor; wl_resource *m_surface; wl_client *m_client;