1/*
2 SPDX-FileCopyrightText: 2014 Martin Gräßlin <mgraesslin@kde.org>
3
4 SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
5*/
6#include "surface.h"
7#include "output.h"
8#include "region.h"
9#include "surface_p.h"
10#include "wayland_pointer_p.h"
11
12#include <QGuiApplication>
13#include <QList>
14#include <QRegion>
15// Wayland
16#include <wayland-client-protocol.h>
17
18namespace KWayland
19{
20namespace Client
21{
22
23QList<Surface *> Surface::Private::s_surfaces = QList<Surface *>();
24
25Surface::Private::Private(Surface *q)
26 : q(q)
27{
28}
29
30Surface::Surface(QObject *parent)
31 : QObject(parent)
32 , d(new Private(this))
33{
34 Private::s_surfaces << this;
35}
36
37Surface::~Surface()
38{
39 Private::s_surfaces.removeAll(t: this);
40 release();
41}
42
43
44void Surface::release()
45{
46 d->surface.release();
47}
48
49void Surface::destroy()
50{
51 d->surface.destroy();
52}
53
54void Surface::setup(wl_surface *surface)
55{
56 d->setup(surface);
57}
58
59void Surface::Private::setup(wl_surface *s)
60{
61 Q_ASSERT(s);
62 Q_ASSERT(!surface);
63 surface.setup(pointer: s);
64 wl_surface_add_listener(wl_surface: s, listener: &s_surfaceListener, data: this);
65}
66
67void Surface::Private::frameCallback(void *data, wl_callback *callback, uint32_t time)
68{
69 Q_UNUSED(time)
70 auto s = reinterpret_cast<Surface::Private *>(data);
71 if (callback) {
72 wl_callback_destroy(wl_callback: callback);
73 }
74 s->handleFrameCallback();
75}
76
77void Surface::Private::handleFrameCallback()
78{
79 frameCallbackInstalled = false;
80 Q_EMIT q->frameRendered();
81}
82
83#ifndef K_DOXYGEN
84const struct wl_callback_listener Surface::Private::s_listener = {.done: frameCallback};
85
86const struct wl_surface_listener Surface::Private::s_surfaceListener = {.enter: enterCallback, .leave: leaveCallback};
87#endif
88
89void Surface::Private::removeOutput(Output *o)
90{
91 if (o && outputs.removeOne(t: o)) {
92 Q_EMIT q->outputLeft(o);
93 }
94}
95
96void Surface::Private::enterCallback(void *data, wl_surface *surface, wl_output *output)
97{
98 Q_UNUSED(surface);
99 auto s = reinterpret_cast<Surface::Private *>(data);
100 Output *o = Output::get(native: output);
101 if (!o) {
102 return;
103 }
104 s->outputs << o;
105 QObject::connect(sender: o, signal: &Output::removed, context: s->q, slot: [s, o]() {
106 s->removeOutput(o);
107 });
108 Q_EMIT s->q->outputEntered(o);
109}
110
111void Surface::Private::leaveCallback(void *data, wl_surface *surface, wl_output *output)
112{
113 Q_UNUSED(surface);
114 auto s = reinterpret_cast<Surface::Private *>(data);
115 s->removeOutput(o: Output::get(native: output));
116}
117
118void Surface::Private::setupFrameCallback()
119{
120 Q_ASSERT(!frameCallbackInstalled);
121 wl_callback *callback = wl_surface_frame(wl_surface: surface);
122 wl_callback_add_listener(wl_callback: callback, listener: &s_listener, data: this);
123 frameCallbackInstalled = true;
124}
125
126void Surface::setupFrameCallback()
127{
128 Q_ASSERT(isValid());
129 d->setupFrameCallback();
130}
131
132void Surface::commit(Surface::CommitFlag flag)
133{
134 Q_ASSERT(isValid());
135 if (flag == CommitFlag::FrameCallback) {
136 setupFrameCallback();
137 }
138 wl_surface_commit(wl_surface: d->surface);
139}
140
141void Surface::damage(const QRegion &region)
142{
143 for (const QRect &rect : region) {
144 damage(rect);
145 }
146}
147
148void Surface::damage(const QRect &rect)
149{
150 Q_ASSERT(isValid());
151 wl_surface_damage(wl_surface: d->surface, x: rect.x(), y: rect.y(), width: rect.width(), height: rect.height());
152}
153
154void Surface::damageBuffer(const QRegion &region)
155{
156 for (const QRect &r : region) {
157 damageBuffer(rect: r);
158 }
159}
160
161void Surface::damageBuffer(const QRect &rect)
162{
163 Q_ASSERT(isValid());
164 wl_surface_damage_buffer(wl_surface: d->surface, x: rect.x(), y: rect.y(), width: rect.width(), height: rect.height());
165}
166
167void Surface::attachBuffer(wl_buffer *buffer, const QPoint &offset)
168{
169 Q_ASSERT(isValid());
170 wl_surface_attach(wl_surface: d->surface, buffer, x: offset.x(), y: offset.y());
171}
172
173void Surface::attachBuffer(Buffer *buffer, const QPoint &offset)
174{
175 attachBuffer(buffer: buffer ? buffer->buffer() : nullptr, offset);
176}
177
178void Surface::attachBuffer(Buffer::Ptr buffer, const QPoint &offset)
179{
180 attachBuffer(buffer: buffer.toStrongRef().data(), offset);
181}
182
183void Surface::setInputRegion(const Region *region)
184{
185 Q_ASSERT(isValid());
186 if (region) {
187 wl_surface_set_input_region(wl_surface: d->surface, region: *region);
188 } else {
189 wl_surface_set_input_region(wl_surface: d->surface, region: nullptr);
190 }
191}
192
193void Surface::setOpaqueRegion(const Region *region)
194{
195 Q_ASSERT(isValid());
196 if (region) {
197 wl_surface_set_opaque_region(wl_surface: d->surface, region: *region);
198 } else {
199 wl_surface_set_opaque_region(wl_surface: d->surface, region: nullptr);
200 }
201}
202
203void Surface::setSize(const QSize &size)
204{
205 if (d->size == size) {
206 return;
207 }
208 d->size = size;
209 Q_EMIT sizeChanged(d->size);
210}
211
212Surface *Surface::get(wl_surface *native)
213{
214 auto it = std::find_if(first: Private::s_surfaces.constBegin(), last: Private::s_surfaces.constEnd(), pred: [native](Surface *s) {
215 return s->d->surface == native;
216 });
217 if (it != Private::s_surfaces.constEnd()) {
218 return *(it);
219 }
220 return nullptr;
221}
222
223const QList<Surface *> &Surface::all()
224{
225 return Private::s_surfaces;
226}
227
228bool Surface::isValid() const
229{
230 return d->surface.isValid();
231}
232
233QSize Surface::size() const
234{
235 return d->size;
236}
237
238Surface::operator wl_surface *()
239{
240 return d->surface;
241}
242
243Surface::operator wl_surface *() const
244{
245 return d->surface;
246}
247
248quint32 Surface::id() const
249{
250 wl_surface *s = *this;
251 return wl_proxy_get_id(proxy: reinterpret_cast<wl_proxy *>(s));
252}
253
254qint32 Surface::scale() const
255{
256 return d->scale;
257}
258
259void Surface::setScale(qint32 scale)
260{
261 d->scale = scale;
262 wl_surface_set_buffer_scale(wl_surface: d->surface, scale);
263}
264
265QList<Output *> Surface::outputs() const
266{
267 return d->outputs;
268}
269
270}
271}
272
273#include "moc_surface.cpp"
274

source code of kwayland/src/client/surface.cpp