Qt
Internal/Contributor docs for the Qt SDK. Note: These are NOT official API docs; those are found at https://doc.qt.io/
Loading...
Searching...
No Matches
qwaylandsurface.cpp
Go to the documentation of this file.
1// Copyright (C) 2017-2015 Pier Luigi Fiorini <pierluigi.fiorini@gmail.com>
2// Copyright (C) 2017 The Qt Company Ltd.
3// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
4// Qt-Security score:critical reason:network-protocol
5
8
9#include "wayland_wrapper/qwlbuffermanager_p.h"
10#include "wayland_wrapper/qwlregion_p.h"
11#include <QtWaylandCompositor/private/qtwaylandcompositorglobal_p.h>
12#if QT_CONFIG(wayland_datadevice)
13#include "wayland_wrapper/qwldatadevice_p.h"
14#include "wayland_wrapper/qwldatadevicemanager_p.h"
15#endif
16
18
19#include <QtWaylandCompositor/QWaylandCompositor>
20#include <QtWaylandCompositor/QWaylandClient>
21#include <QtWaylandCompositor/QWaylandView>
22#include <QtWaylandCompositor/QWaylandBufferRef>
23
24#include <QtWaylandCompositor/private/qwaylandcompositor_p.h>
25#include <QtWaylandCompositor/private/qwaylandview_p.h>
26#include <QtWaylandCompositor/private/qwaylandseat_p.h>
27#include <QtWaylandCompositor/private/qwaylandutils_p.h>
28
29#include <QtCore/private/qobject_p.h>
30
31#include <QtGui/QGuiApplication>
32#include <QtGui/QScreen>
33
34#include <QtCore/QDebug>
35#include <QtCore/QtMath>
36
38
39namespace QtWayland {
41public:
42 FrameCallback(QWaylandSurface *surf, wl_resource *res)
43 : surface(surf)
44 , resource(res)
45 {
46 wl_resource_set_implementation(res, nullptr, this, destroyCallback);
47 }
49 {
50 }
51 void destroy()
52 {
53 surface = nullptr;
54 if (resource)
55 wl_resource_destroy(resource);
56 else
57 delete this;
58 }
59 void sendAndDestroy(uint time)
60 {
61 surface = nullptr;
62 wl_callback_send_done(resource, time);
63 wl_resource_destroy(resource);
64 }
65 static void destroyCallback(wl_resource *res)
66 {
67 FrameCallback *_this = static_cast<FrameCallback *>(wl_resource_get_user_data(res));
68 if (_this->surface)
69 QWaylandSurfacePrivate::get(_this->surface)->removeFrameCallback(_this);
70 delete _this;
71 }
72 QWaylandSurface *surface = nullptr;
73 wl_resource *resource = nullptr;
74};
75}
77 return QRegion(QRect(QPoint(std::numeric_limits<int>::min()/2+1, std::numeric_limits<int>::min()/2+1),
78 QPoint(std::numeric_limits<int>::max()/2, std::numeric_limits<int>::max()/2)));
79}
80
81#ifndef QT_NO_DEBUG
82QList<QWaylandSurfacePrivate *> QWaylandSurfacePrivate::uninitializedSurfaces;
83#endif
84
85QWaylandSurfacePrivate::QWaylandSurfacePrivate()
86 : inputRegion(infiniteRegion())
87{
88 pending.buffer = QWaylandBufferRef();
89 pending.newlyAttached = false;
90 pending.inputRegion = infiniteRegion();
91 pending.bufferScale = 1;
92#ifndef QT_NO_DEBUG
93 addUninitializedSurface(this);
94#endif
95}
96
97QWaylandSurfacePrivate::~QWaylandSurfacePrivate()
98{
99 for (int i = 0; i < views.size(); i++) {
100 QWaylandViewPrivate::get(views.at(i))->markSurfaceAsDestroyed(q_func());
101 }
102 views.clear();
103
104 bufferRef = QWaylandBufferRef();
105
106 for (QtWayland::FrameCallback *c : std::as_const(frameCallbacks))
107 c->destroy();
108 for (QtWayland::FrameCallback *c : std::as_const(pendingFrameCallbacks))
109 c->destroy();
110}
111
112void QWaylandSurfacePrivate::removeFrameCallback(QtWayland::FrameCallback *callback)
113{
114 if (!frameCallbacks.removeOne(callback))
115 pendingFrameCallbacks.removeOne(callback);
116}
117
118void QWaylandSurfacePrivate::notifyViewsAboutDestruction()
119{
120 Q_Q(QWaylandSurface);
121 const auto viewsCopy = views; // Views will be removed from the list when marked as destroyed
122 for (QWaylandView *view : viewsCopy) {
123 QWaylandViewPrivate::get(view)->markSurfaceAsDestroyed(q);
124 }
125 if (hasContent) {
126 hasContent = false;
127 emit q->hasContentChanged();
128 }
129}
130
131#ifndef QT_NO_DEBUG
132void QWaylandSurfacePrivate::addUninitializedSurface(QWaylandSurfacePrivate *surface)
133{
134 Q_ASSERT(!surface->isInitialized);
135 Q_ASSERT(!uninitializedSurfaces.contains(surface));
136 uninitializedSurfaces.append(surface);
137}
138
139void QWaylandSurfacePrivate::removeUninitializedSurface(QWaylandSurfacePrivate *surface)
140{
141 Q_ASSERT(surface->isInitialized);
142 bool removed = uninitializedSurfaces.removeOne(surface);
143 Q_ASSERT(removed);
144}
145
146bool QWaylandSurfacePrivate::hasUninitializedSurface()
147{
148 return uninitializedSurfaces.size();
149}
150#endif
151
152void QWaylandSurfacePrivate::surface_destroy_resource(Resource *)
153{
154 Q_Q(QWaylandSurface);
155 notifyViewsAboutDestruction();
156
157 destroyed = true;
158 emit q->surfaceDestroyed();
159 q->destroy();
160}
161
162void QWaylandSurfacePrivate::surface_destroy(Resource *resource)
163{
164 wl_resource_destroy(resource->handle);
165}
166
167void QWaylandSurfacePrivate::surface_offset(Resource *, int32_t x, int32_t y)
168{
169 pending.offset = QPoint(x, y);
170}
171
172void QWaylandSurfacePrivate::surface_attach(Resource *resource, struct wl_resource *buffer, int x, int y)
173{
174 if (resource->version() >= WL_SURFACE_OFFSET_SINCE_VERSION) {
175 if (Q_UNLIKELY(x != 0 || y != 0)) {
176 wl_resource_post_error(resource->handle, WL_SURFACE_ERROR_INVALID_OFFSET,
177 "invalid buffer offset");
178 return;
179 }
180 // The x and y arguments are ignored and do not change the pending state.
181 } else {
182 pending.offset = QPoint(x, y);
183 }
184
185 pending.buffer = QWaylandBufferRef(getBuffer(buffer));
186 pending.newlyAttached = true;
187}
188
189/*
190 Note: The Wayland protocol specifies that buffer scale and damage can be interleaved, so
191 we cannot scale the damage region until commit. We assume that clients will either use
192 surface_damage or surface_damage_buffer within one frame for one surface.
193*/
194
195void QWaylandSurfacePrivate::surface_damage(Resource *, int32_t x, int32_t y, int32_t width, int32_t height)
196{
197 pending.surfaceDamage = pending.surfaceDamage.united(QRect(x, y, width, height));
198}
199
200void QWaylandSurfacePrivate::surface_damage_buffer(Resource *, int32_t x, int32_t y, int32_t width, int32_t height)
201{
202 pending.bufferDamage = pending.bufferDamage.united(QRect(x, y, width, height));
203}
204
205void QWaylandSurfacePrivate::surface_frame(Resource *resource, uint32_t callback)
206{
207 Q_Q(QWaylandSurface);
208 struct wl_resource *frame_callback = wl_resource_create(resource->client(), &wl_callback_interface, wl_callback_interface.version, callback);
209 pendingFrameCallbacks << new QtWayland::FrameCallback(q, frame_callback);
210}
211
212void QWaylandSurfacePrivate::surface_set_opaque_region(Resource *, struct wl_resource *region)
213{
214 pending.opaqueRegion = region ? QtWayland::Region::fromResource(region)->region() : QRegion();
215}
216
217void QWaylandSurfacePrivate::surface_set_input_region(Resource *, struct wl_resource *region)
218{
219 if (region) {
220 pending.inputRegion = QtWayland::Region::fromResource(region)->region();
221 } else {
222 pending.inputRegion = infiniteRegion();
223 }
224}
225
226void QWaylandSurfacePrivate::surface_commit(Resource *)
227{
228 Q_Q(QWaylandSurface);
229
230 // Needed in order to know whether we want to emit signals later
231 QSize oldBufferSize = bufferSize;
232 QRectF oldSourceGeometry = sourceGeometry;
233 QSize oldDestinationSize = destinationSize;
234 bool oldHasContent = hasContent;
235 int oldBufferScale = bufferScale;
236 Qt::ScreenOrientation oldContentOrientation = contentOrientation;
237
238 // Update all internal state
239 if (pending.buffer.hasBuffer() || pending.newlyAttached)
240 bufferRef = pending.buffer;
241 contentOrientation = pending.contentOrientation;
242 bufferScale = pending.bufferScale;
243 bufferSize = bufferRef.size();
244 QSize surfaceSize = bufferSize / bufferScale;
245 sourceGeometry = !pending.sourceGeometry.isValid() ? QRect(QPoint(), surfaceSize) : pending.sourceGeometry;
246 destinationSize = pending.destinationSize.isEmpty() ? sourceGeometry.size().toSize() : pending.destinationSize;
247 QRect destinationRect(QPoint(), destinationSize);
248 // pending.damage is already in surface coordinates
249 damage = pending.surfaceDamage.intersected(destinationRect);
250 if (!pending.bufferDamage.isNull()) {
251 if (bufferScale == 1) {
252 damage |= pending.bufferDamage.intersected(destinationRect); // Already in surface coordinates
253 } else {
254 // We must transform pending.damage from buffer coordinate system to surface coordinates
255 // TODO(QTBUG-85461): Also support wp_viewport setting more complex transformations
256 auto xform = [](const QRect &r, int scale) -> QRect {
257 QRect res{
258 QPoint{ r.x() / scale, r.y() / scale },
259 QPoint{ (r.right() + scale - 1) / scale, (r.bottom() + scale - 1) / scale }
260 };
261 return res;
262 };
263 for (const QRect &r : pending.bufferDamage)
264 damage |= xform(r, bufferScale).intersected(destinationRect);
265 }
266 }
267 hasContent = bufferRef.hasContent();
268 frameCallbacks << pendingFrameCallbacks;
269 inputRegion = pending.inputRegion.intersected(destinationRect);
270 opaqueRegion = pending.opaqueRegion.intersected(destinationRect);
271 bool becameOpaque = opaqueRegion.boundingRect().contains(destinationRect);
272 if (becameOpaque != isOpaque) {
273 isOpaque = becameOpaque;
274 emit q->isOpaqueChanged();
275 }
276
277 QPoint offsetForNextFrame = pending.offset;
278
279 if (viewport)
280 viewport->checkCommittedState();
281
282 // Clear per-commit state
283 pending.buffer = QWaylandBufferRef();
284 pending.offset = QPoint();
285 pending.newlyAttached = false;
286 pending.bufferDamage = QRegion();
287 pending.surfaceDamage = QRegion();
288 pendingFrameCallbacks.clear();
289
290 // Notify buffers and views
291 if (auto *buffer = bufferRef.buffer())
292 buffer->setCommitted(damage);
293 for (auto *view : std::as_const(views))
294 view->bufferCommitted(bufferRef, damage);
295
296 // Now all double-buffered state has been applied so it's safe to emit general signals
297 // i.e. we won't have inconsistensies such as mismatched surface size and buffer scale in
298 // signal handlers.
299
300 emit q->damaged(damage);
301
302 if (oldContentOrientation != contentOrientation)
303 emit q->contentOrientationChanged();
304
305 if (oldBufferSize != bufferSize)
306 emit q->bufferSizeChanged();
307
308 if (oldBufferScale != bufferScale)
309 emit q->bufferScaleChanged();
310
311 if (oldDestinationSize != destinationSize)
312 emit q->destinationSizeChanged();
313
314 if (oldSourceGeometry != sourceGeometry)
315 emit q->sourceGeometryChanged();
316
317 if (oldHasContent != hasContent)
318 emit q->hasContentChanged();
319
320 if (!offsetForNextFrame.isNull())
321 emit q->offsetForNextFrame(offsetForNextFrame);
322
323 emit q->redraw();
324}
325
326void QWaylandSurfacePrivate::surface_set_buffer_transform(Resource *resource, int32_t orientation)
327{
328 Q_Q(QWaylandSurface);
329 QScreen *screen = nullptr;
330 if (auto *view = q->primaryView()) {
331 if (auto *output = view->output()) {
332 if (auto *window = output->window())
333 screen = window->screen();
334 }
335 }
336 if (screen == nullptr)
337 screen = QGuiApplication::primaryScreen();
338 Qt::ScreenOrientation newContentOrientation = screen->primaryOrientation();
339 bool isPortrait = newContentOrientation == Qt::PortraitOrientation;
340 switch (orientation) {
341 case WL_OUTPUT_TRANSFORM_90:
342 newContentOrientation = isPortrait ? Qt::InvertedLandscapeOrientation : Qt::PortraitOrientation;
343 break;
344 case WL_OUTPUT_TRANSFORM_180:
345 newContentOrientation = isPortrait ? Qt::InvertedPortraitOrientation : Qt::InvertedLandscapeOrientation;
346 break;
347 case WL_OUTPUT_TRANSFORM_270:
348 newContentOrientation = isPortrait ? Qt::LandscapeOrientation : Qt::InvertedPortraitOrientation;
349 break;
350 case WL_OUTPUT_TRANSFORM_NORMAL:
351 newContentOrientation = Qt::PrimaryOrientation;
352 break;
353
354 // Ignore these ones, at least for now
355 case WL_OUTPUT_TRANSFORM_FLIPPED:
356 case WL_OUTPUT_TRANSFORM_FLIPPED_90:
357 case WL_OUTPUT_TRANSFORM_FLIPPED_180:
358 case WL_OUTPUT_TRANSFORM_FLIPPED_270:
359 return;
360
361 default:
362 wl_resource_post_error(resource->handle, WL_SURFACE_ERROR_INVALID_TRANSFORM,
363 "invalid buffer transform");
364 return;
365 }
366 pending.contentOrientation = newContentOrientation;
367}
368
369void QWaylandSurfacePrivate::surface_set_buffer_scale(QtWaylandServer::wl_surface::Resource *resource, int32_t scale)
370{
371 if (Q_UNLIKELY(scale <= 0)) {
372 wl_resource_post_error(resource->handle, WL_SURFACE_ERROR_INVALID_SCALE,
373 "invalid buffer scale");
374 return;
375 }
376
377 pending.bufferScale = scale;
378}
379
380QtWayland::ClientBuffer *QWaylandSurfacePrivate::getBuffer(struct ::wl_resource *buffer)
381{
382 QtWayland::BufferManager *bufMan = QWaylandCompositorPrivate::get(compositor)->bufferManager();
383 return bufMan->getBuffer(buffer);
384}
385
386/*!
387 * \class QWaylandSurfaceRole
388 * \inmodule QtWaylandCompositor
389 * \since 5.8
390 * \brief The QWaylandSurfaceRole class represents the role of the surface in context of wl_surface.
391 *
392 * QWaylandSurfaceRole is used to represent the role of a QWaylandSurface. According to the protocol
393 * specification, the role of a surface is permanent once set, and if the same surface is later
394 * reused for a different role, this constitutes a protocol error. Setting the surface to the same
395 * role multiple times is not an error.
396 *
397 * As an example, the QWaylandXdgShell can assign either "popup" or "toplevel" roles to surfaces.
398 * If \c get_toplevel is requested on a surface which has previously received a \c get_popup
399 * request, then the compositor will issue a protocol error.
400 *
401 * Roles are compared by pointer value, so any two objects of QWaylandSurfaceRole will be considered
402 * different roles, regardless of what their \l{name()}{names} are. A typical way of assigning a
403 * role is to have a static QWaylandSurfaceRole object to represent it.
404 *
405 * \code
406 * class MyShellSurfaceSubType
407 * {
408 * static QWaylandSurfaceRole s_role;
409 * // ...
410 * };
411 *
412 * // ...
413 *
414 * surface->setRole(&MyShellSurfaceSubType::s_role, resource->handle, MY_ERROR_CODE);
415 * \endcode
416 */
417
418/*!
419 * \fn QWaylandSurfaceRole::QWaylandSurfaceRole(const QByteArray &name)
420 *
421 * Creates a QWaylandSurfaceRole and assigns it \a name. The name is used in error messages
422 * involving this QWaylandSurfaceRole.
423 */
424
425/*!
426 * \fn const QByteArray QWaylandSurfaceRole::name()
427 *
428 * Returns the name of the QWaylandSurfaceRole. The name is used in error messages involving this
429 * QWaylandSurfaceRole, for example if an attempt is made to change the role of a surface.
430 */
431
432/*!
433 * \qmltype WaylandSurface
434 * \nativetype QWaylandSurface
435 * \inqmlmodule QtWayland.Compositor
436 * \since 5.8
437 * \brief Represents a rectangular area on an output device.
438 *
439 * This type encapsulates a rectangular area of pixels that is displayed on an output device. It
440 * corresponds to the interface \c wl_surface in the Wayland protocol.
441 */
442
443/*!
444 * \class QWaylandSurface
445 * \inmodule QtWaylandCompositor
446 * \since 5.8
447 * \brief The QWaylandSurface class represents a rectangular area on an output device.
448 *
449 * This class encapsulates a rectangular area of pixels that is displayed on an output device. It
450 * corresponds to the interface \c wl_surface in the Wayland protocol.
451 */
452
453/*!
454 * Constructs an uninitialized QWaylandSurface.
455 */
456QWaylandSurface::QWaylandSurface()
457 : QWaylandObject(*new QWaylandSurfacePrivate())
458{
459}
460
461/*!
462 * Constructs and initializes a QWaylandSurface for the given \a compositor and \a client, and with the given \a id
463 * and \a version.
464 */
465QWaylandSurface::QWaylandSurface(QWaylandCompositor *compositor, QWaylandClient *client, uint id, int version)
466 : QWaylandObject(*new QWaylandSurfacePrivate())
467{
468 initialize(compositor, client, id, version);
469}
470
471/*!
472 * \internal
473 */
474QWaylandSurface::QWaylandSurface(QWaylandSurfacePrivate &dptr)
475 : QWaylandObject(dptr)
476{
477}
478
479/*!
480 * Destroys the QWaylandSurface.
481 */
482QWaylandSurface::~QWaylandSurface()
483{
484 Q_D(QWaylandSurface);
485 if (d->compositor)
486 QWaylandCompositorPrivate::get(d->compositor)->unregisterSurface(this);
487 d->notifyViewsAboutDestruction();
488}
489
490/*!
491 * \qmlmethod void QtWayland.Compositor::WaylandSurface::initialize(WaylandCompositor compositor, WaylandClient client, int id, int version)
492 *
493 * Initializes the WaylandSurface with the given \a compositor and \a client, and with the given \a id
494 * and \a version.
495 */
496
497/*!
498 * Initializes the QWaylandSurface with the given \a compositor and \a client, and with the given \a id
499 * and \a version.
500 */
501void QWaylandSurface::initialize(QWaylandCompositor *compositor, QWaylandClient *client, uint id, int version)
502{
503 Q_D(QWaylandSurface);
504 d->compositor = compositor;
505 d->client = client;
506 d->init(client->client(), id, version);
507 d->isInitialized = true;
508#if QT_CONFIG(im)
509 d->inputMethodControl = new QWaylandInputMethodControl(this);
510#endif
511#ifndef QT_NO_DEBUG
512 QWaylandSurfacePrivate::removeUninitializedSurface(d);
513#endif
514}
515
516/*!
517 * Returns true if the QWaylandSurface has been initialized.
518 */
519bool QWaylandSurface::isInitialized() const
520{
521 Q_D(const QWaylandSurface);
522 return d->isInitialized;
523}
524
525/*!
526 * \qmlproperty WaylandClient QtWayland.Compositor::WaylandSurface::client
527 *
528 * This property holds the client using this WaylandSurface.
529 */
530
531/*!
532 * \property QWaylandSurface::client
533 *
534 * This property holds the client using this QWaylandSurface.
535 */
536QWaylandClient *QWaylandSurface::client() const
537{
538 Q_D(const QWaylandSurface);
539 if (isDestroyed() || !compositor() || !compositor()->clients().contains(d->client))
540 return nullptr;
541
542 return d->client;
543}
544
545/*!
546 * Holds the \c wl_client using this QWaylandSurface.
547 */
548::wl_client *QWaylandSurface::waylandClient() const
549{
550 if (auto *c = client())
551 return c->client();
552
553 return nullptr;
554}
555
556/*!
557 * \qmlproperty bool QtWayland.Compositor::WaylandSurface::hasContent
558 *
559 * This property holds whether the surface currently has a committed, non-null buffer.
560 *
561 * \sa WaylandSurface::bufferSize
562 */
563
564/*!
565 * \property QWaylandSurface::hasContent
566 *
567 * This property holds whether the surface currently has a committed, non-null buffer.
568 *
569 * \sa QWaylandSurface::bufferSize
570 */
571bool QWaylandSurface::hasContent() const
572{
573 Q_D(const QWaylandSurface);
574 return d->hasContent;
575}
576
577/*!
578 * \qmlproperty rect QtWayland.Compositor::WaylandSurface::sourceGeometry
579 * \since 5.13
580 *
581 * This property describes the portion of the attached Wayland buffer that should
582 * be drawn on the screen. The coordinates are from the corner of the buffer and are
583 * scaled by \l bufferScale.
584 *
585 * \sa bufferScale
586 * \sa bufferSize
587 * \sa destinationSize
588 */
589
590/*!
591 * \property QWaylandSurface::sourceGeometry
592 * \since 5.13
593 *
594 * This property describes the portion of the attached QWaylandBuffer that should
595 * be drawn on the screen. The coordinates are from the corner of the buffer and are
596 * scaled by \l bufferScale.
597 *
598 * \sa bufferScale
599 * \sa bufferSize
600 * \sa destinationSize
601 */
602QRectF QWaylandSurface::sourceGeometry() const
603{
604 Q_D(const QWaylandSurface);
605 return d->sourceGeometry;
606}
607
608/*!
609 * \qmlproperty size QtWayland.Compositor::WaylandSurface::destinationSize
610 * \since 5.13
611 *
612 * This property holds the size of this WaylandSurface in surface coordinates.
613 *
614 * \sa bufferScale
615 * \sa bufferSize
616 */
617
618/*!
619 * \property QWaylandSurface::destinationSize
620 * \since 5.13
621 *
622 * This property holds the size of this WaylandSurface in surface coordinates.
623 *
624 * \sa bufferScale
625 * \sa bufferSize
626 */
627QSize QWaylandSurface::destinationSize() const
628{
629 Q_D(const QWaylandSurface);
630 return d->destinationSize;
631}
632
633/*!
634 * \qmlproperty size QtWayland.Compositor::WaylandSurface::bufferSize
635 *
636 * This property holds the size of the current buffer of this WaylandSurface in pixels,
637 * not in surface coordinates.
638 *
639 * For the size in surface coordinates, use \l destinationSize instead.
640 *
641 * \sa destinationSize
642 * \sa bufferScale
643 */
644
645/*!
646 * \property QWaylandSurface::bufferSize
647 *
648 * This property holds the size of the current buffer of this QWaylandSurface in pixels,
649 * not in surface coordinates.
650 *
651 * For the size in surface coordinates, use \l destinationSize instead.
652 *
653 * \sa destinationSize
654 * \sa bufferScale
655 */
656QSize QWaylandSurface::bufferSize() const
657{
658 Q_D(const QWaylandSurface);
659 return d->bufferSize;
660}
661
662/*!
663 * \qmlproperty size QtWayland.Compositor::WaylandSurface::bufferScale
664 *
665 * This property holds the WaylandSurface's buffer scale. The buffer scale lets
666 * a client supply higher resolution buffer data for use on high resolution
667 * outputs.
668 */
669
670/*!
671 * \property QWaylandSurface::bufferScale
672 *
673 * This property holds the QWaylandSurface's buffer scale. The buffer scale
674 * lets a client supply higher resolution buffer data for use on high
675 * resolution outputs.
676 */
677int QWaylandSurface::bufferScale() const
678{
679 Q_D(const QWaylandSurface);
680 return d->bufferScale;
681}
682
683/*!
684 * \qmlproperty enum QtWayland.Compositor::WaylandSurface::contentOrientation
685 *
686 * This property holds the orientation of the WaylandSurface's contents.
687 *
688 * \sa {WaylandOutput::transform}{WaylandOutput.transform}
689 */
690
691/*!
692 * \property QWaylandSurface::contentOrientation
693 *
694 * This property holds the orientation of the QWaylandSurface's contents.
695 *
696 * \sa QWaylandOutput::transform
697 */
698Qt::ScreenOrientation QWaylandSurface::contentOrientation() const
699{
700 Q_D(const QWaylandSurface);
701 return d->contentOrientation;
702}
703
704/*!
705 * \enum QWaylandSurface::Origin
706 *
707 * This enum type is used to specify the origin of a QWaylandSurface's buffer.
708 *
709 * \value OriginTopLeft The origin is the top left corner of the buffer.
710 * \value OriginBottomLeft The origin is the bottom left corner of the buffer.
711 */
712
713/*!
714 * \qmlproperty enum QtWayland.Compositor::WaylandSurface::origin
715 *
716 * This property holds the origin of the WaylandSurface's buffer, or
717 * WaylandSurface.OriginTopLeft if the surface has no buffer.
718 *
719 * It can have the following values:
720 * \list
721 * \li WaylandSurface.OriginTopLeft The origin is the top left corner of the buffer.
722 * \li WaylandSurface.OriginBottomLeft The origin is the bottom left corner of the buffer.
723 * \endlist
724 */
725
726/*!
727 * \property QWaylandSurface::origin
728 *
729 * This property holds the origin of the QWaylandSurface's buffer, or
730 * QWaylandSurface::OriginTopLeft if the surface has no buffer.
731 */
732QWaylandSurface::Origin QWaylandSurface::origin() const
733{
734 Q_D(const QWaylandSurface);
735 return d->bufferRef.origin();
736}
737
738/*!
739 * Returns the compositor for this QWaylandSurface.
740 */
741QWaylandCompositor *QWaylandSurface::compositor() const
742{
743 Q_D(const QWaylandSurface);
744 return d->compositor;
745}
746
747/*!
748 * Prepares all frame callbacks for sending.
749 */
750void QWaylandSurface::frameStarted()
751{
752}
753
754/*!
755 * Sends pending frame callbacks.
756 */
757void QWaylandSurface::sendFrameCallbacks()
758{
759 Q_D(QWaylandSurface);
760 uint time = d->compositor->currentTimeMsecs();
761 const auto frameCallbacks = std::exchange(d->frameCallbacks, {});
762 for (auto *callback : frameCallbacks)
763 callback->sendAndDestroy(time);
764}
765
766/*!
767 * Returns \c true if the QWaylandSurface's input region contains the point \a p.
768 * Otherwise returns \c false.
769 */
770bool QWaylandSurface::inputRegionContains(const QPoint &p) const
771{
772 Q_D(const QWaylandSurface);
773 return d->inputRegion.contains(p);
774}
775
776/*!
777 * Returns \c true if the QWaylandSurface's input region contains the point \a position.
778 * Otherwise returns \c false.
779 *
780 * \since 5.14
781 */
782bool QWaylandSurface::inputRegionContains(const QPointF &position) const
783{
784 Q_D(const QWaylandSurface);
785 // QRegion::contains operates in integers. If a region has a rect (0,0,10,10), (0,0) is
786 // inside while (10,10) is outside. Therefore, we can't use QPoint::toPoint(), which will
787 // round upwards, meaning the point (-0.25,-0.25) would be rounded to (0,0) and count as
788 // being inside the region, and similarly, a point (9.75,9.75) inside the region would be
789 // rounded upwards and count as being outside the region.
790 const QPoint floored(qFloor(position.x()), qFloor(position.y()));
791 return d->inputRegion.contains(floored);
792}
793
794/*!
795 * \qmlmethod void QtWayland.Compositor::WaylandSurface::destroy()
796 *
797 * Destroys the WaylandSurface.
798 */
799
800/*!
801 * Destroys the QWaylandSurface.
802 */
803void QWaylandSurface::destroy()
804{
805 Q_D(QWaylandSurface);
806 d->deref();
807}
808
809/*!
810 * \qmlmethod bool QtWayland.Compositor::WaylandSurface::isDestroyed()
811 *
812 * Returns \c true if the WaylandSurface has been destroyed. Otherwise returns \c false.
813 */
814
815/*!
816 * Returns true if the QWaylandSurface has been destroyed. Otherwise returns false.
817 */
818bool QWaylandSurface::isDestroyed() const
819{
820 Q_D(const QWaylandSurface);
821 return d->destroyed;
822}
823
824/*!
825 * \qmlproperty bool QtWayland.Compositor::WaylandSurface::cursorSurface
826 *
827 * This property holds whether the WaylandSurface is a cursor surface.
828 */
829
830/*!
831 * \property QWaylandSurface::cursorSurface
832 *
833 * This property holds whether the QWaylandSurface is a cursor surface.
834 */
835void QWaylandSurface::markAsCursorSurface(bool cursorSurface)
836{
837 Q_D(QWaylandSurface);
838 if (d->isCursorSurface == cursorSurface)
839 return;
840
841 d->isCursorSurface = cursorSurface;
842 emit cursorSurfaceChanged();
843}
844
845bool QWaylandSurface::isCursorSurface() const
846{
847 Q_D(const QWaylandSurface);
848 return d->isCursorSurface;
849}
850
851/*!
852 * \qmlproperty bool QtWayland.Compositor::WaylandSurface::inhibitsIdle
853 * \since 5.14
854 *
855 * This property holds whether this surface is intended to inhibit the idle
856 * behavior of the compositor such as screen blanking, locking and screen saving.
857 *
858 * \sa IdleInhibitManagerV1
859 */
860
861/*!
862 * \property QWaylandSurface::inhibitsIdle
863 * \since 5.14
864 *
865 * This property holds whether this surface is intended to inhibit the idle
866 * behavior of the compositor such as screen blanking, locking and screen saving.
867 *
868 * \sa QWaylandIdleInhibitManagerV1
869 */
870bool QWaylandSurface::inhibitsIdle() const
871{
872 Q_D(const QWaylandSurface);
873 return !d->idleInhibitors.isEmpty();
874}
875
876/*!
877 * \qmlproperty bool QtWayland.Compositor::WaylandSurface::isOpaque
878 * \since 6.4
879 *
880 * This property holds whether the surface is fully opaque, as reported by the
881 * client through the set_opaque_region request.
882 */
883
884/*!
885 * \property QWaylandSurface::isOpaque
886 * \since 6.4
887 *
888 * This property holds whether the surface is fully opaque, as reported by the
889 * client through the set_opaque_region request.
890 */
891bool QWaylandSurface::isOpaque() const
892{
893 Q_D(const QWaylandSurface);
894 return d->isOpaque;
895}
896
897#if QT_CONFIG(im)
898QWaylandInputMethodControl *QWaylandSurface::inputMethodControl() const
899{
900 Q_D(const QWaylandSurface);
901 return d->inputMethodControl;
902}
903#endif
904
905/*!
906 * Updates the surface with the compositor's retained clipboard selection. Although
907 * this is done automatically when the surface receives keyboard focus, this
908 * function is useful for updating clients which do not have keyboard focus.
909 */
910#if QT_CONFIG(clipboard)
911void QWaylandSurface::updateSelection()
912{
913 Q_D(QWaylandSurface);
914 QWaylandSeat *seat = d->compositor->defaultSeat();
915 if (seat) {
916 const QtWayland::DataDevice *dataDevice = QWaylandSeatPrivate::get(seat)->dataDevice();
917 if (dataDevice) {
918 QWaylandCompositorPrivate::get(d->compositor)->dataDeviceManager()->offerRetainedSelection(
919 dataDevice->resourceMap().value(d->resource()->client())->handle);
920 }
921 }
922}
923#endif
924
925/*!
926 * Returns this QWaylandSurface's primary view.
927 *
928 * \sa QWaylandView::advance(), QWaylandSurface::setPrimaryView()
929 */
930QWaylandView *QWaylandSurface::primaryView() const
931{
932 Q_D(const QWaylandSurface);
933 if (d->views.isEmpty())
934 return nullptr;
935 return d->views.first();
936}
937
938/*!
939 * Sets this QWaylandSurface's primary view to \a view, in case there are
940 * multiple views of this surface. The primary view is the view that
941 * governs the client's refresh rate. It takes care of discarding buffer
942 * references when QWaylandView::advance() is called. See the documentation
943 * for QWaylandView::advance() for more details.
944 *
945 * In shell surface integrations, such as QWaylandWlShellIntegration and
946 * QWaylandXdgShellV5Integration, maximize and fullscreen requests from the
947 * client will only have an effect if the integration has the primary view
948 * of the surface.
949 *
950 * \sa QWaylandView::advance()
951 */
952void QWaylandSurface::setPrimaryView(QWaylandView *view)
953{
954 Q_D(QWaylandSurface);
955
956 if (!view)
957 return;
958
959 int index = d->views.indexOf(view);
960
961 if (index < 0) {
962 view->setSurface(this);
963 index = d->views.indexOf(view);
964 }
965
966 d->views.move(index, 0);
967}
968
969/*!
970 * Returns the views for this QWaylandSurface.
971 */
972QList<QWaylandView *> QWaylandSurface::views() const
973{
974 Q_D(const QWaylandSurface);
975 return d->views;
976}
977
978/*!
979 * Returns the QWaylandSurface corresponding to the Wayland resource \a resource.
980 */
981QWaylandSurface *QWaylandSurface::fromResource(::wl_resource *resource)
982{
983 if (auto p = QtWayland::fromResource<QWaylandSurfacePrivate *>(resource))
984 return p->q_func();
985 return nullptr;
986}
987
988/*!
989 * Returns the Wayland resource corresponding to this QWaylandSurface.
990 */
991struct wl_resource *QWaylandSurface::resource() const
992{
993 Q_D(const QWaylandSurface);
994 return d->resource()->handle;
995}
996
997/*!
998 * Sets a \a role on the surface. A role defines how a surface will be mapped on screen; without a
999 * role a surface is supposed to be hidden. Once a role is assigned to a surface, this becomes its
1000 * permanent role. Any subsequent call to \c setRole() with a different role will trigger a
1001 * protocol error to the \a errorResource and send an \a errorCode to the client. Enforcing this
1002 * requirement is the main purpose of the surface role.
1003 *
1004 * The \a role is compared by pointer value. Any two objects of QWaylandSurfaceRole will be
1005 * considered different roles, regardless of their names.
1006 *
1007 * The surface role is set internally by protocol implementations when a surface is adopted for a
1008 * specific purpose, for example in a \l{Shell Extensions - Qt Wayland Compositor}{shell extension}.
1009 * Unless you are developing extensions which use surfaces in this way, you should not call this
1010 * function.
1011 *
1012 * Returns true if a role can be assigned; false otherwise.
1013 */
1014bool QWaylandSurface::setRole(QWaylandSurfaceRole *role, wl_resource *errorResource, uint32_t errorCode)
1015{
1016 Q_D(QWaylandSurface);
1017
1018 if (d->role && d->role != role) {
1019 wl_resource_post_error(errorResource, errorCode,
1020 "Cannot assign role %s to wl_surface@%d, already has role %s\n",
1021 role->name().constData(), wl_resource_get_id(resource()),
1022 d->role->name().constData());
1023 return false;
1024 }
1025
1026 d->role = role;
1027 return true;
1028}
1029
1030QWaylandSurfaceRole *QWaylandSurface::role() const
1031{
1032 Q_D(const QWaylandSurface);
1033 return d->role;
1034}
1035
1036QWaylandSurfacePrivate *QWaylandSurfacePrivate::get(QWaylandSurface *surface)
1037{
1038 return surface ? surface->d_func() : nullptr;
1039}
1040
1041void QWaylandSurfacePrivate::ref()
1042{
1043 ++refCount;
1044}
1045
1046void QWaylandSurfacePrivate::deref()
1047{
1048 if (--refCount == 0)
1049 QWaylandCompositorPrivate::get(compositor)->destroySurface(q_func());
1050}
1051
1052void QWaylandSurfacePrivate::refView(QWaylandView *view)
1053{
1054 if (views.contains(view))
1055 return;
1056
1057 views.append(view);
1058 ref();
1059 view->bufferCommitted(bufferRef, QRect(QPoint(0,0), bufferRef.size()));
1060}
1061
1062void QWaylandSurfacePrivate::derefView(QWaylandView *view)
1063{
1064 int nViews = views.removeAll(view);
1065
1066 for (int i = 0; i < nViews && refCount > 0; i++) {
1067 deref();
1068 }
1069}
1070
1071void QWaylandSurfacePrivate::initSubsurface(QWaylandSurface *parent, wl_client *client, int id, int version)
1072{
1073 Q_Q(QWaylandSurface);
1074 QWaylandSurface *oldParent = nullptr; // TODO: implement support for switching parents
1075
1076 subsurface = new Subsurface(this);
1077 subsurface->init(client, id, version);
1078 subsurface->parentSurface = parent->d_func();
1079 emit q->parentChanged(parent, oldParent);
1080 emit parent->childAdded(q);
1081}
1082
1083void QWaylandSurfacePrivate::Subsurface::subsurface_set_position(wl_subsurface::Resource *resource, int32_t x, int32_t y)
1084{
1085 Q_UNUSED(resource);
1086 pos = QPoint(x,y);
1087 emit surface->q_func()->subsurfacePositionChanged(pos);
1088}
1089
1090void QWaylandSurfacePrivate::Subsurface::subsurface_place_above(wl_subsurface::Resource *resource, struct wl_resource *sibling)
1091{
1092 Q_UNUSED(resource);
1093 emit surface->q_func()->subsurfacePlaceAbove(QWaylandSurface::fromResource(sibling));
1094}
1095
1096void QWaylandSurfacePrivate::Subsurface::subsurface_place_below(wl_subsurface::Resource *resource, struct wl_resource *sibling)
1097{
1098 Q_UNUSED(resource);
1099 emit surface->q_func()->subsurfacePlaceBelow(QWaylandSurface::fromResource(sibling));
1100}
1101
1102void QWaylandSurfacePrivate::Subsurface::subsurface_set_sync(wl_subsurface::Resource *resource)
1103{
1104 Q_UNUSED(resource);
1105 // TODO: sync/desync implementation
1106 qDebug() << Q_FUNC_INFO;
1107}
1108
1109void QWaylandSurfacePrivate::Subsurface::subsurface_set_desync(wl_subsurface::Resource *resource)
1110{
1111 Q_UNUSED(resource);
1112 // TODO: sync/desync implementation
1113 qDebug() << Q_FUNC_INFO;
1114}
1115
1116/*!
1117 * \qmlsignal QtWayland.Compositor::WaylandSurface::childAdded(WaylandSurface child)
1118 *
1119 * This signal is emitted when a wl_subsurface, \a child, has been added to the surface.
1120 */
1121
1122/*!
1123 * \fn void QWaylandSurface::childAdded(QWaylandSurface *child)
1124 *
1125 * This signal is emitted when a wl_subsurface, \a child, has been added to the surface.
1126 */
1127
1128/*!
1129 * \qmlsignal QtWayland.Compositor::WaylandSurface::surfaceDestroyed()
1130 *
1131 * This signal is emitted when the corresponding wl_surface is destroyed.
1132 */
1133
1134/*!
1135 * \fn void QWaylandSurface::surfaceDestroyed()
1136 *
1137 * This signal is emitted when the corresponding wl_surface is destroyed.
1138 */
1139
1140/*!
1141 * \qmlsignal void QtWayland.Compositor::WaylandSurface::dragStarted(WaylandDrag drag)
1142 *
1143 * This signal is emitted when a \a drag has started from this surface.
1144 */
1145
1146/*!
1147 * \fn void QWaylandSurface::dragStarted(QWaylandDrag *drag)
1148 *
1149 * This signal is emitted when a \a drag has started from this surface.
1150 */
1151
1152/*!
1153 * \fn void damaged(const QRegion &rect)
1154 *
1155 * This signal is emitted when the client tells the compositor that a particular part of, or
1156 * possibly the entire surface has been updated, so the compositor can redraw that part.
1157 *
1158 * While the compositor APIs take care of redrawing automatically, this function may be useful
1159 * if you require a specific, custom behavior.
1160 */
1161
1162/*!
1163 * \fn void parentChanged(QWaylandSurface *newParent, QWaylandSurface *oldParent)
1164 *
1165 * This signal is emitted when the client has requested that this surface should be a
1166 * subsurface of \a newParent.
1167 */
1168
1169QT_END_NAMESPACE
1170
1171#include "moc_qwaylandsurface.cpp"
FrameCallback(QWaylandSurface *surf, wl_resource *res)
static void destroyCallback(wl_resource *res)
Combined button and popup list for selecting options.
static QRegion infiniteRegion()