File indexing completed on 2024-09-22 05:02:00
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 <QtTest/QtTest> 0032 0033 #include <wayland-server-core.h> 0034 0035 struct wl_resource; 0036 0037 namespace MockCompositor 0038 { 0039 class Global : public QObject 0040 { 0041 Q_OBJECT 0042 public: 0043 virtual bool isClean() 0044 { 0045 return true; 0046 } 0047 virtual QString dirtyMessage() 0048 { 0049 return isClean() ? "clean" : "dirty"; 0050 } 0051 }; 0052 0053 class CoreCompositor 0054 { 0055 public: 0056 explicit CoreCompositor(); 0057 ~CoreCompositor(); 0058 bool isClean(); 0059 QString dirtyMessage(); 0060 void dispatch(); 0061 0062 template<typename function_type, typename... arg_types> 0063 auto exec(function_type func, arg_types &&...args) -> decltype(func()) 0064 { 0065 Lock lock(this); 0066 return func(std::forward<arg_types>(args)...); 0067 } 0068 0069 // Unsafe section below, YOU are responsible that the compositor is locked or 0070 // this is run through the mutex() method! 0071 0072 void add(Global *global); 0073 void remove(Global *global); 0074 0075 /*! 0076 * \brief Constructs and adds a new global with the given parameters 0077 * 0078 * Convenience function. i.e. 0079 * 0080 * compositor->add(new MyGlobal(compositor, version); 0081 * 0082 * can be written as: 0083 * 0084 * compositor->add<MyGlobal>(version); 0085 * 0086 * Returns the new global 0087 */ 0088 template<typename global_type, typename... arg_types> 0089 global_type *add(arg_types &&...args) 0090 { 0091 warnIfNotLockedByThread(Q_FUNC_INFO); 0092 auto *global = new global_type(this, std::forward<arg_types>(args)...); 0093 m_globals.append(global); 0094 return global; 0095 } 0096 0097 /*! 0098 * \brief Removes all globals of the given type 0099 * 0100 * Convenience function 0101 */ 0102 template<typename global_type, typename... arg_types> 0103 void removeAll() 0104 { 0105 const auto globals = getAll<global_type>(); 0106 for (auto global : globals) 0107 remove(global); 0108 } 0109 0110 /*! 0111 * \brief Returns a global with the given type, if any 0112 */ 0113 template<typename global_type> 0114 global_type *get() 0115 { 0116 warnIfNotLockedByThread(Q_FUNC_INFO); 0117 for (auto *global : std::as_const(m_globals)) { 0118 if (auto *casted = qobject_cast<global_type *>(global)) 0119 return casted; 0120 } 0121 return nullptr; 0122 } 0123 0124 /*! 0125 * \brief Returns the nth global with the given type, if any 0126 */ 0127 template<typename global_type> 0128 global_type *get(int index) 0129 { 0130 warnIfNotLockedByThread(Q_FUNC_INFO); 0131 for (auto *global : std::as_const(m_globals)) { 0132 if (auto *casted = qobject_cast<global_type *>(global)) { 0133 if (index--) 0134 continue; 0135 return casted; 0136 } 0137 } 0138 return nullptr; 0139 } 0140 0141 /*! 0142 * \brief Returns all globals with the given type, if any 0143 */ 0144 template<typename global_type> 0145 QList<global_type *> getAll() 0146 { 0147 warnIfNotLockedByThread(Q_FUNC_INFO); 0148 QList<global_type *> matching; 0149 for (auto *global : std::as_const(m_globals)) { 0150 if (auto *casted = qobject_cast<global_type *>(global)) 0151 matching.append(casted); 0152 } 0153 return matching; 0154 } 0155 0156 uint nextSerial(); 0157 uint currentTimeMilliseconds(); 0158 wl_client *client(int index = 0); 0159 void warnIfNotLockedByThread(const char *caller = "warnIfNotLockedbyThread"); 0160 0161 public: 0162 // Only use this carefully from the test thread (i.e. lock first) 0163 wl_display *m_display = nullptr; 0164 0165 protected: 0166 class Lock 0167 { 0168 public: 0169 explicit Lock(CoreCompositor *compositor) 0170 : m_compositor(compositor) 0171 , m_threadId(std::this_thread::get_id()) 0172 { 0173 // Can't use a QMutexLocker here, as it's not movable 0174 compositor->m_mutex.lock(); 0175 Q_ASSERT(compositor->m_lock == nullptr); 0176 compositor->m_lock = this; 0177 } 0178 ~Lock() 0179 { 0180 Q_ASSERT(m_compositor->m_lock == this); 0181 m_compositor->m_lock = nullptr; 0182 m_compositor->m_mutex.unlock(); 0183 } 0184 0185 // Move semantics 0186 Lock(Lock &&) = default; 0187 Lock &operator=(Lock &&) = default; 0188 0189 // Disable copying 0190 Lock(const Lock &) = delete; 0191 Lock &operator=(const Lock &) = delete; 0192 0193 bool isOwnedByCurrentThread() const 0194 { 0195 return m_threadId == std::this_thread::get_id(); 0196 } 0197 0198 private: 0199 CoreCompositor *m_compositor = nullptr; 0200 std::thread::id m_threadId; 0201 }; 0202 QByteArray m_socketName; 0203 wl_event_loop *m_eventLoop = nullptr; 0204 bool m_running = true; 0205 QList<Global *> m_globals; 0206 QElapsedTimer m_timer; 0207 0208 private: 0209 Lock *m_lock = nullptr; 0210 QMutex m_mutex; 0211 std::thread m_dispatchThread; 0212 }; 0213 0214 template<typename container_type> 0215 QByteArray toByteArray(container_type container) 0216 { 0217 return QByteArray(reinterpret_cast<const char *>(container.data()), sizeof(container[0]) * container.size()); 0218 } 0219 0220 template<typename return_type> 0221 return_type *fromResource(::wl_resource *resource) 0222 { 0223 if (auto *r = return_type::Resource::fromResource(resource)) 0224 return static_cast<return_type *>(r->object()); 0225 return nullptr; 0226 } 0227 0228 } // namespace MockCompositor