6#include <QtCore/QObject>
7#include <QtCore/QCoreApplication>
8#include <QtCore/QAbstractEventDispatcher>
9#include <QtCore/QMutex>
10#include <QtCore/QDebug>
59 m_head = m_flushedTail = qXcbEventNodeFactory(
nullptr);
60 m_tail.store(m_head, std::memory_order_release);
68 sendCloseConnectionEvent();
79 qCDebug(lcQpaEventReader) <<
"nodes on heap:" << m_nodesOnHeap;
94 if (excludeUserInputEvents) {
95 xcb_generic_event_t *
event =
nullptr;
98 m_inputEvents <<
event;
116 xcb_generic_event_t *
event =
nullptr;
118 event = m_head->
event;
119 if (m_head == m_flushedTail) {
122 m_head->
event =
nullptr;
130 m_queueModified = m_peekerIndexCacheDirty =
true;
135void QXcbEventQueue::dequeueNode()
138 m_head = m_head->
next;
142 m_nodesRestored.fetch_add(1, std::memory_order_release);
147 m_flushedTail = m_tail.load(std::memory_order_acquire);
154 if (m_freeNodes == 0)
155 m_freeNodes = m_nodesRestored.exchange(0, std::memory_order_acquire);
165 node->
next =
nullptr;
172 qCDebug(lcQpaEventReader) <<
"[heap] " << m_nodesOnHeap++;
178 xcb_generic_event_t *
event =
nullptr;
182 auto enqueueEvent = [&tail,
this](xcb_generic_event_t *
event) {
183 if (!isCloseConnectionEvent(
event)) {
184 tail->
next = qXcbEventNodeFactory(
event);
186 m_tail.store(tail, std::memory_order_release);
192 while (!m_closeConnectionDetected && (
event = xcb_wait_for_event(
connection))) {
195 m_newEventsMutex.
lock();
197 while (!m_closeConnectionDetected && (
event = xcb_poll_for_queued_event(
connection)))
200 m_newEventsCondition.
wakeOne();
201 m_newEventsMutex.
unlock();
205 if (!m_closeConnectionDetected) {
226 const qint32 peekerId = m_peekerIdSource++;
227 m_peekerToNode.
insert(peekerId,
nullptr);
233 const auto it = m_peekerToNode.
constFind(peekerId);
235 qCWarning(lcQpaXcb,
"failed to remove unknown peeker id: %d", peekerId);
239 if (m_peekerToNode.
isEmpty()) {
240 m_peekerIdSource = 0;
241 m_peekerIndexCacheDirty =
false;
249 const bool peekerIdProvided = peekerId != -1;
250 auto peekerToNodeIt = m_peekerToNode.
find(peekerId);
252 if (peekerIdProvided && peekerToNodeIt == m_peekerToNode.
end()) {
253 qCWarning(lcQpaXcb,
"failed to find index for unknown peeker id: %d", peekerId);
258 if (useCache && !peekerIdProvided) {
259 qCWarning(lcQpaXcb,
"PeekOption::PeekFromCachedIndex requires peeker id");
263 if (peekerIdProvided && m_peekerIndexCacheDirty) {
264 for (
auto &node : m_peekerToNode)
266 m_peekerIndexCacheDirty =
false;
273 const auto startNode = [
this, useCache, peekerToNodeIt]() ->
QXcbEventNode * {
278 if (cachedNode == m_flushedTail)
280 return cachedNode->
next;
291 m_queueModified =
false;
296 xcb_generic_event_t *
event = node->
event;
301 if (node == m_flushedTail)
304 }
while (!m_queueModified);
308 if (peekerIdProvided && node != startNode && !m_queueModified) {
311 peekerToNodeIt = m_peekerToNode.
find(peekerId);
312 if (peekerToNodeIt != m_peekerToNode.
end())
313 *peekerToNodeIt = node;
324 if (sinceFlushedTail != m_flushedTail)
326 m_newEventsCondition.
wait(&m_newEventsMutex,
time);
329void QXcbEventQueue::sendCloseConnectionEvent()
const
332 xcb_client_message_event_t
event;
336 const xcb_window_t
window = xcb_generate_id(
c);
337 xcb_screen_iterator_t
it = xcb_setup_roots_iterator(m_connection->
setup());
339 xcb_create_window(
c, XCB_COPY_FROM_PARENT,
341 0, 0, 1, 1, 0, XCB_WINDOW_CLASS_INPUT_ONLY,
342 screen->root_visual, 0,
nullptr);
344 event.response_type = XCB_CLIENT_MESSAGE;
349 event.data.data32[0] = 0;
351 xcb_send_event(
c,
false,
window, XCB_EVENT_MASK_NO_EVENT,
reinterpret_cast<const char *
>(&
event));
356bool QXcbEventQueue::isCloseConnectionEvent(
const xcb_generic_event_t *
event)
358 if (
event && (
event->response_type & ~0x80) == XCB_CLIENT_MESSAGE) {
359 auto clientMessage =
reinterpret_cast<const xcb_client_message_event_t *
>(
event);
361 m_closeConnectionDetected =
true;
363 return m_closeConnectionDetected;
368#include "moc_qxcbeventqueue.cpp"
virtual void wakeUp()=0
\threadsafe
static QAbstractEventDispatcher * eventDispatcher()
Returns a pointer to the event dispatcher object for the main thread.
const_iterator constFind(const Key &key) const noexcept
const_iterator constEnd() const noexcept
Returns a const \l{STL-style iterators}{STL-style iterator} pointing to the imaginary item after the ...
iterator find(const Key &key)
Returns an iterator pointing to the item with the key in the hash.
iterator erase(const_iterator it)
iterator end() noexcept
Returns an \l{STL-style iterators}{STL-style iterator} pointing to the imaginary item after the last ...
bool isEmpty() const noexcept
Returns true if the hash contains no items; otherwise returns false.
iterator insert(const Key &key, const T &value)
Inserts a new item with the key and a value of value.
bool isEmpty() const noexcept
void unlock() noexcept
Unlocks the mutex.
void lock() noexcept
Locks the mutex.
void start(Priority=InheritPriority)
bool wait(QDeadlineTimer deadline=QDeadlineTimer(QDeadlineTimer::Forever))
bool wait(QMutex *, QDeadlineTimer=QDeadlineTimer(QDeadlineTimer::Forever))
@ Atom_QT_CLOSE_CONNECTION
xcb_connection_t * xcb_connection() const
const xcb_setup_t * setup() const
xcb_atom_t atom(QXcbAtom::Atom qatom) const
bool isUserInputEvent(xcb_generic_event_t *event) const
bool(*)(xcb_generic_event_t *event, void *peekerData) PeekerCallback
bool removePeekerId(qint32 peekerId)
qint32 generatePeekerId()
QXcbEventQueue(QXcbConnection *connection)
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)
QSet< QString >::iterator it
Combined button and popup list for selecting options.
void qAddPostRoutine(QtCleanUpFunction p)
DBusConnection * connection
#define qCWarning(category,...)
#define qCDebug(category,...)
static Q_CONSTINIT bool dispatcherOwnerDestructing
QT_BEGIN_NAMESPACE static Q_CONSTINIT QBasicMutex qAppExiting
xcb_generic_event_t * event