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 QtCore module of the Qt Toolkit.
7**
8** $QT_BEGIN_LICENSE:LGPL$
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 Lesser General Public License Usage
18** Alternatively, this file may be used under the terms of the GNU Lesser
19** General Public License version 3 as published by the Free Software
20** Foundation and appearing in the file LICENSE.LGPL3 included in the
21** packaging of this file. Please review the following information to
22** ensure the GNU Lesser General Public License version 3 requirements
23** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
24**
25** GNU General Public License Usage
26** Alternatively, this file may be used under the terms of the GNU
27** General Public License version 2.0 or (at your option) the GNU General
28** Public license version 3 or any later version approved by the KDE Free
29** Qt Foundation. The licenses are as published by the Free Software
30** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
31** included in the packaging of this file. Please review the following
32** information to ensure the GNU General Public License requirements will
33** be met: https://www.gnu.org/licenses/gpl-2.0.html and
34** https://www.gnu.org/licenses/gpl-3.0.html.
35**
36** $QT_END_LICENSE$
37**
38****************************************************************************/
39#include "qxcbeventdispatcher.h"
40#include "qxcbconnection.h"
41
42#include <QtCore/QCoreApplication>
43
44#include <qpa/qwindowsysteminterface.h>
45
46QT_BEGIN_NAMESPACE
47
48QXcbUnixEventDispatcher::QXcbUnixEventDispatcher(QXcbConnection *connection, QObject *parent)
49 : QEventDispatcherUNIX(parent)
50 , m_connection(connection)
51{
52}
53
54QXcbUnixEventDispatcher::~QXcbUnixEventDispatcher()
55{
56}
57
58bool QXcbUnixEventDispatcher::processEvents(QEventLoop::ProcessEventsFlags flags)
59{
60 const bool didSendEvents = QEventDispatcherUNIX::processEvents(flags);
61 m_connection->processXcbEvents(flags);
62 // The following line should not be necessary after QTBUG-70095
63 return QWindowSystemInterface::sendWindowSystemEvents(flags) || didSendEvents;
64}
65
66bool QXcbUnixEventDispatcher::hasPendingEvents()
67{
68 extern uint qGlobalPostedEventsCount();
69 return qGlobalPostedEventsCount() || QWindowSystemInterface::windowSystemEventsQueued();
70}
71
72void QXcbUnixEventDispatcher::flush()
73{
74 if (qApp)
75 qApp->sendPostedEvents();
76}
77
78#if QT_CONFIG(glib)
79struct XcbEventSource
80{
81 GSource source;
82 QXcbGlibEventDispatcher *dispatcher;
83 QXcbGlibEventDispatcherPrivate *dispatcher_p;
84 QXcbConnection *connection = nullptr;
85};
86
87static gboolean xcbSourcePrepare(GSource *source, gint *timeout)
88{
89 Q_UNUSED(timeout)
90 auto xcbEventSource = reinterpret_cast<XcbEventSource *>(source);
91 return xcbEventSource->dispatcher_p->wakeUpCalled;
92}
93
94static gboolean xcbSourceCheck(GSource *source)
95{
96 return xcbSourcePrepare(source, nullptr);
97}
98
99static gboolean xcbSourceDispatch(GSource *source, GSourceFunc, gpointer)
100{
101 auto xcbEventSource = reinterpret_cast<XcbEventSource *>(source);
102 QEventLoop::ProcessEventsFlags flags = xcbEventSource->dispatcher->flags();
103 xcbEventSource->connection->processXcbEvents(flags);
104 // The following line should not be necessary after QTBUG-70095
105 QWindowSystemInterface::sendWindowSystemEvents(flags);
106 return true;
107}
108
109QXcbGlibEventDispatcher::QXcbGlibEventDispatcher(QXcbConnection *connection, QObject *parent)
110 : QEventDispatcherGlib(*new QXcbGlibEventDispatcherPrivate(), parent)
111{
112 Q_D(QXcbGlibEventDispatcher);
113
114 m_xcbEventSourceFuncs.prepare = xcbSourcePrepare;
115 m_xcbEventSourceFuncs.check = xcbSourceCheck;
116 m_xcbEventSourceFuncs.dispatch = xcbSourceDispatch;
117 m_xcbEventSourceFuncs.finalize = nullptr;
118
119 m_xcbEventSource = reinterpret_cast<XcbEventSource *>(
120 g_source_new(&m_xcbEventSourceFuncs, sizeof(XcbEventSource)));
121
122 m_xcbEventSource->dispatcher = this;
123 m_xcbEventSource->dispatcher_p = d_func();
124 m_xcbEventSource->connection = connection;
125
126 g_source_set_can_recurse(&m_xcbEventSource->source, true);
127 g_source_attach(&m_xcbEventSource->source, d->mainContext);
128}
129
130QXcbGlibEventDispatcherPrivate::QXcbGlibEventDispatcherPrivate()
131{
132}
133
134QXcbGlibEventDispatcher::~QXcbGlibEventDispatcher()
135{
136 g_source_destroy(&m_xcbEventSource->source);
137 g_source_unref(&m_xcbEventSource->source);
138}
139
140bool QXcbGlibEventDispatcher::processEvents(QEventLoop::ProcessEventsFlags flags)
141{
142 m_flags = flags;
143 return QEventDispatcherGlib::processEvents(m_flags);
144}
145
146#endif // QT_CONFIG(glib)
147
148QAbstractEventDispatcher *QXcbEventDispatcher::createEventDispatcher(QXcbConnection *connection)
149{
150#if QT_CONFIG(glib)
151 if (qEnvironmentVariableIsEmpty("QT_NO_GLIB") && QEventDispatcherGlib::versionSupported()) {
152 qCDebug(lcQpaXcb, "using glib dispatcher");
153 return new QXcbGlibEventDispatcher(connection);
154 } else
155#endif
156 {
157 qCDebug(lcQpaXcb, "using unix dispatcher");
158 return new QXcbUnixEventDispatcher(connection);
159 }
160}
161
162QT_END_NAMESPACE
163