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