Blur protocol in KWayland

a protocol to activate the blur behind windows and to
optionally set a sub region of the window where to apply
the blur to, in case the window is shaped
REVIEW:125015
This commit is contained in:
Marco Martin 2015-08-26 14:42:58 +02:00
parent 029c18ae5c
commit 4c3aa31cd3
11 changed files with 532 additions and 0 deletions

View file

@ -21,6 +21,7 @@ set(SERVER_LIB_SRCS
resource.cpp
seat_interface.cpp
shadow_interface.cpp
blur_interface.cpp
shell_interface.cpp
surface_interface.cpp
subcompositor_interface.cpp
@ -57,6 +58,11 @@ ecm_add_wayland_server_protocol(SERVER_LIB_SRCS
BASENAME shadow
)
ecm_add_wayland_server_protocol(SERVER_LIB_SRCS
PROTOCOL ${KWAYLAND_SOURCE_DIR}/src/client/protocols/blur.xml
BASENAME blur
)
add_library(KF5WaylandServer ${SERVER_LIB_SRCS})
generate_export_header(KF5WaylandServer
BASE_NAME
@ -92,6 +98,7 @@ install(TARGETS KF5WaylandServer EXPORT KF5WaylandTargets ${KF5_INSTALL_TARGETS_
install(FILES
${CMAKE_CURRENT_BINARY_DIR}/KWayland/Server/kwaylandserver_export.h
blur_interface.h
buffer_interface.h
clientconnection.h
compositor_interface.h

View file

@ -135,6 +135,17 @@ target_link_libraries( testRegion Qt5::Test Qt5::Gui KF5::WaylandClient KF5::Way
add_test(kwayland-testRegion testRegion)
ecm_mark_as_test(testRegion)
########################################################
# Test Blur
########################################################
set( testBlur_SRCS
test_wayland_blur.cpp
)
add_executable(testBlur ${testBlur_SRCS})
target_link_libraries( testBlur Qt5::Test Qt5::Gui KF5::WaylandClient KF5::WaylandServer)
add_test(kwayland-testBlur testBlur)
ecm_mark_as_test(testBlur)
########################################################
# Test DataSource
########################################################

View file

@ -0,0 +1,169 @@
/********************************************************************
Copyright 2014 Martin Gräßlin <mgraesslin@kde.org>
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) version 3, or any
later version accepted by the membership of KDE e.V. (or its
successor approved by the membership of KDE e.V.), which shall
act as a proxy defined in Section 6 of version 3 of the license.
This library 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
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library. If not, see <http://www.gnu.org/licenses/>.
*********************************************************************/
// Qt
#include <QtTest/QtTest>
// KWin
#include "../../src/client/compositor.h"
#include "../../src/client/connection_thread.h"
#include "../../src/client/event_queue.h"
#include "../../src/client/region.h"
#include "../../src/client/registry.h"
#include "../../src/client/surface.h"
#include "../../src/client/blur.h"
#include "../../src/server/display.h"
#include "../../src/server/compositor_interface.h"
#include "../../src/server/region_interface.h"
#include "../../src/server/blur_interface.h"
class TestBlur : public QObject
{
Q_OBJECT
public:
explicit TestBlur(QObject *parent = nullptr);
private Q_SLOTS:
void init();
void cleanup();
void testCreate();
private:
KWayland::Server::Display *m_display;
KWayland::Server::CompositorInterface *m_compositorInterface;
KWayland::Server::BlurManagerInterface *m_blurManagerInterface;
KWayland::Client::ConnectionThread *m_connection;
KWayland::Client::Compositor *m_compositor;
KWayland::Client::BlurManager *m_blurManager;
KWayland::Client::EventQueue *m_queue;
QThread *m_thread;
KWayland::Client::Registry m_registry;
};
static const QString s_socketName = QStringLiteral("kwayland-test-wayland-blur-0");
TestBlur::TestBlur(QObject *parent)
: QObject(parent)
, m_display(nullptr)
, m_compositorInterface(nullptr)
, m_connection(nullptr)
, m_compositor(nullptr)
, m_queue(nullptr)
, m_thread(nullptr)
{
}
void TestBlur::init()
{
using namespace KWayland::Server;
delete m_display;
m_display = new Display(this);
m_display->setSocketName(s_socketName);
m_display->start();
QVERIFY(m_display->isRunning());
// setup connection
m_connection = new KWayland::Client::ConnectionThread;
QSignalSpy connectedSpy(m_connection, SIGNAL(connected()));
m_connection->setSocketName(s_socketName);
m_thread = new QThread(this);
m_connection->moveToThread(m_thread);
m_thread->start();
m_connection->initConnection();
QVERIFY(connectedSpy.wait());
m_queue = new KWayland::Client::EventQueue(this);
QVERIFY(!m_queue->isValid());
m_queue->setup(m_connection);
QVERIFY(m_queue->isValid());
QSignalSpy compositorSpy(&m_registry, SIGNAL(compositorAnnounced(quint32,quint32)));
QVERIFY(compositorSpy.isValid());
QSignalSpy blurSpy(&m_registry, SIGNAL(blurAnnounced(quint32,quint32)));
QVERIFY(blurSpy.isValid());
QVERIFY(!m_registry.eventQueue());
m_registry.setEventQueue(m_queue);
QCOMPARE(m_registry.eventQueue(), m_queue);
m_registry.create(m_connection->display());
QVERIFY(m_registry.isValid());
m_registry.setup();
m_compositorInterface = m_display->createCompositor(m_display);
m_compositorInterface->create();
QVERIFY(m_compositorInterface->isValid());
QVERIFY(compositorSpy.wait());
m_compositor = m_registry.createCompositor(compositorSpy.first().first().value<quint32>(), compositorSpy.first().last().value<quint32>(), this);
m_blurManagerInterface = m_display->createBlurManager(m_display);
m_blurManagerInterface->create();
QVERIFY(m_blurManagerInterface->isValid());
QVERIFY(blurSpy.wait());
m_blurManager = m_registry.createBlurManager(blurSpy.first().first().value<quint32>(), blurSpy.first().last().value<quint32>(), this);
}
void TestBlur::cleanup()
{
if (m_compositor) {
delete m_compositor;
m_compositor = nullptr;
}
if (m_queue) {
delete m_queue;
m_queue = nullptr;
}
if (m_thread) {
m_thread->quit();
m_thread->wait();
delete m_thread;
m_thread = nullptr;
}
delete m_connection;
m_connection = nullptr;
delete m_display;
m_display = nullptr;
}
void TestBlur::testCreate()
{
QSignalSpy serverSurfaceCreated(m_compositorInterface, SIGNAL(surfaceCreated(KWayland::Server::SurfaceInterface*)));
QVERIFY(serverSurfaceCreated.isValid());
QScopedPointer<KWayland::Client::Surface> surface(m_compositor->createSurface());
QVERIFY(serverSurfaceCreated.wait());
auto serverSurface = serverSurfaceCreated.first().first().value<KWayland::Server::SurfaceInterface*>();
QSignalSpy blurChanged(serverSurface, SIGNAL(blurChanged()));
auto blur = m_blurManager->createBlur(surface.data(), surface.data());
blur->setRegion(m_compositor->createRegion(QRegion(0, 0, 10, 20), nullptr));
blur->commit();
surface->commit(KWayland::Client::Surface::CommitFlag::None);
QVERIFY(blurChanged.wait());
QCOMPARE(serverSurface->blur()->region(), QRegion(0, 0, 10, 20));
}
QTEST_MAIN(TestBlur)
#include "test_wayland_blur.moc"

View file

@ -34,6 +34,7 @@ License along with this library. If not, see <http://www.gnu.org/licenses/>.
#include "../../src/server/output_interface.h"
#include "../../src/server/seat_interface.h"
#include "../../src/server/shell_interface.h"
#include "../../src/server/blur_interface.h"
#include "../../src/server/subcompositor_interface.h"
// Wayland
#include <wayland-client-protocol.h>
@ -55,6 +56,7 @@ private Q_SLOTS:
void testBindSeat();
void testBindSubCompositor();
void testBindDataDeviceManager();
void testBindBlurManager();
void testGlobalSync();
void testGlobalSyncThreaded();
void testRemoval();
@ -103,6 +105,7 @@ void TestWaylandRegistry::init()
m_subcompositor->create();
m_dataDeviceManager = m_display->createDataDeviceManager();
m_dataDeviceManager->create();
m_display->createBlurManager(this)->create();
}
void TestWaylandRegistry::cleanup()
@ -205,6 +208,11 @@ void TestWaylandRegistry::testBindDataDeviceManager()
TEST_BIND(KWayland::Client::Registry::Interface::DataDeviceManager, SIGNAL(dataDeviceManagerAnnounced(quint32,quint32)), bindDataDeviceManager, wl_data_device_manager_destroy)
}
void TestWaylandRegistry::testBindBlurManager()
{
TEST_BIND(KWayland::Client::Registry::Interface::Blur, SIGNAL(blurAnnounced(quint32,quint32)), bindBlurManager, free)
}
#undef TEST_BIND
void TestWaylandRegistry::testRemoval()

View file

@ -0,0 +1,217 @@
/********************************************************************
Copyright 2015 Martin Gräßlin <mgraesslin@kde.org>
Copyright 2015 Marco Martin <mart@kde.org>
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) version 3, or any
later version accepted by the membership of KDE e.V. (or its
successor approved by the membership of KDE e.V.), which shall
act as a proxy defined in Section 6 of version 3 of the license.
This library 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
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library. If not, see <http://www.gnu.org/licenses/>.
*********************************************************************/
#include "blur_interface.h"
#include "region_interface.h"
#include "display.h"
#include "global_p.h"
#include "resource_p.h"
#include "surface_interface_p.h"
#include <wayland-server.h>
#include <wayland-blur-server-protocol.h>
namespace KWayland
{
namespace Server
{
static const quint32 s_version = 1;
class BlurManagerInterface::Private : public Global::Private
{
public:
Private(BlurManagerInterface *q, Display *d);
private:
void bind(wl_client *client, uint32_t version, uint32_t id) override;
void createBlur(wl_client *client, wl_resource *resource, uint32_t id, wl_resource *surface);
static void createCallback(wl_client *client, wl_resource *resource, uint32_t id, wl_resource *surface);
static void unsetCallback(wl_client *client, wl_resource *resource, wl_resource *surface);
static void unbind(wl_resource *resource);
static Private *cast(wl_resource *r) {
return reinterpret_cast<Private*>(wl_resource_get_user_data(r));
}
BlurManagerInterface *q;
static const struct org_kde_kwin_blur_manager_interface s_interface;
};
const struct org_kde_kwin_blur_manager_interface BlurManagerInterface::Private::s_interface = {
createCallback,
unsetCallback
};
BlurManagerInterface::Private::Private(BlurManagerInterface *q, Display *d)
: Global::Private(d, &org_kde_kwin_blur_manager_interface, s_version)
, q(q)
{
}
void BlurManagerInterface::Private::bind(wl_client *client, uint32_t version, uint32_t id)
{
auto c = display->getConnection(client);
wl_resource *resource = c->createResource(&org_kde_kwin_blur_manager_interface, qMin(version, s_version), id);
if (!resource) {
wl_client_post_no_memory(client);
return;
}
wl_resource_set_implementation(resource, &s_interface, this, unbind);
// TODO: should we track?
}
void BlurManagerInterface::Private::unbind(wl_resource *resource)
{
Q_UNUSED(resource)
// TODO: implement?
}
void BlurManagerInterface::Private::createCallback(wl_client *client, wl_resource *resource, uint32_t id, wl_resource *surface)
{
cast(resource)->createBlur(client, resource, id, surface);
}
void BlurManagerInterface::Private::createBlur(wl_client *client, wl_resource *resource, uint32_t id, wl_resource *surface)
{
SurfaceInterface *s = SurfaceInterface::get(surface);
if (!s) {
return;
}
BlurInterface *blur = new BlurInterface(q, resource);
blur->create(display->getConnection(client), wl_resource_get_version(resource), id);
if (!blur->resource()) {
wl_resource_post_no_memory(resource);
delete blur;
return;
}
QObject::connect(s, &QObject::destroyed, blur,
[blur] {
if (blur->resource()) {
wl_resource_destroy(blur->resource());
delete blur;
}
}
);
s->d_func()->setBlur(QPointer<BlurInterface>(blur));
}
void BlurManagerInterface::Private::unsetCallback(wl_client *client, wl_resource *resource, wl_resource *surface)
{
Q_UNUSED(client)
Q_UNUSED(resource)
SurfaceInterface *s = SurfaceInterface::get(surface);
if (!s) {
return;
}
s->d_func()->setBlur(QPointer<BlurInterface>());
}
BlurManagerInterface::BlurManagerInterface(Display *display, QObject *parent)
: Global(new Private(this, display), parent)
{
}
BlurManagerInterface::~BlurManagerInterface() = default;
class BlurInterface::Private : public Resource::Private
{
public:
Private(BlurInterface *q, BlurManagerInterface *c, wl_resource *parentResource);
~Private();
QRegion pendingRegion;
QRegion currentRegion;
private:
void commit();
//TODO
BlurInterface *q_func() {
return reinterpret_cast<BlurInterface *>(q);
}
static void commitCallback(wl_client *client, wl_resource *resource);
static void setRegionCallback(wl_client *client, wl_resource *resource, wl_resource *region);
static const struct org_kde_kwin_blur_interface s_interface;
};
const struct org_kde_kwin_blur_interface BlurInterface::Private::s_interface = {
commitCallback,
setRegionCallback
};
void BlurInterface::Private::commitCallback(wl_client *client, wl_resource *resource)
{
Q_UNUSED(client)
cast<Private>(resource)->commit();
}
void BlurInterface::Private::commit()
{
currentRegion = pendingRegion;
}
void BlurInterface::Private::setRegionCallback(wl_client *client, wl_resource *resource, wl_resource *region)
{
Q_UNUSED(client)
Private *p = cast<Private>(resource);
RegionInterface *r = RegionInterface::get(region);
if (r) {
p->pendingRegion = r->region();
} else {
p->pendingRegion = QRegion();
}
}
BlurInterface::Private::Private(BlurInterface *q, BlurManagerInterface *c, wl_resource *parentResource)
: Resource::Private(q, c, parentResource, &org_kde_kwin_blur_interface, &s_interface)
{
}
BlurInterface::Private::~Private()
{
if (resource) {
wl_resource_destroy(resource);
resource = nullptr;
}
}
BlurInterface::BlurInterface(BlurManagerInterface *parent, wl_resource *parentResource)
: Resource(new Private(this, parent, parentResource))
{
}
BlurInterface::~BlurInterface() = default;
QRegion BlurInterface::region()
{
Q_D();
return d->currentRegion;
}
BlurInterface::Private *BlurInterface::d_func() const
{
return reinterpret_cast<Private*>(d.data());
}
}
}

View file

@ -0,0 +1,73 @@
/********************************************************************
Copyright 2015 Martin Gräßlin <mgraesslin@kde.org>
Copyright 2015 Marco Martin <mart@kde.org>
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) version 3, or any
later version accepted by the membership of KDE e.V. (or its
successor approved by the membership of KDE e.V.), which shall
act as a proxy defined in Section 6 of version 3 of the license.
This library 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
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library. If not, see <http://www.gnu.org/licenses/>.
*********************************************************************/
#ifndef KWAYLAND_SERVER_BLUR_INTERFACE_H
#define KWAYLAND_SERVER_BLUR_INTERFACE_H
#include "global.h"
#include "resource.h"
#include <QObject>
#include <QMarginsF>
#include <KWayland/Server/kwaylandserver_export.h>
struct wl_region;
namespace KWayland
{
namespace Server
{
class BufferInterface;
class Display;
class KWAYLANDSERVER_EXPORT BlurManagerInterface : public Global
{
Q_OBJECT
public:
virtual ~BlurManagerInterface();
private:
explicit BlurManagerInterface(Display *display, QObject *parent = nullptr);
friend class Display;
class Private;
};
class KWAYLANDSERVER_EXPORT BlurInterface : public Resource
{
Q_OBJECT
public:
virtual ~BlurInterface();
QRegion region();
private:
explicit BlurInterface(BlurManagerInterface *parent, wl_resource *parentResource);
friend class BlurManagerInterface;
class Private;
Private *d_func() const;
};
}
}
#endif

View file

@ -29,6 +29,7 @@ License along with this library. If not, see <http://www.gnu.org/licenses/>.
#include "qtsurfaceextension_interface.h"
#include "seat_interface.h"
#include "shadow_interface.h"
#include "blur_interface.h"
#include "shell_interface.h"
#include "subcompositor_interface.h"
@ -271,6 +272,13 @@ ShadowManagerInterface *Display::createShadowManager(QObject *parent)
return s;
}
BlurManagerInterface *Display::createBlurManager(QObject *parent)
{
auto b = new BlurManagerInterface(this, parent);
connect(this, &Display::aboutToTerminate, b, [this, b] { delete b; });
return b;
}
void Display::createShm()
{
Q_ASSERT(d->display);

View file

@ -46,6 +46,7 @@ class PlasmaWindowManagementInterface;
class QtSurfaceExtensionInterface;
class SeatInterface;
class ShadowManagerInterface;
class BlurManagerInterface;
class ShellInterface;
class SubCompositorInterface;
@ -126,6 +127,7 @@ public:
IdleInterface *createIdle(QObject *parent = nullptr);
FakeInputInterface *createFakeInput(QObject *parent = nullptr);
ShadowManagerInterface *createShadowManager(QObject *parent = nullptr);
BlurManagerInterface *createBlurManager(QObject *parent = nullptr);
/**
* Gets the ClientConnection for the given @p client.

View file

@ -130,6 +130,12 @@ void SurfaceInterface::Private::setShadow(const QPointer<ShadowInterface> &shado
pending.shadowIsSet = true;
}
void SurfaceInterface::Private::setBlur(const QPointer<BlurInterface> &blur)
{
pending.blur = blur;
pending.blurIsSet = true;
}
const struct wl_surface_interface SurfaceInterface::Private::s_interface = {
destroyCallback,
attachCallback,
@ -186,6 +192,7 @@ void SurfaceInterface::Private::commit()
const bool scaleFactorChanged = current.scale != pending.scale;
const bool transformFactorChanged = current.transform != pending.transform;
const bool shadowChanged = pending.shadowIsSet;
const bool blurChanged = pending.blurIsSet;
bool sizeChanged = false;
auto buffer = current.buffer;
if (bufferChanged) {
@ -207,6 +214,10 @@ void SurfaceInterface::Private::commit()
if (shadowChanged) {
shadow = pending.shadow;
}
auto blur = current.blur;
if (blurChanged) {
blur = pending.blur;
}
QList<wl_resource*> callbacks = current.callbacks;
callbacks.append(pending.callbacks);
// copy values
@ -214,6 +225,7 @@ void SurfaceInterface::Private::commit()
current.buffer = buffer;
current.callbacks = callbacks;
current.shadow = shadow;
current.blur = blur;
pending = State{};
pending.children = current.children;
pending.input = current.input;
@ -255,6 +267,9 @@ void SurfaceInterface::Private::commit()
if (shadowChanged) {
emit q->shadowChanged();
}
if (blurChanged) {
emit q->blurChanged();
}
}
void SurfaceInterface::Private::damage(const QRect &rect)
@ -480,6 +495,12 @@ QPointer< ShadowInterface > SurfaceInterface::shadow() const
return d->current.shadow;
}
QPointer< BlurInterface > SurfaceInterface::blur() const
{
Q_D();
return d->current.blur;
}
SurfaceInterface::Private *SurfaceInterface::d_func() const
{
return reinterpret_cast<Private*>(d.data());

View file

@ -33,6 +33,8 @@ namespace KWayland
{
namespace Server
{
class BlurManagerInterface;
class BlurInterface;
class BufferInterface;
class CompositorInterface;
class ShadowManagerInterface;
@ -82,6 +84,12 @@ public:
**/
QPointer<ShadowInterface> shadow() const;
/**
* @returns The Blur for this Surface.
* @since 5.5
**/
QPointer<BlurInterface> blur() const;
static SurfaceInterface *get(wl_resource *native);
/**
* @returns The SurfaceInterface with given @p id for @p client, if it exists, otherwise @c nullptr.
@ -107,11 +115,16 @@ Q_SIGNALS:
* @since 5.4
**/
void shadowChanged();
/**
* @since 5.5
**/
void blurChanged();
private:
friend class CompositorInterface;
friend class SubSurfaceInterface;
friend class ShadowManagerInterface;
friend class BlurManagerInterface;
explicit SurfaceInterface(CompositorInterface *parent, wl_resource *parentResource);
class Private;

View file

@ -41,6 +41,7 @@ public:
bool opaqueIsSet = false;
bool bufferIsSet = false;
bool shadowIsSet = false;
bool blurIsSet = false;
bool inputIsInfinite = true;
qint32 scale = 1;
OutputInterface::Transform transform = OutputInterface::Transform::Normal;
@ -50,6 +51,7 @@ public:
// stacking order: bottom (first) -> top (last)
QList<QPointer<SubSurfaceInterface>> children;
QPointer<ShadowInterface> shadow;
QPointer<BlurInterface> blur;
};
Private(SurfaceInterface *q, CompositorInterface *c, wl_resource *parentResource);
~Private();
@ -61,6 +63,7 @@ public:
bool raiseChild(QPointer<SubSurfaceInterface> subsurface, SurfaceInterface *sibling);
bool lowerChild(QPointer<SubSurfaceInterface> subsurface, SurfaceInterface *sibling);
void setShadow(const QPointer<ShadowInterface> &shadow);
void setBlur(const QPointer<BlurInterface> &blur);
State current;
State pending;