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

KDE's Doxygen guidelines are available online.