8#include <QtCore/QObject>
9#include <QtCore/QCoreApplication>
10#include <QtCore/QAbstractEventDispatcher>
11#include <QtCore/QMutex>
12#include <QtCore/QDebug>
16Q_CONSTINIT
static QBasicMutex qAppExiting;
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
48 : m_connection(connection)
54 qAddPostRoutine([]() {
55 QMutexLocker locker(&qAppExiting);
61 m_head = m_flushedTail = qXcbEventNodeFactory(
nullptr);
62 m_tail.store(m_head, std::memory_order_release);
70 sendCloseConnectionEvent();
75 while (xcb_generic_event_t *event = takeFirst(QEventLoop::AllEvents))
78 if (m_head && m_head->fromHeap)
81 qCDebug(lcQpaEventReader) <<
"nodes on heap:" << m_nodesOnHeap;
95 bool excludeUserInputEvents = flags.testFlag(QEventLoop::ExcludeUserInputEvents);
96 if (excludeUserInputEvents) {
97 xcb_generic_event_t *event =
nullptr;
99 if (m_connection->isUserInputEvent(event)) {
100 m_inputEvents << event;
108 if (!m_inputEvents.isEmpty())
109 return m_inputEvents.takeFirst();
118 xcb_generic_event_t *event =
nullptr;
120 event = m_head->event;
121 if (m_head == m_flushedTail) {
124 m_head->event =
nullptr;
132 m_queueModified = m_peekerIndexCacheDirty =
true;
139 QXcbEventNode *node = m_head;
140 m_head = m_head->next;
144 m_nodesRestored.fetch_add(1, std::memory_order_release);
149 m_flushedTail = m_tail.load(std::memory_order_acquire);
152QXcbEventNode *
QXcbEventQueue::qXcbEventNodeFactory(xcb_generic_event_t *event)
154 static QXcbEventNode qXcbNodePool[
PoolSize];
156 if (m_freeNodes == 0)
157 m_freeNodes = m_nodesRestored.exchange(0, std::memory_order_acquire);
165 QXcbEventNode *node = &qXcbNodePool[m_poolIndex++];
167 node->next =
nullptr;
172 auto node =
new QXcbEventNode(event);
173 node->fromHeap =
true;
174 qCDebug(lcQpaEventReader) <<
"[heap] " << m_nodesOnHeap++;
180 xcb_generic_event_t *event =
nullptr;
181 xcb_connection_t *connection = m_connection->xcb_connection();
182 QXcbEventNode *tail = m_head;
184 auto enqueueEvent = [&tail,
this](xcb_generic_event_t *event) {
185 if (!isCloseConnectionEvent(event)) {
186 tail->next = qXcbEventNodeFactory(event);
188 m_tail.store(tail, std::memory_order_release);
194 while (!m_closeConnectionDetected && (event = xcb_wait_for_event(connection))) {
197 m_newEventsMutex.lock();
199 while (!m_closeConnectionDetected && (event = xcb_poll_for_queued_event(connection)))
202 m_newEventsCondition.wakeOne();
203 m_newEventsMutex.unlock();
207 if (!m_closeConnectionDetected) {
217 QMutexLocker locker(&qAppExiting);
218 if (!dispatcherOwnerDestructing) {
221 if (QCoreApplication::eventDispatcher())
222 QCoreApplication::eventDispatcher()->wakeUp();
228 const qint32 peekerId = m_peekerIdSource++;
229 m_peekerToNode.insert(peekerId,
nullptr);
235 const auto it = m_peekerToNode.constFind(peekerId);
236 if (it == m_peekerToNode.constEnd()) {
237 qCWarning(lcQpaXcb,
"failed to remove unknown peeker id: %d", peekerId);
240 m_peekerToNode.erase(it);
241 if (m_peekerToNode.isEmpty()) {
242 m_peekerIdSource = 0;
243 m_peekerIndexCacheDirty =
false;
249 PeekOptions option, qint32 peekerId)
251 const bool peekerIdProvided = peekerId != -1;
252 auto peekerToNodeIt = m_peekerToNode.find(peekerId);
254 if (peekerIdProvided && peekerToNodeIt == m_peekerToNode.end()) {
255 qCWarning(lcQpaXcb,
"failed to find index for unknown peeker id: %d", peekerId);
260 if (useCache && !peekerIdProvided) {
261 qCWarning(lcQpaXcb,
"PeekOption::PeekFromCachedIndex requires peeker id");
265 if (peekerIdProvided && m_peekerIndexCacheDirty) {
266 for (
auto &node : m_peekerToNode)
268 m_peekerIndexCacheDirty =
false;
275 const auto startNode = [
this, useCache, peekerToNodeIt]() -> QXcbEventNode * {
277 const QXcbEventNode *cachedNode = peekerToNodeIt.value();
280 if (cachedNode == m_flushedTail)
282 return cachedNode->next;
293 m_queueModified =
false;
296 QXcbEventNode *node = startNode;
298 xcb_generic_event_t *event = node->event;
299 if (event && peeker(event, peekerData)) {
303 if (node == m_flushedTail)
306 }
while (!m_queueModified);
310 if (peekerIdProvided && node != startNode && !m_queueModified) {
313 peekerToNodeIt = m_peekerToNode.find(peekerId);
314 if (peekerToNodeIt != m_peekerToNode.end())
315 *peekerToNodeIt = node;
324 QMutexLocker locker(&m_newEventsMutex);
326 if (sinceFlushedTail != m_flushedTail)
328 m_newEventsCondition.wait(&m_newEventsMutex, time);
334 xcb_client_message_event_t event;
335 memset(&event, 0,
sizeof(event));
337 xcb_connection_t *c = m_connection->xcb_connection();
338 const xcb_window_t window = xcb_generate_id(c);
339 xcb_screen_iterator_t it = xcb_setup_roots_iterator(m_connection->setup());
340 xcb_screen_t *screen = it.data;
341 xcb_create_window(c, XCB_COPY_FROM_PARENT,
342 window, screen->root,
343 0, 0, 1, 1, 0, XCB_WINDOW_CLASS_INPUT_ONLY,
344 screen->root_visual, 0,
nullptr);
346 event.response_type = XCB_CLIENT_MESSAGE;
349 event.window = window;
351 event.data.data32[0] = 0;
353 xcb_send_event(c,
false, window, XCB_EVENT_MASK_NO_EVENT,
reinterpret_cast<
const char *>(&event));
354 xcb_destroy_window(c, window);
358bool QXcbEventQueue::isCloseConnectionEvent(
const xcb_generic_event_t *event)
360 if (event && (event->response_type & ~0x80) == XCB_CLIENT_MESSAGE) {
361 auto clientMessage =
reinterpret_cast<
const xcb_client_message_event_t *>(event);
363 m_closeConnectionDetected =
true;
365 return m_closeConnectionDetected;
370#include "moc_qxcbeventqueue.cpp"
@ Atom_QT_CLOSE_CONNECTION
bool(*)(xcb_generic_event_t *event, void *peekerData) PeekerCallback
bool removePeekerId(qint32 peekerId)
qint32 generatePeekerId()
xcb_generic_event_t * takeFirst(QEventLoop::ProcessEventsFlags flags)
xcb_generic_event_t * takeFirst()
void flushBufferedEvents()
void waitForNewEvents(const QXcbEventNode *sinceFlushedTail, unsigned long time=(std::numeric_limits< unsigned long >::max)())
bool peekEventQueue(PeekerCallback peeker, void *peekerData=nullptr, PeekOptions option=PeekDefault, qint32 peekerId=-1)
static Q_CONSTINIT bool dispatcherOwnerDestructing