Qt 6.x
The Qt SDK
Loading...
Searching...
No Matches
qeventdispatcher_glib.cpp
Go to the documentation of this file.
1// Copyright (C) 2016 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3
6
7#include <private/qthread_p.h>
8
9#include "qcoreapplication.h"
10#include "qsocketnotifier.h"
11
12#include <QtCore/qlist.h>
13#include <QtCore/qpair.h>
14
15#include <glib.h>
16
18
20{
21 GPollFD pollfd;
23};
24
26{
27 GSource source;
30};
31
32static gboolean socketNotifierSourcePrepare(GSource *, gint *timeout)
33{
34 if (timeout)
35 *timeout = -1;
36 return false;
37}
38
39static gboolean socketNotifierSourceCheck(GSource *source)
40{
42
43 bool pending = false;
44 for (int i = 0; !pending && i < src->pollfds.size(); ++i) {
45 GPollFDWithQSocketNotifier *p = src->pollfds.at(i);
46
47 if (p->pollfd.revents & G_IO_NVAL) {
48 // disable the invalid socket notifier
49 const char * const t[] = { "Read", "Write", "Exception" };
50 qWarning("QSocketNotifier: Invalid socket %d and type '%s', disabling...",
51 p->pollfd.fd, t[int(p->socketNotifier->type())]);
52 // ### note, modifies src->pollfds!
53 p->socketNotifier->setEnabled(false);
54 i--;
55 } else {
56 pending = pending || ((p->pollfd.revents & p->pollfd.events) != 0);
57 }
58 }
59
60 return pending;
61}
62
63static gboolean socketNotifierSourceDispatch(GSource *source, GSourceFunc, gpointer)
64{
66
68 for (src->activeNotifierPos = 0; src->activeNotifierPos < src->pollfds.size();
69 ++src->activeNotifierPos) {
70 GPollFDWithQSocketNotifier *p = src->pollfds.at(src->activeNotifierPos);
71
72 if ((p->pollfd.revents & p->pollfd.events) != 0)
73 QCoreApplication::sendEvent(p->socketNotifier, &event);
74 }
75
76 return true; // ??? don't remove, right?
77}
78
79Q_CONSTINIT static GSourceFuncs socketNotifierSourceFuncs = {
83 nullptr,
84 nullptr,
85 nullptr
86};
87
89{
90 GSource source;
92 QEventLoop::ProcessEventsFlags processEventsFlags;
94};
95
97{
98 timespec tv = { 0l, 0l };
99 if (!(src->processEventsFlags & QEventLoop::X11ExcludeTimers) && src->timerList.timerWait(tv))
100 *timeout = (tv.tv_sec * 1000) + ((tv.tv_nsec + 999999) / 1000 / 1000);
101 else
102 *timeout = -1;
103
104 return (*timeout == 0);
105}
106
108{
109 if (src->timerList.isEmpty()
110 || (src->processEventsFlags & QEventLoop::X11ExcludeTimers))
111 return false;
112
113 return !src->timerList.hasPendingTimers();
114}
115
116static gboolean timerSourcePrepare(GSource *source, gint *timeout)
117{
118 gint dummy;
119 if (!timeout)
120 timeout = &dummy;
121
122 GTimerSource *src = reinterpret_cast<GTimerSource *>(source);
123 if (src->runWithIdlePriority) {
124 if (timeout)
125 *timeout = -1;
126 return false;
127 }
128
130}
131
132static gboolean timerSourceCheck(GSource *source)
133{
134 GTimerSource *src = reinterpret_cast<GTimerSource *>(source);
135 if (src->runWithIdlePriority)
136 return false;
138}
139
140static gboolean timerSourceDispatch(GSource *source, GSourceFunc, gpointer)
141{
142 GTimerSource *timerSource = reinterpret_cast<GTimerSource *>(source);
144 return true;
145 timerSource->runWithIdlePriority = true;
146 (void) timerSource->timerList.activateTimers();
147 return true; // ??? don't remove, right again?
148}
149
150Q_CONSTINIT static GSourceFuncs timerSourceFuncs = {
154 nullptr,
155 nullptr,
156 nullptr
157};
158
160{
161 GSource source;
163};
164
165static gboolean idleTimerSourcePrepare(GSource *source, gint *timeout)
166{
167 GIdleTimerSource *idleTimerSource = reinterpret_cast<GIdleTimerSource *>(source);
168 GTimerSource *timerSource = idleTimerSource->timerSource;
169 if (!timerSource->runWithIdlePriority) {
170 // Yield to the normal priority timer source
171 if (timeout)
172 *timeout = -1;
173 return false;
174 }
175
176 return timerSourcePrepareHelper(timerSource, timeout);
177}
178
179static gboolean idleTimerSourceCheck(GSource *source)
180{
181 GIdleTimerSource *idleTimerSource = reinterpret_cast<GIdleTimerSource *>(source);
182 GTimerSource *timerSource = idleTimerSource->timerSource;
183 if (!timerSource->runWithIdlePriority) {
184 // Yield to the normal priority timer source
185 return false;
186 }
187 return timerSourceCheckHelper(timerSource);
188}
189
190static gboolean idleTimerSourceDispatch(GSource *source, GSourceFunc, gpointer)
191{
192 GTimerSource *timerSource = reinterpret_cast<GIdleTimerSource *>(source)->timerSource;
193 (void) timerSourceDispatch(&timerSource->source, nullptr, nullptr);
194 return true;
195}
196
197Q_CONSTINIT static GSourceFuncs idleTimerSourceFuncs = {
201 nullptr,
202 nullptr,
203 nullptr
204};
205
207{
208 GSource source;
212};
213
214static gboolean postEventSourcePrepare(GSource *s, gint *timeout)
215{
217 if (!data)
218 return false;
219
220 gint dummy;
221 if (!timeout)
222 timeout = &dummy;
223 const bool canWait = data->canWaitLocked();
224 *timeout = canWait ? -1 : 0;
225
226 GPostEventSource *source = reinterpret_cast<GPostEventSource *>(s);
227 source->d->wakeUpCalled = source->serialNumber.loadRelaxed() != source->lastSerialNumber;
228 return !canWait || source->d->wakeUpCalled;
229}
230
231static gboolean postEventSourceCheck(GSource *source)
232{
233 return postEventSourcePrepare(source, nullptr);
234}
235
236static gboolean postEventSourceDispatch(GSource *s, GSourceFunc, gpointer)
237{
238 GPostEventSource *source = reinterpret_cast<GPostEventSource *>(s);
239 source->lastSerialNumber = source->serialNumber.loadRelaxed();
241 source->d->runTimersOnceWithNormalPriority();
242 return true; // i dunno, george...
243}
244
245Q_CONSTINIT static GSourceFuncs postEventSourceFuncs = {
249 nullptr,
250 nullptr,
251 nullptr
252};
253
254
256 : mainContext(context)
257{
258#if GLIB_MAJOR_VERSION == 2 && GLIB_MINOR_VERSION < 32
259 if (qEnvironmentVariableIsEmpty("QT_NO_THREADED_GLIB")) {
260 Q_CONSTINIT static QBasicMutex mutex;
261 QMutexLocker locker(&mutex);
262 if (!g_thread_supported())
263 g_thread_init(NULL);
264 }
265#endif
266
267 if (mainContext) {
268 g_main_context_ref(mainContext);
269 } else {
271 if (app && QThread::currentThread() == app->thread()) {
272 mainContext = g_main_context_default();
273 g_main_context_ref(mainContext);
274 } else {
275 mainContext = g_main_context_new();
276 }
277 }
278
279#if GLIB_CHECK_VERSION (2, 22, 0)
280 g_main_context_push_thread_default (mainContext);
281#endif
282
283 // setup post event source
284 GSource *source = g_source_new(&postEventSourceFuncs, sizeof(GPostEventSource));
285 g_source_set_name(source, "[Qt] GPostEventSource");
286 postEventSource = reinterpret_cast<GPostEventSource *>(source);
287
289 postEventSource->d = this;
290 g_source_set_can_recurse(&postEventSource->source, true);
291 g_source_attach(&postEventSource->source, mainContext);
292
293 // setup socketNotifierSource
295 g_source_set_name(source, "[Qt] GSocketNotifierSource");
298 g_source_set_can_recurse(&socketNotifierSource->source, true);
299 g_source_attach(&socketNotifierSource->source, mainContext);
300
301 // setup normal and idle timer sources
302 source = g_source_new(&timerSourceFuncs, sizeof(GTimerSource));
303 g_source_set_name(source, "[Qt] GTimerSource");
304 timerSource = reinterpret_cast<GTimerSource *>(source);
308 g_source_set_can_recurse(&timerSource->source, true);
309 g_source_attach(&timerSource->source, mainContext);
310
311 source = g_source_new(&idleTimerSourceFuncs, sizeof(GIdleTimerSource));
312 g_source_set_name(source, "[Qt] GIdleTimerSource");
313 idleTimerSource = reinterpret_cast<GIdleTimerSource *>(source);
315 g_source_set_can_recurse(&idleTimerSource->source, true);
316 g_source_attach(&idleTimerSource->source, mainContext);
317}
318
320{
322}
323
326{
327}
328
331{ }
332
334{
336
337 // destroy all timer sources
338 qDeleteAll(d->timerSource->timerList);
339 d->timerSource->timerList.~QTimerInfoList();
340 g_source_destroy(&d->timerSource->source);
341 g_source_unref(&d->timerSource->source);
342 d->timerSource = nullptr;
343 g_source_destroy(&d->idleTimerSource->source);
344 g_source_unref(&d->idleTimerSource->source);
345 d->idleTimerSource = nullptr;
346
347 // destroy socket notifier source
348 for (int i = 0; i < d->socketNotifierSource->pollfds.size(); ++i) {
349 GPollFDWithQSocketNotifier *p = d->socketNotifierSource->pollfds[i];
350 g_source_remove_poll(&d->socketNotifierSource->source, &p->pollfd);
351 delete p;
352 }
353 d->socketNotifierSource->pollfds.~QList<GPollFDWithQSocketNotifier *>();
354 g_source_destroy(&d->socketNotifierSource->source);
355 g_source_unref(&d->socketNotifierSource->source);
356 d->socketNotifierSource = nullptr;
357
358 // destroy post event source
359 g_source_destroy(&d->postEventSource->source);
360 g_source_unref(&d->postEventSource->source);
361 d->postEventSource = nullptr;
362
363 Q_ASSERT(d->mainContext != nullptr);
364#if GLIB_CHECK_VERSION (2, 22, 0)
365 g_main_context_pop_thread_default (d->mainContext);
366#endif
367 g_main_context_unref(d->mainContext);
368 d->mainContext = nullptr;
369}
370
371bool QEventDispatcherGlib::processEvents(QEventLoop::ProcessEventsFlags flags)
372{
374
375 const bool canWait = flags.testAnyFlag(QEventLoop::WaitForMoreEvents);
376 if (canWait)
378 else
379 emit awake();
380
381 // tell postEventSourcePrepare() and timerSource about any new flags
382 QEventLoop::ProcessEventsFlags savedFlags = d->timerSource->processEventsFlags;
383 d->timerSource->processEventsFlags = flags;
384
386 // force timers to be sent at normal priority
387 d->timerSource->runWithIdlePriority = false;
388 }
389
390 bool result = g_main_context_iteration(d->mainContext, canWait);
391 while (!result && canWait)
392 result = g_main_context_iteration(d->mainContext, canWait);
393
394 d->timerSource->processEventsFlags = savedFlags;
395
396 if (canWait)
397 emit awake();
398
399 return result;
400}
401
403{
405 int sockfd = int(notifier->socket());
406 int type = notifier->type();
407#ifndef QT_NO_DEBUG
408 if (sockfd < 0) {
409 qWarning("QSocketNotifier: Internal error");
410 return;
411 } else if (notifier->thread() != thread()
412 || thread() != QThread::currentThread()) {
413 qWarning("QSocketNotifier: socket notifiers cannot be enabled from another thread");
414 return;
415 }
416#endif
417
419
420
422 p->pollfd.fd = sockfd;
423 switch (type) {
425 p->pollfd.events = G_IO_IN | G_IO_HUP | G_IO_ERR;
426 break;
428 p->pollfd.events = G_IO_OUT | G_IO_ERR;
429 break;
431 p->pollfd.events = G_IO_PRI | G_IO_ERR;
432 break;
433 }
434 p->socketNotifier = notifier;
435
436 d->socketNotifierSource->pollfds.append(p);
437
438 g_source_add_poll(&d->socketNotifierSource->source, &p->pollfd);
439}
440
442{
444#ifndef QT_NO_DEBUG
445 if (notifier->socket() < 0) {
446 qWarning("QSocketNotifier: Internal error");
447 return;
448 } else if (notifier->thread() != thread()
449 || thread() != QThread::currentThread()) {
450 qWarning("QSocketNotifier: socket notifiers cannot be disabled from another thread");
451 return;
452 }
453#endif
454
456
457 for (int i = 0; i < d->socketNotifierSource->pollfds.size(); ++i) {
458 GPollFDWithQSocketNotifier *p = d->socketNotifierSource->pollfds.at(i);
459 if (p->socketNotifier == notifier) {
460 // found it
461 g_source_remove_poll(&d->socketNotifierSource->source, &p->pollfd);
462
463 d->socketNotifierSource->pollfds.removeAt(i);
464 delete p;
465
466 // Keep a position in the list for the next item.
467 if (i <= d->socketNotifierSource->activeNotifierPos)
468 --d->socketNotifierSource->activeNotifierPos;
469
470 return;
471 }
472 }
473}
474
475void QEventDispatcherGlib::registerTimer(int timerId, qint64 interval, Qt::TimerType timerType, QObject *object)
476{
477#ifndef QT_NO_DEBUG
478 if (timerId < 1 || interval < 0 || !object) {
479 qWarning("QEventDispatcherGlib::registerTimer: invalid arguments");
480 return;
481 } else if (object->thread() != thread() || thread() != QThread::currentThread()) {
482 qWarning("QEventDispatcherGlib::registerTimer: timers cannot be started from another thread");
483 return;
484 }
485#endif
486
488 d->timerSource->timerList.registerTimer(timerId, std::chrono::milliseconds{ interval },
489 timerType, object);
490}
491
493{
494#ifndef QT_NO_DEBUG
495 if (timerId < 1) {
496 qWarning("QEventDispatcherGlib::unregisterTimer: invalid argument");
497 return false;
498 } else if (thread() != QThread::currentThread()) {
499 qWarning("QEventDispatcherGlib::unregisterTimer: timers cannot be stopped from another thread");
500 return false;
501 }
502#endif
503
505 return d->timerSource->timerList.unregisterTimer(timerId);
506}
507
509{
510#ifndef QT_NO_DEBUG
511 if (!object) {
512 qWarning("QEventDispatcherGlib::unregisterTimers: invalid argument");
513 return false;
514 } else if (object->thread() != thread() || thread() != QThread::currentThread()) {
515 qWarning("QEventDispatcherGlib::unregisterTimers: timers cannot be stopped from another thread");
516 return false;
517 }
518#endif
519
521 return d->timerSource->timerList.unregisterTimers(object);
522}
523
525{
526 if (!object) {
527 qWarning("QEventDispatcherUNIX:registeredTimers: invalid argument");
528 return QList<TimerInfo>();
529 }
530
531 Q_D(const QEventDispatcherGlib);
532 return d->timerSource->timerList.registeredTimers(object);
533}
534
536{
537#ifndef QT_NO_DEBUG
538 if (timerId < 1) {
539 qWarning("QEventDispatcherGlib::remainingTimeTime: invalid argument");
540 return -1;
541 }
542#endif
543
545 return d->timerSource->timerList.timerRemainingTime(timerId);
546}
547
549{
550 wakeUp();
551}
552
554{
556 d->postEventSource->serialNumber.ref();
557 g_main_context_wakeup(d->mainContext);
558}
559
561{
562#if !defined(GLIB_MAJOR_VERSION) || !defined(GLIB_MINOR_VERSION) || !defined(GLIB_MICRO_VERSION)
563 return false;
564#else
565 return ((GLIB_MAJOR_VERSION << 16) + (GLIB_MINOR_VERSION << 8) + GLIB_MICRO_VERSION) >= 0x020301;
566#endif
567}
568
571{
572}
573
575
576#include "moc_qeventdispatcher_glib_p.cpp"
DarwinBluetooth::LECBManagerNotifier * notifier
void aboutToBlock()
This signal is emitted before the event loop calls a function that could block.
void awake()
This signal is emitted after the event loop returns from a function that could block.
\inmodule QtCore
Definition qatomic.h:112
void storeRelaxed(T newValue) noexcept
\inmodule QtCore
static bool sendEvent(QObject *receiver, QEvent *event)
Sends event event directly to receiver receiver, using the notify() function.
static QCoreApplication * instance() noexcept
Returns a pointer to the application's QCoreApplication (or QGuiApplication/QApplication) instance.
static void sendPostedEvents(QObject *receiver=nullptr, int event_type=0)
Immediately dispatches all events which have been previously queued with QCoreApplication::postEvent(...
GSocketNotifierSource * socketNotifierSource
QEventDispatcherGlibPrivate(GMainContext *context=nullptr)
void unregisterSocketNotifier(QSocketNotifier *socketNotifier) final
Unregisters notifier from the event dispatcher.
void wakeUp() final
\threadsafe
bool unregisterTimers(QObject *object) final
Unregisters all the timers associated with the given object.
void registerSocketNotifier(QSocketNotifier *socketNotifier) final
Registers notifier with the event loop.
void registerTimer(int timerId, qint64 interval, Qt::TimerType timerType, QObject *object) final
Register a timer with the specified timerId, interval, and timerType for the given object.
bool processEvents(QEventLoop::ProcessEventsFlags flags) override
Processes pending events that match flags until there are no more events to process.
QList< TimerInfo > registeredTimers(QObject *object) const final
Returns a list of registered timers for object.
QEventDispatcherGlib(QObject *parent=nullptr)
bool unregisterTimer(int timerId) final
Unregisters the timer with the given timerId.
int remainingTime(int timerId) final
Returns the remaining time in milliseconds with the given timerId.
void interrupt() final
Interrupts event dispatching.
@ X11ExcludeTimers
Definition qeventloop.h:30
@ WaitForMoreEvents
Definition qeventloop.h:29
\inmodule QtCore
Definition qcoreevent.h:45
@ SockAct
Definition qcoreevent.h:98
Definition qlist.h:74
\inmodule QtCore
Definition qmutex.h:317
\inmodule QtCore
Definition qmutex.h:285
\inmodule QtCore
Definition qobject.h:90
QThread * thread() const
Returns the thread in which the object lives.
Definition qobject.cpp:1561
\inmodule QtCore
static Q_AUTOTEST_EXPORT QThreadData * current(bool createIfNecessary=true)
Definition qthread.cpp:1005
static QThread * currentThread()
Definition qthread.cpp:966
static gboolean timerSourcePrepareHelper(GTimerSource *src, gint *timeout)
static gboolean postEventSourceDispatch(GSource *s, GSourceFunc, gpointer)
static gboolean timerSourceCheck(GSource *source)
static gboolean idleTimerSourcePrepare(GSource *source, gint *timeout)
static gboolean socketNotifierSourcePrepare(GSource *, gint *timeout)
static gboolean idleTimerSourceDispatch(GSource *source, GSourceFunc, gpointer)
static gboolean postEventSourcePrepare(GSource *s, gint *timeout)
static Q_CONSTINIT GSourceFuncs postEventSourceFuncs
static gboolean idleTimerSourceCheck(GSource *source)
static gboolean timerSourceCheckHelper(GTimerSource *src)
static gboolean socketNotifierSourceCheck(GSource *source)
static gboolean postEventSourceCheck(GSource *source)
static gboolean socketNotifierSourceDispatch(GSource *source, GSourceFunc, gpointer)
static gboolean timerSourcePrepare(GSource *source, gint *timeout)
static gboolean timerSourceDispatch(GSource *source, GSourceFunc, gpointer)
static Q_CONSTINIT GSourceFuncs timerSourceFuncs
static Q_CONSTINIT GSourceFuncs socketNotifierSourceFuncs
static Q_CONSTINIT GSourceFuncs idleTimerSourceFuncs
struct _GMainContext GMainContext
qDeleteAll(list.begin(), list.end())
Combined button and popup list for selecting options.
TimerType
static void * context
DBusConnection const char DBusError DBusBusType DBusError return DBusConnection DBusHandleMessageFunction void DBusFreeFunction return DBusConnection return DBusConnection return const char DBusError return DBusConnection DBusMessage dbus_uint32_t return DBusConnection dbus_bool_t DBusConnection DBusAddWatchFunction DBusRemoveWatchFunction DBusWatchToggledFunction void DBusFreeFunction return DBusConnection DBusDispatchStatusFunction void DBusFreeFunction DBusTimeout return DBusTimeout return DBusWatch return DBusWatch unsigned int return DBusError const DBusError return const DBusMessage return DBusMessage return DBusMessage return DBusMessage return DBusMessage return DBusMessage return DBusMessageIter int const void return DBusMessageIter DBusMessageIter return DBusMessageIter void DBusMessageIter void int return DBusMessage DBusMessageIter return DBusMessageIter return DBusMessageIter DBusMessageIter const char const char const char const char return DBusMessage return DBusMessage const char return DBusMessage dbus_bool_t return DBusMessage dbus_uint32_t return DBusMessage void
DBusConnection const char DBusError DBusBusType DBusError return DBusConnection DBusHandleMessageFunction void DBusFreeFunction return DBusConnection return DBusConnection return const char DBusError return DBusConnection DBusMessage dbus_uint32_t return DBusConnection dbus_bool_t DBusConnection DBusAddWatchFunction DBusRemoveWatchFunction DBusWatchToggledFunction void DBusFreeFunction return DBusConnection DBusDispatchStatusFunction void DBusFreeFunction DBusTimeout return DBusTimeout return DBusWatch return DBusWatch unsigned int return DBusError const DBusError return const DBusMessage return DBusMessage return DBusMessage return DBusMessage return DBusMessage return DBusMessage return DBusMessageIter int const void return DBusMessageIter DBusMessageIter return DBusMessageIter void DBusMessageIter void int return DBusMessage DBusMessageIter return DBusMessageIter return DBusMessageIter DBusMessageIter const char const char const char const char return DBusMessage return DBusMessage const char return DBusMessage dbus_bool_t return DBusMessage dbus_uint32_t return DBusMessage return DBusPendingCall * pending
#define qWarning
Definition qlogging.h:162
GLuint object
[3]
GLbitfield GLuint64 timeout
[4]
GLenum src
GLenum type
GLbitfield flags
GLint GLsizei GLsizei GLenum GLenum GLsizei void * data
GLsizei GLsizei GLchar * source
struct _cl_event * event
GLdouble GLdouble t
Definition qopenglext.h:243
GLuint64EXT * result
[6]
GLdouble s
[6]
Definition qopenglext.h:235
GLfloat GLfloat p
[1]
#define Q_ASSERT(cond)
Definition qrandom.cpp:47
Q_CORE_EXPORT bool qEnvironmentVariableIsEmpty(const char *varName) noexcept
#define emit
long long qint64
Definition qtypes.h:55
QMutex mutex
[2]
QApplication app(argc, argv)
[0]
QEventDispatcherGlibPrivate * d
QList< GPollFDWithQSocketNotifier * > pollfds
QTimerInfoList timerList
QEventLoop::ProcessEventsFlags processEventsFlags
IUIAutomationTreeWalker __RPC__deref_out_opt IUIAutomationElement ** parent