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

KDE's Doxygen guidelines are available online.