Qt
Internal/Contributor docs for the Qt SDK. <b>Note:</b> These are NOT official API docs; those are found <a href='https://doc.qt.io/'>here</a>.
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/qnumeric_p.h>
8#include <private/qthread_p.h>
9
10#include "qcoreapplication.h"
11#include "qsocketnotifier.h"
12
13#include <QtCore/qlist.h>
14
15#include <glib.h>
16
17using namespace std::chrono;
18using namespace std::chrono_literals;
19
21
27
29{
30 GSource source;
31 QList<GPollFDWithQSocketNotifier *> pollfds;
33};
34
35static gboolean socketNotifierSourcePrepare(GSource *, gint *timeout)
36{
37 if (timeout)
38 *timeout = -1;
39 return false;
40}
41
42static gboolean socketNotifierSourceCheck(GSource *source)
43{
45
46 bool pending = false;
47 for (int i = 0; !pending && i < src->pollfds.size(); ++i) {
48 GPollFDWithQSocketNotifier *p = src->pollfds.at(i);
49
50 if (p->pollfd.revents & G_IO_NVAL) {
51 // disable the invalid socket notifier
52 const char * const t[] = { "Read", "Write", "Exception" };
53 qWarning("QSocketNotifier: Invalid socket %d and type '%s', disabling...",
54 p->pollfd.fd, t[int(p->socketNotifier->type())]);
55 // ### note, modifies src->pollfds!
56 p->socketNotifier->setEnabled(false);
57 i--;
58 } else {
59 pending = pending || ((p->pollfd.revents & p->pollfd.events) != 0);
60 }
61 }
62
63 return pending;
64}
65
66static gboolean socketNotifierSourceDispatch(GSource *source, GSourceFunc, gpointer)
67{
69
71 for (src->activeNotifierPos = 0; src->activeNotifierPos < src->pollfds.size();
72 ++src->activeNotifierPos) {
73 GPollFDWithQSocketNotifier *p = src->pollfds.at(src->activeNotifierPos);
74
75 if ((p->pollfd.revents & p->pollfd.events) != 0)
76 QCoreApplication::sendEvent(p->socketNotifier, &event);
77 }
78
79 return true; // ??? don't remove, right?
80}
81
82Q_CONSTINIT static GSourceFuncs socketNotifierSourceFuncs = {
86 nullptr,
87 nullptr,
88 nullptr
89};
90
92{
93 GSource source;
95 QEventLoop::ProcessEventsFlags processEventsFlags;
97};
98
100{
101 if (src->processEventsFlags & QEventLoop::X11ExcludeTimers) {
102 *timeout = -1;
103 return true;
104 }
105
106 auto remaining = src->timerList.timerWait().value_or(-1ms);
107 *timeout = qt_saturate<gint>(ceil<milliseconds>(remaining).count());
108
109 return (*timeout == 0);
110}
111
113{
114 if (src->timerList.isEmpty()
115 || (src->processEventsFlags & QEventLoop::X11ExcludeTimers))
116 return false;
117
118 return !src->timerList.hasPendingTimers();
119}
120
121static gboolean timerSourcePrepare(GSource *source, gint *timeout)
122{
123 gint dummy;
124 if (!timeout)
125 timeout = &dummy;
126
127 GTimerSource *src = reinterpret_cast<GTimerSource *>(source);
128 if (src->runWithIdlePriority) {
129 if (timeout)
130 *timeout = -1;
131 return false;
132 }
133
135}
136
137static gboolean timerSourceCheck(GSource *source)
138{
139 GTimerSource *src = reinterpret_cast<GTimerSource *>(source);
140 if (src->runWithIdlePriority)
141 return false;
143}
144
145static gboolean timerSourceDispatch(GSource *source, GSourceFunc, gpointer)
146{
147 GTimerSource *timerSource = reinterpret_cast<GTimerSource *>(source);
149 return true;
150 timerSource->runWithIdlePriority = true;
151 (void) timerSource->timerList.activateTimers();
152 return true; // ??? don't remove, right again?
153}
154
155Q_CONSTINIT static GSourceFuncs timerSourceFuncs = {
159 nullptr,
160 nullptr,
161 nullptr
162};
163
169
170static gboolean idleTimerSourcePrepare(GSource *source, gint *timeout)
171{
172 GIdleTimerSource *idleTimerSource = reinterpret_cast<GIdleTimerSource *>(source);
173 GTimerSource *timerSource = idleTimerSource->timerSource;
174 if (!timerSource->runWithIdlePriority) {
175 // Yield to the normal priority timer source
176 if (timeout)
177 *timeout = -1;
178 return false;
179 }
180
181 return timerSourcePrepareHelper(timerSource, timeout);
182}
183
184static gboolean idleTimerSourceCheck(GSource *source)
185{
186 GIdleTimerSource *idleTimerSource = reinterpret_cast<GIdleTimerSource *>(source);
187 GTimerSource *timerSource = idleTimerSource->timerSource;
188 if (!timerSource->runWithIdlePriority) {
189 // Yield to the normal priority timer source
190 return false;
191 }
192 return timerSourceCheckHelper(timerSource);
193}
194
195static gboolean idleTimerSourceDispatch(GSource *source, GSourceFunc, gpointer)
196{
197 GTimerSource *timerSource = reinterpret_cast<GIdleTimerSource *>(source)->timerSource;
198 (void) timerSourceDispatch(&timerSource->source, nullptr, nullptr);
199 return true;
200}
201
202Q_CONSTINIT static GSourceFuncs idleTimerSourceFuncs = {
206 nullptr,
207 nullptr,
208 nullptr
209};
210
218
219static gboolean postEventSourcePrepare(GSource *s, gint *timeout)
220{
222 if (!data)
223 return false;
224
225 gint dummy;
226 if (!timeout)
227 timeout = &dummy;
228 const bool canWait = data->canWaitLocked();
229 *timeout = canWait ? -1 : 0;
230
231 GPostEventSource *source = reinterpret_cast<GPostEventSource *>(s);
232 source->d->wakeUpCalled = source->serialNumber.loadRelaxed() != source->lastSerialNumber;
233 return !canWait || source->d->wakeUpCalled;
234}
235
236static gboolean postEventSourceCheck(GSource *source)
237{
238 return postEventSourcePrepare(source, nullptr);
239}
240
241static gboolean postEventSourceDispatch(GSource *s, GSourceFunc, gpointer)
242{
243 GPostEventSource *source = reinterpret_cast<GPostEventSource *>(s);
244 source->lastSerialNumber = source->serialNumber.loadRelaxed();
246 source->d->runTimersOnceWithNormalPriority();
247 return true; // i dunno, george...
248}
249
250Q_CONSTINIT static GSourceFuncs postEventSourceFuncs = {
254 nullptr,
255 nullptr,
256 nullptr
257};
258
259
261 : mainContext(context)
262{
263#if GLIB_MAJOR_VERSION == 2 && GLIB_MINOR_VERSION < 32
264 if (qEnvironmentVariableIsEmpty("QT_NO_THREADED_GLIB")) {
265 Q_CONSTINIT static QBasicMutex mutex;
266 QMutexLocker locker(&mutex);
267 if (!g_thread_supported())
268 g_thread_init(NULL);
269 }
270#endif
271
272 if (mainContext) {
273 g_main_context_ref(mainContext);
274 } else {
276 if (app && QThread::currentThread() == app->thread()) {
277 mainContext = g_main_context_default();
278 g_main_context_ref(mainContext);
279 } else {
280 mainContext = g_main_context_new();
281 }
282 }
283
284#if GLIB_CHECK_VERSION (2, 22, 0)
285 g_main_context_push_thread_default (mainContext);
286#endif
287
288 // setup post event source
289 GSource *source = g_source_new(&postEventSourceFuncs, sizeof(GPostEventSource));
290 g_source_set_name(source, "[Qt] GPostEventSource");
291 postEventSource = reinterpret_cast<GPostEventSource *>(source);
292
294 postEventSource->d = this;
295 g_source_set_can_recurse(&postEventSource->source, true);
296 g_source_attach(&postEventSource->source, mainContext);
297
298 // setup socketNotifierSource
300 g_source_set_name(source, "[Qt] GSocketNotifierSource");
302 (void) new (&socketNotifierSource->pollfds) QList<GPollFDWithQSocketNotifier *>();
303 g_source_set_can_recurse(&socketNotifierSource->source, true);
304 g_source_attach(&socketNotifierSource->source, mainContext);
305
306 // setup normal and idle timer sources
307 source = g_source_new(&timerSourceFuncs, sizeof(GTimerSource));
308 g_source_set_name(source, "[Qt] GTimerSource");
309 timerSource = reinterpret_cast<GTimerSource *>(source);
313 g_source_set_can_recurse(&timerSource->source, true);
314 g_source_attach(&timerSource->source, mainContext);
315
316 source = g_source_new(&idleTimerSourceFuncs, sizeof(GIdleTimerSource));
317 g_source_set_name(source, "[Qt] GIdleTimerSource");
318 idleTimerSource = reinterpret_cast<GIdleTimerSource *>(source);
320 g_source_set_can_recurse(&idleTimerSource->source, true);
321 g_source_attach(&idleTimerSource->source, mainContext);
322}
323
328
333
337
339{
341
342 // destroy all timer sources
343 d->timerSource->timerList.clearTimers();
344 d->timerSource->timerList.~QTimerInfoList();
345 g_source_destroy(&d->timerSource->source);
346 g_source_unref(&d->timerSource->source);
347 d->timerSource = nullptr;
348 g_source_destroy(&d->idleTimerSource->source);
349 g_source_unref(&d->idleTimerSource->source);
350 d->idleTimerSource = nullptr;
351
352 // destroy socket notifier source
353 for (int i = 0; i < d->socketNotifierSource->pollfds.size(); ++i) {
354 GPollFDWithQSocketNotifier *p = d->socketNotifierSource->pollfds[i];
355 g_source_remove_poll(&d->socketNotifierSource->source, &p->pollfd);
356 delete p;
357 }
358 d->socketNotifierSource->pollfds.~QList<GPollFDWithQSocketNotifier *>();
359 g_source_destroy(&d->socketNotifierSource->source);
360 g_source_unref(&d->socketNotifierSource->source);
361 d->socketNotifierSource = nullptr;
362
363 // destroy post event source
364 g_source_destroy(&d->postEventSource->source);
365 g_source_unref(&d->postEventSource->source);
366 d->postEventSource = nullptr;
367
368 Q_ASSERT(d->mainContext != nullptr);
369#if GLIB_CHECK_VERSION (2, 22, 0)
370 g_main_context_pop_thread_default (d->mainContext);
371#endif
372 g_main_context_unref(d->mainContext);
373 d->mainContext = nullptr;
374}
375
376bool QEventDispatcherGlib::processEvents(QEventLoop::ProcessEventsFlags flags)
377{
379
380 const bool canWait = flags.testAnyFlag(QEventLoop::WaitForMoreEvents);
381 if (canWait)
383 else
384 emit awake();
385
386 // tell postEventSourcePrepare() and timerSource about any new flags
387 QEventLoop::ProcessEventsFlags savedFlags = d->timerSource->processEventsFlags;
388 d->timerSource->processEventsFlags = flags;
389
391 // force timers to be sent at normal priority
392 d->timerSource->runWithIdlePriority = false;
393 }
394
395 bool result = g_main_context_iteration(d->mainContext, canWait);
396 while (!result && canWait)
397 result = g_main_context_iteration(d->mainContext, canWait);
398
399 d->timerSource->processEventsFlags = savedFlags;
400
401 if (canWait)
402 emit awake();
403
404 return result;
405}
406
408{
410 int sockfd = int(notifier->socket());
411 int type = notifier->type();
412#ifndef QT_NO_DEBUG
413 if (sockfd < 0) {
414 qWarning("QSocketNotifier: Internal error");
415 return;
416 } else if (notifier->thread() != thread()
417 || thread() != QThread::currentThread()) {
418 qWarning("QSocketNotifier: socket notifiers cannot be enabled from another thread");
419 return;
420 }
421#endif
422
424
425
427 p->pollfd.fd = sockfd;
428 switch (type) {
430 p->pollfd.events = G_IO_IN | G_IO_HUP | G_IO_ERR;
431 break;
433 p->pollfd.events = G_IO_OUT | G_IO_ERR;
434 break;
436 p->pollfd.events = G_IO_PRI | G_IO_ERR;
437 break;
438 }
439 p->socketNotifier = notifier;
440
441 d->socketNotifierSource->pollfds.append(p);
442
443 g_source_add_poll(&d->socketNotifierSource->source, &p->pollfd);
444}
445
447{
449#ifndef QT_NO_DEBUG
450 if (notifier->socket() < 0) {
451 qWarning("QSocketNotifier: Internal error");
452 return;
453 } else if (notifier->thread() != thread()
454 || thread() != QThread::currentThread()) {
455 qWarning("QSocketNotifier: socket notifiers cannot be disabled from another thread");
456 return;
457 }
458#endif
459
461
462 for (int i = 0; i < d->socketNotifierSource->pollfds.size(); ++i) {
463 GPollFDWithQSocketNotifier *p = d->socketNotifierSource->pollfds.at(i);
464 if (p->socketNotifier == notifier) {
465 // found it
466 g_source_remove_poll(&d->socketNotifierSource->source, &p->pollfd);
467
468 d->socketNotifierSource->pollfds.removeAt(i);
469 delete p;
470
471 // Keep a position in the list for the next item.
472 if (i <= d->socketNotifierSource->activeNotifierPos)
473 --d->socketNotifierSource->activeNotifierPos;
474
475 return;
476 }
477 }
478}
479
481 Qt::TimerType timerType, QObject *object)
482{
483#ifndef QT_NO_DEBUG
484 if (qToUnderlying(timerId) < 1 || interval < 0ns || !object) {
485 qWarning("QEventDispatcherGlib::registerTimer: invalid arguments");
486 return;
487 } else if (object->thread() != thread() || thread() != QThread::currentThread()) {
488 qWarning("QEventDispatcherGlib::registerTimer: timers cannot be started from another thread");
489 return;
490 }
491#endif
492
494 d->timerSource->timerList.registerTimer(timerId, interval, timerType, object);
495}
496
498{
499#ifndef QT_NO_DEBUG
500 if (qToUnderlying(timerId) < 1) {
501 qWarning("QEventDispatcherGlib::unregisterTimer: invalid argument");
502 return false;
503 } else if (thread() != QThread::currentThread()) {
504 qWarning("QEventDispatcherGlib::unregisterTimer: timers cannot be stopped from another thread");
505 return false;
506 }
507#endif
508
510 return d->timerSource->timerList.unregisterTimer(timerId);
511}
512
514{
515#ifndef QT_NO_DEBUG
516 if (!object) {
517 qWarning("QEventDispatcherGlib::unregisterTimers: invalid argument");
518 return false;
519 } else if (object->thread() != thread() || thread() != QThread::currentThread()) {
520 qWarning("QEventDispatcherGlib::unregisterTimers: timers cannot be stopped from another thread");
521 return false;
522 }
523#endif
524
526 return d->timerSource->timerList.unregisterTimers(object);
527}
528
529QList<QEventDispatcherGlib::TimerInfoV2> QEventDispatcherGlib::timersForObject(QObject *object) const
530{
531#ifndef QT_NO_DEBUG
532 if (!object) {
533 qWarning("QEventDispatcherGlib:timersForObject: invalid argument");
534 return {};
535 }
536#endif
537
538 Q_D(const QEventDispatcherGlib);
539 return d->timerSource->timerList.registeredTimers(object);
540}
541
543{
544#ifndef QT_NO_DEBUG
545 if (qToUnderlying(timerId) < 1) {
546 qWarning("QEventDispatcherGlib::remainingTimeTime: invalid argument");
547 return Duration::min();
548 }
549#endif
550
551 Q_D(const QEventDispatcherGlib);
552 return d->timerSource->timerList.remainingDuration(timerId);
553}
554
559
561{
563 d->postEventSource->serialNumber.ref();
564 g_main_context_wakeup(d->mainContext);
565}
566
568{
569#if !defined(GLIB_MAJOR_VERSION) || !defined(GLIB_MINOR_VERSION) || !defined(GLIB_MICRO_VERSION)
570 return false;
571#else
572 return ((GLIB_MAJOR_VERSION << 16) + (GLIB_MINOR_VERSION << 8) + GLIB_MICRO_VERSION) >= 0x020301;
573#endif
574}
575
580
582
583#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.
std::chrono::nanoseconds Duration
A {std::chrono::duration} type that is used in various API in this class.
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) override final
Unregisters all the timers associated with the given object.
void registerSocketNotifier(QSocketNotifier *socketNotifier) final
Registers notifier with the event loop.
bool processEvents(QEventLoop::ProcessEventsFlags flags) override
Processes pending events that match flags until there are no more events to process.
QList< TimerInfoV2 > timersForObject(QObject *object) const override final
Duration remainingTime(Qt::TimerId timerId) const override final
Returns the remaining time of the timer with the given timerId.
void registerTimer(Qt::TimerId timerId, Duration interval, Qt::TimerType timerType, QObject *object) override final
QEventDispatcherGlib(QObject *parent=nullptr)
bool unregisterTimer(Qt::TimerId timerId) override final
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
\inmodule QtCore
Definition qmutex.h:313
\inmodule QtCore
Definition qmutex.h:281
\inmodule QtCore
Definition qobject.h:103
QThread * thread() const
Returns the thread in which the object lives.
Definition qobject.cpp:1598
\inmodule QtCore
static Q_AUTOTEST_EXPORT QThreadData * current(bool createIfNecessary=true)
Definition qthread.cpp:1087
static QThread * currentThread()
Definition qthread.cpp:1039
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
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:166
GLenum GLenum GLsizei count
GLuint object
[3]
GLbitfield GLuint64 timeout
[4]
GLint GLsizei GLsizei GLenum GLenum GLsizei void * data
GLenum src
GLenum type
GLbitfield flags
GLsizei GLsizei GLchar * source
struct _cl_event * event
GLdouble s
[6]
Definition qopenglext.h:235
GLdouble GLdouble t
Definition qopenglext.h:243
GLuint64EXT * result
[6]
GLfloat GLfloat p
[1]
#define Q_ASSERT(cond)
Definition qrandom.cpp:47
Q_CORE_EXPORT bool qEnvironmentVariableIsEmpty(const char *varName) noexcept
#define emit
QT_BEGIN_NAMESPACE constexpr std::underlying_type_t< Enum > qToUnderlying(Enum e) noexcept
QMutex mutex
[2]
QApplication app(argc, argv)
[0]
QEventDispatcherGlibPrivate * d
QList< GPollFDWithQSocketNotifier * > pollfds
QTimerInfoList timerList
QEventLoop::ProcessEventsFlags processEventsFlags