80 if (timerInfoList.isEmpty()) {
82 Q_ASSERT(!runLoopTimerRef);
86 using DoubleSeconds = std::chrono::duration<
double, std::ratio<1>>;
87 if (!runLoopTimerRef) {
89 CFAbsoluteTime ttf = CFAbsoluteTimeGetCurrent();
90 CFTimeInterval interval;
91 CFTimeInterval oneyear = CFTimeInterval(3600. * 24. * 365.);
94 if (
auto opt = timerInfoList.timerWait()) {
96 DoubleSeconds secs{*opt};
97 interval = qMax(secs.count(), 0.0000001);
104 CFRunLoopTimerContext info = { 0,
this,
nullptr,
nullptr,
nullptr };
107 runLoopTimerRef = CFRunLoopTimerCreate(
nullptr, ttf, oneyear, 0, 0, QCocoaEventDispatcherPrivate::runLoopTimerCallback, &info);
108 Q_ASSERT(runLoopTimerRef);
110 CFRunLoopAddTimer(mainRunLoop(), runLoopTimerRef, kCFRunLoopCommonModes);
113 CFAbsoluteTime ttf = CFAbsoluteTimeGetCurrent();
114 CFTimeInterval interval;
117 if (
auto opt = timerInfoList.timerWait()) {
119 DoubleSeconds secs{*opt};
120 interval = qMax(secs.count(), 0.0000001);
124 interval = CFRunLoopTimerGetInterval(runLoopTimerRef);
128 CFRunLoopTimerSetNextFireDate(runLoopTimerRef, ttf);
289 Q_D(QCocoaEventDispatcher);
294 d->propagateInterrupt =
false;
295 const auto boolBlockerUndo = qScopeGuard([d](){
296 if (d->propagateInterrupt)
298 d->propagateInterrupt =
false;
300 QScopedValueRollback interruptBlocker(d->interrupt,
false);
302 bool interruptLater =
false;
307 uint oldflags = d->processEventsFlags;
308 d->processEventsFlags = flags;
313 ++d->processEventsCalled;
315 bool excludeUserEvents = d->processEventsFlags & QEventLoop::ExcludeUserInputEvents;
321 QMacAutoReleasePool pool;
322 NSEvent* event = nil;
325 if (d->sendQueuedUserInputEvents())
336 const bool canExec_3rdParty = d->nsAppRunCalledByQt || ![NSApp isRunning];
337 const bool canExec_Qt = (!excludeUserEvents
338 && ((d->processEventsFlags & QEventLoop::DialogExec)
339 || (d->processEventsFlags & QEventLoop::EventLoopExec)));
341 if (canExec_Qt && canExec_3rdParty) {
345 if (NSModalSession session = d->currentModalSession()) {
346 QScopedValueRollback execGuard(d->currentExecIsNSAppRun,
false);
347 qCDebug(lcEventDispatcher) <<
"Running modal session" << session;
348 while ([NSApp runModalSession:session] == NSModalResponseContinue && !d->interrupt) {
349 qt_mac_waitForMoreEvents(NSModalPanelRunLoopMode);
350 if (session != d->currentModalSessionCached) {
361 if (!d->interrupt && session == d->currentModalSessionCached) {
365 d->temporarilyStopAllModalSessions();
369 if (d->cleanupModalSessionsNeeded)
370 d->cleanupModalSessions();
373 d->nsAppRunCalledByQt =
true;
374 QScopedValueRollback execGuard(d->currentExecIsNSAppRun,
true);
379 int lastSerialCopy = d->lastSerial;
380 const bool hadModalSession = d->currentModalSessionCached;
383 d->ensureNSAppInitialized();
384 if (NSModalSession session = d->currentModalSession()) {
386 if (!excludeUserEvents) {
389 if (flags & QEventLoop::WaitForMoreEvents)
390 qt_mac_waitForMoreEvents(NSModalPanelRunLoopMode);
391 qCDebug(lcEventDispatcher) <<
"Running modal session" << session;
392 NSInteger status = [NSApp runModalSession:session];
393 if (status != NSModalResponseContinue && session == d->currentModalSessionCached) {
397 d->temporarilyStopAllModalSessions();
401 if (d->cleanupModalSessionsNeeded)
402 d->cleanupModalSessions();
409 event = [NSApp nextEventMatchingMask:NSEventMaskAny
411 inMode:NSModalPanelRunLoopMode
415 if (isUserInputEvent(event)) {
417 d->queuedUserInputEvents.append(event);
420 if (!filterNativeEvent(
"NSEvent", event,
nullptr)) {
421 [NSApp sendEvent:event];
425 }
while (!d->interrupt && event);
428 event = [NSApp nextEventMatchingMask:NSEventMaskAny
430 inMode:NSDefaultRunLoopMode
434 if (flags & QEventLoop::ExcludeUserInputEvents) {
435 if (isUserInputEvent(event)) {
437 d->queuedUserInputEvents.append(event);
441 if (!filterNativeEvent(
"NSEvent", event,
nullptr)) {
442 [NSApp sendEvent:event];
448 if (d->cleanupModalSessionsNeeded)
449 d->cleanupModalSessions();
451 }
while (!d->interrupt && event);
453 if ((d->processEventsFlags & QEventLoop::EventLoopExec) == 0) {
455 bool oldInterrupt = d->interrupt;
456 d->processPostedEvents();
457 if (!oldInterrupt && d->interrupt && !d->currentModalSession()) {
463 d->propagateInterrupt =
true;
465 retVal = d->processTimers() || retVal;
469 retVal = retVal || lastSerialCopy != d->lastSerial;
476 if (hadModalSession && !d->currentModalSessionCached)
477 interruptLater =
true;
479 bool canWait = (d->threadData.loadRelaxed()->canWait
482 && (d->processEventsFlags & QEventLoop::WaitForMoreEvents));
486 qt_mac_waitForMoreEvents();
487 d->processEventsFlags &= ~QEventLoop::WaitForMoreEvents;
495 d->processEventsFlags = oldflags;
496 --d->processEventsCalled;
609 if (cocoaModalSessionStack.isEmpty())
612 int sessionCount = cocoaModalSessionStack.size();
613 for (
int i=0; i<sessionCount; ++i) {
614 QCocoaModalSessionInfo &info = cocoaModalSessionStack[i];
619 QMacAutoReleasePool pool;
623 NSWindow *nswindow = cocoaWindow->nativeWindow();
629 info.nswindow = nswindow;
630 [(NSWindow*) info.nswindow retain];
631 QRect rect = cocoaWindow->geometry();
632 info.session = [NSApp beginModalSessionForWindow:nswindow];
633 qCDebug(lcEventDispatcher) <<
"Begun modal session" << info.session
634 <<
"for" << nswindow;
640 cocoaWindow =
static_cast<
QCocoaWindow *>(info.window->handle());
644 if (rect != cocoaWindow->geometry())
645 cocoaWindow->setGeometry(rect);
778 Q_D(QCocoaEventDispatcher);
780 d->cfSocketNotifier.setHostEventDispatcher(
this);
781 d->cfSocketNotifier.setMaybeCancelWaitForMoreEventsCallback(qt_mac_maybeCancelWaitForMoreEventsForwarder);
784 CFRunLoopAddCommonMode(mainRunLoop(), (CFStringRef) NSModalPanelRunLoopMode);
786 CFRunLoopSourceContext context;
787 bzero(&context,
sizeof(CFRunLoopSourceContext));
789 context.equal = runLoopSourceEqualCallback;
793 d->activateTimersSourceRef = CFRunLoopSourceCreate(kCFAllocatorDefault, 0, &context);
794 Q_ASSERT(d->activateTimersSourceRef);
795 CFRunLoopAddSource(mainRunLoop(), d->activateTimersSourceRef, kCFRunLoopCommonModes);
799 d->postedEventsSource = CFRunLoopSourceCreate(kCFAllocatorDefault, 0, &context);
800 Q_ASSERT(d->postedEventsSource);
801 CFRunLoopAddSource(mainRunLoop(), d->postedEventsSource, kCFRunLoopCommonModes);
804 CFRunLoopObserverContext observerContext;
805 bzero(&observerContext,
sizeof(CFRunLoopObserverContext));
806 observerContext.info =
this;
807 d->waitingObserver = CFRunLoopObserverCreate(kCFAllocatorDefault,
808 kCFRunLoopBeforeWaiting | kCFRunLoopAfterWaiting,
810 QCocoaEventDispatcherPrivate::waitingObserverCallback,
812 CFRunLoopAddObserver(mainRunLoop(), d->waitingObserver, kCFRunLoopCommonModes);
949 Q_D(QCocoaEventDispatcher);
951 d->timerInfoList.clearTimers();
952 d->maybeStopCFRunLoopTimer();
953 CFRunLoopRemoveSource(mainRunLoop(), d->activateTimersSourceRef, kCFRunLoopCommonModes);
954 CFRelease(d->activateTimersSourceRef);
957 for (
int i = 0; i < d->cocoaModalSessionStack.count(); ++i) {
958 QCocoaModalSessionInfo &info = d->cocoaModalSessionStack[i];
960 qCDebug(lcEventDispatcher) <<
"Ending modal session" << info.session
961 <<
"for" << info.nswindow <<
"during shutdown";
962 [NSApp endModalSession:info.session];
963 [(NSWindow *)info.nswindow release];
968 for (
int i = 0; i < d->queuedUserInputEvents.count(); ++i) {
969 NSEvent *nsevent =
static_cast<NSEvent *>(d->queuedUserInputEvents.at(i));
973 d->cfSocketNotifier.removeSocketNotifiers();
975 CFRunLoopRemoveSource(mainRunLoop(), d->postedEventsSource, kCFRunLoopCommonModes);
976 CFRelease(d->postedEventsSource);
978 CFRunLoopObserverInvalidate(d->waitingObserver);
979 CFRelease(d->waitingObserver);