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

KDE's Doxygen guidelines are available online.