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