File indexing completed on 2024-06-23 05:32:04

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 #pragma once
0030 
0031 #include "corecompositor.h"
0032 
0033 #include <qwayland-server-wayland.h>
0034 
0035 namespace MockCompositor
0036 {
0037 class WlCompositor;
0038 class Output;
0039 class Pointer;
0040 class Touch;
0041 class Keyboard;
0042 class CursorRole;
0043 class ShmPool;
0044 class ShmBuffer;
0045 class DataDevice;
0046 
0047 template<typename T>
0048 T resource_cast(::wl_resource *resource)
0049 {
0050     using ObjectType = std::remove_pointer_t<std::remove_cv_t<T>>;
0051     if (auto resourceContainer = ObjectType::Resource::fromResource(resource)) {
0052         return static_cast<T>(resourceContainer->object());
0053     }
0054     return T();
0055 }
0056 
0057 class Buffer : public QObject, public QtWaylandServer::wl_buffer
0058 {
0059     Q_OBJECT
0060 public:
0061     explicit Buffer(wl_client *client, int id, int version)
0062         : QtWaylandServer::wl_buffer(client, id, version)
0063     {
0064     }
0065     virtual QSize size() const = 0;
0066     bool m_destroyed = false;
0067 
0068 protected:
0069     void buffer_destroy_resource(Resource *resource) override
0070     {
0071         Q_UNUSED(resource);
0072         m_destroyed = true;
0073         // The client side resource has been destroyed, but we keep this object because it may be
0074         // be used as a reference by e.g. surface for the currently committed buffer so it's not
0075         // yet safe to free it.
0076 
0077         // TODO: The memory should be freed by its factory
0078     }
0079     void buffer_destroy(Resource *resource) override
0080     {
0081         wl_resource_destroy(resource->handle);
0082     }
0083 };
0084 
0085 class Callback : public QObject, public QtWaylandServer::wl_callback
0086 {
0087     Q_OBJECT
0088 public:
0089     explicit Callback(wl_client *client, int id, int version = 1)
0090         : QtWaylandServer::wl_callback(client, id, version)
0091     {
0092     }
0093     ~Callback() override
0094     {
0095         if (!m_destroyed)
0096             wl_resource_destroy(resource()->handle);
0097     }
0098     void send_done(uint32_t data) = delete; // use state-tracking method below instead
0099     void sendDone(uint data)
0100     {
0101         Q_ASSERT(!m_done);
0102         QtWaylandServer::wl_callback::send_done(data);
0103         m_done = true;
0104     }
0105     void sendDoneAndDestroy(uint data)
0106     {
0107         sendDone(data);
0108         wl_resource_destroy(resource()->handle);
0109     }
0110     bool m_done = false;
0111     bool m_destroyed = false;
0112 
0113 protected:
0114     void callback_destroy_resource(Resource *resource) override
0115     {
0116         Q_UNUSED(resource);
0117         m_destroyed = true;
0118     }
0119 };
0120 
0121 class SurfaceRole : public QObject
0122 {
0123     Q_OBJECT
0124 };
0125 
0126 class Surface : public QObject, public QtWaylandServer::wl_surface
0127 {
0128     Q_OBJECT
0129 public:
0130     explicit Surface(WlCompositor *wlCompositor, wl_client *client, int id, int version)
0131         : QtWaylandServer::wl_surface(client, id, version)
0132         , m_wlCompositor(wlCompositor)
0133     {
0134     }
0135     ~Surface() override
0136     {
0137         qDeleteAll(m_commits);
0138     } // TODO: maybe make sure buffers are released?
0139     void sendFrameCallbacks();
0140     void sendEnter(Output *output);
0141     void send_enter(::wl_resource *output) = delete;
0142     void sendLeave(Output *output);
0143     void send_leave(::wl_resource *output) = delete;
0144 
0145     WlCompositor *m_wlCompositor;
0146     struct PerCommitData {
0147         Callback *frame = nullptr;
0148         QPoint attachOffset;
0149         bool attached = false;
0150     };
0151     struct DoubleBufferedState {
0152         PerCommitData commitSpecific;
0153         Buffer *buffer = nullptr;
0154         uint configureSerial = 0;
0155         int bufferScale = 1;
0156     } m_pending, m_committed;
0157     QList<DoubleBufferedState *> m_commits;
0158     QList<Callback *> m_waitingFrameCallbacks;
0159     QList<Output *> m_outputs;
0160     SurfaceRole *m_role = nullptr;
0161 
0162 signals:
0163     void attach(void *buffer, QPoint offset);
0164     void commit();
0165     void bufferCommitted();
0166 
0167 protected:
0168     void surface_destroy_resource(Resource *resource) override;
0169     void surface_destroy(Resource *resource) override
0170     {
0171         wl_resource_destroy(resource->handle);
0172     }
0173     void surface_attach(Resource *resource, wl_resource *buffer, int32_t x, int32_t y) override;
0174     void surface_set_buffer_scale(Resource *resource, int32_t scale) override;
0175     void surface_commit(Resource *resource) override;
0176     void surface_frame(Resource *resource, uint32_t callback) override;
0177 };
0178 
0179 class Region : public QtWaylandServer::wl_region
0180 {
0181 public:
0182     explicit Region(wl_client *client, int id, int version)
0183         : QtWaylandServer::wl_region(client, id, version)
0184     {
0185     }
0186 
0187     void region_destroy_resource(Resource *resource) override
0188     {
0189         Q_UNUSED(resource);
0190         delete this;
0191     }
0192 };
0193 
0194 class WlCompositor : public Global, public QtWaylandServer::wl_compositor
0195 {
0196     Q_OBJECT
0197 public:
0198     explicit WlCompositor(CoreCompositor *compositor, int version = 3)
0199         : QtWaylandServer::wl_compositor(compositor->m_display, version)
0200         , m_compositor(compositor)
0201     {
0202     }
0203     bool isClean() override;
0204     QString dirtyMessage() override;
0205     QList<Surface *> m_surfaces;
0206     CoreCompositor *m_compositor = nullptr;
0207 
0208 signals:
0209     void surfaceCreated(Surface *surface);
0210 
0211 protected:
0212     void compositor_create_surface(Resource *resource, uint32_t id) override
0213     {
0214         auto *surface = new Surface(this, resource->client(), id, resource->version());
0215         m_surfaces.append(surface);
0216         emit surfaceCreated(surface);
0217     }
0218 
0219     void compositor_create_region(Resource *resource, uint32_t id) override
0220     {
0221         new Region(resource->client(), id, resource->version());
0222     }
0223 };
0224 
0225 struct OutputMode {
0226     explicit OutputMode() = default;
0227     explicit OutputMode(const QSize &resolution, int refreshRate = 60000)
0228         : resolution(resolution)
0229         , refreshRate(refreshRate)
0230     {
0231     }
0232     QSize resolution = QSize(1920, 1080);
0233     int refreshRate = 60000; // In mHz
0234     // TODO: flags (they're currently hard-coded)
0235 
0236     // in mm
0237     QSize physicalSizeForDpi(int dpi)
0238     {
0239         return (QSizeF(resolution) * 25.4 / dpi).toSize();
0240     }
0241 };
0242 
0243 struct OutputData {
0244     using Subpixel = QtWaylandServer::wl_output::subpixel;
0245     using Transform = QtWaylandServer::wl_output::transform;
0246     explicit OutputData() = default;
0247 
0248     // for geometry event
0249     QPoint position;
0250     QSize physicalSize = QSize(0, 0); // means unknown physical size
0251     QString make = "Make";
0252     QString model = "Model";
0253     QString connector; // passing empty string will autogenerate
0254     Subpixel subpixel = Subpixel::subpixel_unknown;
0255     Transform transform = Transform::transform_normal;
0256 
0257     int scale = 1; // for scale event
0258     OutputMode mode; // for mode event
0259 };
0260 
0261 class Output : public Global, public QtWaylandServer::wl_output
0262 {
0263     Q_OBJECT
0264 public:
0265     explicit Output(CoreCompositor *compositor, OutputData data = OutputData())
0266         : QtWaylandServer::wl_output(compositor->m_display, 2)
0267         , m_data(std::move(data))
0268     {
0269     }
0270 
0271     void send_geometry() = delete;
0272     void sendGeometry();
0273     void sendGeometry(Resource *resource); // Sends to only one client
0274 
0275     void send_scale(int32_t factor) = delete;
0276     void sendScale(int factor);
0277     void sendScale(Resource *resource); // Sends current scale to only one client
0278 
0279     void sendDone(wl_client *client);
0280     void sendDone();
0281 
0282     int scale() const
0283     {
0284         return m_data.scale;
0285     }
0286 
0287     OutputData m_data;
0288 
0289 protected:
0290     void output_bind_resource(Resource *resource) override;
0291 };
0292 
0293 class Seat : public Global, public QtWaylandServer::wl_seat
0294 {
0295     Q_OBJECT
0296 public:
0297     explicit Seat(CoreCompositor *compositor,
0298                   uint capabilities = Seat::capability_pointer | Seat::capability_keyboard | Seat::capability_touch,
0299                   int version = 5);
0300     ~Seat() override;
0301     void send_capabilities(Resource *resource, uint capabilities) = delete; // Use wrapper instead
0302     void send_capabilities(uint capabilities) = delete; // Use wrapper instead
0303     void setCapabilities(uint capabilities);
0304 
0305     CoreCompositor *m_compositor = nullptr;
0306 
0307     Pointer *m_pointer = nullptr;
0308     QList<Pointer *> m_oldPointers;
0309 
0310     Touch *m_touch = nullptr;
0311     QList<Touch *> m_oldTouchs;
0312 
0313     Keyboard *m_keyboard = nullptr;
0314     QList<Keyboard *> m_oldKeyboards;
0315 
0316     uint m_capabilities = 0;
0317 
0318 protected:
0319     void seat_bind_resource(Resource *resource) override
0320     {
0321         wl_seat::send_capabilities(resource->handle, m_capabilities);
0322     }
0323 
0324     void seat_get_pointer(Resource *resource, uint32_t id) override;
0325     void seat_get_touch(Resource *resource, uint32_t id) override;
0326     void seat_get_keyboard(Resource *resource, uint32_t id) override;
0327 
0328     //    void seat_release(Resource *resource) override;
0329 };
0330 
0331 class Pointer : public QObject, public QtWaylandServer::wl_pointer
0332 {
0333     Q_OBJECT
0334 public:
0335     explicit Pointer(Seat *seat)
0336         : m_seat(seat)
0337     {
0338     }
0339     Surface *cursorSurface();
0340     CursorRole *m_cursorRole = nullptr; // TODO: cleanup
0341     void send_enter() = delete;
0342     uint sendEnter(Surface *surface, const QPointF &position);
0343     void send_leave() = delete;
0344     uint sendLeave(Surface *surface);
0345     void sendMotion(wl_client *client, const QPointF &position);
0346     uint sendButton(wl_client *client, uint button, uint state);
0347     void sendAxis(wl_client *client, axis axis, qreal value);
0348     void sendAxisDiscrete(wl_client *client, axis axis, int discrete);
0349     void sendAxisSource(wl_client *client, axis_source source);
0350     void sendAxisStop(wl_client *client, axis axis);
0351     void sendFrame(wl_client *client);
0352 
0353     Seat *m_seat = nullptr;
0354     QList<uint> m_enterSerials;
0355     QPoint m_hotspot;
0356 
0357 signals:
0358     void setCursor(uint serial); // TODO: add arguments?
0359 
0360 protected:
0361     void pointer_set_cursor(Resource *resource, uint32_t serial, ::wl_resource *surface, int32_t hotspot_x, int32_t hotspot_y) override;
0362     // TODO
0363 };
0364 
0365 class CursorRole : public SurfaceRole
0366 {
0367     Q_OBJECT
0368 public:
0369     explicit CursorRole(Surface *surface) // TODO: needs some more args
0370         : m_surface(surface)
0371     {
0372     }
0373     static CursorRole *fromSurface(Surface *surface)
0374     {
0375         return qobject_cast<CursorRole *>(surface->m_role);
0376     }
0377     Surface *m_surface = nullptr;
0378 };
0379 
0380 class Touch : public QObject, public QtWaylandServer::wl_touch
0381 {
0382     Q_OBJECT
0383 public:
0384     explicit Touch(Seat *seat)
0385         : m_seat(seat)
0386     {
0387     }
0388     uint sendDown(Surface *surface, const QPointF &position, int id);
0389     uint sendUp(wl_client *client, int id);
0390     void sendMotion(wl_client *client, const QPointF &position, int id);
0391     void sendFrame(wl_client *client);
0392 
0393     Seat *m_seat = nullptr;
0394 };
0395 
0396 class Keyboard : public QObject, public QtWaylandServer::wl_keyboard
0397 {
0398     Q_OBJECT
0399 public:
0400     explicit Keyboard(Seat *seat)
0401         : m_seat(seat)
0402     {
0403     }
0404     // TODO: Keymap event
0405     uint sendEnter(Surface *surface);
0406     uint sendLeave(Surface *surface);
0407     uint sendKey(wl_client *client, uint key, uint state);
0408     Seat *m_seat = nullptr;
0409     Surface *m_enteredSurface = nullptr;
0410 };
0411 
0412 class Shm : public Global, public QtWaylandServer::wl_shm
0413 {
0414     Q_OBJECT
0415 public:
0416     explicit Shm(CoreCompositor *compositor, QList<format> formats = {format_argb8888, format_xrgb8888, format_rgb888}, int version = 1);
0417     bool isClean() override;
0418     CoreCompositor *m_compositor = nullptr;
0419     QList<ShmPool *> m_pools;
0420     const QList<format> m_formats;
0421 
0422 protected:
0423     void shm_create_pool(Resource *resource, uint32_t id, int32_t fd, int32_t size) override;
0424     void shm_bind_resource(Resource *resource) override
0425     {
0426         for (auto format : std::as_const(m_formats))
0427             send_format(resource->handle, format);
0428     }
0429 };
0430 
0431 class ShmPool : QObject, public QtWaylandServer::wl_shm_pool
0432 {
0433     Q_OBJECT
0434 public:
0435     explicit ShmPool(Shm *shm, wl_client *client, int id, int version = 1);
0436     Shm *m_shm = nullptr;
0437     QList<ShmBuffer *> m_buffers;
0438 
0439 protected:
0440     void shm_pool_create_buffer(Resource *resource, uint32_t id, int32_t offset, int32_t width, int32_t height, int32_t stride, uint32_t format) override;
0441     void shm_pool_destroy_resource(Resource *resource) override;
0442     void shm_pool_destroy(Resource *resource) override
0443     {
0444         wl_resource_destroy(resource->handle);
0445     }
0446 };
0447 
0448 class ShmBuffer : public Buffer
0449 {
0450     Q_OBJECT
0451 public:
0452     static ShmBuffer *fromBuffer(Buffer *buffer)
0453     {
0454         return qobject_cast<ShmBuffer *>(buffer);
0455     }
0456     explicit ShmBuffer(int offset, const QSize &size, int stride, Shm::format format, wl_client *client, int id, int version = 1)
0457         : Buffer(client, id, version)
0458         , m_offset(offset)
0459         , m_size(size)
0460         , m_stride(stride)
0461         , m_format(format)
0462     {
0463     }
0464     QSize size() const override
0465     {
0466         return m_size;
0467     }
0468     const int m_offset;
0469     const QSize m_size;
0470     const int m_stride;
0471     const Shm::format m_format;
0472 };
0473 
0474 } // namespace MockCompositor