1/****************************************************************************
2**
3** Copyright (C) 2018 The Qt Company Ltd.
4** Contact: https://www.qt.io/licensing/
5**
6** This file is part of the test suite of the Qt Toolkit.
7**
8** $QT_BEGIN_LICENSE:GPL-EXCEPT$
9** Commercial License Usage
10** Licensees holding valid commercial Qt licenses may use this file in
11** accordance with the commercial license agreement provided with the
12** Software or, alternatively, in accordance with the terms contained in
13** a written agreement between you and The Qt Company. For licensing terms
14** and conditions see https://www.qt.io/terms-conditions. For further
15** information use the contact form at https://www.qt.io/contact-us.
16**
17** GNU General Public License Usage
18** Alternatively, this file may be used under the terms of the GNU
19** General Public License version 3 as published by the Free Software
20** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
21** included in the packaging of this file. Please review the following
22** information to ensure the GNU General Public License requirements will
23** be met: https://www.gnu.org/licenses/gpl-3.0.html.
24**
25** $QT_END_LICENSE$
26**
27****************************************************************************/
28
29#ifndef MOCKCOMPOSITOR_CORECOMPOSITOR_H
30#define MOCKCOMPOSITOR_CORECOMPOSITOR_H
31
32#include <QtTest/QtTest>
33
34#include <wayland-server-core.h>
35
36struct wl_resource;
37
38namespace MockCompositor {
39
40class Global : public QObject
41{
42 Q_OBJECT
43public:
44 virtual bool isClean() { return true; }
45 virtual QString dirtyMessage() { return isClean() ? "clean" : "dirty"; }
46};
47
48class CoreCompositor
49{
50public:
51 explicit CoreCompositor();
52 ~CoreCompositor();
53 bool isClean();
54 QString dirtyMessage();
55 void dispatch();
56
57 template<typename function_type, typename... arg_types>
58 auto exec(function_type func, arg_types&&... args) -> decltype(func())
59 {
60 Lock lock(this);
61 return func(std::forward<arg_types>(args)...);
62 }
63
64 template<typename function_type, typename... arg_types>
65 auto call(function_type func, arg_types&&... args) -> decltype(func())
66 {
67 Lock lock(this);
68 auto boundFunc = std::bind(func, this);
69 return boundFunc(this, std::forward<arg_types>(args)...);
70 }
71
72 // Unsafe section below, YOU are responsible that the compositor is locked or
73 // this is run through the mutex() method!
74
75 void add(Global *global);
76 void remove(Global *global);
77
78 /*!
79 * \brief Constructs and adds a new global with the given parameters
80 *
81 * Convenience function. i.e.
82 *
83 * compositor->add(new MyGlobal(compositor, version);
84 *
85 * can be written as:
86 *
87 * compositor->add<MyGlobal>(version);
88 *
89 * Returns the new global
90 */
91 template<typename global_type, typename... arg_types>
92 global_type *add(arg_types&&... args)
93 {
94 warnIfNotLockedByThread(Q_FUNC_INFO);
95 auto *global = new global_type(this, std::forward<arg_types>(args)...);
96 m_globals.append(global);
97 return global;
98 }
99
100 /*!
101 * \brief Removes all globals of the given type
102 *
103 * Convenience function
104 */
105 template<typename global_type, typename... arg_types>
106 void removeAll()
107 {
108 const auto globals = getAll<global_type>();
109 for (auto global : globals)
110 remove(global);
111 }
112
113 /*!
114 * \brief Returns a global with the given type, if any
115 */
116 template<typename global_type>
117 global_type *get()
118 {
119 warnIfNotLockedByThread(Q_FUNC_INFO);
120 for (auto *global : qAsConst(t&: m_globals)) {
121 if (auto *casted = qobject_cast<global_type *>(global))
122 return casted;
123 }
124 return nullptr;
125 }
126
127 /*!
128 * \brief Returns the nth global with the given type, if any
129 */
130 template<typename global_type>
131 global_type *get(int index)
132 {
133 warnIfNotLockedByThread(Q_FUNC_INFO);
134 for (auto *global : qAsConst(t&: m_globals)) {
135 if (auto *casted = qobject_cast<global_type *>(global)) {
136 if (index--)
137 continue;
138 return casted;
139 }
140 }
141 return nullptr;
142 }
143
144 /*!
145 * \brief Returns all globals with the given type, if any
146 */
147 template<typename global_type>
148 QVector<global_type *> getAll()
149 {
150 warnIfNotLockedByThread(Q_FUNC_INFO);
151 QVector<global_type *> matching;
152 for (auto *global : qAsConst(t&: m_globals)) {
153 if (auto *casted = qobject_cast<global_type *>(global))
154 matching.append(casted);
155 }
156 return matching;
157 }
158
159 uint nextSerial();
160 uint currentTimeMilliseconds();
161 wl_client *client(int index = 0);
162 void warnIfNotLockedByThread(const char* caller = "warnIfNotLockedbyThread");
163
164public:
165 // Only use this carefully from the test thread (i.e. lock first)
166 wl_display *m_display = nullptr;
167protected:
168 class Lock {
169 public:
170 explicit Lock(CoreCompositor *compositor)
171 : m_compositor(compositor)
172 , m_threadId(std::this_thread::get_id())
173 {
174 // Can't use a QMutexLocker here, as it's not movable
175 compositor->m_mutex.lock();
176 Q_ASSERT(compositor->m_lock == nullptr);
177 compositor->m_lock = this;
178 }
179 ~Lock()
180 {
181 Q_ASSERT(m_compositor->m_lock == this);
182 m_compositor->m_lock = nullptr;
183 m_compositor->m_mutex.unlock();
184 }
185
186 // Move semantics
187 Lock(Lock &&) = default;
188 Lock &operator=(Lock &&) = default;
189
190 // Disable copying
191 Lock(const Lock &) = delete;
192 Lock &operator=(const Lock &) = delete;
193
194 bool isOwnedByCurrentThread() const { return m_threadId == std::this_thread::get_id(); }
195 private:
196 CoreCompositor *m_compositor = nullptr;
197 std::thread::id m_threadId;
198 };
199 QByteArray m_socketName;
200 wl_event_loop *m_eventLoop = nullptr;
201 bool m_running = true;
202 QVector<Global *> m_globals;
203 QElapsedTimer m_timer;
204
205private:
206 Lock *m_lock = nullptr;
207 QMutex m_mutex;
208 std::thread m_dispatchThread;
209};
210
211template<typename container_type>
212QByteArray toByteArray(container_type container)
213{
214 return QByteArray(reinterpret_cast<const char *>(container.data()), sizeof (container[0]) * container.size());
215}
216
217template<typename return_type>
218return_type *fromResource(::wl_resource *resource) {
219 if (auto *r = return_type::Resource::fromResource(resource))
220 return static_cast<return_type *>(r->object());
221 return nullptr;
222}
223
224} // namespace MockCompositor
225
226#endif // MOCKCOMPOSITOR_CORECOMPOSITOR_H
227

source code of qtwayland/tests/auto/client/shared/corecompositor.h