KWaylandServer

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

KDE's Doxygen guidelines are available online.