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