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