Qt
Internal/Contributor docs for the Qt SDK. Note: These are NOT official API docs; those are found at https://doc.qt.io/
Loading...
Searching...
No Matches
qeventdispatcher_cf.mm
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
5
6#include <QtCore/qdebug.h>
7#include <QtCore/qmetaobject.h>
8#include <QtCore/qthread.h>
9#include <QtCore/private/qcoreapplication_p.h>
10#include <QtCore/private/qcore_unix_p.h>
11#include <QtCore/private/qthread_p.h>
12
13#include <limits>
14
15#ifdef Q_OS_MACOS
16# include <AppKit/NSApplication.h>
17#elif defined(Q_OS_WATCHOS)
18# include <WatchKit/WatchKit.h>
19#else
20# include <UIKit/UIApplication.h>
21#endif
22
23QT_BEGIN_NAMESPACE
24namespace QtPrivate {
26Q_LOGGING_CATEGORY(lcEventDispatcherTimers, "qt.eventdispatcher.timers");
27}
28using namespace QtPrivate;
29QT_END_NAMESPACE
30
31QT_USE_NAMESPACE
32
33/*
34 During scroll view panning, and possibly other gestures, UIKit will
35 request a switch to UITrackingRunLoopMode via GSEventPushRunLoopMode,
36 which records the new runloop mode and stops the current runloop.
37
38 Unfortunately the runloop mode is just stored on an internal stack, used
39 when UIKit itself is running the runloop, and is not available through e.g.
40 CFRunLoopCopyCurrentMode, which only knows about the current running
41 runloop mode, not the requested future runloop mode.
42
43 To ensure that we pick up this new runloop mode and use it when calling
44 CFRunLoopRunInMode from processEvents, we listen for the notification
45 emitted by [UIApplication pushRunLoopMode:requester:].
46
47 Without this workaround we end up always running in the default runloop
48 mode, resulting in missing momentum-phases in UIScrollViews such as the
49 emoji keyboard.
50*/
51@interface QT_MANGLE_NAMESPACE(RunLoopModeTracker) : NSObject
52@end
53
54QT_NAMESPACE_ALIAS_OBJC_CLASS(RunLoopModeTracker);
55
56@implementation QT_MANGLE_NAMESPACE(RunLoopModeTracker) {
57 QStack<CFStringRef> m_runLoopModes;
58}
59
60- (instancetype)init
61{
62 if ((self = [super init])) {
63 m_runLoopModes.push(kCFRunLoopDefaultMode);
64
65#if !defined(Q_OS_WATCHOS)
66 if (!qt_apple_isApplicationExtension()) {
67 [[NSNotificationCenter defaultCenter]
68 addObserver:self selector:@selector(receivedNotification:)
69 name:nil object:qt_apple_sharedApplication()];
70 }
71#endif
72 }
73
74 return self;
75}
76
77- (void)dealloc
78{
79 [NSNotificationCenter.defaultCenter removeObserver:self];
80
81 [super dealloc];
82}
83
84static CFStringRef runLoopMode(NSDictionary *dictionary)
85{
86 for (NSString *key in dictionary) {
87 if (CFStringHasSuffix((CFStringRef)key, CFSTR("RunLoopMode")))
88 return (CFStringRef)dictionary[key];
89 }
90
91 return nil;
92}
93
94- (void)receivedNotification:(NSNotification *)notification
95{
96 if (CFStringHasSuffix((CFStringRef)notification.name, CFSTR("RunLoopModePushNotification"))) {
97 if (CFStringRef mode = runLoopMode(notification.userInfo))
98 m_runLoopModes.push(mode);
99 else
100 qCWarning(lcEventDispatcher) << "Encountered run loop push notification without run loop mode!";
101
102 } else if (CFStringHasSuffix((CFStringRef)notification.name, CFSTR("RunLoopModePopNotification"))) {
103 CFStringRef mode = runLoopMode(notification.userInfo);
104 if (CFStringCompare(mode, self.currentMode, 0) == kCFCompareEqualTo)
105 m_runLoopModes.pop();
106 else
107 qCWarning(lcEventDispatcher) << "Tried to pop run loop mode"
108 << qPrintable(QString::fromCFString(mode)) << "that was never pushed!";
109
110 Q_ASSERT(m_runLoopModes.size() >= 1);
111 }
112}
113
114- (CFStringRef)currentMode
115{
116 return m_runLoopModes.top();
117}
118
119@end
120
121QT_BEGIN_NAMESPACE
122
123class RunLoopDebugger : public QObject
124{
125 Q_OBJECT
126
127 Q_ENUMS(Activity)
128 Q_ENUMS(Result)
129
130public:
131
132 #define Q_MIRROR_ENUM(name) name = name
133
134 enum Activity {
135 Q_MIRROR_ENUM(kCFRunLoopEntry),
136 Q_MIRROR_ENUM(kCFRunLoopBeforeTimers),
137 Q_MIRROR_ENUM(kCFRunLoopBeforeSources),
138 Q_MIRROR_ENUM(kCFRunLoopBeforeWaiting),
139 Q_MIRROR_ENUM(kCFRunLoopAfterWaiting),
140 Q_MIRROR_ENUM(kCFRunLoopExit)
141 };
142
143 enum Result {
144 Q_MIRROR_ENUM(kCFRunLoopRunFinished),
145 Q_MIRROR_ENUM(kCFRunLoopRunStopped),
146 Q_MIRROR_ENUM(kCFRunLoopRunTimedOut),
147 Q_MIRROR_ENUM(kCFRunLoopRunHandledSource)
148 };
149};
150
151#define Q_ENUM_PRINTER(enumName)
152 static const char* qPrintable##enumName(int value)
153 {
154 return RunLoopDebugger::staticMetaObject.enumerator(RunLoopDebugger::staticMetaObject.indexOfEnumerator(#enumName)).valueToKey(value);
155 }
156
159
160QDebug operator<<(QDebug s, timespec tv)
161{
162 s << tv.tv_sec << "." << qSetFieldWidth(9) << qSetPadChar(QChar(48)) << tv.tv_nsec << Qt::reset;
163 return s;
164}
165
167static const CFTimeInterval kCFTimeIntervalDistantFuture = std::numeric_limits<CFTimeInterval>::max();
168
169#pragma mark - Class definition
170
171QEventDispatcherCoreFoundation::QEventDispatcherCoreFoundation(QObject *parent)
172 : QAbstractEventDispatcherV2(parent)
173 , m_processEvents(QEventLoop::EventLoopExec)
174 , m_postedEventsRunLoopSource(this, &QEventDispatcherCoreFoundation::processPostedEvents)
175 , m_runLoopActivityObserver(this, &QEventDispatcherCoreFoundation::handleRunLoopActivity, kCFRunLoopAllActivities)
176 , m_runLoopModeTracker([[RunLoopModeTracker alloc] init])
177 , m_runLoopTimer(0)
178 , m_blockedRunLoopTimer(0)
179 , m_overdueTimerScheduled(false)
180{
181}
182
183void QEventDispatcherCoreFoundation::startingUp()
184{
185 // The following code must run on the event dispatcher thread, so that
186 // CFRunLoopGetCurrent() returns the correct run loop.
187 Q_ASSERT(QThread::currentThread() == thread());
188
189 m_runLoop = QCFType<CFRunLoopRef>::constructFromGet(CFRunLoopGetCurrent());
190 m_cfSocketNotifier.setHostEventDispatcher(this);
191 m_postedEventsRunLoopSource.addToMode(kCFRunLoopCommonModes);
192 m_runLoopActivityObserver.addToMode(kCFRunLoopCommonModes);
193}
194
195QEventDispatcherCoreFoundation::~QEventDispatcherCoreFoundation()
196{
197 invalidateTimer();
198 m_timerInfoList.clearTimers();
199
200 m_cfSocketNotifier.removeSocketNotifiers();
201}
202
203QEventLoop *QEventDispatcherCoreFoundation::currentEventLoop() const
204{
205 QEventLoop *eventLoop = QThreadData::current()->eventLoops.top();
206 Q_ASSERT(eventLoop);
207 return eventLoop;
208}
209
210/*!
211 Processes all pending events that match \a flags until there are no
212 more events to process. Returns \c true if pending events were handled;
213 otherwise returns \c false.
214
215 Note:
216
217 - All events are considered equal. This function should process
218 both system/native events (that we may or may not care about),
219 as well as Qt-events (posted events and timers).
220
221 - The function should not return until all queued/available events
222 have been processed. If the WaitForMoreEvents is set, the
223 function should wait only if there were no events ready,
224 and _then_ process all newly queued/available events.
225
226 These notes apply to other function in this class as well.
227*/
228bool QEventDispatcherCoreFoundation::processEvents(QEventLoop::ProcessEventsFlags flags)
229{
230 QT_APPLE_SCOPED_LOG_ACTIVITY(lcEventDispatcher().isDebugEnabled(), "processEvents");
231
232 bool eventsProcessed = false;
233
234 if (flags & (QEventLoop::ExcludeUserInputEvents | QEventLoop::ExcludeSocketNotifiers))
235 qCWarning(lcEventDispatcher) << "processEvents() flags" << flags << "not supported on iOS";
236
237 qCDebug(lcEventDispatcher) << "Processing events with flags" << flags;
238
239 if (m_blockedRunLoopTimer) {
240 Q_ASSERT(m_blockedRunLoopTimer == m_runLoopTimer);
241
242 qCDebug(lcEventDispatcher) << "Recursing from blocked timer" << m_blockedRunLoopTimer;
243 m_runLoopTimer = 0; // Unset current timer to force creation of new timer
244 updateTimers();
245 }
246
247 if (m_processEvents.deferredWakeUp) {
248 // We may be processing events recursively as a result of processing a posted event,
249 // in which case we need to signal the run-loop source so that this iteration of
250 // processEvents will take care of the newly posted events.
251 m_postedEventsRunLoopSource.signal();
252 m_processEvents.deferredWakeUp = false;
253
254 qCDebug(lcEventDispatcher) << "Processed deferred wake-up";
255 }
256
257 // The documentation states that this signal is emitted after the event
258 // loop returns from a function that could block, which is not the case
259 // here, but all the other event dispatchers emit awake at the start of
260 // processEvents, and the QEventLoop auto-test has an explicit check for
261 // this behavior, so we assume it's for a good reason and do it as well.
262 emit awake();
263
264 ProcessEventsState previousState = m_processEvents;
265 m_processEvents = ProcessEventsState(flags);
266
267 bool returnAfterSingleSourceHandled = !(m_processEvents.flags & QEventLoop::EventLoopExec);
268
269 Q_FOREVER {
270 CFStringRef mode = [m_runLoopModeTracker currentMode];
271
272 CFTimeInterval duration = (m_processEvents.flags & QEventLoop::WaitForMoreEvents) ?
273 kCFTimeIntervalDistantFuture : kCFTimeIntervalMinimum;
274
275 qCDebug(lcEventDispatcher) << "Calling CFRunLoopRunInMode =" << qPrintable(QString::fromCFString(mode))
276 << "for" << duration << "ms, processing single source =" << returnAfterSingleSourceHandled;
277
278 SInt32 result = CFRunLoopRunInMode(mode, duration, returnAfterSingleSourceHandled);
279
280 qCDebug(lcEventDispatcher) << "result =" << qPrintableResult(result);
281
282 eventsProcessed |= (result == kCFRunLoopRunHandledSource
283 || m_processEvents.processedPostedEvents
284 || m_processEvents.processedTimers);
285
286 if (result == kCFRunLoopRunFinished) {
287 // This should only happen at application shutdown, as the main runloop
288 // will presumably always have sources registered.
289 break;
290 } else if (m_processEvents.wasInterrupted) {
291
292 if (m_processEvents.flags & QEventLoop::EventLoopExec) {
293 Q_ASSERT(result == kCFRunLoopRunStopped);
294
295 // The runloop was potentially stopped (interrupted) by us, as a response to
296 // a Qt event loop being asked to exit. We check that the topmost eventloop
297 // is still supposed to keep going and return if not. Note that the runloop
298 // might get stopped as a result of a non-top eventloop being asked to exit,
299 // in which case we continue running the top event loop until that is asked
300 // to exit, and then unwind back to the previous event loop which will break
301 // immediately, since it has already been exited.
302
303 if (!currentEventLoop()->isRunning()) {
304 qCDebug(lcEventDispatcher) << "Top level event loop was exited";
305 break;
306 } else {
307 qCDebug(lcEventDispatcher) << "Top level event loop still running, making another pass";
308 }
309 } else {
310 // We were called manually, through processEvents(), and should stop processing
311 // events, even if we didn't finish processing all the queued events.
312 qCDebug(lcEventDispatcher) << "Top level processEvents was interrupted";
313 break;
314 }
315 }
316
317 if (m_processEvents.flags & QEventLoop::EventLoopExec) {
318 // We were called from QEventLoop's exec(), which blocks until the event
319 // loop is asked to exit by calling processEvents repeatedly. Instead of
320 // re-entering this method again and again from QEventLoop, we can block
321 // here, one lever closer to CFRunLoopRunInMode, by running the native
322 // event loop again and again until we're interrupted by QEventLoop.
323 continue;
324 } else {
325 // We were called 'manually', through processEvents()
326
327 if (result == kCFRunLoopRunHandledSource) {
328 // We processed one or more sources, but there might still be other
329 // sources that did not get a chance to process events, so we need
330 // to do another pass.
331
332 // But we should only wait for more events the first time
333 m_processEvents.flags &= ~int(QEventLoop::WaitForMoreEvents);
334 continue;
335
336 } else if (m_overdueTimerScheduled && !m_processEvents.processedTimers) {
337 // CFRunLoopRunInMode does not guarantee that a scheduled timer with a fire
338 // date in the past (overdue) will fire on the next run loop pass. The Qt
339 // APIs on the other hand document eg. zero-interval timers to always be
340 // handled after processing all available window-system events.
341 qCDebug(lcEventDispatcher) << "Manually processing timers due to overdue timer";
342 processTimers(0);
343 eventsProcessed = true;
344 }
345 }
346
347 break;
348 }
349
350 if (m_blockedRunLoopTimer) {
351 invalidateTimer();
352 m_runLoopTimer = m_blockedRunLoopTimer;
353 }
354
355 if (m_processEvents.deferredUpdateTimers)
356 updateTimers();
357
358 if (m_processEvents.deferredWakeUp) {
359 m_postedEventsRunLoopSource.signal();
360 qCDebug(lcEventDispatcher) << "Processed deferred wake-up";
361 }
362
363 bool wasInterrupted = m_processEvents.wasInterrupted;
364
365 // Restore state of previous processEvents() call
366 m_processEvents = previousState;
367
368 if (wasInterrupted) {
369 // The current processEvents run has been interrupted, but there may still be
370 // others below it (eg, in the case of nested event loops). We need to trigger
371 // another interrupt so that the parent processEvents call has a chance to check
372 // if it should continue.
373 qCDebug(lcEventDispatcher) << "Forwarding interrupt in case of nested processEvents";
374 interrupt();
375 }
376
377 qCDebug(lcEventDispatcher) << "Returning with eventsProcessed =" << eventsProcessed;
378
379 return eventsProcessed;
380}
381
382bool QEventDispatcherCoreFoundation::processPostedEvents()
383{
384 QT_APPLE_SCOPED_LOG_ACTIVITY(lcEventDispatcher().isDebugEnabled(), "processPostedEvents");
385
386 if (m_processEvents.processedPostedEvents && !(m_processEvents.flags & QEventLoop::EventLoopExec)) {
387 qCDebug(lcEventDispatcher) << "Already processed events this pass";
388 return false;
389 }
390
391 m_processEvents.processedPostedEvents = true;
392
393 qCDebug(lcEventDispatcher) << "Sending posted events for"
394 << QEventLoop::ProcessEventsFlags(m_processEvents.flags.loadRelaxed());
395 QCoreApplication::sendPostedEvents();
396
397 return true;
398}
399
400void QEventDispatcherCoreFoundation::processTimers(CFRunLoopTimerRef timer)
401{
402 QT_APPLE_SCOPED_LOG_ACTIVITY(lcEventDispatcher().isDebugEnabled(), "processTimers");
403
404 if (m_processEvents.processedTimers && !(m_processEvents.flags & QEventLoop::EventLoopExec)) {
405 qCDebug(lcEventDispatcher) << "Already processed timers this pass";
406 m_processEvents.deferredUpdateTimers = true;
407 return;
408 }
409
410 qCDebug(lcEventDispatcher) << "CFRunLoopTimer" << timer << "fired, activating Qt timers";
411
412 // Activating Qt timers might recurse into processEvents() if a timer-callback
413 // brings up a new event-loop or tries to processes events manually. Although
414 // a CFRunLoop can recurse inside its callbacks, a single CFRunLoopTimer can
415 // not. So, for each recursion into processEvents() from a timer-callback we
416 // need to set up a new timer-source. Instead of doing it preemtivly each
417 // time we activate Qt timers, we set a flag here, and let processEvents()
418 // decide whether or not it needs to bring up a new timer source.
419
420 // We may have multiple recused timers, so keep track of the previous blocked timer
421 CFRunLoopTimerRef previouslyBlockedRunLoopTimer = m_blockedRunLoopTimer;
422
423 m_blockedRunLoopTimer = timer;
424 m_timerInfoList.activateTimers();
425 m_blockedRunLoopTimer = previouslyBlockedRunLoopTimer;
426 m_processEvents.processedTimers = true;
427
428 // Now that the timer source is unblocked we may need to schedule it again
429 updateTimers();
430}
431
432Q_STATIC_LOGGING_CATEGORY(lcEventDispatcherActivity, "qt.eventdispatcher.activity")
433
434void QEventDispatcherCoreFoundation::handleRunLoopActivity(CFRunLoopActivity activity)
435{
436 qCDebug(lcEventDispatcherActivity) << "Runloop entered activity" << qPrintableActivity(activity);
437
438 switch (activity) {
439 case kCFRunLoopBeforeWaiting:
440 if (m_processEvents.processedTimers
441 && !(m_processEvents.flags & QEventLoop::EventLoopExec)
442 && m_processEvents.flags & QEventLoop::WaitForMoreEvents) {
443 // CoreFoundation does not treat a timer as a reason to exit CFRunLoopRunInMode
444 // when asked to only process a single source, so we risk waiting a long time for
445 // a 'proper' source to fire (typically a system source that we don't control).
446 // To fix this we do an explicit interrupt after processing our timer, so that
447 // processEvents() gets a chance to re-evaluate the state of things.
448 interrupt();
449 }
450 emit aboutToBlock();
451 break;
452 case kCFRunLoopAfterWaiting:
453 emit awake();
454 break;
455 case kCFRunLoopEntry:
456 case kCFRunLoopBeforeTimers:
457 case kCFRunLoopBeforeSources:
458 case kCFRunLoopExit:
459 break;
460 default:
461 Q_UNREACHABLE();
462 }
463}
464
465void QEventDispatcherCoreFoundation::wakeUp()
466{
467 if (m_processEvents.processedPostedEvents && !(m_processEvents.flags & QEventLoop::EventLoopExec)) {
468 // A manual processEvents call should only result in processing the events posted
469 // up until then. Any newly posted events as result of processing existing posted
470 // events should be handled in the next call to processEvents(). Since we're using
471 // a run-loop source to process our posted events we need to prevent it from being
472 // signaled as a result of posting new events, otherwise we end up in an infinite
473 // loop. We do however need to signal the source at some point, so that the newly
474 // posted event gets processed on the next processEvents() call, so we flag the
475 // need to do a deferred wake-up.
476 m_processEvents.deferredWakeUp = true;
477 qCDebug(lcEventDispatcher) << "Already processed posted events, deferring wakeUp";
478 return;
479 }
480
481 m_postedEventsRunLoopSource.signal();
482 if (m_runLoop)
483 CFRunLoopWakeUp(m_runLoop);
484
485 qCDebug(lcEventDispatcher) << "Signaled posted event run-loop source";
486}
487
488void QEventDispatcherCoreFoundation::interrupt()
489{
490 qCDebug(lcEventDispatcher) << "Marking current processEvent as interrupted";
491 m_processEvents.wasInterrupted = true;
492 CFRunLoopStop(m_runLoop);
493}
494
495#pragma mark - Socket notifiers
496
497void QEventDispatcherCoreFoundation::registerSocketNotifier(QSocketNotifier *notifier)
498{
499 m_cfSocketNotifier.registerSocketNotifier(notifier);
500}
501
502void QEventDispatcherCoreFoundation::unregisterSocketNotifier(QSocketNotifier *notifier)
503{
504 m_cfSocketNotifier.unregisterSocketNotifier(notifier);
505}
506
507#pragma mark - Timers
508
509void QEventDispatcherCoreFoundation::registerTimer(Qt::TimerId timerId, Duration interval,
510 Qt::TimerType timerType, QObject *object)
511{
512 qCDebug(lcEventDispatcherTimers) << "Registering timer with id =" << int(timerId) << "interval =" << interval
513 << "type =" << timerType << "object =" << object;
514
515 Q_ASSERT(qToUnderlying(timerId) > 0 && interval.count() >= 0 && object);
516 Q_ASSERT(object->thread() == thread() && thread() == QThread::currentThread());
517
518 m_timerInfoList.registerTimer(timerId, interval, timerType, object);
519 updateTimers();
520}
521
522bool QEventDispatcherCoreFoundation::unregisterTimer(Qt::TimerId timerId)
523{
524 Q_ASSERT(qToUnderlying(timerId) > 0);
525 Q_ASSERT(thread() == QThread::currentThread());
526
527 bool returnValue = m_timerInfoList.unregisterTimer(timerId);
528
529 qCDebug(lcEventDispatcherTimers) << "Unegistered timer with id =" << qToUnderlying(timerId)
530 << "Timers left:" << m_timerInfoList.size();
531
532 updateTimers();
533 return returnValue;
534}
535
536bool QEventDispatcherCoreFoundation::unregisterTimers(QObject *object)
537{
538 Q_ASSERT(object && object->thread() == thread() && thread() == QThread::currentThread());
539
540 bool returnValue = m_timerInfoList.unregisterTimers(object);
541
542 qCDebug(lcEventDispatcherTimers) << "Unegistered timers for object =" << object << "Timers left:" << m_timerInfoList.size();
543
544 updateTimers();
545 return returnValue;
546}
547
548QList<QAbstractEventDispatcher::TimerInfoV2>
549QEventDispatcherCoreFoundation::timersForObject(QObject *object) const
550{
551 Q_ASSERT(object);
552 return m_timerInfoList.registeredTimers(object);
553}
554
555QEventDispatcherCoreFoundation::Duration
556QEventDispatcherCoreFoundation::remainingTime(Qt::TimerId timerId) const
557{
558 Q_ASSERT(qToUnderlying(timerId) > 0);
559 return m_timerInfoList.remainingDuration(timerId);
560}
561
562void QEventDispatcherCoreFoundation::updateTimers()
563{
564 if (m_timerInfoList.size() > 0) {
565 // We have Qt timers registered, so create or reschedule CF timer to match
566
567 using namespace std::chrono_literals;
568 using DoubleSeconds = std::chrono::duration<double, std::ratio<1>>;
569
570 CFAbsoluteTime timeToFire;
571 auto opt = m_timerInfoList.timerWait();
572 DoubleSeconds secs{};
573 if (opt) {
574 // We have a timer ready to fire right now, or some time in the future
575 secs = DoubleSeconds{*opt};
576 timeToFire = CFAbsoluteTimeGetCurrent() + secs.count();
577 } else {
578 // We have timers, but they are all currently blocked by callbacks
579 timeToFire = kCFTimeIntervalDistantFuture;
580 }
581
582 if (!m_runLoopTimer) {
583 m_runLoopTimer = CFRunLoopTimerCreateWithHandler(kCFAllocatorDefault,
584 timeToFire, kCFTimeIntervalDistantFuture, 0, 0, ^(CFRunLoopTimerRef timer) {
585 processTimers(timer);
586 });
587
588 CFRunLoopAddTimer(m_runLoop, m_runLoopTimer, kCFRunLoopCommonModes);
589 qCDebug(lcEventDispatcherTimers) << "Created new CFRunLoopTimer" << m_runLoopTimer;
590
591 } else {
592 CFRunLoopTimerSetNextFireDate(m_runLoopTimer, timeToFire);
593 qCDebug(lcEventDispatcherTimers) << "Re-scheduled CFRunLoopTimer" << m_runLoopTimer;
594 }
595
596 m_overdueTimerScheduled = secs > 0s;
597
598 qCDebug(lcEventDispatcherTimers) << "Next timeout in" << secs;
599
600 } else {
601 // No Qt timers are registered, so make sure we're not running any CF timers
602 invalidateTimer();
603
604 m_overdueTimerScheduled = false;
605 }
606}
607
608void QEventDispatcherCoreFoundation::invalidateTimer()
609{
610 if (!m_runLoopTimer || (m_runLoopTimer == m_blockedRunLoopTimer))
611 return;
612
613 CFRunLoopTimerInvalidate(m_runLoopTimer);
614 qCDebug(lcEventDispatcherTimers) << "Invalidated CFRunLoopTimer" << m_runLoopTimer;
615
616 CFRelease(m_runLoopTimer);
617 m_runLoopTimer = 0;
618}
619
620QT_END_NAMESPACE
621
622#include "qeventdispatcher_cf.moc"
623#include "moc_qeventdispatcher_cf_p.cpp"
Q_LOGGING_CATEGORY(lcEventDispatcher, "qt.eventdispatcher")
Q_STATIC_LOGGING_CATEGORY(lcAccessibilityCore, "qt.accessibility.core")
#define Q_ENUM_PRINTER(enumName)
#define Q_MIRROR_ENUM(name)
static const CFTimeInterval kCFTimeIntervalMinimum
static const CFTimeInterval kCFTimeIntervalDistantFuture
QDebug operator<<(QDebug debug, QIODevice::OpenMode modes)