File indexing completed on 2024-05-19 16:35:33
0001 /* 0002 SPDX-FileCopyrightText: 2020 Vlad Zahorodnii <vlad.zahorodnii@kde.org> 0003 0004 SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL 0005 */ 0006 0007 #include "xdgshell_interface.h" 0008 #include "xdgshell_interface_p.h" 0009 0010 #include "display.h" 0011 #include "output_interface.h" 0012 #include "seat_interface.h" 0013 #include "utils.h" 0014 0015 #include <QTimer> 0016 0017 namespace KWaylandServer 0018 { 0019 static const int s_version = 4; 0020 0021 XdgShellInterfacePrivate::XdgShellInterfacePrivate(XdgShellInterface *shell) 0022 : q(shell) 0023 { 0024 } 0025 0026 XdgShellInterfacePrivate::Resource *XdgShellInterfacePrivate::resourceForXdgSurface(XdgSurfaceInterface *surface) const 0027 { 0028 return xdgSurfaces.value(surface); 0029 } 0030 0031 void XdgShellInterfacePrivate::unregisterXdgSurface(XdgSurfaceInterface *surface) 0032 { 0033 xdgSurfaces.remove(surface); 0034 } 0035 0036 /** 0037 * @todo Whether the ping is delayed or has timed out is out of domain of the XdgShellInterface. 0038 * Such matter must be handled somewhere else, e.g. XdgToplevelWindow, not here! 0039 */ 0040 void XdgShellInterfacePrivate::registerPing(quint32 serial) 0041 { 0042 QTimer *timer = new QTimer(q); 0043 timer->setInterval(1000); 0044 QObject::connect(timer, &QTimer::timeout, q, [this, serial, attempt = 0]() mutable { 0045 ++attempt; 0046 if (attempt == 1) { 0047 Q_EMIT q->pingDelayed(serial); 0048 return; 0049 } 0050 Q_EMIT q->pingTimeout(serial); 0051 delete pings.take(serial); 0052 }); 0053 pings.insert(serial, timer); 0054 timer->start(); 0055 } 0056 0057 XdgShellInterfacePrivate *XdgShellInterfacePrivate::get(XdgShellInterface *shell) 0058 { 0059 return shell->d.get(); 0060 } 0061 0062 void XdgShellInterfacePrivate::xdg_wm_base_destroy_resource(Resource *resource) 0063 { 0064 const QList<XdgSurfaceInterface *> surfaces = xdgSurfaces.keys(resource); 0065 qDeleteAll(surfaces); 0066 } 0067 0068 void XdgShellInterfacePrivate::xdg_wm_base_destroy(Resource *resource) 0069 { 0070 if (xdgSurfaces.key(resource)) { 0071 wl_resource_post_error(resource->handle, error_defunct_surfaces, "xdg_wm_base was destroyed before children"); 0072 return; 0073 } 0074 wl_resource_destroy(resource->handle); 0075 } 0076 0077 void XdgShellInterfacePrivate::xdg_wm_base_create_positioner(Resource *resource, uint32_t id) 0078 { 0079 wl_resource *positionerResource = wl_resource_create(resource->client(), &xdg_positioner_interface, resource->version(), id); 0080 new XdgPositionerPrivate(positionerResource); 0081 } 0082 0083 void XdgShellInterfacePrivate::xdg_wm_base_get_xdg_surface(Resource *resource, uint32_t id, ::wl_resource *surfaceResource) 0084 { 0085 SurfaceInterface *surface = SurfaceInterface::get(surfaceResource); 0086 0087 if (surface->buffer()) { 0088 wl_resource_post_error(resource->handle, XDG_SURFACE_ERROR_UNCONFIGURED_BUFFER, "xdg_surface must not have a buffer at creation"); 0089 return; 0090 } 0091 0092 wl_resource *xdgSurfaceResource = wl_resource_create(resource->client(), &xdg_surface_interface, resource->version(), id); 0093 0094 XdgSurfaceInterface *xdgSurface = new XdgSurfaceInterface(q, surface, xdgSurfaceResource); 0095 xdgSurfaces.insert(xdgSurface, resource); 0096 } 0097 0098 void XdgShellInterfacePrivate::xdg_wm_base_pong(Resource *resource, uint32_t serial) 0099 { 0100 if (QTimer *timer = pings.take(serial)) { 0101 delete timer; 0102 } 0103 Q_EMIT q->pongReceived(serial); 0104 } 0105 0106 XdgShellInterface::XdgShellInterface(Display *display, QObject *parent) 0107 : QObject(parent) 0108 , d(new XdgShellInterfacePrivate(this)) 0109 { 0110 d->display = display; 0111 d->init(*display, s_version); 0112 } 0113 0114 XdgShellInterface::~XdgShellInterface() 0115 { 0116 } 0117 0118 Display *XdgShellInterface::display() const 0119 { 0120 return d->display; 0121 } 0122 0123 quint32 XdgShellInterface::ping(XdgSurfaceInterface *surface) 0124 { 0125 XdgShellInterfacePrivate::Resource *clientResource = d->resourceForXdgSurface(surface); 0126 if (!clientResource) 0127 return 0; 0128 0129 quint32 serial = d->display->nextSerial(); 0130 d->send_ping(clientResource->handle, serial); 0131 d->registerPing(serial); 0132 0133 return serial; 0134 } 0135 0136 XdgSurfaceInterfacePrivate::XdgSurfaceInterfacePrivate(XdgSurfaceInterface *xdgSurface) 0137 : q(xdgSurface) 0138 { 0139 } 0140 0141 void XdgSurfaceInterfacePrivate::commit() 0142 { 0143 if (surface->buffer()) { 0144 firstBufferAttached = true; 0145 } 0146 0147 if (next.acknowledgedConfigureIsSet) { 0148 current.acknowledgedConfigure = next.acknowledgedConfigure; 0149 next.acknowledgedConfigureIsSet = false; 0150 Q_EMIT q->configureAcknowledged(current.acknowledgedConfigure); 0151 } 0152 0153 if (next.windowGeometryIsSet) { 0154 current.windowGeometry = next.windowGeometry; 0155 next.windowGeometryIsSet = false; 0156 Q_EMIT q->windowGeometryChanged(current.windowGeometry); 0157 } 0158 } 0159 0160 void XdgSurfaceInterfacePrivate::reset() 0161 { 0162 firstBufferAttached = false; 0163 isConfigured = false; 0164 isInitialized = false; 0165 current = XdgSurfaceState{}; 0166 next = XdgSurfaceState{}; 0167 Q_EMIT q->resetOccurred(); 0168 } 0169 0170 XdgSurfaceInterfacePrivate *XdgSurfaceInterfacePrivate::get(XdgSurfaceInterface *surface) 0171 { 0172 return surface->d.get(); 0173 } 0174 0175 void XdgSurfaceInterfacePrivate::xdg_surface_destroy_resource(Resource *resource) 0176 { 0177 delete q; 0178 } 0179 0180 void XdgSurfaceInterfacePrivate::xdg_surface_destroy(Resource *resource) 0181 { 0182 if (toplevel || popup) { 0183 qWarning() << "Tried to destroy xdg_surface before its role object"; 0184 } 0185 wl_resource_destroy(resource->handle); 0186 } 0187 0188 void XdgSurfaceInterfacePrivate::xdg_surface_get_toplevel(Resource *resource, uint32_t id) 0189 { 0190 const SurfaceRole *surfaceRole = SurfaceRole::get(surface); 0191 if (surfaceRole) { 0192 wl_resource_post_error(resource->handle, error_already_constructed, "the surface already has a role assigned %s", surfaceRole->name().constData()); 0193 return; 0194 } 0195 0196 wl_resource *toplevelResource = wl_resource_create(resource->client(), &xdg_toplevel_interface, resource->version(), id); 0197 0198 toplevel = new XdgToplevelInterface(q, toplevelResource); 0199 Q_EMIT shell->toplevelCreated(toplevel); 0200 } 0201 0202 void XdgSurfaceInterfacePrivate::xdg_surface_get_popup(Resource *resource, uint32_t id, ::wl_resource *parentResource, ::wl_resource *positionerResource) 0203 { 0204 const SurfaceRole *surfaceRole = SurfaceRole::get(surface); 0205 if (surfaceRole) { 0206 wl_resource_post_error(resource->handle, error_already_constructed, "the surface already has a role assigned %s", surfaceRole->name().constData()); 0207 return; 0208 } 0209 0210 XdgPositioner positioner = XdgPositioner::get(positionerResource); 0211 if (!positioner.isComplete()) { 0212 auto shellPrivate = XdgShellInterfacePrivate::get(shell); 0213 wl_resource_post_error(shellPrivate->resourceForXdgSurface(q)->handle, 0214 QtWaylandServer::xdg_wm_base::error_invalid_positioner, 0215 "xdg_positioner is incomplete"); 0216 return; 0217 } 0218 0219 XdgSurfaceInterface *parentXdgSurface = XdgSurfaceInterface::get(parentResource); 0220 SurfaceInterface *parentSurface = nullptr; 0221 if (parentXdgSurface) { 0222 parentSurface = parentXdgSurface->surface(); 0223 } 0224 0225 wl_resource *popupResource = wl_resource_create(resource->client(), &xdg_popup_interface, resource->version(), id); 0226 0227 popup = new XdgPopupInterface(q, parentSurface, positioner, popupResource); 0228 Q_EMIT shell->popupCreated(popup); 0229 } 0230 0231 void XdgSurfaceInterfacePrivate::xdg_surface_set_window_geometry(Resource *resource, int32_t x, int32_t y, int32_t width, int32_t height) 0232 { 0233 if (!toplevel && !popup) { 0234 wl_resource_post_error(resource->handle, error_not_constructed, "xdg_surface must have a role"); 0235 return; 0236 } 0237 0238 if (width < 1 || height < 1) { 0239 wl_resource_post_error(resource->handle, -1, "invalid window geometry size (%dx%d)", width, height); 0240 return; 0241 } 0242 0243 next.windowGeometry = QRect(x, y, width, height); 0244 next.windowGeometryIsSet = true; 0245 } 0246 0247 void XdgSurfaceInterfacePrivate::xdg_surface_ack_configure(Resource *resource, uint32_t serial) 0248 { 0249 next.acknowledgedConfigure = serial; 0250 next.acknowledgedConfigureIsSet = true; 0251 } 0252 0253 XdgSurfaceInterface::XdgSurfaceInterface(XdgShellInterface *shell, SurfaceInterface *surface, ::wl_resource *resource) 0254 : d(new XdgSurfaceInterfacePrivate(this)) 0255 { 0256 d->shell = shell; 0257 d->surface = surface; 0258 d->init(resource); 0259 } 0260 0261 XdgSurfaceInterface::~XdgSurfaceInterface() 0262 { 0263 delete d->toplevel; 0264 delete d->popup; 0265 0266 Q_EMIT aboutToBeDestroyed(); 0267 XdgShellInterfacePrivate::get(d->shell)->unregisterXdgSurface(this); 0268 } 0269 0270 XdgToplevelInterface *XdgSurfaceInterface::toplevel() const 0271 { 0272 return d->toplevel; 0273 } 0274 0275 XdgPopupInterface *XdgSurfaceInterface::popup() const 0276 { 0277 return d->popup; 0278 } 0279 0280 XdgShellInterface *XdgSurfaceInterface::shell() const 0281 { 0282 return d->shell; 0283 } 0284 0285 SurfaceInterface *XdgSurfaceInterface::surface() const 0286 { 0287 return d->surface; 0288 } 0289 0290 bool XdgSurfaceInterface::isConfigured() const 0291 { 0292 return d->isConfigured; 0293 } 0294 0295 QRect XdgSurfaceInterface::windowGeometry() const 0296 { 0297 return d->current.windowGeometry; 0298 } 0299 0300 XdgSurfaceInterface *XdgSurfaceInterface::get(::wl_resource *resource) 0301 { 0302 if (auto surfacePrivate = resource_cast<XdgSurfaceInterfacePrivate *>(resource)) { 0303 return surfacePrivate->q; 0304 } 0305 return nullptr; 0306 } 0307 0308 XdgToplevelInterfacePrivate::XdgToplevelInterfacePrivate(XdgToplevelInterface *toplevel, XdgSurfaceInterface *surface) 0309 : SurfaceRole(surface->surface(), QByteArrayLiteral("xdg_toplevel")) 0310 , q(toplevel) 0311 , xdgSurface(surface) 0312 { 0313 } 0314 0315 void XdgToplevelInterfacePrivate::commit() 0316 { 0317 auto xdgSurfacePrivate = XdgSurfaceInterfacePrivate::get(xdgSurface); 0318 if (xdgSurfacePrivate->firstBufferAttached && !xdgSurfacePrivate->surface->buffer()) { 0319 reset(); 0320 return; 0321 } 0322 0323 xdgSurfacePrivate->commit(); 0324 0325 if (current.minimumSize != next.minimumSize) { 0326 current.minimumSize = next.minimumSize; 0327 Q_EMIT q->minimumSizeChanged(current.minimumSize); 0328 } 0329 if (current.maximumSize != next.maximumSize) { 0330 current.maximumSize = next.maximumSize; 0331 Q_EMIT q->maximumSizeChanged(current.maximumSize); 0332 } 0333 0334 if (!xdgSurfacePrivate->isInitialized) { 0335 Q_EMIT q->initializeRequested(); 0336 xdgSurfacePrivate->isInitialized = true; 0337 } 0338 } 0339 0340 void XdgToplevelInterfacePrivate::reset() 0341 { 0342 auto xdgSurfacePrivate = XdgSurfaceInterfacePrivate::get(xdgSurface); 0343 xdgSurfacePrivate->reset(); 0344 0345 windowTitle = QString(); 0346 windowClass = QString(); 0347 current = next = State(); 0348 0349 Q_EMIT q->resetOccurred(); 0350 } 0351 0352 void XdgToplevelInterfacePrivate::xdg_toplevel_destroy_resource(Resource *resource) 0353 { 0354 delete q; 0355 } 0356 0357 void XdgToplevelInterfacePrivate::xdg_toplevel_destroy(Resource *resource) 0358 { 0359 wl_resource_destroy(resource->handle); 0360 } 0361 0362 void XdgToplevelInterfacePrivate::xdg_toplevel_set_parent(Resource *resource, ::wl_resource *parentResource) 0363 { 0364 XdgToplevelInterface *parent = XdgToplevelInterface::get(parentResource); 0365 if (parentXdgToplevel == parent) { 0366 return; 0367 } 0368 parentXdgToplevel = parent; 0369 Q_EMIT q->parentXdgToplevelChanged(); 0370 } 0371 0372 void XdgToplevelInterfacePrivate::xdg_toplevel_set_title(Resource *resource, const QString &title) 0373 { 0374 if (windowTitle == title) { 0375 return; 0376 } 0377 windowTitle = title; 0378 Q_EMIT q->windowTitleChanged(title); 0379 } 0380 0381 void XdgToplevelInterfacePrivate::xdg_toplevel_set_app_id(Resource *resource, const QString &app_id) 0382 { 0383 if (windowClass == app_id) { 0384 return; 0385 } 0386 windowClass = app_id; 0387 Q_EMIT q->windowClassChanged(app_id); 0388 } 0389 0390 void XdgToplevelInterfacePrivate::xdg_toplevel_show_window_menu(Resource *resource, ::wl_resource *seatResource, uint32_t serial, int32_t x, int32_t y) 0391 { 0392 auto xdgSurfacePrivate = XdgSurfaceInterfacePrivate::get(xdgSurface); 0393 0394 if (!xdgSurfacePrivate->isConfigured) { 0395 wl_resource_post_error(resource->handle, QtWaylandServer::xdg_surface::error_not_constructed, "surface has not been configured yet"); 0396 return; 0397 } 0398 0399 SeatInterface *seat = SeatInterface::get(seatResource); 0400 Q_EMIT q->windowMenuRequested(seat, QPoint(x, y), serial); 0401 } 0402 0403 void XdgToplevelInterfacePrivate::xdg_toplevel_move(Resource *resource, ::wl_resource *seatResource, uint32_t serial) 0404 { 0405 auto xdgSurfacePrivate = XdgSurfaceInterfacePrivate::get(xdgSurface); 0406 0407 if (!xdgSurfacePrivate->isConfigured) { 0408 wl_resource_post_error(resource->handle, QtWaylandServer::xdg_surface::error_not_constructed, "surface has not been configured yet"); 0409 return; 0410 } 0411 0412 SeatInterface *seat = SeatInterface::get(seatResource); 0413 Q_EMIT q->moveRequested(seat, serial); 0414 } 0415 0416 void XdgToplevelInterfacePrivate::xdg_toplevel_resize(Resource *resource, ::wl_resource *seatResource, uint32_t serial, uint32_t xdgEdges) 0417 { 0418 auto xdgSurfacePrivate = XdgSurfaceInterfacePrivate::get(xdgSurface); 0419 0420 if (!xdgSurfacePrivate->isConfigured) { 0421 wl_resource_post_error(resource->handle, QtWaylandServer::xdg_surface::error_not_constructed, "surface has not been configured yet"); 0422 return; 0423 } 0424 0425 SeatInterface *seat = SeatInterface::get(seatResource); 0426 Q_EMIT q->resizeRequested(seat, XdgToplevelInterface::ResizeAnchor(xdgEdges), serial); 0427 } 0428 0429 void XdgToplevelInterfacePrivate::xdg_toplevel_set_max_size(Resource *resource, int32_t width, int32_t height) 0430 { 0431 if (width < 0 || height < 0) { 0432 wl_resource_post_error(resource->handle, -1, "width and height must be positive or zero"); 0433 return; 0434 } 0435 next.maximumSize = QSize(width, height); 0436 } 0437 0438 void XdgToplevelInterfacePrivate::xdg_toplevel_set_min_size(Resource *resource, int32_t width, int32_t height) 0439 { 0440 if (width < 0 || height < 0) { 0441 wl_resource_post_error(resource->handle, -1, "width and height must be positive or zero"); 0442 return; 0443 } 0444 next.minimumSize = QSize(width, height); 0445 } 0446 0447 void XdgToplevelInterfacePrivate::xdg_toplevel_set_maximized(Resource *resource) 0448 { 0449 Q_EMIT q->maximizeRequested(); 0450 } 0451 0452 void XdgToplevelInterfacePrivate::xdg_toplevel_unset_maximized(Resource *resource) 0453 { 0454 Q_EMIT q->unmaximizeRequested(); 0455 } 0456 0457 void XdgToplevelInterfacePrivate::xdg_toplevel_set_fullscreen(Resource *resource, ::wl_resource *outputResource) 0458 { 0459 OutputInterface *output = OutputInterface::get(outputResource); 0460 Q_EMIT q->fullscreenRequested(output); 0461 } 0462 0463 void XdgToplevelInterfacePrivate::xdg_toplevel_unset_fullscreen(Resource *resource) 0464 { 0465 Q_EMIT q->unfullscreenRequested(); 0466 } 0467 0468 void XdgToplevelInterfacePrivate::xdg_toplevel_set_minimized(Resource *resource) 0469 { 0470 Q_EMIT q->minimizeRequested(); 0471 } 0472 0473 XdgToplevelInterfacePrivate *XdgToplevelInterfacePrivate::get(XdgToplevelInterface *toplevel) 0474 { 0475 return toplevel->d.get(); 0476 } 0477 0478 XdgToplevelInterfacePrivate *XdgToplevelInterfacePrivate::get(wl_resource *resource) 0479 { 0480 return resource_cast<XdgToplevelInterfacePrivate *>(resource); 0481 } 0482 0483 XdgToplevelInterface::XdgToplevelInterface(XdgSurfaceInterface *surface, ::wl_resource *resource) 0484 : d(new XdgToplevelInterfacePrivate(this, surface)) 0485 { 0486 d->init(resource); 0487 } 0488 0489 XdgToplevelInterface::~XdgToplevelInterface() 0490 { 0491 Q_EMIT aboutToBeDestroyed(); 0492 } 0493 0494 XdgShellInterface *XdgToplevelInterface::shell() const 0495 { 0496 return d->xdgSurface->shell(); 0497 } 0498 0499 XdgSurfaceInterface *XdgToplevelInterface::xdgSurface() const 0500 { 0501 return d->xdgSurface; 0502 } 0503 0504 SurfaceInterface *XdgToplevelInterface::surface() const 0505 { 0506 return d->xdgSurface->surface(); 0507 } 0508 0509 bool XdgToplevelInterface::isConfigured() const 0510 { 0511 return d->xdgSurface->isConfigured(); 0512 } 0513 0514 XdgToplevelInterface *XdgToplevelInterface::parentXdgToplevel() const 0515 { 0516 return d->parentXdgToplevel; 0517 } 0518 0519 QString XdgToplevelInterface::windowTitle() const 0520 { 0521 return d->windowTitle; 0522 } 0523 0524 QString XdgToplevelInterface::windowClass() const 0525 { 0526 return d->windowClass; 0527 } 0528 0529 QSize XdgToplevelInterface::minimumSize() const 0530 { 0531 return d->current.minimumSize.isEmpty() ? QSize(0, 0) : d->current.minimumSize; 0532 } 0533 0534 QSize XdgToplevelInterface::maximumSize() const 0535 { 0536 return d->current.maximumSize.isEmpty() ? QSize(INT_MAX, INT_MAX) : d->current.maximumSize; 0537 } 0538 0539 quint32 XdgToplevelInterface::sendConfigure(const QSize &size, const States &states) 0540 { 0541 // Note that the states listed in the configure event must be an array of uint32_t. 0542 0543 uint32_t statesData[8] = {0}; 0544 int i = 0; 0545 0546 if (states & State::MaximizedHorizontal && states & State::MaximizedVertical) { 0547 statesData[i++] = QtWaylandServer::xdg_toplevel::state_maximized; 0548 } 0549 if (states & State::FullScreen) { 0550 statesData[i++] = QtWaylandServer::xdg_toplevel::state_fullscreen; 0551 } 0552 if (states & State::Resizing) { 0553 statesData[i++] = QtWaylandServer::xdg_toplevel::state_resizing; 0554 } 0555 if (states & State::Activated) { 0556 statesData[i++] = QtWaylandServer::xdg_toplevel::state_activated; 0557 } 0558 0559 if (d->resource()->version() >= XDG_TOPLEVEL_STATE_TILED_LEFT_SINCE_VERSION) { 0560 if (states & State::TiledLeft) { 0561 statesData[i++] = QtWaylandServer::xdg_toplevel::state_tiled_left; 0562 } 0563 if (states & State::TiledTop) { 0564 statesData[i++] = QtWaylandServer::xdg_toplevel::state_tiled_top; 0565 } 0566 if (states & State::TiledRight) { 0567 statesData[i++] = QtWaylandServer::xdg_toplevel::state_tiled_right; 0568 } 0569 if (states & State::TiledBottom) { 0570 statesData[i++] = QtWaylandServer::xdg_toplevel::state_tiled_bottom; 0571 } 0572 } 0573 0574 const QByteArray xdgStates = QByteArray::fromRawData(reinterpret_cast<char *>(statesData), sizeof(uint32_t) * i); 0575 const quint32 serial = xdgSurface()->shell()->display()->nextSerial(); 0576 0577 d->send_configure(size.width(), size.height(), xdgStates); 0578 0579 auto xdgSurfacePrivate = XdgSurfaceInterfacePrivate::get(xdgSurface()); 0580 xdgSurfacePrivate->send_configure(serial); 0581 xdgSurfacePrivate->isConfigured = true; 0582 0583 return serial; 0584 } 0585 0586 void XdgToplevelInterface::sendClose() 0587 { 0588 d->send_close(); 0589 } 0590 0591 void XdgToplevelInterface::sendConfigureBounds(const QSize &size) 0592 { 0593 if (d->resource()->version() >= XDG_TOPLEVEL_CONFIGURE_BOUNDS_SINCE_VERSION) { 0594 d->send_configure_bounds(size.width(), size.height()); 0595 } 0596 } 0597 0598 XdgToplevelInterface *XdgToplevelInterface::get(::wl_resource *resource) 0599 { 0600 if (auto toplevelPrivate = resource_cast<XdgToplevelInterfacePrivate *>(resource)) { 0601 return toplevelPrivate->q; 0602 } 0603 return nullptr; 0604 } 0605 0606 XdgPopupInterfacePrivate *XdgPopupInterfacePrivate::get(XdgPopupInterface *popup) 0607 { 0608 return popup->d.get(); 0609 } 0610 0611 XdgPopupInterfacePrivate::XdgPopupInterfacePrivate(XdgPopupInterface *popup, XdgSurfaceInterface *surface) 0612 : SurfaceRole(surface->surface(), QByteArrayLiteral("xdg_popup")) 0613 , q(popup) 0614 , xdgSurface(surface) 0615 { 0616 } 0617 0618 void XdgPopupInterfacePrivate::commit() 0619 { 0620 if (!parentSurface) { 0621 auto shellPrivate = XdgShellInterfacePrivate::get(xdgSurface->shell()); 0622 wl_resource_post_error(shellPrivate->resourceForXdgSurface(xdgSurface)->handle, 0623 QtWaylandServer::xdg_wm_base::error_invalid_popup_parent, 0624 "no xdg_popup parent surface has been specified"); 0625 return; 0626 } 0627 0628 auto xdgSurfacePrivate = XdgSurfaceInterfacePrivate::get(xdgSurface); 0629 if (xdgSurfacePrivate->firstBufferAttached && !xdgSurfacePrivate->surface->buffer()) { 0630 reset(); 0631 return; 0632 } 0633 0634 xdgSurfacePrivate->commit(); 0635 0636 if (!xdgSurfacePrivate->isInitialized) { 0637 Q_EMIT q->initializeRequested(); 0638 xdgSurfacePrivate->isInitialized = true; 0639 } 0640 } 0641 0642 void XdgPopupInterfacePrivate::reset() 0643 { 0644 auto xdgSurfacePrivate = XdgSurfaceInterfacePrivate::get(xdgSurface); 0645 xdgSurfacePrivate->reset(); 0646 } 0647 0648 void XdgPopupInterfacePrivate::xdg_popup_destroy_resource(Resource *resource) 0649 { 0650 delete q; 0651 } 0652 0653 void XdgPopupInterfacePrivate::xdg_popup_destroy(Resource *resource) 0654 { 0655 // TODO: We need to post an error with the code XDG_WM_BASE_ERROR_NOT_THE_TOPMOST_POPUP if 0656 // this popup is not the topmost grabbing popup. We most likely need a grab abstraction or 0657 // something to determine whether the given popup has an explicit grab. 0658 wl_resource_destroy(resource->handle); 0659 } 0660 0661 void XdgPopupInterfacePrivate::xdg_popup_grab(Resource *resource, ::wl_resource *seatHandle, uint32_t serial) 0662 { 0663 if (xdgSurface->surface()->buffer()) { 0664 wl_resource_post_error(resource->handle, error_invalid_grab, "xdg_surface is already mapped"); 0665 return; 0666 } 0667 SeatInterface *seat = SeatInterface::get(seatHandle); 0668 Q_EMIT q->grabRequested(seat, serial); 0669 } 0670 0671 void XdgPopupInterfacePrivate::xdg_popup_reposition(Resource *resource, ::wl_resource *positionerResource, uint32_t token) 0672 { 0673 positioner = XdgPositioner::get(positionerResource); 0674 Q_EMIT q->repositionRequested(token); 0675 } 0676 0677 XdgPopupInterface::XdgPopupInterface(XdgSurfaceInterface *surface, SurfaceInterface *parentSurface, const XdgPositioner &positioner, ::wl_resource *resource) 0678 : d(new XdgPopupInterfacePrivate(this, surface)) 0679 { 0680 d->parentSurface = parentSurface; 0681 d->positioner = positioner; 0682 d->init(resource); 0683 } 0684 0685 XdgPopupInterface::~XdgPopupInterface() 0686 { 0687 Q_EMIT aboutToBeDestroyed(); 0688 } 0689 0690 SurfaceInterface *XdgPopupInterface::parentSurface() const 0691 { 0692 return d->parentSurface; 0693 } 0694 0695 XdgSurfaceInterface *XdgPopupInterface::xdgSurface() const 0696 { 0697 return d->xdgSurface; 0698 } 0699 0700 SurfaceInterface *XdgPopupInterface::surface() const 0701 { 0702 return d->xdgSurface->surface(); 0703 } 0704 0705 bool XdgPopupInterface::isConfigured() const 0706 { 0707 return d->xdgSurface->isConfigured(); 0708 } 0709 0710 XdgPositioner XdgPopupInterface::positioner() const 0711 { 0712 return d->positioner; 0713 } 0714 0715 quint32 XdgPopupInterface::sendConfigure(const QRect &rect) 0716 { 0717 const quint32 serial = xdgSurface()->shell()->display()->nextSerial(); 0718 0719 d->send_configure(rect.x(), rect.y(), rect.width(), rect.height()); 0720 0721 auto xdgSurfacePrivate = XdgSurfaceInterfacePrivate::get(xdgSurface()); 0722 xdgSurfacePrivate->send_configure(serial); 0723 xdgSurfacePrivate->isConfigured = true; 0724 0725 return serial; 0726 } 0727 0728 void XdgPopupInterface::sendPopupDone() 0729 { 0730 d->send_popup_done(); 0731 } 0732 0733 void XdgPopupInterface::sendRepositioned(quint32 token) 0734 { 0735 Q_ASSERT(d->resource()->version() >= XDG_POPUP_REPOSITIONED_SINCE_VERSION); 0736 d->send_repositioned(token); 0737 } 0738 0739 XdgPopupInterface *XdgPopupInterface::get(::wl_resource *resource) 0740 { 0741 if (auto popupPrivate = resource_cast<XdgPopupInterfacePrivate *>(resource)) { 0742 return popupPrivate->q; 0743 } 0744 return nullptr; 0745 } 0746 0747 XdgPositionerPrivate::XdgPositionerPrivate(::wl_resource *resource) 0748 : data(new XdgPositionerData) 0749 { 0750 init(resource); 0751 } 0752 0753 XdgPositionerPrivate *XdgPositionerPrivate::get(wl_resource *resource) 0754 { 0755 return resource_cast<XdgPositionerPrivate *>(resource); 0756 } 0757 0758 void XdgPositionerPrivate::xdg_positioner_destroy_resource(Resource *resource) 0759 { 0760 delete this; 0761 } 0762 0763 void XdgPositionerPrivate::xdg_positioner_destroy(Resource *resource) 0764 { 0765 wl_resource_destroy(resource->handle); 0766 } 0767 0768 void XdgPositionerPrivate::xdg_positioner_set_size(Resource *resource, int32_t width, int32_t height) 0769 { 0770 if (width < 1 || height < 1) { 0771 wl_resource_post_error(resource->handle, error_invalid_input, "width and height must be positive and non-zero"); 0772 return; 0773 } 0774 data->size = QSize(width, height); 0775 } 0776 0777 void XdgPositionerPrivate::xdg_positioner_set_anchor_rect(Resource *resource, int32_t x, int32_t y, int32_t width, int32_t height) 0778 { 0779 if (width < 1 || height < 1) { 0780 wl_resource_post_error(resource->handle, error_invalid_input, "width and height must be positive and non-zero"); 0781 return; 0782 } 0783 data->anchorRect = QRect(x, y, width, height); 0784 } 0785 0786 void XdgPositionerPrivate::xdg_positioner_set_anchor(Resource *resource, uint32_t anchor) 0787 { 0788 if (anchor > anchor_bottom_right) { 0789 wl_resource_post_error(resource->handle, error_invalid_input, "unknown anchor point"); 0790 return; 0791 } 0792 0793 switch (anchor) { 0794 case anchor_top: 0795 data->anchorEdges = Qt::TopEdge; 0796 break; 0797 case anchor_top_right: 0798 data->anchorEdges = Qt::TopEdge | Qt::RightEdge; 0799 break; 0800 case anchor_right: 0801 data->anchorEdges = Qt::RightEdge; 0802 break; 0803 case anchor_bottom_right: 0804 data->anchorEdges = Qt::BottomEdge | Qt::RightEdge; 0805 break; 0806 case anchor_bottom: 0807 data->anchorEdges = Qt::BottomEdge; 0808 break; 0809 case anchor_bottom_left: 0810 data->anchorEdges = Qt::BottomEdge | Qt::LeftEdge; 0811 break; 0812 case anchor_left: 0813 data->anchorEdges = Qt::LeftEdge; 0814 break; 0815 case anchor_top_left: 0816 data->anchorEdges = Qt::TopEdge | Qt::LeftEdge; 0817 break; 0818 default: 0819 data->anchorEdges = Qt::Edges(); 0820 break; 0821 } 0822 } 0823 0824 void XdgPositionerPrivate::xdg_positioner_set_parent_size(Resource *resource, int32_t width, int32_t height) 0825 { 0826 data->parentSize = QSize(width, height); 0827 } 0828 0829 void XdgPositionerPrivate::xdg_positioner_set_reactive(Resource *resource) 0830 { 0831 data->isReactive = true; 0832 } 0833 0834 void XdgPositionerPrivate::xdg_positioner_set_parent_configure(Resource *resource, uint32_t serial) 0835 { 0836 data->parentConfigure = serial; 0837 } 0838 0839 void XdgPositionerPrivate::xdg_positioner_set_gravity(Resource *resource, uint32_t gravity) 0840 { 0841 if (gravity > gravity_bottom_right) { 0842 wl_resource_post_error(resource->handle, error_invalid_input, "unknown gravity direction"); 0843 return; 0844 } 0845 0846 switch (gravity) { 0847 case gravity_top: 0848 data->gravityEdges = Qt::TopEdge; 0849 break; 0850 case gravity_top_right: 0851 data->gravityEdges = Qt::TopEdge | Qt::RightEdge; 0852 break; 0853 case gravity_right: 0854 data->gravityEdges = Qt::RightEdge; 0855 break; 0856 case gravity_bottom_right: 0857 data->gravityEdges = Qt::BottomEdge | Qt::RightEdge; 0858 break; 0859 case gravity_bottom: 0860 data->gravityEdges = Qt::BottomEdge; 0861 break; 0862 case gravity_bottom_left: 0863 data->gravityEdges = Qt::BottomEdge | Qt::LeftEdge; 0864 break; 0865 case gravity_left: 0866 data->gravityEdges = Qt::LeftEdge; 0867 break; 0868 case gravity_top_left: 0869 data->gravityEdges = Qt::TopEdge | Qt::LeftEdge; 0870 break; 0871 default: 0872 data->gravityEdges = Qt::Edges(); 0873 break; 0874 } 0875 } 0876 0877 void XdgPositionerPrivate::xdg_positioner_set_constraint_adjustment(Resource *resource, uint32_t constraint_adjustment) 0878 { 0879 if (constraint_adjustment & constraint_adjustment_flip_x) { 0880 data->flipConstraintAdjustments |= Qt::Horizontal; 0881 } else { 0882 data->flipConstraintAdjustments &= ~Qt::Horizontal; 0883 } 0884 0885 if (constraint_adjustment & constraint_adjustment_flip_y) { 0886 data->flipConstraintAdjustments |= Qt::Vertical; 0887 } else { 0888 data->flipConstraintAdjustments &= ~Qt::Vertical; 0889 } 0890 0891 if (constraint_adjustment & constraint_adjustment_slide_x) { 0892 data->slideConstraintAdjustments |= Qt::Horizontal; 0893 } else { 0894 data->slideConstraintAdjustments &= ~Qt::Horizontal; 0895 } 0896 0897 if (constraint_adjustment & constraint_adjustment_slide_y) { 0898 data->slideConstraintAdjustments |= Qt::Vertical; 0899 } else { 0900 data->slideConstraintAdjustments &= ~Qt::Vertical; 0901 } 0902 0903 if (constraint_adjustment & constraint_adjustment_resize_x) { 0904 data->resizeConstraintAdjustments |= Qt::Horizontal; 0905 } else { 0906 data->resizeConstraintAdjustments &= ~Qt::Horizontal; 0907 } 0908 0909 if (constraint_adjustment & constraint_adjustment_resize_y) { 0910 data->resizeConstraintAdjustments |= Qt::Vertical; 0911 } else { 0912 data->resizeConstraintAdjustments &= ~Qt::Vertical; 0913 } 0914 } 0915 0916 void XdgPositionerPrivate::xdg_positioner_set_offset(Resource *resource, int32_t x, int32_t y) 0917 { 0918 data->offset = QPoint(x, y); 0919 } 0920 0921 XdgPositioner::XdgPositioner() 0922 : d(new XdgPositionerData) 0923 { 0924 } 0925 0926 XdgPositioner::XdgPositioner(const XdgPositioner &other) 0927 : d(other.d) 0928 { 0929 } 0930 0931 XdgPositioner::~XdgPositioner() 0932 { 0933 } 0934 0935 XdgPositioner &XdgPositioner::operator=(const XdgPositioner &other) 0936 { 0937 d = other.d; 0938 return *this; 0939 } 0940 0941 bool XdgPositioner::isComplete() const 0942 { 0943 return d->size.isValid() && d->anchorRect.isValid(); 0944 } 0945 0946 Qt::Orientations XdgPositioner::slideConstraintAdjustments() const 0947 { 0948 return d->slideConstraintAdjustments; 0949 } 0950 0951 Qt::Orientations XdgPositioner::flipConstraintAdjustments() const 0952 { 0953 return d->flipConstraintAdjustments; 0954 } 0955 0956 Qt::Orientations XdgPositioner::resizeConstraintAdjustments() const 0957 { 0958 return d->resizeConstraintAdjustments; 0959 } 0960 0961 Qt::Edges XdgPositioner::anchorEdges() const 0962 { 0963 return d->anchorEdges; 0964 } 0965 0966 Qt::Edges XdgPositioner::gravityEdges() const 0967 { 0968 return d->gravityEdges; 0969 } 0970 0971 QSize XdgPositioner::size() const 0972 { 0973 return d->size; 0974 } 0975 0976 QRect XdgPositioner::anchorRect() const 0977 { 0978 return d->anchorRect; 0979 } 0980 0981 QPoint XdgPositioner::offset() const 0982 { 0983 return d->offset; 0984 } 0985 0986 QSize XdgPositioner::parentSize() const 0987 { 0988 return d->parentSize; 0989 } 0990 0991 bool XdgPositioner::isReactive() const 0992 { 0993 return d->isReactive; 0994 } 0995 0996 quint32 XdgPositioner::parentConfigure() const 0997 { 0998 return d->parentConfigure; 0999 } 1000 1001 XdgPositioner XdgPositioner::get(::wl_resource *resource) 1002 { 1003 XdgPositionerPrivate *xdgPositionerPrivate = XdgPositionerPrivate::get(resource); 1004 if (xdgPositionerPrivate) 1005 return XdgPositioner(xdgPositionerPrivate->data); 1006 return XdgPositioner(); 1007 } 1008 1009 XdgPositioner::XdgPositioner(const QSharedDataPointer<XdgPositionerData> &data) 1010 : d(data) 1011 { 1012 } 1013 1014 } // namespace KWaylandServer