KWayland

subcompositor_interface.cpp
1 /*
2  SPDX-FileCopyrightText: 2014 Martin Gräßlin <[email protected]>
3 
4  SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
5 */
6 #include "subcompositor_interface.h"
7 #include "display.h"
8 #include "global_p.h"
9 #include "subsurface_interface_p.h"
10 #include "surface_interface_p.h"
11 // Wayland
12 #include <wayland-server.h>
13 
14 namespace KWayland
15 {
16 namespace Server
17 {
18 class SubCompositorInterface::Private : public Global::Private
19 {
20 public:
21  Private(SubCompositorInterface *q, Display *d);
22 
23 private:
24  void bind(wl_client *client, uint32_t version, uint32_t id) override;
25  void subsurface(wl_client *client, wl_resource *resource, uint32_t id, wl_resource *surface, wl_resource *parent);
26 
27  static void unbind(wl_resource *resource);
28  static void destroyCallback(wl_client *client, wl_resource *resource);
29  static void subsurfaceCallback(wl_client *client, wl_resource *resource, uint32_t id, wl_resource *surface, wl_resource *parent);
30 
31  static Private *cast(wl_resource *r)
32  {
33  return reinterpret_cast<Private *>(wl_resource_get_user_data(r));
34  }
35 
36  SubCompositorInterface *q;
37  static const struct wl_subcompositor_interface s_interface;
38  static const quint32 s_version;
39 };
40 
41 const quint32 SubCompositorInterface::Private::s_version = 1;
42 
43 #ifndef K_DOXYGEN
44 const struct wl_subcompositor_interface SubCompositorInterface::Private::s_interface = {destroyCallback, subsurfaceCallback};
45 #endif
46 
47 SubCompositorInterface::Private::Private(SubCompositorInterface *q, Display *d)
48  : Global::Private(d, &wl_subcompositor_interface, s_version)
49  , q(q)
50 {
51 }
52 
53 void SubCompositorInterface::Private::bind(wl_client *client, uint32_t version, uint32_t id)
54 {
55  auto c = display->getConnection(client);
56  wl_resource *resource = c->createResource(&wl_subcompositor_interface, qMin(version, s_version), id);
57  if (!resource) {
58  wl_client_post_no_memory(client);
59  return;
60  }
61  wl_resource_set_implementation(resource, &s_interface, this, unbind);
62 }
63 
64 void SubCompositorInterface::Private::unbind(wl_resource *resource)
65 {
66  Q_UNUSED(resource)
67 }
68 
69 void SubCompositorInterface::Private::destroyCallback(wl_client *client, wl_resource *resource)
70 {
71  Q_UNUSED(client)
72  Q_UNUSED(resource)
73  wl_resource_destroy(resource);
74 }
75 
76 void SubCompositorInterface::Private::subsurfaceCallback(wl_client *client, wl_resource *resource, uint32_t id, wl_resource *surface, wl_resource *sparent)
77 {
78  cast(resource)->subsurface(client, resource, id, surface, sparent);
79 }
80 
81 void SubCompositorInterface::Private::subsurface(wl_client *client,
82  wl_resource *resource,
83  uint32_t id,
84  wl_resource *nativeSurface,
85  wl_resource *nativeParentSurface)
86 {
87  Q_UNUSED(client)
88  SurfaceInterface *surface = SurfaceInterface::get(nativeSurface);
89  SurfaceInterface *parentSurface = SurfaceInterface::get(nativeParentSurface);
90  if (!surface || !parentSurface) {
91  wl_resource_post_error(resource, WL_SUBCOMPOSITOR_ERROR_BAD_SURFACE, "Surface or parent surface not found");
92  return;
93  }
94  if (surface == parentSurface) {
95  wl_resource_post_error(resource, WL_SUBCOMPOSITOR_ERROR_BAD_SURFACE, "Cannot become sub composite to same surface");
96  return;
97  }
98  // TODO: add check that surface is not already used in an interface (e.g. Shell)
99  // TODO: add check that parentSurface is not a child of surface
100  SubSurfaceInterface *s = new SubSurfaceInterface(q, resource);
101  s->d_func()->create(display->getConnection(client), wl_resource_get_version(resource), id, surface, parentSurface);
102  if (!s->resource()) {
103  wl_resource_post_no_memory(resource);
104  delete s;
105  return;
106  }
107  Q_EMIT q->subSurfaceCreated(s);
108 }
109 
110 SubCompositorInterface::SubCompositorInterface(Display *display, QObject *parent)
111  : Global(new Private(this, display), parent)
112 {
113 }
114 
115 SubCompositorInterface::~SubCompositorInterface() = default;
116 
117 #ifndef K_DOXYGEN
118 const struct wl_subsurface_interface SubSurfaceInterface::Private::s_interface =
119  {resourceDestroyedCallback, setPositionCallback, placeAboveCallback, placeBelowCallback, setSyncCallback, setDeSyncCallback};
120 #endif
121 
122 SubSurfaceInterface::Private::Private(SubSurfaceInterface *q, SubCompositorInterface *compositor, wl_resource *parentResource)
123  : Resource::Private(q, compositor, parentResource, &wl_subsurface_interface, &s_interface)
124 {
125 }
126 
127 SubSurfaceInterface::Private::~Private()
128 {
129  // no need to notify the surface as it's tracking a QPointer which will be reset automatically
130  if (parent) {
131  Q_Q(SubSurfaceInterface);
132  reinterpret_cast<SurfaceInterface::Private *>(parent->d.data())->removeChild(QPointer<SubSurfaceInterface>(q));
133  }
134 }
135 
136 void SubSurfaceInterface::Private::create(ClientConnection *client, quint32 version, quint32 id, SurfaceInterface *s, SurfaceInterface *p)
137 {
138  create(client, version, id);
139  if (!resource) {
140  return;
141  }
142  surface = s;
143  parent = p;
144  Q_Q(SubSurfaceInterface);
145  surface->d_func()->subSurface = QPointer<SubSurfaceInterface>(q);
146  // copy current state to subSurfacePending state
147  // it's the reference for all new pending state which needs to be committed
148  surface->d_func()->subSurfacePending = surface->d_func()->current;
149  surface->d_func()->subSurfacePending.blurIsSet = false;
150  surface->d_func()->subSurfacePending.bufferIsSet = false;
151  surface->d_func()->subSurfacePending.childrenChanged = false;
152  surface->d_func()->subSurfacePending.contrastIsSet = false;
153  surface->d_func()->subSurfacePending.callbacks.clear();
154  surface->d_func()->subSurfacePending.inputIsSet = false;
155  surface->d_func()->subSurfacePending.inputIsInfinite = true;
156  surface->d_func()->subSurfacePending.opaqueIsSet = false;
157  surface->d_func()->subSurfacePending.shadowIsSet = false;
158  surface->d_func()->subSurfacePending.slideIsSet = false;
159  parent->d_func()->addChild(QPointer<SubSurfaceInterface>(q));
160 
161  QObject::connect(surface.data(), &QObject::destroyed, q, [this] {
162  // from spec: "If the wl_surface associated with the wl_subsurface is destroyed,
163  // the wl_subsurface object becomes inert. Note, that destroying either object
164  // takes effect immediately."
165  if (parent) {
166  Q_Q(SubSurfaceInterface);
167  reinterpret_cast<SurfaceInterface::Private *>(parent->d.data())->removeChild(QPointer<SubSurfaceInterface>(q));
168  }
169  });
170 }
171 
172 void SubSurfaceInterface::Private::commit()
173 {
174  if (scheduledPosChange) {
175  scheduledPosChange = false;
176  pos = scheduledPos;
177  scheduledPos = QPoint();
178  Q_Q(SubSurfaceInterface);
179  Q_EMIT q->positionChanged(pos);
180  }
181  if (surface) {
182  surface->d_func()->commitSubSurface();
183  }
184 }
185 
186 void SubSurfaceInterface::Private::setPositionCallback(wl_client *client, wl_resource *resource, int32_t x, int32_t y)
187 {
188  Q_UNUSED(client)
189  // TODO: is this a fixed position?
190  cast<Private>(resource)->setPosition(QPoint(x, y));
191 }
192 
193 void SubSurfaceInterface::Private::setPosition(const QPoint &p)
194 {
195  Q_Q(SubSurfaceInterface);
196  if (!q->isSynchronized()) {
197  // workaround for https://bugreports.qt.io/browse/QTBUG-52118
198  // apply directly as Qt doesn't commit the parent surface
199  pos = p;
200  Q_EMIT q->positionChanged(pos);
201  return;
202  }
203  if (scheduledPos == p) {
204  return;
205  }
206  scheduledPos = p;
207  scheduledPosChange = true;
208 }
209 
210 void SubSurfaceInterface::Private::placeAboveCallback(wl_client *client, wl_resource *resource, wl_resource *sibling)
211 {
212  Q_UNUSED(client)
213  cast<Private>(resource)->placeAbove(SurfaceInterface::get(sibling));
214 }
215 
216 void SubSurfaceInterface::Private::placeAbove(SurfaceInterface *sibling)
217 {
218  if (parent.isNull()) {
219  // TODO: raise error
220  return;
221  }
222  Q_Q(SubSurfaceInterface);
223  if (!parent->d_func()->raiseChild(QPointer<SubSurfaceInterface>(q), sibling)) {
224  wl_resource_post_error(resource, WL_SUBCOMPOSITOR_ERROR_BAD_SURFACE, "Incorrect sibling");
225  }
226 }
227 
228 void SubSurfaceInterface::Private::placeBelowCallback(wl_client *client, wl_resource *resource, wl_resource *sibling)
229 {
230  Q_UNUSED(client)
231  cast<Private>(resource)->placeBelow(SurfaceInterface::get(sibling));
232 }
233 
234 void SubSurfaceInterface::Private::placeBelow(SurfaceInterface *sibling)
235 {
236  if (parent.isNull()) {
237  // TODO: raise error
238  return;
239  }
240  Q_Q(SubSurfaceInterface);
241  if (!parent->d_func()->lowerChild(QPointer<SubSurfaceInterface>(q), sibling)) {
242  wl_resource_post_error(resource, WL_SUBCOMPOSITOR_ERROR_BAD_SURFACE, "Incorrect sibling");
243  }
244 }
245 
246 void SubSurfaceInterface::Private::setSyncCallback(wl_client *client, wl_resource *resource)
247 {
248  Q_UNUSED(client)
249  cast<Private>(resource)->setMode(Mode::Synchronized);
250 }
251 
252 void SubSurfaceInterface::Private::setDeSyncCallback(wl_client *client, wl_resource *resource)
253 {
254  Q_UNUSED(client)
255  cast<Private>(resource)->setMode(Mode::Desynchronized);
256 }
257 
258 void SubSurfaceInterface::Private::setMode(Mode m)
259 {
260  if (mode == m) {
261  return;
262  }
263  if (m == Mode::Desynchronized && (!parent->subSurface() || !parent->subSurface()->isSynchronized())) {
264  // no longer synchronized, this is like calling commit
265  if (surface) {
266  surface->d_func()->commit();
267  surface->d_func()->commitSubSurface();
268  }
269  }
270  mode = m;
271  Q_Q(SubSurfaceInterface);
272  Q_EMIT q->modeChanged(m);
273 }
274 
275 SubSurfaceInterface::SubSurfaceInterface(SubCompositorInterface *parent, wl_resource *parentResource)
276  : Resource(new Private(this, parent, parentResource))
277 {
278  Q_UNUSED(parent)
279 }
280 
281 SubSurfaceInterface::~SubSurfaceInterface() = default;
282 
283 QPoint SubSurfaceInterface::position() const
284 {
285  Q_D();
286  return d->pos;
287 }
288 
289 QPointer<SurfaceInterface> SubSurfaceInterface::surface()
290 {
291  // TODO: remove with ABI break (KF6)
292  Q_D();
293  return d->surface;
294 }
295 
296 QPointer<SurfaceInterface> SubSurfaceInterface::surface() const
297 {
298  Q_D();
299  return d->surface;
300 }
301 
302 QPointer<SurfaceInterface> SubSurfaceInterface::parentSurface()
303 {
304  // TODO: remove with ABI break (KF6)
305  Q_D();
306  return d->parent;
307 }
308 
309 QPointer<SurfaceInterface> SubSurfaceInterface::parentSurface() const
310 {
311  Q_D();
312  return d->parent;
313 }
314 
315 SubSurfaceInterface::Mode SubSurfaceInterface::mode() const
316 {
317  Q_D();
318  return d->mode;
319 }
320 
321 bool SubSurfaceInterface::isSynchronized() const
322 {
323  Q_D();
324  if (d->mode == Mode::Synchronized) {
325  return true;
326  }
327  if (d->parent.isNull()) {
328  // that shouldn't happen, but let's assume false
329  return false;
330  }
331  if (!d->parent->subSurface().isNull()) {
332  // follow parent's mode
333  return d->parent->subSurface()->isSynchronized();
334  }
335  // parent is no subsurface, thus parent is in desync mode and this surface is in desync mode
336  return false;
337 }
338 
339 QPointer<SurfaceInterface> SubSurfaceInterface::mainSurface() const
340 {
341  Q_D();
342  if (!d->parent) {
344  }
345  if (d->parent->d_func()->subSurface) {
346  return d->parent->d_func()->subSurface->mainSurface();
347  }
348  return d->parent;
349 }
350 
351 SubSurfaceInterface::Private *SubSurfaceInterface::d_func() const
352 {
353  return reinterpret_cast<SubSurfaceInterface::Private *>(d.data());
354 }
355 
356 }
357 }
QAction * create(StandardAction id, const QObject *recvr, Func slot, QObject *parent)
void clear()
T * data() const const
bool isNull() const const
QMetaObject::Connection connect(const QObject *sender, const char *signal, const QObject *receiver, const char *method, Qt::ConnectionType type)
QObject * parent() const const
void destroyed(QObject *obj)
Q_EMITQ_EMIT
This file is part of the KDE documentation.
Documentation copyright © 1996-2021 The KDE developers.
Generated on Thu Sep 23 2021 22:51:10 by doxygen 1.8.11 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.