blob: d110768ec001395e74b1715b7243200772d3768e (
plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
|
// Copyright (C) 2018 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
#include "corecompositor.h"
#include <thread>
namespace MockCompositor {
CoreCompositor::CoreCompositor(CompositorType t, int socketFd)
: m_type(t)
, m_display(wl_display_create())
, m_eventLoop(wl_display_get_event_loop(m_display))
// Start dispatching
, m_dispatchThread([this](){
while (m_running) {
std::this_thread::sleep_for(std::chrono::milliseconds(20));
dispatch();
}
})
{
if (socketFd == -1) {
QByteArray socketName = wl_display_add_socket_auto(m_display);
qputenv("WAYLAND_DISPLAY", socketName);
} else {
wl_display_add_socket_fd(m_display, socketFd);
}
m_timer.start();
Q_ASSERT(isClean());
}
CoreCompositor::~CoreCompositor()
{
m_running = false;
m_dispatchThread.join();
wl_display_destroy_clients(m_display);
wl_display_destroy(m_display);
qDebug() << "cleanup";
}
bool CoreCompositor::isClean()
{
Lock lock(this);
for (auto *global : std::as_const(m_globals)) {
if (!global->isClean())
return false;
}
return true;
}
QString CoreCompositor::dirtyMessage()
{
Lock lock(this);
QStringList messages;
for (auto *global : std::as_const(m_globals)) {
if (!global->isClean())
messages << (global->metaObject()->className() % QLatin1String(": ") % global->dirtyMessage());
}
return messages.join(", ");
}
void CoreCompositor::dispatch(int timeout)
{
Lock lock(this);
wl_display_flush_clients(m_display);
wl_event_loop_dispatch(m_eventLoop, timeout);
}
/*!
* \brief Adds a new global interface for the compositor
*
* Takes ownership of \a global
*/
void CoreCompositor::add(Global *global)
{
warnIfNotLockedByThread(Q_FUNC_INFO);
m_globals.append(global);
}
void CoreCompositor::remove(Global *global)
{
warnIfNotLockedByThread(Q_FUNC_INFO);
m_globals.removeAll(global);
delete global;
}
uint CoreCompositor::nextSerial()
{
warnIfNotLockedByThread(Q_FUNC_INFO);
return wl_display_next_serial(m_display);
}
uint CoreCompositor::currentTimeMilliseconds()
{
warnIfNotLockedByThread(Q_FUNC_INFO);
return uint(m_timer.elapsed());
}
wl_client *CoreCompositor::client(int index)
{
warnIfNotLockedByThread(Q_FUNC_INFO);
wl_list *clients = wl_display_get_client_list(m_display);
wl_client *client = nullptr;
int i = 0;
wl_client_for_each(client, clients) {
if (i++ == index)
return client;
}
return nullptr;
}
void CoreCompositor::warnIfNotLockedByThread(const char *caller)
{
if (!m_lock || !m_lock->isOwnedByCurrentThread()) {
qWarning() << caller << "called without locking the compositor to the current thread."
<< "This means the compositor can start dispatching at any moment,"
<< "potentially leading to threading issues."
<< "Unless you know what you are doing you should probably fix the test"
<< "by locking the compositor before accessing it (see mutex()).";
}
}
} // namespace MockCompositor
|