File indexing completed on 2025-02-16 05:09:07
0001 /**************************************************************************** 0002 ** 0003 ** Copyright (C) 2018 The Qt Company Ltd. 0004 ** Contact: https://www.qt.io/licensing/ 0005 ** 0006 ** This file is part of the test suite of the Qt Toolkit. 0007 ** 0008 ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ 0009 ** Commercial License Usage 0010 ** Licensees holding valid commercial Qt licenses may use this file in 0011 ** accordance with the commercial license agreement provided with the 0012 ** Software or, alternatively, in accordance with the terms contained in 0013 ** a written agreement between you and The Qt Company. For licensing terms 0014 ** and conditions see https://www.qt.io/terms-conditions. For further 0015 ** information use the contact form at https://www.qt.io/contact-us. 0016 ** 0017 ** GNU General Public License Usage 0018 ** Alternatively, this file may be used under the terms of the GNU 0019 ** General Public License version 3 as published by the Free Software 0020 ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT 0021 ** included in the packaging of this file. Please review the following 0022 ** information to ensure the GNU General Public License requirements will 0023 ** be met: https://www.gnu.org/licenses/gpl-3.0.html. 0024 ** 0025 ** $QT_END_LICENSE$ 0026 ** 0027 ****************************************************************************/ 0028 0029 #include "coreprotocol.h" 0030 #include "datadevice.h" 0031 0032 namespace MockCompositor 0033 { 0034 void Surface::sendFrameCallbacks() 0035 { 0036 uint time = m_wlCompositor->m_compositor->currentTimeMilliseconds(); 0037 for (auto *callback : m_waitingFrameCallbacks) 0038 callback->sendDone(time); 0039 m_waitingFrameCallbacks.clear(); 0040 } 0041 0042 void Surface::sendEnter(Output *output) 0043 { 0044 m_outputs.append(output); 0045 const auto outputResources = output->resourceMap().values(resource()->client()); 0046 for (auto outputResource : outputResources) 0047 wl_surface::send_enter(resource()->handle, outputResource->handle); 0048 } 0049 0050 void Surface::sendLeave(Output *output) 0051 { 0052 m_outputs.removeOne(output); 0053 const auto outputResources = output->resourceMap().values(resource()->client()); 0054 for (auto outputResource : outputResources) 0055 wl_surface::send_leave(resource()->handle, outputResource->handle); 0056 } 0057 0058 void Surface::surface_destroy_resource(Resource *resource) 0059 { 0060 Q_UNUSED(resource); 0061 for (auto *commit : m_commits) 0062 delete commit->commitSpecific.frame; 0063 bool removed = m_wlCompositor->m_surfaces.removeOne(this); 0064 Q_ASSERT(removed); 0065 delete this; 0066 } 0067 0068 void Surface::surface_attach(Resource *resource, wl_resource *buffer, int32_t x, int32_t y) 0069 { 0070 Q_UNUSED(resource); 0071 QPoint offset(x, y); 0072 m_pending.buffer = fromResource<Buffer>(buffer); 0073 m_pending.commitSpecific.attachOffset = offset; 0074 m_pending.commitSpecific.attached = true; 0075 emit attach(buffer, offset); 0076 } 0077 0078 void Surface::surface_set_buffer_scale(QtWaylandServer::wl_surface::Resource *resource, int32_t scale) 0079 { 0080 Q_UNUSED(resource); 0081 m_pending.bufferScale = scale; 0082 } 0083 0084 void Surface::surface_commit(Resource *resource) 0085 { 0086 Q_UNUSED(resource); 0087 m_committed = m_pending; 0088 m_commits.append(new DoubleBufferedState(m_committed)); 0089 0090 if (auto *frame = m_pending.commitSpecific.frame) 0091 m_waitingFrameCallbacks.append(frame); 0092 0093 m_pending.commitSpecific = PerCommitData(); 0094 emit commit(); 0095 if (m_committed.commitSpecific.attached) 0096 emit bufferCommitted(); 0097 } 0098 0099 void Surface::surface_frame(Resource *resource, uint32_t callback) 0100 { 0101 // Although valid, there is really no point having multiple frame requests in the same commit. 0102 // Make sure we don't do it 0103 QCOMPARE(m_pending.commitSpecific.frame, nullptr); 0104 0105 auto *frame = new Callback(resource->client(), callback, 1); 0106 m_pending.commitSpecific.frame = frame; 0107 } 0108 0109 bool WlCompositor::isClean() 0110 { 0111 for (auto *surface : std::as_const(m_surfaces)) { 0112 if (!CursorRole::fromSurface(surface)) 0113 return false; 0114 } 0115 return true; 0116 } 0117 0118 QString WlCompositor::dirtyMessage() 0119 { 0120 if (isClean()) 0121 return "clean"; 0122 QStringList messages; 0123 for (auto *s : std::as_const(m_surfaces)) { 0124 QString role = s->m_role ? s->m_role->staticMetaObject.className() : "none/unknown"; 0125 messages << "Surface with role: " + role; 0126 } 0127 return "Dirty, surfaces left:\n\t" + messages.join("\n\t"); 0128 } 0129 0130 void Output::sendGeometry() 0131 { 0132 const auto resources = resourceMap().values(); 0133 for (auto r : resources) 0134 sendGeometry(r); 0135 } 0136 0137 void Output::sendGeometry(Resource *resource) 0138 { 0139 wl_output::send_geometry(resource->handle, 0140 m_data.position.x(), 0141 m_data.position.y(), 0142 m_data.physicalSize.width(), 0143 m_data.physicalSize.height(), 0144 m_data.subpixel, 0145 m_data.make, 0146 m_data.model, 0147 m_data.transform); 0148 } 0149 0150 void Output::sendScale(int factor) 0151 { 0152 m_data.scale = factor; 0153 const auto resources = resourceMap().values(); 0154 for (auto r : resources) 0155 sendScale(r); 0156 } 0157 0158 void Output::sendScale(Resource *resource) 0159 { 0160 wl_output::send_scale(resource->handle, m_data.scale); 0161 } 0162 0163 void Output::sendDone(wl_client *client) 0164 { 0165 auto resources = resourceMap().values(client); 0166 for (auto *r : resources) 0167 wl_output::send_done(r->handle); 0168 } 0169 0170 void Output::sendDone() 0171 { 0172 const auto resources = resourceMap().values(); 0173 for (auto r : resources) 0174 wl_output::send_done(r->handle); 0175 } 0176 0177 void Output::output_bind_resource(QtWaylandServer::wl_output::Resource *resource) 0178 { 0179 sendGeometry(resource); 0180 send_mode(resource->handle, mode_preferred | mode_current, m_data.mode.resolution.width(), m_data.mode.resolution.height(), m_data.mode.refreshRate); 0181 sendScale(resource); 0182 wl_output::send_done(resource->handle); 0183 } 0184 0185 // Seat stuff 0186 Seat::Seat(CoreCompositor *compositor, uint capabilities, int version) // TODO: check version 0187 : QtWaylandServer::wl_seat(compositor->m_display, version) 0188 , m_compositor(compositor) 0189 { 0190 setCapabilities(capabilities); 0191 } 0192 0193 Seat::~Seat() 0194 { 0195 qDeleteAll(m_oldPointers); 0196 delete m_pointer; 0197 0198 qDeleteAll(m_oldTouchs); 0199 delete m_touch; 0200 0201 qDeleteAll(m_oldKeyboards); 0202 delete m_keyboard; 0203 } 0204 0205 void Seat::setCapabilities(uint capabilities) 0206 { 0207 m_capabilities = capabilities; 0208 0209 if (m_capabilities & capability_pointer) { 0210 if (!m_pointer) 0211 m_pointer = (new Pointer(this)); 0212 } else if (m_pointer) { 0213 m_oldPointers << m_pointer; 0214 m_pointer = nullptr; 0215 } 0216 0217 if (m_capabilities & capability_touch) { 0218 if (!m_touch) 0219 m_touch = (new Touch(this)); 0220 } else if (m_touch) { 0221 m_oldTouchs << m_touch; 0222 m_touch = nullptr; 0223 } 0224 0225 if (m_capabilities & capability_keyboard) { 0226 if (!m_keyboard) 0227 m_keyboard = (new Keyboard(this)); 0228 } else if (m_keyboard) { 0229 m_oldKeyboards << m_keyboard; 0230 m_keyboard = nullptr; 0231 } 0232 0233 for (auto *resource : resourceMap()) 0234 wl_seat::send_capabilities(resource->handle, capabilities); 0235 } 0236 0237 void Seat::seat_get_pointer(Resource *resource, uint32_t id) 0238 { 0239 if (~m_capabilities & capability_pointer) { 0240 qWarning() << "Client requested a wl_pointer without the capability being available." 0241 << "This Could be a race condition when hotunplugging," 0242 << "but is most likely a client error"; 0243 Pointer *pointer = new Pointer(this); 0244 pointer->add(resource->client(), id, resource->version()); 0245 // TODO: mark as destroyed 0246 m_oldPointers << pointer; 0247 return; 0248 } 0249 m_pointer->add(resource->client(), id, resource->version()); 0250 } 0251 0252 void Seat::seat_get_touch(QtWaylandServer::wl_seat::Resource *resource, uint32_t id) 0253 { 0254 if (~m_capabilities & capability_touch) { 0255 qWarning() << "Client requested a wl_touch without the capability being available." 0256 << "This Could be a race condition when hotunplugging," 0257 << "but is most likely a client error"; 0258 Touch *touch = new Touch(this); 0259 touch->add(resource->client(), id, resource->version()); 0260 // TODO: mark as destroyed 0261 m_oldTouchs << touch; 0262 return; 0263 } 0264 m_touch->add(resource->client(), id, resource->version()); 0265 } 0266 0267 void Seat::seat_get_keyboard(QtWaylandServer::wl_seat::Resource *resource, uint32_t id) 0268 { 0269 if (~m_capabilities & capability_keyboard) { 0270 qWarning() << "Client requested a wl_keyboard without the capability being available." 0271 << "This Could be a race condition when hotunplugging," 0272 << "but is most likely a client error"; 0273 Keyboard *keyboard = new Keyboard(this); 0274 keyboard->add(resource->client(), id, resource->version()); 0275 // TODO: mark as destroyed 0276 m_oldKeyboards << keyboard; 0277 return; 0278 } 0279 m_keyboard->add(resource->client(), id, resource->version()); 0280 } 0281 0282 Surface *Pointer::cursorSurface() 0283 { 0284 return m_cursorRole ? m_cursorRole->m_surface : nullptr; 0285 } 0286 0287 uint Pointer::sendEnter(Surface *surface, const QPointF &position) 0288 { 0289 wl_fixed_t x = wl_fixed_from_double(position.x()); 0290 wl_fixed_t y = wl_fixed_from_double(position.y()); 0291 0292 uint serial = m_seat->m_compositor->nextSerial(); 0293 m_enterSerials << serial; 0294 m_cursorRole = nullptr; // According to the protocol, the pointer image is undefined after enter 0295 0296 wl_client *client = surface->resource()->client(); 0297 const auto pointerResources = resourceMap().values(client); 0298 for (auto *r : pointerResources) 0299 wl_pointer::send_enter(r->handle, serial, surface->resource()->handle, x, y); 0300 return serial; 0301 } 0302 0303 uint Pointer::sendLeave(Surface *surface) 0304 { 0305 uint serial = m_seat->m_compositor->nextSerial(); 0306 0307 wl_client *client = surface->resource()->client(); 0308 const auto pointerResources = resourceMap().values(client); 0309 for (auto *r : pointerResources) 0310 wl_pointer::send_leave(r->handle, serial, surface->resource()->handle); 0311 return serial; 0312 } 0313 0314 // Make sure you call enter, frame etc. first 0315 void Pointer::sendMotion(wl_client *client, const QPointF &position) 0316 { 0317 wl_fixed_t x = wl_fixed_from_double(position.x()); 0318 wl_fixed_t y = wl_fixed_from_double(position.y()); 0319 auto time = m_seat->m_compositor->currentTimeMilliseconds(); 0320 const auto pointerResources = resourceMap().values(client); 0321 for (auto *r : pointerResources) 0322 send_motion(r->handle, time, x, y); 0323 } 0324 0325 // Make sure you call enter, frame etc. first 0326 uint Pointer::sendButton(wl_client *client, uint button, uint state) 0327 { 0328 Q_ASSERT(state == button_state_pressed || state == button_state_released); 0329 auto time = m_seat->m_compositor->currentTimeMilliseconds(); 0330 uint serial = m_seat->m_compositor->nextSerial(); 0331 const auto pointerResources = resourceMap().values(client); 0332 for (auto *r : pointerResources) 0333 send_button(r->handle, serial, time, button, state); 0334 return serial; 0335 } 0336 0337 // Make sure you call enter, frame etc. first 0338 void Pointer::sendAxis(wl_client *client, axis axis, qreal value) 0339 { 0340 auto time = m_seat->m_compositor->currentTimeMilliseconds(); 0341 wl_fixed_t val = wl_fixed_from_double(value); 0342 const auto pointerResources = resourceMap().values(client); 0343 for (auto *r : pointerResources) 0344 send_axis(r->handle, time, axis, val); 0345 } 0346 0347 void Pointer::sendAxisDiscrete(wl_client *client, QtWaylandServer::wl_pointer::axis axis, int discrete) 0348 { 0349 // TODO: assert v5 or newer 0350 const auto pointerResources = resourceMap().values(client); 0351 for (auto *r : pointerResources) 0352 send_axis_discrete(r->handle, axis, discrete); 0353 } 0354 0355 void Pointer::sendAxisSource(wl_client *client, QtWaylandServer::wl_pointer::axis_source source) 0356 { 0357 // TODO: assert v5 or newer 0358 const auto pointerResources = resourceMap().values(client); 0359 for (auto *r : pointerResources) 0360 send_axis_source(r->handle, source); 0361 } 0362 0363 void Pointer::sendAxisStop(wl_client *client, QtWaylandServer::wl_pointer::axis axis) 0364 { 0365 // TODO: assert v5 or newer 0366 auto time = m_seat->m_compositor->currentTimeMilliseconds(); 0367 const auto pointerResources = resourceMap().values(client); 0368 for (auto *r : pointerResources) 0369 send_axis_stop(r->handle, time, axis); 0370 } 0371 0372 void Pointer::sendFrame(wl_client *client) 0373 { 0374 // TODO: assert version 5 or newer? 0375 const auto pointerResources = resourceMap().values(client); 0376 for (auto *r : pointerResources) 0377 send_frame(r->handle); 0378 } 0379 0380 void Pointer::pointer_set_cursor(Resource *resource, uint32_t serial, wl_resource *surface, int32_t hotspot_x, int32_t hotspot_y) 0381 { 0382 Q_UNUSED(resource); 0383 auto *s = fromResource<Surface>(surface); 0384 QVERIFY(s); 0385 0386 if (s->m_role) { 0387 m_cursorRole = CursorRole::fromSurface(s); 0388 QVERIFY(m_cursorRole); 0389 } else { 0390 m_cursorRole = new CursorRole(s); // TODO: make sure we don't leak CursorRole 0391 s->m_role = m_cursorRole; 0392 } 0393 0394 // Directly checking the last serial would be racy, we may just have sent leaves/enters which 0395 // the client hasn't yet seen. Instead just check if the serial matches an enter serial since 0396 // the last time the client sent a set_cursor request. 0397 QVERIFY(m_enterSerials.contains(serial)); 0398 while (m_enterSerials.first() < serial) { 0399 m_enterSerials.removeFirst(); 0400 } 0401 0402 m_hotspot = QPoint(hotspot_x, hotspot_y); 0403 emit setCursor(serial); 0404 } 0405 0406 uint Touch::sendDown(Surface *surface, const QPointF &position, int id) 0407 { 0408 wl_fixed_t x = wl_fixed_from_double(position.x()); 0409 wl_fixed_t y = wl_fixed_from_double(position.y()); 0410 uint serial = m_seat->m_compositor->nextSerial(); 0411 auto time = m_seat->m_compositor->currentTimeMilliseconds(); 0412 wl_client *client = surface->resource()->client(); 0413 0414 const auto touchResources = resourceMap().values(client); 0415 for (auto *r : touchResources) 0416 wl_touch::send_down(r->handle, serial, time, surface->resource()->handle, id, x, y); 0417 0418 return serial; 0419 } 0420 0421 uint Touch::sendUp(wl_client *client, int id) 0422 { 0423 uint serial = m_seat->m_compositor->nextSerial(); 0424 auto time = m_seat->m_compositor->currentTimeMilliseconds(); 0425 0426 const auto touchResources = resourceMap().values(client); 0427 for (auto *r : touchResources) 0428 wl_touch::send_up(r->handle, serial, time, id); 0429 0430 return serial; 0431 } 0432 0433 void Touch::sendMotion(wl_client *client, const QPointF &position, int id) 0434 { 0435 wl_fixed_t x = wl_fixed_from_double(position.x()); 0436 wl_fixed_t y = wl_fixed_from_double(position.y()); 0437 0438 auto time = m_seat->m_compositor->currentTimeMilliseconds(); 0439 0440 const auto touchResources = resourceMap().values(client); 0441 for (auto *r : touchResources) 0442 wl_touch::send_motion(r->handle, time, id, x, y); 0443 } 0444 0445 void Touch::sendFrame(wl_client *client) 0446 { 0447 const auto touchResources = resourceMap().values(client); 0448 for (auto *r : touchResources) 0449 send_frame(r->handle); 0450 } 0451 0452 uint Keyboard::sendEnter(Surface *surface) 0453 { 0454 auto serial = m_seat->m_compositor->nextSerial(); 0455 wl_client *client = surface->resource()->client(); 0456 const auto pointerResources = resourceMap().values(client); 0457 for (auto *r : pointerResources) 0458 send_enter(r->handle, serial, surface->resource()->handle, QByteArray()); 0459 m_enteredSurface = surface; 0460 return serial; 0461 } 0462 0463 uint Keyboard::sendLeave(Surface *surface) 0464 { 0465 auto serial = m_seat->m_compositor->nextSerial(); 0466 wl_client *client = surface->resource()->client(); 0467 const auto pointerResources = resourceMap().values(client); 0468 for (auto *r : pointerResources) 0469 send_leave(r->handle, serial, surface->resource()->handle); 0470 m_enteredSurface = nullptr; 0471 return serial; 0472 } 0473 0474 uint Keyboard::sendKey(wl_client *client, uint key, uint state) 0475 { 0476 Q_ASSERT(state == key_state_pressed || state == key_state_released); 0477 auto time = m_seat->m_compositor->currentTimeMilliseconds(); 0478 uint serial = m_seat->m_compositor->nextSerial(); 0479 const auto pointerResources = resourceMap().values(client); 0480 for (auto *r : pointerResources) 0481 send_key(r->handle, serial, time, key, state); 0482 return serial; 0483 } 0484 0485 // Shm implementation 0486 Shm::Shm(CoreCompositor *compositor, QList<format> formats, int version) 0487 : QtWaylandServer::wl_shm(compositor->m_display, version) 0488 , m_compositor(compositor) 0489 , m_formats(formats) 0490 { 0491 // Some formats are specified as mandatory 0492 Q_ASSERT(m_formats.contains(format_argb8888)); 0493 Q_ASSERT(m_formats.contains(format_xrgb8888)); 0494 } 0495 0496 bool Shm::isClean() 0497 { 0498 // for (ShmPool *pool : std::as_const(m_pools)) { 0499 // //TODO: return false if not cursor buffer 0500 // if (pool->m_buffers.isEmpty()) { 0501 // return false; 0502 // } 0503 // } 0504 return true; 0505 } 0506 0507 void Shm::shm_create_pool(Resource *resource, uint32_t id, int32_t fd, int32_t size) 0508 { 0509 Q_UNUSED(fd); 0510 Q_UNUSED(size); 0511 auto *pool = new ShmPool(this, resource->client(), id, 1); 0512 m_pools.append(pool); 0513 } 0514 0515 ShmPool::ShmPool(Shm *shm, wl_client *client, int id, int version) 0516 : QtWaylandServer::wl_shm_pool(client, id, version) 0517 , m_shm(shm) 0518 { 0519 } 0520 0521 void ShmPool::shm_pool_create_buffer(Resource *resource, uint32_t id, int32_t offset, int32_t width, int32_t height, int32_t stride, uint32_t format) 0522 { 0523 QSize size(width, height); 0524 new ShmBuffer(offset, size, stride, Shm::format(format), resource->client(), id); 0525 } 0526 0527 void ShmPool::shm_pool_destroy_resource(Resource *resource) 0528 { 0529 Q_UNUSED(resource); 0530 bool removed = m_shm->m_pools.removeOne(this); 0531 Q_ASSERT(removed); 0532 delete this; 0533 } 0534 0535 } // namespace MockCompositor