KWayland

shell.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 "shell.h"
7 #include "event_queue.h"
8 #include "output.h"
9 #include "seat.h"
10 #include "surface.h"
11 #include "wayland_pointer_p.h"
12 // Qt
13 #include <QGuiApplication>
14 #include <QVector>
15 #include <qpa/qplatformnativeinterface.h>
16 // Wayland
17 #include <wayland-client-protocol.h>
18 
19 namespace KWayland
20 {
21 namespace Client
22 {
23 class Q_DECL_HIDDEN Shell::Private
24 {
25 public:
26  WaylandPointer<wl_shell, wl_shell_destroy> shell;
27  EventQueue *queue = nullptr;
28 };
29 
30 Shell::Shell(QObject *parent)
31  : QObject(parent)
32  , d(new Private)
33 {
34 }
35 
36 Shell::~Shell()
37 {
38  release();
39 }
40 
41 void Shell::destroy()
42 {
43  if (!d->shell) {
44  return;
45  }
46  Q_EMIT interfaceAboutToBeDestroyed();
47  d->shell.destroy();
48 }
49 
50 void Shell::release()
51 {
52  if (!d->shell) {
53  return;
54  }
55  Q_EMIT interfaceAboutToBeReleased();
56  d->shell.release();
57 }
58 
59 void Shell::setup(wl_shell *shell)
60 {
61  Q_ASSERT(!d->shell);
62  Q_ASSERT(shell);
63  d->shell.setup(shell);
64 }
65 
66 void Shell::setEventQueue(EventQueue *queue)
67 {
68  d->queue = queue;
69 }
70 
71 EventQueue *Shell::eventQueue()
72 {
73  return d->queue;
74 }
75 
76 ShellSurface *Shell::createSurface(wl_surface *surface, QObject *parent)
77 {
78  Q_ASSERT(isValid());
79  ShellSurface *s = new ShellSurface(parent);
80  connect(this, &Shell::interfaceAboutToBeReleased, s, &ShellSurface::release);
81  connect(this, &Shell::interfaceAboutToBeDestroyed, s, &ShellSurface::destroy);
82  auto w = wl_shell_get_shell_surface(d->shell, surface);
83  if (d->queue) {
84  d->queue->addProxy(w);
85  }
86  s->setup(w);
87  return s;
88 }
89 
90 ShellSurface *Shell::createSurface(Surface *surface, QObject *parent)
91 {
92  Q_ASSERT(surface);
93  return createSurface(*surface, parent);
94 }
95 
96 bool Shell::isValid() const
97 {
98  return d->shell.isValid();
99 }
100 
101 Shell::operator wl_shell *()
102 {
103  return d->shell;
104 }
105 
106 Shell::operator wl_shell *() const
107 {
108  return d->shell;
109 }
110 
111 class Q_DECL_HIDDEN ShellSurface::Private
112 {
113 public:
114  Private(ShellSurface *q);
115  void setup(wl_shell_surface *surface);
116 
117  WaylandPointer<wl_shell_surface, wl_shell_surface_destroy> surface;
118  QSize size;
119  static QVector<ShellSurface *> s_surfaces;
120 
121 private:
122  void ping(uint32_t serial);
123  static void pingCallback(void *data, struct wl_shell_surface *shellSurface, uint32_t serial);
124  static void configureCallback(void *data, struct wl_shell_surface *shellSurface, uint32_t edges, int32_t width, int32_t height);
125  static void popupDoneCallback(void *data, struct wl_shell_surface *shellSurface);
126 
127  ShellSurface *q;
128  static const struct wl_shell_surface_listener s_listener;
129 };
130 
131 QVector<ShellSurface *> ShellSurface::Private::s_surfaces = QVector<ShellSurface *>();
132 
133 ShellSurface::Private::Private(ShellSurface *q)
134  : q(q)
135 {
136 }
137 
138 void ShellSurface::Private::setup(wl_shell_surface *s)
139 {
140  Q_ASSERT(s);
141  Q_ASSERT(!surface);
142  surface.setup(s);
143  wl_shell_surface_add_listener(surface, &s_listener, this);
144 }
145 
146 ShellSurface *ShellSurface::fromWindow(QWindow *window)
147 {
148  if (!window) {
149  return nullptr;
150  }
151  QPlatformNativeInterface *native = qApp->platformNativeInterface();
152  if (!native) {
153  return nullptr;
154  }
155  window->create();
156  wl_shell_surface *s = reinterpret_cast<wl_shell_surface *>(native->nativeResourceForWindow(QByteArrayLiteral("wl_shell_surface"), window));
157  if (!s) {
158  return nullptr;
159  }
160  if (auto surface = get(s)) {
161  return surface;
162  }
163  ShellSurface *surface = new ShellSurface(window);
164  surface->d->surface.setup(s, true);
165  return surface;
166 }
167 
168 ShellSurface *ShellSurface::fromQtWinId(WId wid)
169 {
170  QWindow *window = nullptr;
171 
172  for (auto win : qApp->allWindows()) {
173  if (win->winId() == wid) {
174  window = win;
175  break;
176  }
177  }
178 
179  if (!window) {
180  return nullptr;
181  }
182  return fromWindow(window);
183 }
184 
185 ShellSurface *ShellSurface::get(wl_shell_surface *native)
186 {
187  auto it = std::find_if(Private::s_surfaces.constBegin(), Private::s_surfaces.constEnd(), [native](ShellSurface *s) {
188  return s->d->surface == native;
189  });
190  if (it != Private::s_surfaces.constEnd()) {
191  return *(it);
192  }
193  return nullptr;
194 }
195 
196 ShellSurface::ShellSurface(QObject *parent)
197  : QObject(parent)
198  , d(new Private(this))
199 {
200  Private::s_surfaces << this;
201 }
202 
203 ShellSurface::~ShellSurface()
204 {
205  Private::s_surfaces.removeOne(this);
206  release();
207 }
208 
209 void ShellSurface::release()
210 {
211  d->surface.release();
212 }
213 
214 void ShellSurface::destroy()
215 {
216  d->surface.destroy();
217 }
218 
219 #ifndef K_DOXYGEN
220 const struct wl_shell_surface_listener ShellSurface::Private::s_listener = {pingCallback, configureCallback, popupDoneCallback};
221 #endif
222 
223 void ShellSurface::Private::configureCallback(void *data, wl_shell_surface *shellSurface, uint32_t edges, int32_t width, int32_t height)
224 {
225  Q_UNUSED(edges)
226  auto s = reinterpret_cast<ShellSurface::Private *>(data);
227  Q_ASSERT(s->surface == shellSurface);
228  s->q->setSize(QSize(width, height));
229 }
230 
231 void ShellSurface::Private::pingCallback(void *data, wl_shell_surface *shellSurface, uint32_t serial)
232 {
233  auto s = reinterpret_cast<ShellSurface::Private *>(data);
234  Q_ASSERT(s->surface == shellSurface);
235  s->ping(serial);
236 }
237 
238 void ShellSurface::Private::popupDoneCallback(void *data, wl_shell_surface *shellSurface)
239 {
240  auto s = reinterpret_cast<ShellSurface::Private *>(data);
241  Q_ASSERT(s->surface == shellSurface);
242  Q_EMIT s->q->popupDone();
243 }
244 
245 void ShellSurface::setup(wl_shell_surface *surface)
246 {
247  d->setup(surface);
248 }
249 
250 void ShellSurface::Private::ping(uint32_t serial)
251 {
252  wl_shell_surface_pong(surface, serial);
253  Q_EMIT q->pinged();
254 }
255 
256 void ShellSurface::setSize(const QSize &size)
257 {
258  if (d->size == size) {
259  return;
260  }
261  d->size = size;
262  Q_EMIT sizeChanged(size);
263 }
264 
265 void ShellSurface::setFullscreen(Output *output)
266 {
267  Q_ASSERT(isValid());
268  wl_shell_surface_set_fullscreen(d->surface, WL_SHELL_SURFACE_FULLSCREEN_METHOD_DEFAULT, 0, output ? output->output() : nullptr);
269 }
270 
271 void ShellSurface::setMaximized(Output *output)
272 {
273  Q_ASSERT(isValid());
274  wl_shell_surface_set_maximized(d->surface, output ? output->output() : nullptr);
275 }
276 
277 void ShellSurface::setToplevel()
278 {
279  Q_ASSERT(isValid());
280  wl_shell_surface_set_toplevel(d->surface);
281 }
282 
283 void ShellSurface::setTransient(Surface *parent, const QPoint &offset, TransientFlags flags)
284 {
285  Q_ASSERT(isValid());
286  uint32_t wlFlags = 0;
287  if (flags.testFlag(TransientFlag::NoFocus)) {
288  wlFlags |= WL_SHELL_SURFACE_TRANSIENT_INACTIVE;
289  }
290  wl_shell_surface_set_transient(d->surface, *parent, offset.x(), offset.y(), wlFlags);
291 }
292 
293 void ShellSurface::setTransientPopup(Surface *parent, Seat *grabbedSeat, quint32 grabSerial, const QPoint &offset, TransientFlags flags)
294 {
295  Q_ASSERT(isValid());
296  Q_ASSERT(parent);
297  Q_ASSERT(grabbedSeat);
298  uint32_t wlFlags = 0;
299  if (flags.testFlag(TransientFlag::NoFocus)) {
300  wlFlags |= WL_SHELL_SURFACE_TRANSIENT_INACTIVE;
301  }
302  wl_shell_surface_set_popup(d->surface, *grabbedSeat, grabSerial, *parent, offset.x(), offset.y(), wlFlags);
303 }
304 
305 void ShellSurface::requestMove(Seat *seat, quint32 serial)
306 {
307  Q_ASSERT(isValid());
308  Q_ASSERT(seat);
309 
310  wl_shell_surface_move(d->surface, *seat, serial);
311 }
312 
313 void ShellSurface::requestResize(Seat *seat, quint32 serial, Qt::Edges edges)
314 {
315  Q_ASSERT(isValid());
316  Q_ASSERT(seat);
317 
318  uint wlEdge = WL_SHELL_SURFACE_RESIZE_NONE;
319  if (edges.testFlag(Qt::TopEdge)) {
320  if (edges.testFlag(Qt::LeftEdge) && ((edges & ~Qt::LeftEdge) == Qt::TopEdge)) {
321  wlEdge = WL_SHELL_SURFACE_RESIZE_TOP_LEFT;
322  } else if (edges.testFlag(Qt::RightEdge) && ((edges & ~Qt::RightEdge) == Qt::TopEdge)) {
323  wlEdge = WL_SHELL_SURFACE_RESIZE_TOP_RIGHT;
324  } else if ((edges & ~Qt::TopEdge) == Qt::Edges()) {
325  wlEdge = WL_SHELL_SURFACE_RESIZE_TOP;
326  }
327  } else if (edges.testFlag(Qt::BottomEdge)) {
328  if (edges.testFlag(Qt::LeftEdge) && ((edges & ~Qt::LeftEdge) == Qt::BottomEdge)) {
329  wlEdge = WL_SHELL_SURFACE_RESIZE_BOTTOM_LEFT;
330  } else if (edges.testFlag(Qt::RightEdge) && ((edges & ~Qt::RightEdge) == Qt::BottomEdge)) {
331  wlEdge = WL_SHELL_SURFACE_RESIZE_BOTTOM_RIGHT;
332  } else if ((edges & ~Qt::BottomEdge) == Qt::Edges()) {
333  wlEdge = WL_SHELL_SURFACE_RESIZE_BOTTOM;
334  }
335  } else if (edges.testFlag(Qt::RightEdge) && ((edges & ~Qt::RightEdge) == Qt::Edges())) {
336  wlEdge = WL_SHELL_SURFACE_RESIZE_RIGHT;
337  } else if (edges.testFlag(Qt::LeftEdge) && ((edges & ~Qt::LeftEdge) == Qt::Edges())) {
338  wlEdge = WL_SHELL_SURFACE_RESIZE_LEFT;
339  }
340 
341  wl_shell_surface_resize(d->surface, *seat, serial, wlEdge);
342 }
343 
344 void ShellSurface::setTitle(const QString &title)
345 {
346  wl_shell_surface_set_title(d->surface, title.toUtf8().constData());
347 }
348 
349 void ShellSurface::setWindowClass(const QByteArray &windowClass)
350 {
351  wl_shell_surface_set_class(d->surface, windowClass.constData());
352 }
353 
354 QSize ShellSurface::size() const
355 {
356  return d->size;
357 }
358 
359 bool ShellSurface::isValid() const
360 {
361  return d->surface.isValid();
362 }
363 
364 ShellSurface::operator wl_shell_surface *()
365 {
366  return d->surface;
367 }
368 
369 ShellSurface::operator wl_shell_surface *() const
370 {
371  return d->surface;
372 }
373 
374 }
375 }
bool isValid() const const
typedef Edges
void setup(wl_shell_surface *surface)
Setup this ShellSurface to manage the surface.
Definition: shell.cpp:245
Wrapper class for wl_event_queue interface.
Definition: event_queue.h:54
Wrapper for the wl_seat interface.
Definition: seat.h:51
Wrapper for the wl_output interface.
Definition: output.h:54
void create()
int x() const const
int y() const const
Wrapper for the wl_surface interface.
Definition: surface.h:43
const char * constData() const const
Wrapper for the wl_shell_surface interface.
Definition: shell.h:166
QObject(QObject *parent)
QMetaObject::Connection connect(const QObject *sender, const char *signal, const QObject *receiver, const char *method, Qt::ConnectionType type)
QObject * parent() const const
bool testFlag(Enum flag) const const
Q_EMITQ_EMIT
void pinged()
Signal is emitted when the ShellSurface received a ping request.
QByteArray toUtf8() const const
This file is part of the KDE documentation.
Documentation copyright © 1996-2021 The KDE developers.
Generated on Sun Sep 26 2021 22:51:14 by doxygen 1.8.11 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.