| 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 |  | 
| 36 | QT_BEGIN_NAMESPACE | 
| 37 |  | 
| 38 | namespace QtWayland { | 
| 39 | class FrameCallback { | 
| 40 | public: | 
| 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 | } | 
| 74 | static 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 | 
| 80 | QList<QWaylandSurfacePrivate *> QWaylandSurfacePrivate::uninitializedSurfaces; | 
| 81 | #endif | 
| 82 |  | 
| 83 | QWaylandSurfacePrivate::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 |  | 
| 95 | QWaylandSurfacePrivate::~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 |  | 
| 110 | void QWaylandSurfacePrivate::removeFrameCallback(QtWayland::FrameCallback *callback) | 
| 111 | { | 
| 112 |     pendingFrameCallbacks.removeOne(t: callback); | 
| 113 |     frameCallbacks.removeOne(t: callback); | 
| 114 | } | 
| 115 |  | 
| 116 | void 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 | 
| 130 | void QWaylandSurfacePrivate::addUninitializedSurface(QWaylandSurfacePrivate *surface) | 
| 131 | { | 
| 132 |     Q_ASSERT(!surface->isInitialized); | 
| 133 |     Q_ASSERT(!uninitializedSurfaces.contains(surface)); | 
| 134 |     uninitializedSurfaces.append(t: surface); | 
| 135 | } | 
| 136 |  | 
| 137 | void QWaylandSurfacePrivate::removeUninitializedSurface(QWaylandSurfacePrivate *surface) | 
| 138 | { | 
| 139 |     Q_ASSERT(surface->isInitialized); | 
| 140 |     bool removed = uninitializedSurfaces.removeOne(t: surface); | 
| 141 |     Q_ASSERT(removed); | 
| 142 | } | 
| 143 |  | 
| 144 | bool QWaylandSurfacePrivate::hasUninitializedSurface() | 
| 145 | { | 
| 146 |     return uninitializedSurfaces.size(); | 
| 147 | } | 
| 148 | #endif | 
| 149 |  | 
| 150 | void 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 |  | 
| 160 | void QWaylandSurfacePrivate::surface_destroy(Resource *resource) | 
| 161 | { | 
| 162 |     wl_resource_destroy(resource->handle); | 
| 163 | } | 
| 164 |  | 
| 165 | void 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 |  | 
| 178 | void 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 |  | 
| 183 | void 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 |  | 
| 188 | void 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 |  | 
| 195 | void QWaylandSurfacePrivate::surface_set_opaque_region(Resource *, struct wl_resource *region) | 
| 196 | { | 
| 197 |     pending.opaqueRegion = region ? QtWayland::Region::fromResource(resource: region)->region() : QRegion(); | 
| 198 | } | 
| 199 |  | 
| 200 | void 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 |  | 
| 209 | void 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 |  | 
| 304 | void 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 |  | 
| 328 | void QWaylandSurfacePrivate::surface_set_buffer_scale(QtWaylandServer::wl_surface::Resource *resource, int32_t scale) | 
| 329 | { | 
| 330 |     Q_UNUSED(resource); | 
| 331 |     pending.bufferScale = scale; | 
| 332 | } | 
| 333 |  | 
| 334 | QtWayland::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 |  * \nativetype 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 |  */ | 
| 410 | QWaylandSurface::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 |  */ | 
| 419 | QWaylandSurface::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 |  */ | 
| 428 | QWaylandSurface::QWaylandSurface(QWaylandSurfacePrivate &dptr) | 
| 429 |     : QWaylandObject(dptr) | 
| 430 | { | 
| 431 | } | 
| 432 |  | 
| 433 | /*! | 
| 434 |  * Destroys the QWaylandSurface. | 
| 435 |  */ | 
| 436 | QWaylandSurface::~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 |  */ | 
| 455 | void 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 |  */ | 
| 473 | bool 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 |  */ | 
| 490 | QWaylandClient *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 |  */ | 
| 521 | bool 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 |  */ | 
| 552 | QRectF 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 |  */ | 
| 577 | QSize 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 |  */ | 
| 606 | QSize 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 |  */ | 
| 627 | int 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 |  */ | 
| 648 | Qt::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 |  */ | 
| 682 | QWaylandSurface::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 |  */ | 
| 691 | QWaylandCompositor *QWaylandSurface::compositor() const | 
| 692 | { | 
| 693 |     Q_D(const QWaylandSurface); | 
| 694 |     return d->compositor; | 
| 695 | } | 
| 696 |  | 
| 697 | /*! | 
| 698 |  * Prepares all frame callbacks for sending. | 
| 699 |  */ | 
| 700 | void 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 |  */ | 
| 710 | void 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 |  */ | 
| 730 | bool 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 |  */ | 
| 742 | bool 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 |  */ | 
| 763 | void 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 |  */ | 
| 778 | bool 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 |  */ | 
| 795 | void 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 |  | 
| 805 | bool 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 |  */ | 
| 830 | bool 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 |  */ | 
| 851 | bool QWaylandSurface::isOpaque() const | 
| 852 | { | 
| 853 |     Q_D(const QWaylandSurface); | 
| 854 |     return d->isOpaque; | 
| 855 | } | 
| 856 |  | 
| 857 | #if QT_CONFIG(im) | 
| 858 | QWaylandInputMethodControl *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) | 
| 871 | void 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 |  */ | 
| 890 | QWaylandView *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 |  */ | 
| 912 | void 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 |  */ | 
| 932 | QList<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 |  */ | 
| 941 | QWaylandSurface *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 |  */ | 
| 951 | struct 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 |  */ | 
| 974 | bool 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 |  | 
| 990 | QWaylandSurfaceRole *QWaylandSurface::role() const | 
| 991 | { | 
| 992 |     Q_D(const QWaylandSurface); | 
| 993 |     return d->role; | 
| 994 | } | 
| 995 |  | 
| 996 | QWaylandSurfacePrivate *QWaylandSurfacePrivate::get(QWaylandSurface *surface) | 
| 997 | { | 
| 998 |     return surface ? surface->d_func() : nullptr; | 
| 999 | } | 
| 1000 |  | 
| 1001 | void QWaylandSurfacePrivate::ref() | 
| 1002 | { | 
| 1003 |     ++refCount; | 
| 1004 | } | 
| 1005 |  | 
| 1006 | void QWaylandSurfacePrivate::deref() | 
| 1007 | { | 
| 1008 |     if (--refCount == 0) | 
| 1009 |         QWaylandCompositorPrivate::get(compositor)->destroySurface(surface: q_func()); | 
| 1010 | } | 
| 1011 |  | 
| 1012 | void 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 |  | 
| 1022 | void 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 |  | 
| 1031 | void 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 |  | 
| 1043 | void 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 |  | 
| 1051 | void 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 |  | 
| 1057 | void 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 |  | 
| 1063 | void 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 |  | 
| 1070 | void 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 |  | 
| 1130 | QT_END_NAMESPACE | 
| 1131 |  | 
| 1132 | #include "moc_qwaylandsurface.cpp" | 
| 1133 |  |