1 | // Copyright (C) 2018 The Qt Company Ltd. |
---|---|
2 | // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only |
3 | |
4 | #include "qwaylandxdgshell.h" |
5 | #include "qwaylandxdgshell_p.h" |
6 | |
7 | #if QT_CONFIG(wayland_compositor_quick) |
8 | #include "qwaylandxdgshellintegration_p.h" |
9 | #endif |
10 | #include <QtWaylandCompositor/private/qwaylandutils_p.h> |
11 | |
12 | #include "qwaylandxdgdialogv1_p.h" |
13 | |
14 | #include <QtWaylandCompositor/QWaylandCompositor> |
15 | #include <QtWaylandCompositor/QWaylandSeat> |
16 | #include <QtWaylandCompositor/QWaylandSurface> |
17 | #include <QtWaylandCompositor/QWaylandSurfaceRole> |
18 | #include <QtWaylandCompositor/QWaylandResource> |
19 | |
20 | #include <QtCore/QObject> |
21 | |
22 | #include <algorithm> |
23 | |
24 | QT_BEGIN_NAMESPACE |
25 | |
26 | QWaylandXdgShellPrivate::QWaylandXdgShellPrivate() |
27 | { |
28 | } |
29 | |
30 | void QWaylandXdgShellPrivate::ping(QtWaylandServer::xdg_wm_base::Resource *resource, uint32_t serial) |
31 | { |
32 | m_pings.insert(value: serial); |
33 | send_ping(resource->handle, serial); |
34 | } |
35 | |
36 | void QWaylandXdgShellPrivate::registerXdgSurface(QWaylandXdgSurface *xdgSurface) |
37 | { |
38 | m_xdgSurfaces.insert(key: xdgSurface->surface()->client()->client(), value: xdgSurface); |
39 | } |
40 | |
41 | void QWaylandXdgShellPrivate::unregisterXdgSurface(QWaylandXdgSurface *xdgSurface) |
42 | { |
43 | auto xdgSurfacePrivate = QWaylandXdgSurfacePrivate::get(xdgSurface); |
44 | if (!m_xdgSurfaces.remove(xdgSurfacePrivate->resource()->client(), xdgSurface)) |
45 | qWarning(msg: "%s Unexpected state. Can't find registered xdg surface\n", Q_FUNC_INFO); |
46 | } |
47 | |
48 | QWaylandXdgSurface *QWaylandXdgShellPrivate::xdgSurfaceFromSurface(QWaylandSurface *surface) |
49 | { |
50 | for (QWaylandXdgSurface *xdgSurface : std::as_const(t&: m_xdgSurfaces)) { |
51 | if (surface == xdgSurface->surface()) |
52 | return xdgSurface; |
53 | } |
54 | return nullptr; |
55 | } |
56 | |
57 | void QWaylandXdgShellPrivate::xdg_wm_base_destroy(Resource *resource) |
58 | { |
59 | if (!m_xdgSurfaces.values(resource->client()).empty()) |
60 | wl_resource_post_error(resource->handle, XDG_WM_BASE_ERROR_DEFUNCT_SURFACES, |
61 | "xdg_shell was destroyed before children"); |
62 | |
63 | wl_resource_destroy(resource->handle); |
64 | } |
65 | |
66 | void QWaylandXdgShellPrivate::xdg_wm_base_create_positioner(QtWaylandServer::xdg_wm_base::Resource *resource, uint32_t id) |
67 | { |
68 | QWaylandResource positionerResource(wl_resource_create(resource->client(), &xdg_positioner_interface, |
69 | wl_resource_get_version(resource->handle), id)); |
70 | |
71 | new QWaylandXdgPositioner(positionerResource); |
72 | } |
73 | |
74 | void QWaylandXdgShellPrivate::xdg_wm_base_get_xdg_surface(Resource *resource, uint32_t id, wl_resource *surfaceResource) |
75 | { |
76 | Q_Q(QWaylandXdgShell); |
77 | QWaylandSurface *surface = QWaylandSurface::fromResource(resource: surfaceResource); |
78 | |
79 | if (surface->role() != nullptr) { |
80 | wl_resource_post_error(resource->handle, XDG_WM_BASE_ERROR_ROLE, |
81 | "wl_surface@%d, already has role %s\n", |
82 | wl_resource_get_id(surface->resource()), |
83 | surface->role()->name().constData()); |
84 | return; |
85 | } |
86 | |
87 | if (surface->hasContent()) { |
88 | //TODO: According to the spec, this is a client error, but there's no appropriate error code |
89 | qWarning() << "get_xdg_surface requested on a xdg_surface with content"; |
90 | } |
91 | |
92 | QWaylandResource xdgSurfaceResource(wl_resource_create(resource->client(), &xdg_surface_interface, |
93 | wl_resource_get_version(resource->handle), id)); |
94 | |
95 | QWaylandXdgSurface *xdgSurface = new QWaylandXdgSurface(q, surface, xdgSurfaceResource); |
96 | |
97 | registerXdgSurface(xdgSurface); |
98 | emit q->xdgSurfaceCreated(xdgSurface); |
99 | } |
100 | |
101 | void QWaylandXdgShellPrivate::xdg_wm_base_pong(Resource *resource, uint32_t serial) |
102 | { |
103 | Q_UNUSED(resource); |
104 | Q_Q(QWaylandXdgShell); |
105 | if (m_pings.remove(value: serial)) |
106 | emit q->pong(serial); |
107 | else |
108 | qWarning(msg: "Received an unexpected pong!"); |
109 | } |
110 | |
111 | /*! |
112 | * \qmltype XdgShell |
113 | * \nativetype QWaylandXdgShell |
114 | * \inqmlmodule QtWayland.Compositor.XdgShell |
115 | * \since 5.12 |
116 | * \brief Provides an extension for desktop-style user interfaces. |
117 | * |
118 | * The XdgShell extension provides a way to associate a XdgToplevel or XdgPopup |
119 | * with a regular Wayland surface. Using the XdgToplevel interface, the client |
120 | * can request that the surface is resized, moved, and so on. |
121 | * |
122 | * XdgShell corresponds to the Wayland interface, \c xdg_shell. |
123 | * |
124 | * To provide the functionality of the shell extension in a compositor, create |
125 | * an instance of the XdgShell component and add it to the list of extensions |
126 | * supported by the compositor: |
127 | * |
128 | * \qml |
129 | * import QtWayland.Compositor.XdgShell |
130 | * |
131 | * WaylandCompositor { |
132 | * XdgShell { |
133 | * // ... |
134 | * } |
135 | * } |
136 | * \endqml |
137 | */ |
138 | |
139 | /*! |
140 | * \class QWaylandXdgShell |
141 | * \inmodule QtWaylandCompositor |
142 | * \since 5.12 |
143 | * \brief The QWaylandXdgShell class is an extension for desktop-style user interfaces. |
144 | * |
145 | * The QWaylandXdgShell extension provides a way to associate a QWaylandXdgToplevel or |
146 | * QWaylandXdgPopup with a regular Wayland surface. Using the QWaylandXdgToplevel interface, |
147 | * the client can request that the surface is resized, moved, and so on. |
148 | * |
149 | * QWaylandXdgShell corresponds to the Wayland interface, \c xdg_shell. |
150 | */ |
151 | |
152 | /*! |
153 | * Constructs a QWaylandXdgShell object. |
154 | */ |
155 | QWaylandXdgShell::QWaylandXdgShell() |
156 | : QWaylandShellTemplate<QWaylandXdgShell>(*new QWaylandXdgShellPrivate()) |
157 | { |
158 | } |
159 | |
160 | /*! |
161 | * Constructs a QWaylandXdgShell object for the provided \a compositor. |
162 | */ |
163 | QWaylandXdgShell::QWaylandXdgShell(QWaylandCompositor *compositor) |
164 | : QWaylandShellTemplate<QWaylandXdgShell>(compositor, *new QWaylandXdgShellPrivate()) |
165 | { |
166 | } |
167 | |
168 | /*! |
169 | * Initializes the shell extension. |
170 | */ |
171 | void QWaylandXdgShell::initialize() |
172 | { |
173 | Q_D(QWaylandXdgShell); |
174 | QWaylandShellTemplate::initialize(); |
175 | QWaylandCompositor *compositor = static_cast<QWaylandCompositor *>(extensionContainer()); |
176 | if (!compositor) { |
177 | qWarning() << "Failed to find QWaylandCompositor when initializing QWaylandXdgShell"; |
178 | return; |
179 | } |
180 | d->init(compositor->display(), 1); |
181 | |
182 | handleSeatChanged(newSeat: compositor->defaultSeat(), oldSeat: nullptr); |
183 | |
184 | connect(sender: compositor, signal: &QWaylandCompositor::defaultSeatChanged, |
185 | context: this, slot: &QWaylandXdgShell::handleSeatChanged); |
186 | |
187 | // Support the dialog extension unconditionally. |
188 | QObject *dialogExtension = new QWaylandXdgDialogV1Global(compositor); |
189 | dialogExtension->setParent(this); |
190 | } |
191 | |
192 | /*! |
193 | * Returns the Wayland interface for the QWaylandXdgShell. |
194 | */ |
195 | const struct wl_interface *QWaylandXdgShell::interface() |
196 | { |
197 | return QWaylandXdgShellPrivate::interface(); |
198 | } |
199 | |
200 | QByteArray QWaylandXdgShell::interfaceName() |
201 | { |
202 | return QWaylandXdgShellPrivate::interfaceName(); |
203 | } |
204 | |
205 | /*! |
206 | * \qmlmethod void XdgShell::ping(WaylandClient client) |
207 | * |
208 | * Sends a ping event to \a client. If the client replies to the event the |
209 | * \l pong signal will be emitted. |
210 | */ |
211 | |
212 | /*! |
213 | * Sends a ping event to \a client. If the client replies to the event the |
214 | * \l pong signal will be emitted. |
215 | */ |
216 | uint QWaylandXdgShell::ping(QWaylandClient *client) |
217 | { |
218 | Q_D(QWaylandXdgShell); |
219 | |
220 | QWaylandCompositor *compositor = static_cast<QWaylandCompositor *>(extensionContainer()); |
221 | Q_ASSERT(compositor); |
222 | |
223 | uint32_t serial = compositor->nextSerial(); |
224 | |
225 | QWaylandXdgShellPrivate::Resource *clientResource = d->resourceMap().value(client->client(), nullptr); |
226 | Q_ASSERT(clientResource); |
227 | |
228 | d->ping(clientResource, serial); |
229 | return serial; |
230 | } |
231 | |
232 | void QWaylandXdgShell::handleSeatChanged(QWaylandSeat *newSeat, QWaylandSeat *oldSeat) |
233 | { |
234 | if (oldSeat != nullptr) { |
235 | disconnect(sender: oldSeat, signal: &QWaylandSeat::keyboardFocusChanged, |
236 | receiver: this, slot: &QWaylandXdgShell::handleFocusChanged); |
237 | } |
238 | |
239 | if (newSeat != nullptr) { |
240 | connect(sender: newSeat, signal: &QWaylandSeat::keyboardFocusChanged, |
241 | context: this, slot: &QWaylandXdgShell::handleFocusChanged); |
242 | } |
243 | } |
244 | |
245 | void QWaylandXdgShell::handleFocusChanged(QWaylandSurface *newSurface, QWaylandSurface *oldSurface) |
246 | { |
247 | Q_D(QWaylandXdgShell); |
248 | |
249 | QWaylandXdgSurface *newXdgSurface = d->xdgSurfaceFromSurface(surface: newSurface); |
250 | QWaylandXdgSurface *oldXdgSurface = d->xdgSurfaceFromSurface(surface: oldSurface); |
251 | |
252 | if (newXdgSurface) |
253 | QWaylandXdgSurfacePrivate::get(xdgSurface: newXdgSurface)->handleFocusReceived(); |
254 | |
255 | if (oldXdgSurface) |
256 | QWaylandXdgSurfacePrivate::get(xdgSurface: oldXdgSurface)->handleFocusLost(); |
257 | } |
258 | |
259 | QWaylandXdgSurfacePrivate::QWaylandXdgSurfacePrivate() |
260 | { |
261 | } |
262 | |
263 | void QWaylandXdgSurfacePrivate::setWindowType(Qt::WindowType windowType) |
264 | { |
265 | if (m_windowType == windowType) |
266 | return; |
267 | |
268 | m_windowType = windowType; |
269 | |
270 | Q_Q(QWaylandXdgSurface); |
271 | emit q->windowTypeChanged(); |
272 | } |
273 | |
274 | void QWaylandXdgSurfacePrivate::handleFocusLost() |
275 | { |
276 | if (m_toplevel) |
277 | QWaylandXdgToplevelPrivate::get(toplevel: m_toplevel)->handleFocusLost(); |
278 | } |
279 | |
280 | void QWaylandXdgSurfacePrivate::handleFocusReceived() |
281 | { |
282 | if (m_toplevel) |
283 | QWaylandXdgToplevelPrivate::get(toplevel: m_toplevel)->handleFocusReceived(); |
284 | } |
285 | |
286 | QRect QWaylandXdgSurfacePrivate::calculateFallbackWindowGeometry() const |
287 | { |
288 | // TODO: The unset window geometry should include subsurfaces as well, so this solution |
289 | // won't work too well on those kinds of clients. |
290 | return QRect(QPoint(), m_surface->destinationSize()); |
291 | } |
292 | |
293 | void QWaylandXdgSurfacePrivate::updateFallbackWindowGeometry() |
294 | { |
295 | Q_Q(QWaylandXdgSurface); |
296 | if (!m_unsetWindowGeometry) |
297 | return; |
298 | |
299 | const QRect unsetGeometry = calculateFallbackWindowGeometry(); |
300 | if (unsetGeometry == m_windowGeometry) |
301 | return; |
302 | |
303 | m_windowGeometry = unsetGeometry; |
304 | emit q->windowGeometryChanged(); |
305 | } |
306 | |
307 | void QWaylandXdgSurfacePrivate::xdg_surface_destroy_resource(QtWaylandServer::xdg_surface::Resource *resource) |
308 | { |
309 | Q_UNUSED(resource); |
310 | Q_Q(QWaylandXdgSurface); |
311 | QWaylandXdgShellPrivate::get(xdgShell: m_xdgShell)->unregisterXdgSurface(xdgSurface: q); |
312 | delete q; |
313 | } |
314 | |
315 | void QWaylandXdgSurfacePrivate::xdg_surface_destroy(QtWaylandServer::xdg_surface::Resource *resource) |
316 | { |
317 | wl_resource_destroy(resource->handle); |
318 | } |
319 | |
320 | void QWaylandXdgSurfacePrivate::xdg_surface_get_toplevel(QtWaylandServer::xdg_surface::Resource *resource, uint32_t id) |
321 | { |
322 | Q_Q(QWaylandXdgSurface); |
323 | |
324 | if (m_toplevel || m_popup) { |
325 | wl_resource_post_error(resource->handle, XDG_SURFACE_ERROR_ALREADY_CONSTRUCTED, |
326 | "xdg_surface already has a role object"); |
327 | return; |
328 | } |
329 | |
330 | if (!m_surface->setRole(QWaylandXdgToplevel::role(), resource->handle, XDG_WM_BASE_ERROR_ROLE)) |
331 | return; |
332 | |
333 | QWaylandResource topLevelResource(wl_resource_create(resource->client(), &xdg_toplevel_interface, |
334 | wl_resource_get_version(resource->handle), id)); |
335 | |
336 | m_toplevel = new QWaylandXdgToplevel(q, topLevelResource); |
337 | emit q->toplevelCreated(); |
338 | emit m_xdgShell->toplevelCreated(toplevel: m_toplevel, xdgSurface: q); |
339 | q->connect(sender: m_toplevel, signal: &QWaylandXdgToplevel::modalChanged, context: q, slot: [q, this](){ |
340 | q->setModal(m_toplevel->isModal()); |
341 | }); |
342 | } |
343 | |
344 | void QWaylandXdgSurfacePrivate::xdg_surface_get_popup(QtWaylandServer::xdg_surface::Resource *resource, uint32_t id, wl_resource *parentResource, wl_resource *positionerResource) |
345 | { |
346 | Q_Q(QWaylandXdgSurface); |
347 | |
348 | if (m_toplevel || m_popup) { |
349 | wl_resource_post_error(resource->handle, XDG_SURFACE_ERROR_ALREADY_CONSTRUCTED, |
350 | "xdg_surface already has a role object"); |
351 | return; |
352 | } |
353 | |
354 | QWaylandXdgSurface *parent = QWaylandXdgSurface::fromResource(resource: parentResource); |
355 | if (!parent) { |
356 | wl_resource_post_error(resource->handle, XDG_WM_BASE_ERROR_INVALID_POPUP_PARENT, |
357 | "xdg_surface.get_popup with invalid popup parent"); |
358 | return; |
359 | } |
360 | |
361 | QWaylandXdgPositioner *positioner = QWaylandXdgPositioner::fromResource(resource: positionerResource); |
362 | if (!positioner) { |
363 | wl_resource_post_error(resource->handle, XDG_WM_BASE_ERROR_INVALID_POSITIONER, |
364 | "xdg_surface.get_popup without positioner"); |
365 | return; |
366 | } |
367 | |
368 | if (!positioner->m_data.isComplete()) { |
369 | QWaylandXdgPositionerData p = positioner->m_data; |
370 | wl_resource_post_error(resource->handle, XDG_WM_BASE_ERROR_INVALID_POSITIONER, |
371 | "xdg_surface.get_popup with invalid positioner (size: %dx%d, anchorRect: %dx%d)", |
372 | p.size.width(), p.size.height(), p.anchorRect.width(), p.anchorRect.height()); |
373 | return; |
374 | } |
375 | |
376 | QRect anchorBounds(QPoint(0, 0), parent->windowGeometry().size()); |
377 | if (!anchorBounds.contains(r: positioner->m_data.anchorRect)) { |
378 | // TODO: this is a protocol error and should ideally be handled like this: |
379 | //wl_resource_post_error(resource->handle, XDG_WM_BASE_ERROR_INVALID_POSITIONER, |
380 | // "xdg_positioner anchor rect extends beyound its parent's window geometry"); |
381 | //return; |
382 | // However, our own clients currently do this, so we'll settle for a gentle warning instead. |
383 | qCWarning(qLcWaylandCompositor) << "Ignoring client protocol error: xdg_positioner anchor" |
384 | << "rect extends beyond its parent's window geometry"; |
385 | } |
386 | |
387 | if (!m_surface->setRole(QWaylandXdgPopup::role(), resource->handle, XDG_WM_BASE_ERROR_ROLE)) |
388 | return; |
389 | |
390 | QWaylandResource popupResource(wl_resource_create(resource->client(), &xdg_popup_interface, |
391 | wl_resource_get_version(resource->handle), id)); |
392 | |
393 | m_popup = new QWaylandXdgPopup(q, parent, positioner, popupResource); |
394 | emit q->popupCreated(); |
395 | emit m_xdgShell->popupCreated(popup: m_popup, xdgSurface: q); |
396 | } |
397 | |
398 | void QWaylandXdgSurfacePrivate::xdg_surface_ack_configure(QtWaylandServer::xdg_surface::Resource *resource, uint32_t serial) |
399 | { |
400 | if (m_toplevel) { |
401 | QWaylandXdgToplevelPrivate::get(toplevel: m_toplevel)->handleAckConfigure(serial); |
402 | } else if (m_popup) { |
403 | QWaylandXdgPopupPrivate::get(popup: m_popup)->handleAckConfigure(serial); |
404 | } else { |
405 | wl_resource_post_error(resource->handle, XDG_SURFACE_ERROR_NOT_CONSTRUCTED, |
406 | "ack_configure requested on an unconstructed xdg_surface"); |
407 | } |
408 | } |
409 | |
410 | void QWaylandXdgSurfacePrivate::xdg_surface_set_window_geometry(QtWaylandServer::xdg_surface::Resource *resource, int32_t x, int32_t y, int32_t width, int32_t height) |
411 | { |
412 | Q_Q(QWaylandXdgSurface); |
413 | |
414 | if (!q->surface()->role()) { |
415 | wl_resource_post_error(resource->handle, XDG_SURFACE_ERROR_NOT_CONSTRUCTED, |
416 | "set_window_geometry requested on an unconstructed xdg_surface"); |
417 | return; |
418 | } |
419 | |
420 | if (width <= 0 || height <= 0) { |
421 | // The protocol spec says "setting an invalid size will raise an error". But doesn't tell |
422 | // which error to raise, and there's no fitting error in the xdg_surface_error enum. |
423 | // So until this is fixed, just output a warning and return. |
424 | qWarning() << "Invalid (non-positive) dimensions received in set_window_geometry"; |
425 | return; |
426 | } |
427 | |
428 | m_unsetWindowGeometry = false; |
429 | |
430 | QRect geometry(x, y, width, height); |
431 | |
432 | if (m_windowGeometry == geometry) |
433 | return; |
434 | |
435 | m_windowGeometry = geometry; |
436 | emit q->windowGeometryChanged(); |
437 | } |
438 | |
439 | /*! |
440 | * \qmltype XdgSurface |
441 | * \nativetype QWaylandXdgSurface |
442 | * \inqmlmodule QtWayland.Compositor.XdgShell |
443 | * \since 5.12 |
444 | * \brief XdgSurface provides desktop-style compositor-specific features to an xdg surface. |
445 | * |
446 | * This type is part of the \l{XdgShell} extension and provides a way to |
447 | * extend the functionality of an existing \l{WaylandSurface} with features |
448 | * specific to desktop-style compositors, such as resizing and moving the |
449 | * surface. |
450 | * |
451 | * It corresponds to the Wayland interface \c xdg_surface. |
452 | */ |
453 | |
454 | /*! |
455 | * \class QWaylandXdgSurface |
456 | * \inmodule QtWaylandCompositor |
457 | * \since 5.12 |
458 | * \brief The QWaylandXdgSurface class provides desktop-style compositor-specific features to an xdg surface. |
459 | * |
460 | * This class is part of the QWaylandXdgShell extension and provides a way to |
461 | * extend the functionality of an existing QWaylandSurface with features |
462 | * specific to desktop-style compositors, such as resizing and moving the |
463 | * surface. |
464 | * |
465 | * It corresponds to the Wayland interface \c xdg_surface. |
466 | */ |
467 | |
468 | /*! |
469 | * Constructs a QWaylandXdgSurface. |
470 | */ |
471 | QWaylandXdgSurface::QWaylandXdgSurface() |
472 | : QWaylandShellSurfaceTemplate<QWaylandXdgSurface>(*new QWaylandXdgSurfacePrivate) |
473 | { |
474 | } |
475 | |
476 | /*! |
477 | * Constructs a QWaylandXdgSurface for \a surface and initializes it with the |
478 | * given \a xdgShell, \a surface, and resource \a res. |
479 | */ |
480 | QWaylandXdgSurface::QWaylandXdgSurface(QWaylandXdgShell *xdgShell, QWaylandSurface *surface, const QWaylandResource &res) |
481 | : QWaylandShellSurfaceTemplate<QWaylandXdgSurface>(*new QWaylandXdgSurfacePrivate) |
482 | { |
483 | initialize(xdgShell, surface, resource: res); |
484 | } |
485 | |
486 | /*! |
487 | * \qmlmethod void XdgSurface::initialize(object xdgShell, object surface, object client, int id) |
488 | * |
489 | * Initializes the XdgSurface, associating it with the given \a xdgShell, \a surface, |
490 | * \a client, and \a id. |
491 | */ |
492 | |
493 | /*! |
494 | * Initializes the QWaylandXdgSurface, associating it with the given \a xdgShell, \a surface |
495 | * and \a resource. |
496 | */ |
497 | void QWaylandXdgSurface::initialize(QWaylandXdgShell *xdgShell, QWaylandSurface *surface, const QWaylandResource &resource) |
498 | { |
499 | Q_D(QWaylandXdgSurface); |
500 | d->m_xdgShell = xdgShell; |
501 | d->m_surface = surface; |
502 | d->init(resource.resource()); |
503 | setExtensionContainer(surface); |
504 | d->m_windowGeometry = d->calculateFallbackWindowGeometry(); |
505 | connect(sender: surface, signal: &QWaylandSurface::destinationSizeChanged, context: this, slot: &QWaylandXdgSurface::handleSurfaceSizeChanged); |
506 | connect(sender: surface, signal: &QWaylandSurface::bufferScaleChanged, context: this, slot: &QWaylandXdgSurface::handleBufferScaleChanged); |
507 | emit shellChanged(); |
508 | emit surfaceChanged(); |
509 | QWaylandCompositorExtension::initialize(); |
510 | } |
511 | |
512 | /*! |
513 | * \qmlproperty enum XdgSurface::windowType |
514 | * |
515 | * This property holds the window type of the XdgSurface. |
516 | */ |
517 | Qt::WindowType QWaylandXdgSurface::windowType() const |
518 | { |
519 | Q_D(const QWaylandXdgSurface); |
520 | return d->m_windowType; |
521 | } |
522 | |
523 | /*! |
524 | * \qmlproperty rect XdgSurface::windowGeometry |
525 | * |
526 | * This property holds the window geometry of the QWaylandXdgSurface. The window |
527 | * geometry describes the window's visible bounds from the user's perspective. |
528 | * The geometry includes title bars and borders if drawn by the client, but |
529 | * excludes drop shadows. It is meant to be used for aligning and tiling |
530 | * windows. |
531 | */ |
532 | |
533 | /*! |
534 | * \property QWaylandXdgSurface::windowGeometry |
535 | * |
536 | * This property holds the window geometry of the QWaylandXdgSurface. The window |
537 | * geometry describes the window's visible bounds from the user's perspective. |
538 | * The geometry includes title bars and borders if drawn by the client, but |
539 | * excludes drop shadows. It is meant to be used for aligning and tiling |
540 | * windows. |
541 | */ |
542 | QRect QWaylandXdgSurface::windowGeometry() const |
543 | { |
544 | Q_D(const QWaylandXdgSurface); |
545 | return d->m_windowGeometry; |
546 | } |
547 | |
548 | /*! |
549 | * \internal |
550 | */ |
551 | void QWaylandXdgSurface::initialize() |
552 | { |
553 | QWaylandCompositorExtension::initialize(); |
554 | } |
555 | |
556 | void QWaylandXdgSurface::handleSurfaceSizeChanged() |
557 | { |
558 | Q_D(QWaylandXdgSurface); |
559 | d->updateFallbackWindowGeometry(); |
560 | } |
561 | |
562 | void QWaylandXdgSurface::handleBufferScaleChanged() |
563 | { |
564 | Q_D(QWaylandXdgSurface); |
565 | d->updateFallbackWindowGeometry(); |
566 | } |
567 | |
568 | /*! |
569 | * \qmlproperty XdgShell XdgSurface::shell |
570 | * |
571 | * This property holds the shell associated with this XdgSurface. |
572 | */ |
573 | |
574 | /*! |
575 | * \property QWaylandXdgSurface::shell |
576 | * |
577 | * This property holds the shell associated with this QWaylandXdgSurface. |
578 | */ |
579 | QWaylandXdgShell *QWaylandXdgSurface::shell() const |
580 | { |
581 | Q_D(const QWaylandXdgSurface); |
582 | return d->m_xdgShell; |
583 | } |
584 | |
585 | /*! |
586 | * \qmlproperty WaylandSurface XdgSurface::surface |
587 | * |
588 | * This property holds the surface associated with this XdgSurface. |
589 | */ |
590 | |
591 | /*! |
592 | * \property QWaylandXdgSurface::surface |
593 | * |
594 | * This property holds the surface associated with this QWaylandXdgSurface. |
595 | */ |
596 | QWaylandSurface *QWaylandXdgSurface::surface() const |
597 | { |
598 | Q_D(const QWaylandXdgSurface); |
599 | return d->m_surface; |
600 | } |
601 | |
602 | /*! |
603 | * \qmlproperty XdgToplevel XdgSurface::toplevel |
604 | * |
605 | * This property holds the properties and methods that are specific to the |
606 | * toplevel XdgSurface. |
607 | * |
608 | * \sa popup, XdgShell::toplevelCreated |
609 | */ |
610 | |
611 | /*! |
612 | * \property QWaylandXdgSurface::toplevel |
613 | * |
614 | * This property holds the properties and methods that are specific to the |
615 | * toplevel QWaylandXdgSurface. |
616 | * |
617 | * \sa QWaylandXdgSurface::popup, QWaylandXdgShell::toplevelCreated |
618 | */ |
619 | QWaylandXdgToplevel *QWaylandXdgSurface::toplevel() const |
620 | { |
621 | Q_D(const QWaylandXdgSurface); |
622 | return d->m_toplevel; |
623 | } |
624 | |
625 | /*! |
626 | * \qmlproperty XdgPopup XdgSurface::popup |
627 | * |
628 | * This property holds the properties and methods that are specific to the |
629 | * popup XdgSurface. |
630 | * |
631 | * \sa toplevel, XdgShell::popupCreated |
632 | */ |
633 | |
634 | /*! |
635 | * \property QWaylandXdgSurface::popup |
636 | * |
637 | * This property holds the properties and methods that are specific to the |
638 | * popup QWaylandXdgSurface. |
639 | * |
640 | * \sa QWaylandXdgSurface::toplevel, QWaylandXdgShell::popupCreated |
641 | */ |
642 | QWaylandXdgPopup *QWaylandXdgSurface::popup() const |
643 | { |
644 | Q_D(const QWaylandXdgSurface); |
645 | return d->m_popup; |
646 | } |
647 | |
648 | /*! |
649 | * Returns the Wayland interface for the QWaylandXdgSurface. |
650 | */ |
651 | const wl_interface *QWaylandXdgSurface::interface() |
652 | { |
653 | return QWaylandXdgSurfacePrivate::interface(); |
654 | } |
655 | |
656 | /*! |
657 | * \internal |
658 | */ |
659 | QByteArray QWaylandXdgSurface::interfaceName() |
660 | { |
661 | return QWaylandXdgSurfacePrivate::interfaceName(); |
662 | } |
663 | |
664 | /*! |
665 | * Returns the QWaylandXdgSurface corresponding to the \a resource. |
666 | */ |
667 | QWaylandXdgSurface *QWaylandXdgSurface::fromResource(wl_resource *resource) |
668 | { |
669 | if (auto p = QtWayland::fromResource<QWaylandXdgSurfacePrivate *>(resource)) |
670 | return p->q_func(); |
671 | return nullptr; |
672 | } |
673 | |
674 | #if QT_CONFIG(wayland_compositor_quick) |
675 | QWaylandQuickShellIntegration *QWaylandXdgSurface::createIntegration(QWaylandQuickShellSurfaceItem *item) |
676 | { |
677 | Q_D(const QWaylandXdgSurface); |
678 | |
679 | if (d->m_toplevel) |
680 | return new QtWayland::XdgToplevelIntegration(item); |
681 | |
682 | if (d->m_popup) |
683 | return new QtWayland::XdgPopupIntegration(item); |
684 | |
685 | return nullptr; |
686 | } |
687 | #endif |
688 | |
689 | /*! |
690 | * \qmltype XdgToplevel |
691 | * \nativetype QWaylandXdgToplevel |
692 | * \inqmlmodule QtWayland.Compositor.XdgShell |
693 | * \since 5.12 |
694 | * \brief XdgToplevel represents the toplevel window specific parts of an xdg surface. |
695 | * |
696 | * This type is part of the \l{XdgShell} extension and provides a way to |
697 | * extend the functionality of an XdgSurface with features |
698 | * specific to desktop-style windows. |
699 | * |
700 | * It corresponds to the Wayland interface \c xdg_toplevel. |
701 | */ |
702 | |
703 | /*! |
704 | * \class QWaylandXdgToplevel |
705 | * \inmodule QtWaylandCompositor |
706 | * \since 5.12 |
707 | * \brief The QWaylandXdgToplevel class represents the toplevel window specific parts of an xdg surface. |
708 | * |
709 | * This class is part of the QWaylandXdgShell extension and provides a way to |
710 | * extend the functionality of an QWaylandXdgSurface with features |
711 | * specific to desktop-style windows. |
712 | * |
713 | * It corresponds to the Wayland interface \c xdg_toplevel. |
714 | */ |
715 | |
716 | /*! |
717 | * Constructs a QWaylandXdgToplevel for the given \a xdgSurface and \a resource. |
718 | */ |
719 | QWaylandXdgToplevel::QWaylandXdgToplevel(QWaylandXdgSurface *xdgSurface, QWaylandResource &resource) |
720 | : QObject(*new QWaylandXdgToplevelPrivate(xdgSurface, resource)) |
721 | { |
722 | QList<QWaylandXdgToplevel::State> states; |
723 | sendConfigure(size: {0, 0}, states); |
724 | } |
725 | |
726 | QWaylandXdgToplevel::~QWaylandXdgToplevel() |
727 | { |
728 | Q_D(QWaylandXdgToplevel); |
729 | // Usually, the decoration is destroyed by the client (according to the protocol), |
730 | // but if the client misbehaves, or is shut down, we need to clean up here. |
731 | if (Q_UNLIKELY(d->m_decoration)) |
732 | wl_resource_destroy(d->m_decoration->resource()->handle); |
733 | Q_ASSERT(!d->m_decoration); |
734 | } |
735 | |
736 | /*! |
737 | * \qmlproperty XdgSurface XdgToplevel::xdgSurface |
738 | * |
739 | * This property holds the XdgSurface for this XdgToplevel. |
740 | */ |
741 | |
742 | /*! |
743 | * \property QWaylandXdgToplevel::xdgSurface |
744 | * |
745 | * This property holds the QWaylandXdgSurface for this QWaylandXdgToplevel. |
746 | */ |
747 | QWaylandXdgSurface *QWaylandXdgToplevel::xdgSurface() const |
748 | { |
749 | Q_D(const QWaylandXdgToplevel); |
750 | return d->m_xdgSurface; |
751 | } |
752 | |
753 | /*! |
754 | * \qmlproperty XdgToplevel XdgToplevel::parentToplevel |
755 | * |
756 | * This property holds the XdgToplevel parent of this XdgToplevel. |
757 | */ |
758 | |
759 | /*! |
760 | * \property QWaylandXdgToplevel::parentToplevel |
761 | * |
762 | * This property holds the XdgToplevel parent of this XdgToplevel. |
763 | * |
764 | */ |
765 | QWaylandXdgToplevel *QWaylandXdgToplevel::parentToplevel() const |
766 | { |
767 | Q_D(const QWaylandXdgToplevel); |
768 | return d->m_parentToplevel; |
769 | } |
770 | |
771 | /*! |
772 | * \qmlproperty string XdgToplevel::title |
773 | * |
774 | * This property holds the title of the XdgToplevel. |
775 | */ |
776 | |
777 | /*! |
778 | * \property QWaylandXdgToplevel::title |
779 | * |
780 | * This property holds the title of the QWaylandXdgToplevel. |
781 | */ |
782 | QString QWaylandXdgToplevel::title() const |
783 | { |
784 | Q_D(const QWaylandXdgToplevel); |
785 | return d->m_title; |
786 | } |
787 | |
788 | /*! |
789 | * \qmlproperty string XdgToplevel::appId |
790 | * |
791 | * This property holds the app id of the XdgToplevel. |
792 | */ |
793 | |
794 | /*! |
795 | * \property QWaylandXdgToplevel::appId |
796 | * |
797 | * This property holds the app id of the QWaylandXdgToplevel. |
798 | */ |
799 | QString QWaylandXdgToplevel::appId() const |
800 | { |
801 | Q_D(const QWaylandXdgToplevel); |
802 | return d->m_appId; |
803 | } |
804 | |
805 | /*! |
806 | * \qmlproperty size XdgToplevel::maxSize |
807 | * |
808 | * This property holds the maximum size of the XdgToplevel as requested by the client. |
809 | * |
810 | * The compositor is free to ignore this value and request a larger size. |
811 | */ |
812 | |
813 | /*! |
814 | * \property QWaylandXdgToplevel::maxSize |
815 | * |
816 | * This property holds the maximum size of the QWaylandXdgToplevel. |
817 | * |
818 | * The compositor is free to ignore this value and request a larger size. |
819 | */ |
820 | QSize QWaylandXdgToplevel::maxSize() const |
821 | { |
822 | Q_D(const QWaylandXdgToplevel); |
823 | return d->m_maxSize; |
824 | } |
825 | |
826 | /*! |
827 | * \qmlproperty size XdgToplevel::minSize |
828 | * |
829 | * This property holds the minimum size of the XdgToplevel as requested by the client. |
830 | * |
831 | * The compositor is free to ignore this value and request a smaller size. |
832 | */ |
833 | |
834 | /*! |
835 | * \property QWaylandXdgToplevel::minSize |
836 | * |
837 | * This property holds the minimum size of the QWaylandXdgToplevel. |
838 | * |
839 | * The compositor is free to ignore this value and request a smaller size. |
840 | */ |
841 | QSize QWaylandXdgToplevel::minSize() const |
842 | { |
843 | Q_D(const QWaylandXdgToplevel); |
844 | return d->m_minSize; |
845 | } |
846 | |
847 | /*! |
848 | * \property QWaylandXdgToplevel::states |
849 | * |
850 | * This property holds the last states the client acknowledged for this QWaylandToplevel. |
851 | */ |
852 | QList<QWaylandXdgToplevel::State> QWaylandXdgToplevel::states() const |
853 | { |
854 | Q_D(const QWaylandXdgToplevel); |
855 | return d->m_lastAckedConfigure.states; |
856 | } |
857 | |
858 | /*! |
859 | * \qmlproperty bool XdgToplevel::maximized |
860 | * |
861 | * This property holds whether the client has acknowledged that it should be maximized. |
862 | */ |
863 | |
864 | /*! |
865 | * \property QWaylandXdgToplevel::maximized |
866 | * |
867 | * This property holds whether the client has acknowledged that it should be maximized. |
868 | */ |
869 | bool QWaylandXdgToplevel::maximized() const |
870 | { |
871 | Q_D(const QWaylandXdgToplevel); |
872 | return d->m_lastAckedConfigure.states.contains(t: QWaylandXdgToplevel::State::MaximizedState); |
873 | } |
874 | |
875 | /*! |
876 | * \qmlproperty bool XdgToplevel::fullscreen |
877 | * |
878 | * This property holds whether the client has acknowledged that it should be fullscreen. |
879 | */ |
880 | |
881 | /*! |
882 | * \property QWaylandXdgToplevel::fullscreen |
883 | * |
884 | * This property holds whether the client has acknowledged that it should be fullscreen. |
885 | */ |
886 | bool QWaylandXdgToplevel::fullscreen() const |
887 | { |
888 | Q_D(const QWaylandXdgToplevel); |
889 | return d->m_lastAckedConfigure.states.contains(t: QWaylandXdgToplevel::State::FullscreenState); |
890 | } |
891 | |
892 | /*! |
893 | * \qmlproperty bool XdgToplevel::resizing |
894 | * |
895 | * This property holds whether the client has acknowledged that it is being resized. |
896 | */ |
897 | |
898 | /*! |
899 | * \property QWaylandXdgToplevel::resizing |
900 | * |
901 | * This property holds whether the client has acknowledged that it is being resized. |
902 | */ |
903 | bool QWaylandXdgToplevel::resizing() const |
904 | { |
905 | Q_D(const QWaylandXdgToplevel); |
906 | return d->m_lastAckedConfigure.states.contains(t: QWaylandXdgToplevel::State::ResizingState); |
907 | } |
908 | |
909 | /*! |
910 | * \qmlproperty bool XdgToplevel::activated |
911 | * |
912 | * This property holds whether toplevel is drawing itself as having input focus. |
913 | */ |
914 | |
915 | /*! |
916 | * \property QWaylandXdgToplevel::activated |
917 | * |
918 | * This property holds whether toplevel is drawing itself as having input focus. |
919 | */ |
920 | bool QWaylandXdgToplevel::activated() const |
921 | { |
922 | Q_D(const QWaylandXdgToplevel); |
923 | return d->m_lastAckedConfigure.states.contains(t: QWaylandXdgToplevel::State::ActivatedState); |
924 | } |
925 | |
926 | /*! |
927 | * \qmlproperty bool XdgToplevel::modal |
928 | * |
929 | * This property holds whether toplevel blocks other windows from receiving input. |
930 | * \since 6.8 |
931 | */ |
932 | |
933 | /*! |
934 | * \property QWaylandXdgToplevel::modal |
935 | * |
936 | * This property holds whether toplevel blocks other windows from receiving input. |
937 | * \since 6.8 |
938 | */ |
939 | bool QWaylandXdgToplevel::isModal() const |
940 | { |
941 | Q_D(const QWaylandXdgToplevel); |
942 | return d->m_modal; |
943 | } |
944 | |
945 | void QWaylandXdgToplevel::setModal(bool newModal) |
946 | { |
947 | Q_D(QWaylandXdgToplevel); |
948 | if (d->m_modal == newModal) |
949 | return; |
950 | d->m_modal = newModal; |
951 | emit modalChanged(); |
952 | } |
953 | |
954 | /*! |
955 | * \enum QWaylandXdgToplevel::DecorationMode |
956 | * |
957 | * This enum type is used to specify the window decoration mode for toplevel windows. |
958 | * |
959 | * \value ServerSideDecoration The compositor should draw window decorations. |
960 | * \value ClientSideDecoration The client should draw window decorations. |
961 | */ |
962 | |
963 | /*! |
964 | * \qmlproperty enumeration XdgToplevel::decorationMode |
965 | * |
966 | * This property holds the current window decoration mode for this toplevel. |
967 | * |
968 | * The possible values are: |
969 | * \value XdgToplevel.ServerSideDecoration The compositor should draw window decorations. |
970 | * \value XdgToplevel.ClientSideDecoration The client should draw window decorations. |
971 | * |
972 | * \sa XdgDecorationManagerV1 |
973 | */ |
974 | |
975 | /*! |
976 | * \property QWaylandXdgToplevel::decorationMode |
977 | * |
978 | * This property holds the current window decoration mode for this toplevel. |
979 | * |
980 | * \sa QWaylandXdgDecorationManagerV1 |
981 | */ |
982 | QWaylandXdgToplevel::DecorationMode QWaylandXdgToplevel::decorationMode() const |
983 | { |
984 | Q_D(const QWaylandXdgToplevel); |
985 | return d->m_decoration ? d->m_decoration->configuredMode() : DecorationMode::ClientSideDecoration; |
986 | } |
987 | |
988 | /*! |
989 | * \qmlmethod size XdgToplevel::sizeForResize(size size, point delta, uint edges) |
990 | * |
991 | * Convenience for computing the new size given the current \a size, a \a delta, and |
992 | * the \a edges active in the drag. |
993 | */ |
994 | |
995 | /*! |
996 | * Convenience for computing the new size given the current \a size, a \a delta, and |
997 | * the \a edges active in the drag. |
998 | */ |
999 | QSize QWaylandXdgToplevel::sizeForResize(const QSizeF &size, const QPointF &delta, Qt::Edges edges) const |
1000 | { |
1001 | qreal width = size.width(); |
1002 | qreal height = size.height(); |
1003 | if (edges & Qt::LeftEdge) |
1004 | width -= delta.x(); |
1005 | else if (edges & Qt::RightEdge) |
1006 | width += delta.x(); |
1007 | |
1008 | if (edges & Qt::TopEdge) |
1009 | height -= delta.y(); |
1010 | else if (edges & Qt::BottomEdge) |
1011 | height += delta.y(); |
1012 | |
1013 | QSize newSize = QSize(width, height) |
1014 | .expandedTo(otherSize: minSize()) |
1015 | .expandedTo(otherSize: {1, 1}); // We don't want to send a size of (0,0) as that means that the client decides |
1016 | |
1017 | if (maxSize().isValid()) |
1018 | newSize = newSize.boundedTo(otherSize: maxSize()); |
1019 | |
1020 | return newSize; |
1021 | } |
1022 | |
1023 | /*! |
1024 | * Sends a configure event to the client. Parameter \a size contains the pixel size |
1025 | * of the surface. A size of zero means the client is free to decide the size. |
1026 | * Known \a states are enumerated in QWaylandXdgToplevel::State. |
1027 | */ |
1028 | uint QWaylandXdgToplevel::sendConfigure(const QSize &size, const QList<QWaylandXdgToplevel::State> &states) |
1029 | { |
1030 | if (!size.isValid()) { |
1031 | qWarning() << "Can't configure xdg_toplevel with an invalid size"<< size; |
1032 | return 0; |
1033 | } |
1034 | Q_D(QWaylandXdgToplevel); |
1035 | auto statesBytes = QByteArray::fromRawData(data: reinterpret_cast<const char *>(states.data()), |
1036 | size: states.size() * static_cast<int>(sizeof(State))); |
1037 | uint32_t serial = d->m_xdgSurface->surface()->compositor()->nextSerial(); |
1038 | d->m_pendingConfigures.append(t: QWaylandXdgToplevelPrivate::ConfigureEvent{states, size, serial}); |
1039 | d->send_configure(size.width(), size.height(), statesBytes); |
1040 | QWaylandXdgSurfacePrivate::get(xdgSurface: d->m_xdgSurface)->send_configure(serial); |
1041 | return serial; |
1042 | } |
1043 | |
1044 | /*! |
1045 | * \qmlmethod int XdgToplevel::sendConfigure(size size, list<int> states) |
1046 | * |
1047 | * Sends a configure event to the client. \a size contains the pixel size of the surface. |
1048 | * A size of zero means the client is free to decide the size. |
1049 | * Known \a states are enumerated in XdgToplevel::State. |
1050 | */ |
1051 | uint QWaylandXdgToplevel::sendConfigure(const QSize &size, const QList<int> &states) |
1052 | { |
1053 | QList<State> s; |
1054 | for (auto state : states) |
1055 | s << State(state); |
1056 | return sendConfigure(size, states: s); |
1057 | } |
1058 | |
1059 | /*! |
1060 | * \qmlmethod void XdgToplevel::sendClose() |
1061 | * |
1062 | * Sends a close event to the client. The client may choose to ignore the event. |
1063 | */ |
1064 | |
1065 | /*! |
1066 | * Sends a close event to the client. The client may choose to ignore the event. |
1067 | */ |
1068 | void QWaylandXdgToplevel::sendClose() |
1069 | { |
1070 | Q_D(QWaylandXdgToplevel); |
1071 | d->send_close(); |
1072 | } |
1073 | |
1074 | /*! |
1075 | * \qmlmethod void XdgToplevel::sendMaximized(size size) |
1076 | * |
1077 | * Convenience for sending a configure event with the maximized state set, and |
1078 | * fullscreen and resizing removed. The activated state is left in its current state. |
1079 | * |
1080 | * \a size is the new size of the window. |
1081 | */ |
1082 | |
1083 | /*! |
1084 | * Convenience for sending a configure event with the maximized state set, and |
1085 | * fullscreen and resizing removed. The activated state is left in its current state. |
1086 | * |
1087 | * \a size is the new size of the window. |
1088 | */ |
1089 | uint QWaylandXdgToplevel::sendMaximized(const QSize &size) |
1090 | { |
1091 | Q_D(QWaylandXdgToplevel); |
1092 | QWaylandXdgToplevelPrivate::ConfigureEvent conf = d->lastSentConfigure(); |
1093 | |
1094 | if (!conf.states.contains(t: QWaylandXdgToplevel::State::MaximizedState)) |
1095 | conf.states.append(t: QWaylandXdgToplevel::State::MaximizedState); |
1096 | conf.states.removeOne(t: QWaylandXdgToplevel::State::FullscreenState); |
1097 | conf.states.removeOne(t: QWaylandXdgToplevel::State::ResizingState); |
1098 | |
1099 | return sendConfigure(size, states: conf.states); |
1100 | } |
1101 | |
1102 | /*! |
1103 | * \qmlmethod void XdgToplevel::sendUnmaximized(size size) |
1104 | * |
1105 | * Convenience for sending a configure event with the maximized, fullscreen and |
1106 | * resizing states removed, and fullscreen and resizing removed. The activated |
1107 | * state is left in its current state. |
1108 | * |
1109 | * \a size is the new size of the window. If \a size is zero, the client decides the size. |
1110 | */ |
1111 | |
1112 | /*! |
1113 | * Convenience for sending a configure event with the maximized, fullscreen and |
1114 | * resizing states removed, and fullscreen and resizing removed. The activated |
1115 | * state is left in its current state. |
1116 | * |
1117 | * \a size is the new size of the window. If \a size is zero, the client decides the size. |
1118 | */ |
1119 | uint QWaylandXdgToplevel::sendUnmaximized(const QSize &size) |
1120 | { |
1121 | Q_D(QWaylandXdgToplevel); |
1122 | QWaylandXdgToplevelPrivate::ConfigureEvent conf = d->lastSentConfigure(); |
1123 | |
1124 | conf.states.removeOne(t: QWaylandXdgToplevel::State::MaximizedState); |
1125 | conf.states.removeOne(t: QWaylandXdgToplevel::State::FullscreenState); |
1126 | conf.states.removeOne(t: QWaylandXdgToplevel::State::ResizingState); |
1127 | |
1128 | return sendConfigure(size, states: conf.states); |
1129 | |
1130 | } |
1131 | |
1132 | /*! |
1133 | * \qmlmethod void XdgToplevel::sendFullscreen(size size) |
1134 | * |
1135 | * Convenience for sending a configure event with the fullscreen state set, and |
1136 | * maximized and resizing removed. The activated state is left in its current state. |
1137 | * |
1138 | * \sa sendUnmaximized |
1139 | * |
1140 | * \a size is the new size of the window. |
1141 | */ |
1142 | |
1143 | /*! |
1144 | * Convenience for sending a configure event with the fullscreen state set, and |
1145 | * maximized and resizing removed. The activated state is left in its current state. |
1146 | * |
1147 | * \sa sendUnmaximized |
1148 | * |
1149 | * \a size is the new size of the window. |
1150 | */ |
1151 | uint QWaylandXdgToplevel::sendFullscreen(const QSize &size) |
1152 | { |
1153 | Q_D(QWaylandXdgToplevel); |
1154 | QWaylandXdgToplevelPrivate::ConfigureEvent conf = d->lastSentConfigure(); |
1155 | |
1156 | if (!conf.states.contains(t: QWaylandXdgToplevel::State::FullscreenState)) |
1157 | conf.states.append(t: QWaylandXdgToplevel::State::FullscreenState); |
1158 | conf.states.removeOne(t: QWaylandXdgToplevel::State::MaximizedState); |
1159 | conf.states.removeOne(t: QWaylandXdgToplevel::State::ResizingState); |
1160 | |
1161 | return sendConfigure(size, states: conf.states); |
1162 | } |
1163 | |
1164 | /*! |
1165 | * \qmlmethod void XdgToplevel::sendResizing(size maxSize) |
1166 | * |
1167 | * Convenience for sending a configure event with the resizing state set, and |
1168 | * maximized and fullscreen removed. The activated state is left in its current state. |
1169 | * |
1170 | * \a maxSize is the new size of the window. |
1171 | */ |
1172 | |
1173 | /*! |
1174 | * Convenience for sending a configure event with the resizing state set, and |
1175 | * maximized and fullscreen removed. The activated state is left in its current state. |
1176 | * |
1177 | * \a maxSize is the new size of the window. |
1178 | */ |
1179 | uint QWaylandXdgToplevel::sendResizing(const QSize &maxSize) |
1180 | { |
1181 | Q_D(QWaylandXdgToplevel); |
1182 | QWaylandXdgToplevelPrivate::ConfigureEvent conf = d->lastSentConfigure(); |
1183 | |
1184 | if (!conf.states.contains(t: QWaylandXdgToplevel::State::ResizingState)) |
1185 | conf.states.append(t: QWaylandXdgToplevel::State::ResizingState); |
1186 | conf.states.removeOne(t: QWaylandXdgToplevel::State::MaximizedState); |
1187 | conf.states.removeOne(t: QWaylandXdgToplevel::State::FullscreenState); |
1188 | |
1189 | return sendConfigure(size: maxSize, states: conf.states); |
1190 | } |
1191 | |
1192 | /*! |
1193 | * Returns the surface role for the QWaylandToplevel. |
1194 | */ |
1195 | QWaylandSurfaceRole *QWaylandXdgToplevel::role() |
1196 | { |
1197 | return &QWaylandXdgToplevelPrivate::s_role; |
1198 | } |
1199 | |
1200 | /*! |
1201 | * Returns the QWaylandXdgToplevel corresponding to the \a resource. |
1202 | */ |
1203 | QWaylandXdgToplevel *QWaylandXdgToplevel::fromResource(wl_resource *resource) |
1204 | { |
1205 | if (auto p = QtWayland::fromResource<QWaylandXdgToplevelPrivate *>(resource)) |
1206 | return p->q_func(); |
1207 | return nullptr; |
1208 | } |
1209 | |
1210 | /*! |
1211 | * \qmlsignal XdgShell::xdgSurfaceCreated(XdgSurface xdgSurface) |
1212 | * |
1213 | * This signal is emitted when the client has created a \c xdg_surface. |
1214 | * Note that \a xdgSurface is not mapped, i.e. according to the \c xdg-shell |
1215 | * protocol it should not be displayed, until it has received a role object. |
1216 | * |
1217 | * \sa toplevelCreated(), popupCreated() |
1218 | */ |
1219 | |
1220 | /*! |
1221 | * \fn void QWaylandXdgShell::xdgSurfaceCreated(QWaylandXdgSurface *xdgSurface) |
1222 | * |
1223 | * This signal is emitted when the client has created a \c xdg_surface. |
1224 | * Note that \a xdgSurface is not mapped, i.e. according to the \c xdg-shell |
1225 | * protocol it should not be displayed, until it has received a role object. |
1226 | * |
1227 | * \sa toplevelCreated(), popupCreated() |
1228 | */ |
1229 | |
1230 | /*! |
1231 | * \qmlsignal XdgShell::toplevelCreated(XdgToplevel toplevel, XdgSurface xdgSurface) |
1232 | * |
1233 | * This signal is emitted when the client has created a \c xdg_toplevel. |
1234 | * A common use case is to let the handler of this signal instantiate a ShellSurfaceItem or |
1235 | * WaylandQuickItem for displaying \a toplevel in a QtQuick scene. |
1236 | * |
1237 | * \a xdgSurface is the XdgSurface \a toplevel is the role object for. |
1238 | */ |
1239 | |
1240 | /*! |
1241 | * \fn void QWaylandXdgShell::toplevelCreated(QWaylandXdgToplevel *toplevel, QWaylandXdgSurface *xdgSurface) |
1242 | * |
1243 | * This signal is emitted when the client has created a \c xdg_toplevel. |
1244 | * A common use case is to let the handler of this signal instantiate a QWaylandShellSurfaceItem or |
1245 | * QWaylandQuickItem for displaying \a toplevel in a QtQuick scene. |
1246 | * |
1247 | * \a xdgSurface is the XdgSurface \a toplevel is the role object for. |
1248 | */ |
1249 | |
1250 | /*! |
1251 | * \qmlsignal XdgShell::popupCreated(XdgPopup popup, XdgSurface xdgSurface) |
1252 | * |
1253 | * This signal is emitted when the client has created a \c xdg_popup. |
1254 | * A common use case is to let the handler of this signal instantiate a ShellSurfaceItem or |
1255 | * WaylandQuickItem for displaying \a popup in a QtQuick scene. |
1256 | * |
1257 | * \a xdgSurface is the XdgSurface \a popup is the role object for. |
1258 | */ |
1259 | |
1260 | /*! |
1261 | * \fn void QWaylandXdgShell::popupCreated(QWaylandXdgPopup *popup, QWaylandXdgSurface *xdgSurface) |
1262 | * |
1263 | * This signal is emitted when the client has created a \c xdg_popup. |
1264 | * A common use case is to let the handler of this signal instantiate a QWaylandShellSurfaceItem or |
1265 | * QWaylandQuickItem for displaying \a popup in a QtQuick scene. |
1266 | * |
1267 | * \a xdgSurface is the XdgSurface \a popup is the role object for. |
1268 | */ |
1269 | |
1270 | /*! |
1271 | * \qmlsignal XdgShell::pong(int serial) |
1272 | * |
1273 | * This signal is emitted when the client has responded to a ping event with serial, \a serial. |
1274 | * |
1275 | * \sa ping() |
1276 | */ |
1277 | |
1278 | /*! |
1279 | * \fn void QWaylandXdgShell::pong(uint serial) |
1280 | * |
1281 | * This signal is emitted when the client has responded to a ping event with serial, \a serial. |
1282 | * |
1283 | * \sa QWaylandXdgShell::ping() |
1284 | */ |
1285 | |
1286 | QList<int> QWaylandXdgToplevel::statesAsInts() const |
1287 | { |
1288 | QList<int> list; |
1289 | const auto s = states(); |
1290 | list.reserve(size: s.size()); |
1291 | for (auto state : s) { |
1292 | list << static_cast<int>(state); |
1293 | } |
1294 | return list; |
1295 | } |
1296 | |
1297 | QWaylandSurfaceRole QWaylandXdgToplevelPrivate::s_role("xdg_toplevel"); |
1298 | |
1299 | QWaylandXdgToplevelPrivate::QWaylandXdgToplevelPrivate(QWaylandXdgSurface *xdgSurface, const QWaylandResource &resource) |
1300 | : m_xdgSurface(xdgSurface) |
1301 | { |
1302 | init(resource.resource()); |
1303 | } |
1304 | |
1305 | void QWaylandXdgToplevelPrivate::handleAckConfigure(uint serial) |
1306 | { |
1307 | Q_Q(QWaylandXdgToplevel); |
1308 | ConfigureEvent config; |
1309 | Q_FOREVER { |
1310 | if (m_pendingConfigures.empty()) { |
1311 | qWarning(msg: "Toplevel received an unexpected ack_configure!"); |
1312 | return; |
1313 | } |
1314 | |
1315 | // This won't work unless there always is a toplevel.configure for each xdgsurface.configure |
1316 | config = m_pendingConfigures.takeFirst(); |
1317 | |
1318 | if (config.serial == serial) |
1319 | break; |
1320 | } |
1321 | |
1322 | QList<uint> changedStates; |
1323 | std::set_symmetric_difference( |
1324 | first1: m_lastAckedConfigure.states.begin(), last1: m_lastAckedConfigure.states.end(), |
1325 | first2: config.states.begin(), last2: config.states.end(), |
1326 | result: std::back_inserter(x&: changedStates)); |
1327 | |
1328 | m_lastAckedConfigure = config; |
1329 | |
1330 | for (uint state : changedStates) { |
1331 | switch (state) { |
1332 | case state_maximized: |
1333 | emit q->maximizedChanged(); |
1334 | break; |
1335 | case state_fullscreen: |
1336 | emit q->fullscreenChanged(); |
1337 | break; |
1338 | case state_resizing: |
1339 | emit q->resizingChanged(); |
1340 | break; |
1341 | case state_activated: |
1342 | emit q->activatedChanged(); |
1343 | break; |
1344 | } |
1345 | } |
1346 | |
1347 | if (!changedStates.empty()) |
1348 | emit q->statesChanged(); |
1349 | } |
1350 | |
1351 | void QWaylandXdgToplevelPrivate::handleFocusLost() |
1352 | { |
1353 | Q_Q(QWaylandXdgToplevel); |
1354 | QWaylandXdgToplevelPrivate::ConfigureEvent current = lastSentConfigure(); |
1355 | current.states.removeOne(t: QWaylandXdgToplevel::State::ActivatedState); |
1356 | q->sendConfigure(size: current.size, states: current.states); |
1357 | } |
1358 | |
1359 | void QWaylandXdgToplevelPrivate::handleFocusReceived() |
1360 | { |
1361 | Q_Q(QWaylandXdgToplevel); |
1362 | QWaylandXdgToplevelPrivate::ConfigureEvent current = lastSentConfigure(); |
1363 | if (!current.states.contains(t: QWaylandXdgToplevel::State::ActivatedState)) { |
1364 | current.states.push_back(t: QWaylandXdgToplevel::State::ActivatedState); |
1365 | q->sendConfigure(size: current.size, states: current.states); |
1366 | } |
1367 | } |
1368 | |
1369 | Qt::Edges QWaylandXdgToplevelPrivate::convertToEdges(resize_edge edge) |
1370 | { |
1371 | return Qt::Edges(((edge & 0b1100) >> 1) | ((edge & 0b0010) << 2) | (edge & 0b0001)); |
1372 | } |
1373 | |
1374 | void QWaylandXdgToplevelPrivate::xdg_toplevel_destroy_resource(QtWaylandServer::xdg_toplevel::Resource *resource) |
1375 | { |
1376 | Q_UNUSED(resource); |
1377 | Q_Q(QWaylandXdgToplevel); |
1378 | delete q; |
1379 | } |
1380 | |
1381 | void QWaylandXdgToplevelPrivate::xdg_toplevel_destroy(QtWaylandServer::xdg_toplevel::Resource *resource) |
1382 | { |
1383 | if (Q_UNLIKELY(m_decoration)) |
1384 | qWarning() << "Client error: xdg_toplevel destroyed before its decoration object"; |
1385 | |
1386 | wl_resource_destroy(resource->handle); |
1387 | //TODO: Should the xdg surface be desroyed as well? Or is it allowed to recreate a new toplevel for it? |
1388 | } |
1389 | |
1390 | void QWaylandXdgToplevelPrivate::xdg_toplevel_set_parent(QtWaylandServer::xdg_toplevel::Resource *resource, wl_resource *parent) |
1391 | { |
1392 | Q_UNUSED(resource); |
1393 | QWaylandXdgToplevel *parentToplevel = QWaylandXdgToplevel::fromResource(resource: parent); |
1394 | |
1395 | Q_Q(QWaylandXdgToplevel); |
1396 | |
1397 | if (m_parentToplevel != parentToplevel) { |
1398 | m_parentToplevel = parentToplevel; |
1399 | emit q->parentToplevelChanged(); |
1400 | } |
1401 | |
1402 | if (m_parentToplevel && m_xdgSurface->windowType() != Qt::WindowType::SubWindow) { |
1403 | // There's a parent now, which means the surface is transient |
1404 | QWaylandXdgSurfacePrivate::get(xdgSurface: m_xdgSurface)->setWindowType(Qt::WindowType::SubWindow); |
1405 | } else if (!m_parentToplevel && m_xdgSurface->windowType() != Qt::WindowType::Window) { |
1406 | // When the surface has no parent it is toplevel |
1407 | QWaylandXdgSurfacePrivate::get(xdgSurface: m_xdgSurface)->setWindowType(Qt::WindowType::Window); |
1408 | } |
1409 | } |
1410 | |
1411 | void QWaylandXdgToplevelPrivate::xdg_toplevel_set_title(QtWaylandServer::xdg_toplevel::Resource *resource, const QString &title) |
1412 | { |
1413 | Q_UNUSED(resource); |
1414 | if (title == m_title) |
1415 | return; |
1416 | Q_Q(QWaylandXdgToplevel); |
1417 | m_title = title; |
1418 | emit q->titleChanged(); |
1419 | } |
1420 | |
1421 | void QWaylandXdgToplevelPrivate::xdg_toplevel_set_app_id(QtWaylandServer::xdg_toplevel::Resource *resource, const QString &app_id) |
1422 | { |
1423 | Q_UNUSED(resource); |
1424 | if (app_id == m_appId) |
1425 | return; |
1426 | Q_Q(QWaylandXdgToplevel); |
1427 | m_appId = app_id; |
1428 | emit q->appIdChanged(); |
1429 | } |
1430 | |
1431 | void QWaylandXdgToplevelPrivate::xdg_toplevel_show_window_menu(QtWaylandServer::xdg_toplevel::Resource *resource, wl_resource *seatResource, uint32_t serial, int32_t x, int32_t y) |
1432 | { |
1433 | Q_UNUSED(resource); |
1434 | Q_UNUSED(serial); |
1435 | QPoint position(x, y); |
1436 | auto seat = QWaylandSeat::fromSeatResource(resource: seatResource); |
1437 | Q_Q(QWaylandXdgToplevel); |
1438 | emit q->showWindowMenu(seat, localSurfacePosition: position); |
1439 | } |
1440 | |
1441 | void QWaylandXdgToplevelPrivate::xdg_toplevel_move(Resource *resource, wl_resource *seatResource, uint32_t serial) |
1442 | { |
1443 | Q_UNUSED(resource); |
1444 | Q_UNUSED(serial); |
1445 | Q_Q(QWaylandXdgToplevel); |
1446 | QWaylandSeat *seat = QWaylandSeat::fromSeatResource(resource: seatResource); |
1447 | emit q->startMove(seat); |
1448 | } |
1449 | |
1450 | void QWaylandXdgToplevelPrivate::xdg_toplevel_resize(QtWaylandServer::xdg_toplevel::Resource *resource, wl_resource *seatResource, uint32_t serial, uint32_t edges) |
1451 | { |
1452 | Q_UNUSED(resource); |
1453 | Q_UNUSED(serial); |
1454 | Q_Q(QWaylandXdgToplevel); |
1455 | QWaylandSeat *seat = QWaylandSeat::fromSeatResource(resource: seatResource); |
1456 | emit q->startResize(seat, convertToEdges(resize_edge(edges))); |
1457 | } |
1458 | |
1459 | void QWaylandXdgToplevelPrivate::xdg_toplevel_set_max_size(QtWaylandServer::xdg_toplevel::Resource *resource, int32_t width, int32_t height) |
1460 | { |
1461 | Q_UNUSED(resource); |
1462 | |
1463 | QSize maxSize(width, height); |
1464 | if (width == 0 && height == 0) |
1465 | maxSize = QSize(); // Wayland size of zero means unspecified which best translates to invalid |
1466 | |
1467 | if (m_maxSize == maxSize) |
1468 | return; |
1469 | |
1470 | if (width < 0 || height < 0) { |
1471 | // The spec says raise a protocol error, but there's no matching error defined |
1472 | qWarning() << "Received a xdg_toplevel.set_max_size request with a negative size"; |
1473 | return; |
1474 | } |
1475 | |
1476 | if (m_minSize.isValid() && maxSize.isValid() && |
1477 | (maxSize.width() < m_minSize.width() || maxSize.height() < m_minSize.height())) { |
1478 | // The spec says raise a protocol error, but there's no matching error defined |
1479 | qWarning() << "Received a xdg_toplevel.set_max_size request with a size smaller than the minimium size"; |
1480 | return; |
1481 | } |
1482 | |
1483 | m_maxSize = maxSize; |
1484 | |
1485 | Q_Q(QWaylandXdgToplevel); |
1486 | emit q->maxSizeChanged(); |
1487 | } |
1488 | |
1489 | void QWaylandXdgToplevelPrivate::xdg_toplevel_set_min_size(QtWaylandServer::xdg_toplevel::Resource *resource, int32_t width, int32_t height) |
1490 | { |
1491 | Q_UNUSED(resource); |
1492 | |
1493 | QSize minSize(width, height); |
1494 | if (width == 0 && height == 0) |
1495 | minSize = QSize(); // Wayland size of zero means unspecified |
1496 | |
1497 | if (m_minSize == minSize) |
1498 | return; |
1499 | |
1500 | if (width < 0 || height < 0) { |
1501 | // The spec says raise a protocol error, but there's no matching error defined |
1502 | qWarning() << "Received a xdg_toplevel.set_min_size request with a negative size"; |
1503 | return; |
1504 | } |
1505 | |
1506 | if (m_maxSize.isValid() && minSize.isValid() && |
1507 | (minSize.width() > m_maxSize.width() || minSize.height() > m_maxSize.height())) { |
1508 | // The spec says raise a protocol error, but there's no matching error defined |
1509 | qWarning() << "Received a xdg_toplevel.set_min_size request with a size larger than the maximum size"; |
1510 | return; |
1511 | } |
1512 | |
1513 | m_minSize = minSize; |
1514 | |
1515 | Q_Q(QWaylandXdgToplevel); |
1516 | emit q->minSizeChanged(); |
1517 | } |
1518 | |
1519 | void QWaylandXdgToplevelPrivate::xdg_toplevel_set_maximized(QtWaylandServer::xdg_toplevel::Resource *resource) |
1520 | { |
1521 | Q_UNUSED(resource); |
1522 | Q_Q(QWaylandXdgToplevel); |
1523 | emit q->setMaximized(); |
1524 | } |
1525 | |
1526 | void QWaylandXdgToplevelPrivate::xdg_toplevel_unset_maximized(QtWaylandServer::xdg_toplevel::Resource *resource) |
1527 | { |
1528 | Q_UNUSED(resource); |
1529 | Q_Q(QWaylandXdgToplevel); |
1530 | emit q->unsetMaximized(); |
1531 | } |
1532 | |
1533 | void QWaylandXdgToplevelPrivate::xdg_toplevel_set_fullscreen(QtWaylandServer::xdg_toplevel::Resource *resource, wl_resource *output_res) |
1534 | { |
1535 | Q_UNUSED(resource); |
1536 | Q_Q(QWaylandXdgToplevel); |
1537 | QWaylandOutput *output = output_res ? QWaylandOutput::fromResource(resource: output_res) : nullptr; |
1538 | emit q->setFullscreen(output); |
1539 | } |
1540 | |
1541 | void QWaylandXdgToplevelPrivate::xdg_toplevel_unset_fullscreen(QtWaylandServer::xdg_toplevel::Resource *resource) |
1542 | { |
1543 | Q_UNUSED(resource); |
1544 | Q_Q(QWaylandXdgToplevel); |
1545 | emit q->unsetFullscreen(); |
1546 | } |
1547 | |
1548 | void QWaylandXdgToplevelPrivate::xdg_toplevel_set_minimized(QtWaylandServer::xdg_toplevel::Resource *resource) |
1549 | { |
1550 | Q_UNUSED(resource); |
1551 | Q_Q(QWaylandXdgToplevel); |
1552 | emit q->setMinimized(); |
1553 | } |
1554 | |
1555 | /*! |
1556 | * \qmltype XdgPopup |
1557 | * \nativetype QWaylandXdgPopup |
1558 | * \inqmlmodule QtWayland.Compositor.XdgShell |
1559 | * \since 5.12 |
1560 | * \brief XdgPopup represents the popup specific parts of and xdg surface. |
1561 | * |
1562 | * This type is part of the \l{XdgShell} extension and provides a way to extend |
1563 | * extend the functionality of an \l{XdgSurface} with features |
1564 | * specific to desktop-style menus for an xdg surface. |
1565 | * |
1566 | * It corresponds to the Wayland interface \c xdg_popup. |
1567 | */ |
1568 | |
1569 | /*! |
1570 | * \class QWaylandXdgPopup |
1571 | * \inmodule QtWaylandCompositor |
1572 | * \since 5.12 |
1573 | * \brief The QWaylandXdgPopup class represents the popup specific parts of an xdg surface. |
1574 | * |
1575 | * This class is part of the QWaylandXdgShell extension and provides a way to |
1576 | * extend the functionality of a QWaylandXdgSurface with features |
1577 | * specific to desktop-style menus for an xdg surface. |
1578 | * |
1579 | * It corresponds to the Wayland interface \c xdg_popup. |
1580 | */ |
1581 | |
1582 | /*! |
1583 | * Constructs a QWaylandXdgPopup. |
1584 | */ |
1585 | QWaylandXdgPopup::QWaylandXdgPopup(QWaylandXdgSurface *xdgSurface, QWaylandXdgSurface *parentXdgSurface, |
1586 | QWaylandXdgPositioner *positioner, QWaylandResource &resource) |
1587 | : QObject(*new QWaylandXdgPopupPrivate(xdgSurface, parentXdgSurface, positioner, resource)) |
1588 | { |
1589 | } |
1590 | |
1591 | /*! |
1592 | * \qmlproperty XdgSurface XdgPopup::xdgSurface |
1593 | * |
1594 | * This property holds the XdgSurface associated with this XdgPopup. |
1595 | */ |
1596 | |
1597 | /*! |
1598 | * \property QWaylandXdgPopup::xdgSurface |
1599 | * |
1600 | * This property holds the QWaylandXdgSurface associated with this QWaylandXdgPopup. |
1601 | */ |
1602 | QWaylandXdgSurface *QWaylandXdgPopup::xdgSurface() const |
1603 | { |
1604 | Q_D(const QWaylandXdgPopup); |
1605 | return d->m_xdgSurface; |
1606 | } |
1607 | |
1608 | /*! |
1609 | * \qmlproperty XdgSurface XdgPopup::parentXdgSurface |
1610 | * |
1611 | * This property holds the XdgSurface associated with the parent of this XdgPopup. |
1612 | */ |
1613 | |
1614 | /*! |
1615 | * \property QWaylandXdgPopup::parentXdgSurface |
1616 | * |
1617 | * This property holds the QWaylandXdgSurface associated with the parent of this |
1618 | * QWaylandXdgPopup. |
1619 | */ |
1620 | QWaylandXdgSurface *QWaylandXdgPopup::parentXdgSurface() const |
1621 | { |
1622 | Q_D(const QWaylandXdgPopup); |
1623 | return d->m_parentXdgSurface; |
1624 | } |
1625 | |
1626 | /*! |
1627 | * \qmlproperty rect XdgPopup::configuredGeometry |
1628 | * |
1629 | * The window geometry the popup received in the configure event. Relative to the |
1630 | * upper left corner of the parent surface. |
1631 | */ |
1632 | |
1633 | /*! |
1634 | * \property QWaylandXdgPopup::configuredGeometry |
1635 | * |
1636 | * The window geometry the popup received in the configure event. Relative to the |
1637 | * upper left corner of the parent surface. |
1638 | */ |
1639 | QRect QWaylandXdgPopup::configuredGeometry() const |
1640 | { |
1641 | Q_D(const QWaylandXdgPopup); |
1642 | return d->m_geometry; |
1643 | } |
1644 | |
1645 | /*! |
1646 | * \qmlproperty rect XdgPopup::anchorRect |
1647 | * |
1648 | * The anchor rectangle relative to the parent window geometry that the child |
1649 | * surface should be placed relative to. |
1650 | */ |
1651 | |
1652 | /*! |
1653 | * \property QWaylandXdgPopup::anchorRect |
1654 | * |
1655 | * Returns the anchor rectangle relative to the parent window geometry that the child |
1656 | * surface should be placed relative to. |
1657 | */ |
1658 | QRect QWaylandXdgPopup::anchorRect() const |
1659 | { |
1660 | Q_D(const QWaylandXdgPopup); |
1661 | return d->m_positionerData.anchorRect; |
1662 | } |
1663 | |
1664 | /*! |
1665 | * \qmlproperty enumeration XdgPopup::anchorEdges |
1666 | * |
1667 | * This property holds the set of edges on the anchor rect that the child surface should be placed |
1668 | * relative to. If no edges are specified in a direction, the anchor point should be |
1669 | * centered between the edges. |
1670 | * |
1671 | * The possible values are: |
1672 | * \value Qt.TopEdge The top edge of the rectangle. |
1673 | * \value Qt.LeftEdge The left edge of the rectangle. |
1674 | * \value Qt.RightEdge The right edge of the rectangle. |
1675 | * \value Qt.BottomEdge The bottom edge of the rectangle. |
1676 | */ |
1677 | |
1678 | /*! |
1679 | * \property QWaylandXdgPopup::anchorEdges |
1680 | * |
1681 | * Returns the set of edges on the anchor rect that the child surface should be placed |
1682 | * relative to. If no edges are specified in a direction, the anchor point should be |
1683 | * centered between the edges. |
1684 | */ |
1685 | Qt::Edges QWaylandXdgPopup::anchorEdges() const |
1686 | { |
1687 | Q_D(const QWaylandXdgPopup); |
1688 | return d->m_positionerData.anchorEdges; |
1689 | } |
1690 | |
1691 | /*! |
1692 | * \qmlproperty rect XdgPopup::gravityEdges |
1693 | * |
1694 | * Specifies in what direction the surface should be positioned, relative to the anchor |
1695 | * point. |
1696 | * |
1697 | * The possible values are: |
1698 | * \value Qt.TopEdge The surface should slide towards the top of the screen. |
1699 | * \value Qt.LeftEdge The surface should slide towards the left of the screen. |
1700 | * \value Qt.RightEdge The surface should slide towards the right of the screen. |
1701 | * \value Qt.BottomEdge The surface should slide towards the bottom of the screen. |
1702 | */ |
1703 | |
1704 | /*! |
1705 | * \property QWaylandXdgPopup::gravityEdges |
1706 | * |
1707 | * Specifies in what direction the surface should be positioned, relative to the anchor |
1708 | * point. |
1709 | */ |
1710 | Qt::Edges QWaylandXdgPopup::gravityEdges() const |
1711 | { |
1712 | Q_D(const QWaylandXdgPopup); |
1713 | return d->m_positionerData.gravityEdges; |
1714 | } |
1715 | |
1716 | /*! |
1717 | * \qmlproperty enumeration XdgPopup::slideConstraints |
1718 | * |
1719 | * This property holds the orientations in which the child should slide to fit within the screen. |
1720 | * |
1721 | * Possible values: |
1722 | * \value Qt.Horizontal Horizontal |
1723 | * \value Qt.Vertical Vertical |
1724 | */ |
1725 | |
1726 | /*! |
1727 | * \property QWaylandXdgPopup::slideConstraints |
1728 | * |
1729 | * This property holds the orientations in which the child should slide to fit within the screen. |
1730 | */ |
1731 | Qt::Orientations QWaylandXdgPopup::slideConstraints() const |
1732 | { |
1733 | Q_D(const QWaylandXdgPopup); |
1734 | const uint flags = d->m_positionerData.constraintAdjustments; |
1735 | |
1736 | Qt::Orientations constraints = {}; |
1737 | |
1738 | if (flags & XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_SLIDE_X) |
1739 | constraints |= Qt::Horizontal; |
1740 | if (flags & XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_SLIDE_Y) |
1741 | constraints |= Qt::Vertical; |
1742 | |
1743 | return constraints; |
1744 | } |
1745 | |
1746 | /*! |
1747 | * \qmlproperty enumeration XdgPopup::flipConstraints |
1748 | * |
1749 | * This property holds the orientations in which the child should flip to fit within the screen. |
1750 | * |
1751 | * Possible values: |
1752 | * \value Qt.Horizontal Horizontal |
1753 | * \value Qt.Vertical Vertical |
1754 | */ |
1755 | |
1756 | /*! |
1757 | * \property QWaylandXdgPopup::flipConstraints |
1758 | * |
1759 | * This property holds the orientations in which the child should flip to fit within the screen. |
1760 | */ |
1761 | Qt::Orientations QWaylandXdgPopup::flipConstraints() const |
1762 | { |
1763 | Q_D(const QWaylandXdgPopup); |
1764 | const uint flags = d->m_positionerData.constraintAdjustments; |
1765 | |
1766 | Qt::Orientations constraints = {}; |
1767 | |
1768 | if (flags & XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_FLIP_X) |
1769 | constraints |= Qt::Horizontal; |
1770 | if (flags & XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_FLIP_Y) |
1771 | constraints |= Qt::Vertical; |
1772 | |
1773 | return constraints; |
1774 | } |
1775 | |
1776 | /*! |
1777 | * \qmlproperty enumeration XdgPopup::resizeConstraints |
1778 | * |
1779 | * This property holds the orientations in which the child should resize to fit within the screen. |
1780 | * |
1781 | * Possible values: |
1782 | * \value Qt.Horizontal Horizontal |
1783 | * \value Qt.Vertical Vertical |
1784 | */ |
1785 | |
1786 | /*! |
1787 | * \property QWaylandXdgPopup::resizeConstraints |
1788 | * |
1789 | * This property holds the orientations in which the child should resize to fit within the screen. |
1790 | */ |
1791 | Qt::Orientations QWaylandXdgPopup::resizeConstraints() const |
1792 | { |
1793 | Q_D(const QWaylandXdgPopup); |
1794 | const uint flags = d->m_positionerData.constraintAdjustments; |
1795 | |
1796 | Qt::Orientations constraints = {}; |
1797 | |
1798 | if (flags & XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_RESIZE_X) |
1799 | constraints |= Qt::Horizontal; |
1800 | if (flags & XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_RESIZE_Y) |
1801 | constraints |= Qt::Vertical; |
1802 | |
1803 | return constraints; |
1804 | } |
1805 | |
1806 | /*! |
1807 | * \qmlproperty point XdgPopup::offset |
1808 | * |
1809 | * The position relative to the position of the anchor on the anchor rectangle and |
1810 | * the anchor on the surface. |
1811 | */ |
1812 | |
1813 | /*! |
1814 | * \property QWaylandXdgPopup::offset |
1815 | * |
1816 | * Returns the surface position relative to the position of the anchor on the anchor |
1817 | * rectangle and the anchor on the surface. |
1818 | */ |
1819 | QPoint QWaylandXdgPopup::offset() const |
1820 | { |
1821 | Q_D(const QWaylandXdgPopup); |
1822 | return d->m_positionerData.offset; |
1823 | } |
1824 | |
1825 | /*! |
1826 | * \qmlproperty size XdgPopup::positionerSize |
1827 | * |
1828 | * The size requested for the window geometry by the positioner object. |
1829 | */ |
1830 | |
1831 | /*! |
1832 | * \property QWaylandXdgPopup::positionerSize |
1833 | * |
1834 | * Returns the size requested for the window geometry by the positioner object. |
1835 | */ |
1836 | QSize QWaylandXdgPopup::positionerSize() const |
1837 | { |
1838 | Q_D(const QWaylandXdgPopup); |
1839 | return d->m_positionerData.size; |
1840 | } |
1841 | |
1842 | /*! |
1843 | * \qmlproperty point XdgPopup::unconstrainedPosition |
1844 | * |
1845 | * The position of the surface relative to the parent window geometry if the surface |
1846 | * is not constrained. I.e. when not moved to fit inside the screen or similar. |
1847 | */ |
1848 | |
1849 | /*! |
1850 | * \property QWaylandXdgPopup::unconstrainedPosition |
1851 | * |
1852 | * The position of the surface relative to the parent window geometry if the surface |
1853 | * is not constrained. I.e. when not moved to fit inside the screen or similar. |
1854 | */ |
1855 | QPoint QWaylandXdgPopup::unconstrainedPosition() const |
1856 | { |
1857 | Q_D(const QWaylandXdgPopup); |
1858 | return d->m_positionerData.unconstrainedPosition(); |
1859 | } |
1860 | |
1861 | /*! |
1862 | * \qmlmethod int XdgPopup::sendConfigure(rect geometry) |
1863 | * |
1864 | * Sends a configure event to the client. \a geometry contains the window geometry |
1865 | * relative to the upper left corner of the window geometry of the parent surface. |
1866 | * |
1867 | * This implicitly sends a configure event to the corresponding XdgSurface as well. |
1868 | */ |
1869 | |
1870 | /*! |
1871 | * Sends a configure event to the client. \a geometry contains the window geometry |
1872 | * relative to the upper left corner of the window geometry of the parent surface. |
1873 | * |
1874 | * This implicitly sends a configure event to the corresponding QWaylandXdgSurface |
1875 | * as well. |
1876 | */ |
1877 | uint QWaylandXdgPopup::sendConfigure(const QRect &geometry) |
1878 | { |
1879 | Q_D(QWaylandXdgPopup); |
1880 | return d->sendConfigure(geometry); |
1881 | } |
1882 | |
1883 | /*! |
1884 | * \qmlmethod void XdgPopup::sendPopupDone() |
1885 | * \since 5.14 |
1886 | * |
1887 | * Dismiss the popup. According to the \c xdg-shell protocol this should make the |
1888 | * client destroy the popup. |
1889 | */ |
1890 | |
1891 | /*! |
1892 | * \since 5.14 |
1893 | * |
1894 | * Dismiss the popup. According to the \c xdg-shell protocol this should make the |
1895 | * client destroy the popup. |
1896 | */ |
1897 | void QWaylandXdgPopup::sendPopupDone() |
1898 | { |
1899 | Q_D(QWaylandXdgPopup); |
1900 | d->send_popup_done(); |
1901 | } |
1902 | |
1903 | /*! |
1904 | * Returns the surface role for the QWaylandPopup. |
1905 | */ |
1906 | QWaylandSurfaceRole *QWaylandXdgPopup::role() |
1907 | { |
1908 | return &QWaylandXdgPopupPrivate::s_role; |
1909 | } |
1910 | |
1911 | QWaylandXdgPopupPrivate::QWaylandXdgPopupPrivate(QWaylandXdgSurface *xdgSurface, QWaylandXdgSurface *parentXdgSurface, |
1912 | QWaylandXdgPositioner *positioner, const QWaylandResource &resource) |
1913 | : m_xdgSurface(xdgSurface) |
1914 | , m_parentXdgSurface(parentXdgSurface) |
1915 | , m_positionerData(positioner->m_data) |
1916 | { |
1917 | Q_ASSERT(m_positionerData.isComplete()); |
1918 | init(resource.resource()); |
1919 | |
1920 | QWaylandXdgSurfacePrivate::get(xdgSurface: m_xdgSurface)->setWindowType(Qt::WindowType::Popup); |
1921 | |
1922 | //TODO: Need an API for sending a different initial configure |
1923 | sendConfigure(geometry: QRect(m_positionerData.unconstrainedPosition(), m_positionerData.size)); |
1924 | } |
1925 | |
1926 | void QWaylandXdgPopupPrivate::handleAckConfigure(uint serial) |
1927 | { |
1928 | Q_Q(QWaylandXdgPopup); |
1929 | ConfigureEvent config; |
1930 | Q_FOREVER { |
1931 | if (m_pendingConfigures.empty()) { |
1932 | qWarning(msg: "Popup received an unexpected ack_configure!"); |
1933 | return; |
1934 | } |
1935 | |
1936 | // This won't work unless there always is a popup.configure for each xdgsurface.configure |
1937 | config = m_pendingConfigures.takeFirst(); |
1938 | |
1939 | if (config.serial == serial) |
1940 | break; |
1941 | } |
1942 | |
1943 | if (m_geometry == config.geometry) |
1944 | return; |
1945 | |
1946 | m_geometry = config.geometry; |
1947 | emit q->configuredGeometryChanged(); |
1948 | } |
1949 | |
1950 | uint QWaylandXdgPopupPrivate::sendConfigure(const QRect &geometry) |
1951 | { |
1952 | uint32_t serial = m_xdgSurface->surface()->compositor()->nextSerial(); |
1953 | m_pendingConfigures.append(t: QWaylandXdgPopupPrivate::ConfigureEvent{.geometry: geometry, .serial: serial}); |
1954 | send_configure(geometry.x(), geometry.y(), geometry.width(), geometry.height()); |
1955 | QWaylandXdgSurfacePrivate::get(xdgSurface: m_xdgSurface)->send_configure(serial); |
1956 | return serial; |
1957 | } |
1958 | |
1959 | void QWaylandXdgPopupPrivate::xdg_popup_destroy(QtWaylandServer::xdg_popup::Resource *resource) |
1960 | { |
1961 | Q_UNUSED(resource); |
1962 | qWarning() << Q_FUNC_INFO << "Not implemented"; //TODO |
1963 | } |
1964 | |
1965 | void QWaylandXdgPopupPrivate::xdg_popup_grab(QtWaylandServer::xdg_popup::Resource *resource, wl_resource *seat, uint32_t serial) |
1966 | { |
1967 | Q_UNUSED(resource); |
1968 | Q_UNUSED(serial); |
1969 | Q_UNUSED(seat); |
1970 | qWarning() << Q_FUNC_INFO << "Not implemented"; //TODO |
1971 | //switch keyboard focus |
1972 | //eventually send configure with activated. |
1973 | } |
1974 | |
1975 | QWaylandSurfaceRole QWaylandXdgPopupPrivate::s_role("xdg_popup"); |
1976 | |
1977 | QWaylandXdgPositionerData::QWaylandXdgPositionerData() |
1978 | : offset(0, 0) |
1979 | {} |
1980 | |
1981 | bool QWaylandXdgPositionerData::isComplete() const |
1982 | { |
1983 | return size.width() > 0 && size.height() > 0 && anchorRect.size().width() > 0 && anchorRect.size().height() > 0; |
1984 | } |
1985 | |
1986 | QPoint QWaylandXdgPositionerData::anchorPoint() const |
1987 | { |
1988 | int yPosition = 0; |
1989 | if (anchorEdges & Qt::TopEdge) |
1990 | yPosition = anchorRect.top(); |
1991 | else if (anchorEdges & Qt::BottomEdge) |
1992 | yPosition = anchorRect.bottom() + 1; |
1993 | else |
1994 | yPosition = anchorRect.top() + anchorRect.height() / 2; |
1995 | |
1996 | int xPosition = 0; |
1997 | if (anchorEdges & Qt::LeftEdge) |
1998 | xPosition = anchorRect.left(); |
1999 | else if (anchorEdges & Qt::RightEdge) |
2000 | xPosition = anchorRect.right() + 1; |
2001 | else |
2002 | xPosition = anchorRect.left() + anchorRect.width() / 2; |
2003 | |
2004 | return QPoint(xPosition, yPosition); |
2005 | } |
2006 | |
2007 | QPoint QWaylandXdgPositionerData::unconstrainedPosition() const |
2008 | { |
2009 | int gravityOffsetY = 0; |
2010 | if (gravityEdges & Qt::TopEdge) |
2011 | gravityOffsetY = -size.height(); |
2012 | else if (!(gravityEdges & Qt::BottomEdge)) |
2013 | gravityOffsetY = -size.height() / 2; |
2014 | |
2015 | int gravityOffsetX = 0; |
2016 | if (gravityEdges & Qt::LeftEdge) |
2017 | gravityOffsetX = -size.width(); |
2018 | else if (!(gravityEdges & Qt::RightEdge)) |
2019 | gravityOffsetX = -size.width() / 2; |
2020 | |
2021 | QPoint gravityOffset(gravityOffsetX, gravityOffsetY); |
2022 | return anchorPoint() + gravityOffset + offset; |
2023 | } |
2024 | |
2025 | QWaylandXdgPositioner::QWaylandXdgPositioner(const QWaylandResource &resource) |
2026 | { |
2027 | init(resource.resource()); |
2028 | } |
2029 | |
2030 | void QWaylandXdgPositioner::xdg_positioner_destroy_resource(QtWaylandServer::xdg_positioner::Resource *resource) |
2031 | { |
2032 | Q_UNUSED(resource); |
2033 | delete this; |
2034 | } |
2035 | |
2036 | void QWaylandXdgPositioner::xdg_positioner_destroy(QtWaylandServer::xdg_positioner::Resource *resource) |
2037 | { |
2038 | wl_resource_destroy(resource->handle); |
2039 | } |
2040 | |
2041 | void QWaylandXdgPositioner::xdg_positioner_set_size(QtWaylandServer::xdg_positioner::Resource *resource, int32_t width, int32_t height) |
2042 | { |
2043 | if (width <= 0 || height <= 0) { |
2044 | wl_resource_post_error(resource->handle, XDG_POSITIONER_ERROR_INVALID_INPUT, |
2045 | "xdg_positioner.set_size requested with non-positive dimensions"); |
2046 | return; |
2047 | } |
2048 | |
2049 | QSize size(width, height); |
2050 | m_data.size = size; |
2051 | } |
2052 | |
2053 | void QWaylandXdgPositioner::xdg_positioner_set_anchor_rect(QtWaylandServer::xdg_positioner::Resource *resource, int32_t x, int32_t y, int32_t width, int32_t height) |
2054 | { |
2055 | if (width <= 0 || height <= 0) { |
2056 | wl_resource_post_error(resource->handle, XDG_POSITIONER_ERROR_INVALID_INPUT, |
2057 | "xdg_positioner.set_anchor_rect requested with non-positive dimensions"); |
2058 | return; |
2059 | } |
2060 | |
2061 | QRect anchorRect(x, y, width, height); |
2062 | m_data.anchorRect = anchorRect; |
2063 | } |
2064 | |
2065 | void QWaylandXdgPositioner::xdg_positioner_set_anchor(QtWaylandServer::xdg_positioner::Resource *resource, uint32_t anchor) |
2066 | { |
2067 | Qt::Edges anchorEdges = convertToEdges(xdg_positioner::anchor(anchor)); |
2068 | |
2069 | if ((anchorEdges & Qt::BottomEdge && anchorEdges & Qt::TopEdge) || |
2070 | (anchorEdges & Qt::LeftEdge && anchorEdges & Qt::RightEdge)) { |
2071 | wl_resource_post_error(resource->handle, XDG_POSITIONER_ERROR_INVALID_INPUT, |
2072 | "xdg_positioner.set_anchor requested with parallel edges"); |
2073 | return; |
2074 | } |
2075 | |
2076 | m_data.anchorEdges = anchorEdges; |
2077 | } |
2078 | |
2079 | void QWaylandXdgPositioner::xdg_positioner_set_gravity(QtWaylandServer::xdg_positioner::Resource *resource, uint32_t gravity) |
2080 | { |
2081 | Qt::Edges gravityEdges = convertToEdges(xdg_positioner::gravity(gravity)); |
2082 | |
2083 | if ((gravityEdges & Qt::BottomEdge && gravityEdges & Qt::TopEdge) || |
2084 | (gravityEdges & Qt::LeftEdge && gravityEdges & Qt::RightEdge)) { |
2085 | wl_resource_post_error(resource->handle, XDG_POSITIONER_ERROR_INVALID_INPUT, |
2086 | "xdg_positioner.set_gravity requested with parallel edges"); |
2087 | return; |
2088 | } |
2089 | |
2090 | m_data.gravityEdges = gravityEdges; |
2091 | } |
2092 | |
2093 | void QWaylandXdgPositioner::xdg_positioner_set_constraint_adjustment(QtWaylandServer::xdg_positioner::Resource *resource, uint32_t constraint_adjustment) |
2094 | { |
2095 | Q_UNUSED(resource); |
2096 | m_data.constraintAdjustments = constraint_adjustment; |
2097 | } |
2098 | |
2099 | void QWaylandXdgPositioner::xdg_positioner_set_offset(QtWaylandServer::xdg_positioner::Resource *resource, int32_t x, int32_t y) |
2100 | { |
2101 | Q_UNUSED(resource); |
2102 | m_data.offset = QPoint(x, y); |
2103 | } |
2104 | |
2105 | QWaylandXdgPositioner *QWaylandXdgPositioner::fromResource(wl_resource *resource) |
2106 | { |
2107 | return QtWayland::fromResource<QWaylandXdgPositioner *>(resource); |
2108 | } |
2109 | |
2110 | Qt::Edges QWaylandXdgPositioner::convertToEdges(anchor anchor) |
2111 | { |
2112 | switch (anchor) { |
2113 | case anchor_none: |
2114 | return Qt::Edges(); |
2115 | case anchor_top: |
2116 | return Qt::TopEdge; |
2117 | case anchor_bottom: |
2118 | return Qt::BottomEdge; |
2119 | case anchor_left: |
2120 | return Qt::LeftEdge; |
2121 | case anchor_right: |
2122 | return Qt::RightEdge; |
2123 | case anchor_top_left: |
2124 | return Qt::TopEdge | Qt::LeftEdge; |
2125 | case anchor_bottom_left: |
2126 | return Qt::BottomEdge | Qt::LeftEdge; |
2127 | case anchor_top_right: |
2128 | return Qt::TopEdge | Qt::RightEdge; |
2129 | case anchor_bottom_right: |
2130 | return Qt::BottomEdge | Qt::RightEdge; |
2131 | default: |
2132 | qWarning() << "Unknown Wayland xdg edge"<< anchor; |
2133 | return Qt::Edges(); |
2134 | } |
2135 | } |
2136 | |
2137 | Qt::Edges QWaylandXdgPositioner::convertToEdges(QWaylandXdgPositioner::gravity gravity) |
2138 | { |
2139 | return convertToEdges(anchor(gravity)); |
2140 | } |
2141 | |
2142 | |
2143 | QT_END_NAMESPACE |
2144 | |
2145 | #include "moc_qwaylandxdgshell.cpp" |
2146 |
Definitions
- QWaylandXdgShellPrivate
- ping
- registerXdgSurface
- unregisterXdgSurface
- xdgSurfaceFromSurface
- xdg_wm_base_destroy
- xdg_wm_base_create_positioner
- xdg_wm_base_get_xdg_surface
- xdg_wm_base_pong
- QWaylandXdgShell
- QWaylandXdgShell
- initialize
- interface
- interfaceName
- ping
- handleSeatChanged
- handleFocusChanged
- QWaylandXdgSurfacePrivate
- setWindowType
- handleFocusLost
- handleFocusReceived
- calculateFallbackWindowGeometry
- updateFallbackWindowGeometry
- xdg_surface_destroy_resource
- xdg_surface_destroy
- xdg_surface_get_toplevel
- xdg_surface_get_popup
- xdg_surface_ack_configure
- xdg_surface_set_window_geometry
- QWaylandXdgSurface
- QWaylandXdgSurface
- initialize
- windowType
- windowGeometry
- initialize
- handleSurfaceSizeChanged
- handleBufferScaleChanged
- shell
- surface
- toplevel
- popup
- interface
- interfaceName
- fromResource
- createIntegration
- QWaylandXdgToplevel
- ~QWaylandXdgToplevel
- xdgSurface
- parentToplevel
- title
- appId
- maxSize
- minSize
- states
- maximized
- fullscreen
- resizing
- activated
- isModal
- setModal
- decorationMode
- sizeForResize
- sendConfigure
- sendConfigure
- sendClose
- sendMaximized
- sendUnmaximized
- sendFullscreen
- sendResizing
- role
- fromResource
- statesAsInts
- s_role
- QWaylandXdgToplevelPrivate
- handleAckConfigure
- handleFocusLost
- handleFocusReceived
- convertToEdges
- xdg_toplevel_destroy_resource
- xdg_toplevel_destroy
- xdg_toplevel_set_parent
- xdg_toplevel_set_title
- xdg_toplevel_set_app_id
- xdg_toplevel_show_window_menu
- xdg_toplevel_move
- xdg_toplevel_resize
- xdg_toplevel_set_max_size
- xdg_toplevel_set_min_size
- xdg_toplevel_set_maximized
- xdg_toplevel_unset_maximized
- xdg_toplevel_set_fullscreen
- xdg_toplevel_unset_fullscreen
- xdg_toplevel_set_minimized
- QWaylandXdgPopup
- xdgSurface
- parentXdgSurface
- configuredGeometry
- anchorRect
- anchorEdges
- gravityEdges
- slideConstraints
- flipConstraints
- resizeConstraints
- offset
- positionerSize
- unconstrainedPosition
- sendConfigure
- sendPopupDone
- role
- QWaylandXdgPopupPrivate
- handleAckConfigure
- sendConfigure
- xdg_popup_destroy
- xdg_popup_grab
- s_role
- QWaylandXdgPositionerData
- isComplete
- anchorPoint
- unconstrainedPosition
- QWaylandXdgPositioner
- xdg_positioner_destroy_resource
- xdg_positioner_destroy
- xdg_positioner_set_size
- xdg_positioner_set_anchor_rect
- xdg_positioner_set_anchor
- xdg_positioner_set_gravity
- xdg_positioner_set_constraint_adjustment
- xdg_positioner_set_offset
- fromResource
- convertToEdges
Learn Advanced QML with KDAB
Find out more