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

source code of qtwayland/src/compositor/compositor_api/qwaylandsurface.cpp