44#include <QtGui/qevent.h>
45#include <QtGui/qguiapplication.h>
46#include <QtGui/private/qguiapplication_p.h>
48#include <QtCore/qmutex.h>
49#include <QtCore/qscopeguard.h>
50#include <QtCore/qsocketnotifier.h>
51#include <QtCore/private/qthread_p.h>
52#include <QtCore/private/qcore_mac_p.h>
54#include <qpa/qplatformwindow.h>
55#include <qpa/qplatformnativeinterface.h>
57#include <QtCore/qdebug.h>
65 return CFRunLoopGetMain();
70 return info1 == info2;
86 CFRunLoopSourceSignal(
d->activateTimersSourceRef);
92 if (
d->initializingNSApplication) {
93 qCDebug(lcEventDispatcher) <<
"Deferring" << __FUNCTION__ <<
"due to NSApp initialization";
96 CFRunLoopSourceSignal(
d->activateTimersSourceRef);
100 d->maybeCancelWaitForMoreEvents();
107 return activated > 0;
118 using DoubleSeconds = std::chrono::duration<double, std::ratio<1>>;
121 CFAbsoluteTime ttf = CFAbsoluteTimeGetCurrent();
122 CFTimeInterval interval;
123 CFTimeInterval oneyear = CFTimeInterval(3600. * 24. * 365.);
128 DoubleSeconds secs{*
opt};
129 interval =
qMax(secs.count(), 0.0000001);
136 CFRunLoopTimerContext
info = { 0,
this,
nullptr,
nullptr,
nullptr };
145 CFAbsoluteTime ttf = CFAbsoluteTimeGetCurrent();
146 CFTimeInterval interval;
151 DoubleSeconds secs{*
opt};
152 interval =
qMax(secs.count(), 0.0000001);
179 qWarning(
"QCocoaEventDispatcher::registerTimer: invalid arguments");
182 qWarning(
"QObject::startTimer: timers cannot be started from another thread");
188 d->timerInfoList.registerTimer(timerId, interval, timerType,
obj);
189 d->maybeStartCFRunLoopTimer();
196 qWarning(
"QCocoaEventDispatcher::unregisterTimer: invalid argument");
199 qWarning(
"QObject::killTimer: timers cannot be stopped from another thread");
205 bool returnValue =
d->timerInfoList.unregisterTimer(timerId);
206 if (!
d->timerInfoList.isEmpty())
207 d->maybeStartCFRunLoopTimer();
209 d->maybeStopCFRunLoopTimer();
217 qWarning(
"QCocoaEventDispatcher::unregisterTimers: invalid argument");
220 qWarning(
"QObject::killTimers: timers cannot be stopped from another thread");
226 bool returnValue =
d->timerInfoList.unregisterTimers(
obj);
227 if (!
d->timerInfoList.isEmpty())
228 d->maybeStartCFRunLoopTimer();
230 d->maybeStopCFRunLoopTimer();
234QList<QCocoaEventDispatcher::TimerInfoV2>
239 qWarning(
"QCocoaEventDispatcher:registeredTimers: invalid argument");
245 return d->timerInfoList.registeredTimers(
object);
258 d->cfSocketNotifier.registerSocketNotifier(
notifier);
264 d->cfSocketNotifier.unregisterSocketNotifier(
notifier);
270 case NSEventTypeLeftMouseDown:
271 case NSEventTypeLeftMouseUp:
272 case NSEventTypeRightMouseDown:
273 case NSEventTypeRightMouseUp:
274 case NSEventTypeMouseMoved:
275 case NSEventTypeLeftMouseDragged:
276 case NSEventTypeRightMouseDragged:
277 case NSEventTypeMouseEntered:
278 case NSEventTypeMouseExited:
279 case NSEventTypeKeyDown:
280 case NSEventTypeKeyUp:
281 case NSEventTypeFlagsChanged:
282 case NSEventTypeCursorUpdate:
283 case NSEventTypeScrollWheel:
284 case NSEventTypeTabletPoint:
285 case NSEventTypeTabletProximity:
286 case NSEventTypeOtherMouseDown:
287 case NSEventTypeOtherMouseUp:
288 case NSEventTypeOtherMouseDragged:
289#ifndef QT_NO_GESTURES
290 case NSEventTypeGesture:
291 case NSEventTypeMagnify:
292 case NSEventTypeSwipe:
293 case NSEventTypeRotate:
294 case NSEventTypeBeginGesture:
295 case NSEventTypeEndGesture:
311 NSEvent*
event = [NSApp nextEventMatchingMask:NSEventMaskAny
312 untilDate:[NSDate distantFuture]
316 [NSApp postEvent:
event atStart:YES];
326 d->propagateInterrupt =
false;
328 if (
d->propagateInterrupt)
330 d->propagateInterrupt =
false;
334 bool interruptLater =
false;
339 uint oldflags =
d->processEventsFlags;
340 d->processEventsFlags =
flags;
345 ++
d->processEventsCalled;
354 NSEvent*
event = nil;
357 if (
d->sendQueuedUserInputEvents())
368 const bool canExec_3rdParty =
d->nsAppRunCalledByQt || ![NSApp
isRunning];
369 const bool canExec_Qt = (!excludeUserEvents
373 if (canExec_Qt && canExec_3rdParty) {
379 qCDebug(lcEventDispatcher) <<
"Running modal session" << session;
380 while ([NSApp runModalSession:session] == NSModalResponseContinue && !
d->interrupt) {
382 if (session !=
d->currentModalSessionCached) {
393 if (!
d->interrupt && session ==
d->currentModalSessionCached) {
397 d->temporarilyStopAllModalSessions();
401 if (
d->cleanupModalSessionsNeeded)
402 d->cleanupModalSessions();
405 d->nsAppRunCalledByQt =
true;
411 int lastSerialCopy =
d->lastSerial;
412 const bool hadModalSession =
d->currentModalSessionCached;
415 d->ensureNSAppInitialized();
418 if (!excludeUserEvents) {
423 qCDebug(lcEventDispatcher) <<
"Running modal session" << session;
424 NSInteger status = [NSApp runModalSession:session];
425 if (status != NSModalResponseContinue && session ==
d->currentModalSessionCached) {
429 d->temporarilyStopAllModalSessions();
433 if (
d->cleanupModalSessionsNeeded)
434 d->cleanupModalSessions();
441 event = [NSApp nextEventMatchingMask:NSEventMaskAny
443 inMode:NSModalPanelRunLoopMode
449 d->queuedUserInputEvents.append(
event);
453 [NSApp sendEvent:
event];
457 }
while (!
d->interrupt &&
event);
460 event = [NSApp nextEventMatchingMask:NSEventMaskAny
462 inMode:NSDefaultRunLoopMode
469 d->queuedUserInputEvents.append(
event);
474 [NSApp sendEvent:
event];
480 if (
d->cleanupModalSessionsNeeded)
481 d->cleanupModalSessions();
483 }
while (!
d->interrupt &&
event);
487 bool oldInterrupt =
d->interrupt;
488 d->processPostedEvents();
489 if (!oldInterrupt &&
d->interrupt && !
d->currentModalSession()) {
495 d->propagateInterrupt =
true;
497 retVal =
d->processTimers() || retVal;
501 retVal = retVal || lastSerialCopy !=
d->lastSerial;
508 if (hadModalSession && !
d->currentModalSessionCached)
509 interruptLater =
true;
511 bool canWait = (
d->threadData.loadRelaxed()->canWait
519 d->processEventsFlags &=
~QEventLoop::WaitForMoreEvents;
527 d->processEventsFlags = oldflags;
528 --
d->processEventsCalled;
548 qWarning(
"QCocoaEventDispatcher::remainingTime: invalid argument");
549 return Duration::min();
554 return d->timerInfoList.remainingDuration(timerId);
560 d->serialNumber.ref();
561 CFRunLoopSourceSignal(
d->postedEventsSource);
592 qCDebug(lcEventDispatcher) <<
"Ensuring NSApplication is initialized";
600 CFRunLoopPerformBlock(
mainRunLoop(), kCFRunLoopCommonModes, ^{
601 qCDebug(lcEventDispatcher) <<
"NSApplication has been initialized; Stopping NSApp";
606 qCDebug(lcEventDispatcher) <<
"Finished ensuring NSApplication is initialized";
621 for (
int i=0;
i<stackSize; ++
i) {
624 qCDebug(lcEventDispatcher) <<
"Temporarily ending modal session" <<
info.session
625 <<
"for" <<
info.nswindow;
627 info.session =
nullptr;
645 for (
int i=0;
i<sessionCount; ++
i) {
661 info.nswindow = nswindow;
662 [(NSWindow*)
info.nswindow retain];
664 info.session = [NSApp beginModalSessionForWindow:nswindow];
665 qCDebug(lcEventDispatcher) <<
"Begun modal session" <<
info.session
666 <<
"for" << nswindow;
702 for (
int i=stackSize-1;
i>=0; --
i) {
715 qCDebug(lcEventDispatcher) <<
"Ending modal session" <<
info.session
716 <<
"for" <<
info.nswindow;
729 qCDebug(lcEventDispatcher) <<
"Adding modal session for" <<
window;
732 [&](
const auto &sessionInfo) { return sessionInfo.window == window; })) {
733 qCWarning(lcEventDispatcher) <<
"Modal session for" <<
window <<
"already exists!";
757 qCDebug(lcEventDispatcher) <<
"Removing modal session for" <<
window;
767 int endedSessions = 0;
768 for (
int i=stackSize-1;
i>=0; --
i) {
773 info.window =
nullptr;
774 if (
i + endedSessions == stackSize-1) {
786 : processEventsFlags(0),
788 blockSendPostedEvents(
false),
789 currentExecIsNSAppRun(
false),
790 nsAppRunCalledByQt(
false),
791 cleanupModalSessionsNeeded(
false),
792 processEventsCalled(0),
793 currentModalSessionCached(
nullptr),
809 d->cfSocketNotifier.setHostEventDispatcher(
this);
813 CFRunLoopAddCommonMode(
mainRunLoop(), (CFStringRef) NSModalPanelRunLoopMode);
815 CFRunLoopSourceContext
context;
816 bzero(&
context,
sizeof(CFRunLoopSourceContext));
822 d->activateTimersSourceRef = CFRunLoopSourceCreate(kCFAllocatorDefault, 0, &
context);
824 CFRunLoopAddSource(
mainRunLoop(),
d->activateTimersSourceRef, kCFRunLoopCommonModes);
828 d->postedEventsSource = CFRunLoopSourceCreate(kCFAllocatorDefault, 0, &
context);
830 CFRunLoopAddSource(
mainRunLoop(),
d->postedEventsSource, kCFRunLoopCommonModes);
833 CFRunLoopObserverContext observerContext;
834 bzero(&observerContext,
sizeof(CFRunLoopObserverContext));
835 observerContext.info =
this;
836 d->waitingObserver = CFRunLoopObserverCreate(kCFAllocatorDefault,
837 kCFRunLoopBeforeWaiting | kCFRunLoopAfterWaiting,
841 CFRunLoopAddObserver(
mainRunLoop(),
d->waitingObserver, kCFRunLoopCommonModes);
845 CFRunLoopActivity activity,
void *
info)
847 if (activity == kCFRunLoopBeforeWaiting)
858 bool didSendEvent =
false;
861 if (!
q->filterNativeEvent(
"NSEvent",
event,
nullptr)) {
862 [NSApp sendEvent:
event];
909 if (
d->initializingNSApplication) {
910 qCDebug(lcEventDispatcher) <<
"Deferring" << __FUNCTION__ <<
"due to NSApp initialization";
913 CFRunLoopSourceSignal(
d->postedEventsSource);
919 d->maybeCancelWaitForMoreEvents();
922 d->sendQueuedUserInputEvents();
923 d->processPostedEvents();
924 d->maybeCancelWaitForMoreEvents();
932 [NSApp postEvent:[NSEvent otherEventWithType:NSEventTypeApplicationDefined
location:NSZeroPoint
933 modifierFlags:0 timestamp:0. windowNumber:0
context:nil
934 subtype:QtCocoaEventSubTypeWakeup data1:0 data2:0] atStart:NO];
960 d->cancelWaitForMoreEvents();
969 if (!cocoaEventDispatcher)
973 cocoaEventDispatcherPrivate->
interrupt =
false;
980 d->timerInfoList.clearTimers();
981 d->maybeStopCFRunLoopTimer();
982 CFRunLoopRemoveSource(
mainRunLoop(),
d->activateTimersSourceRef, kCFRunLoopCommonModes);
983 CFRelease(
d->activateTimersSourceRef);
986 for (
int i = 0;
i <
d->cocoaModalSessionStack.count(); ++
i) {
989 qCDebug(lcEventDispatcher) <<
"Ending modal session" <<
info.session
990 <<
"for" <<
info.nswindow <<
"during shutdown";
991 [NSApp endModalSession:
info.session];
997 for (
int i = 0;
i <
d->queuedUserInputEvents.count(); ++
i) {
998 NSEvent *nsevent =
static_cast<NSEvent *
>(
d->queuedUserInputEvents.at(
i));
1002 d->cfSocketNotifier.removeSocketNotifiers();
1004 CFRunLoopRemoveSource(
mainRunLoop(),
d->postedEventsSource, kCFRunLoopCommonModes);
1005 CFRelease(
d->postedEventsSource);
1007 CFRunLoopObserverInvalidate(
d->waitingObserver);
1008 CFRelease(
d->waitingObserver);
1013QtCocoaInterruptDispatcher::QtCocoaInterruptDispatcher() :
cancelled(
false)
1024QtCocoaInterruptDispatcher::~QtCocoaInterruptDispatcher()
1036 instance->cancelled =
true;
DarwinBluetooth::LECBManagerNotifier * notifier
static QAbstractEventDispatcher * instance(QThread *thread=nullptr)
Returns a pointer to the event dispatcher object for the specified thread.
bool filterNativeEvent(const QByteArray &eventType, void *message, qintptr *result)
Sends message through the event filters that were set by installNativeEventFilter().
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.
T loadRelaxed() const noexcept
Type loadRelaxed() const noexcept
void beginModalSession(QWindow *widget)
void endModalSession(QWindow *widget)
NSModalSession currentModalSessionCached
bool sendQueuedUserInputEvents()
static void postedEventsSourceCallback(void *info)
bool blockSendPostedEvents
QCocoaEventDispatcherPrivate()
void temporarilyStopAllModalSessions()
CFRunLoopSourceRef postedEventsSource
static void runLoopTimerCallback(CFRunLoopTimerRef, void *info)
void processPostedEvents()
QList< void * > queuedUserInputEvents
CFRunLoopTimerRef runLoopTimerRef
void maybeCancelWaitForMoreEvents()
bool hasModalSession() const
static void activateTimersSourceCallback(void *info)
void maybeStopCFRunLoopTimer()
void cancelWaitForMoreEvents()
void cleanupModalSessions()
void ensureNSAppInitialized()
static void waitingObserverCallback(CFRunLoopObserverRef observer, CFRunLoopActivity activity, void *info)
QTimerInfoList timerInfoList
NSModalSession currentModalSession()
bool initializingNSApplication
bool cleanupModalSessionsNeeded
void maybeStartCFRunLoopTimer()
QStack< QCocoaModalSessionInfo > cocoaModalSessionStack
bool currentExecIsNSAppRun
QList< TimerInfoV2 > timersForObject(QObject *object) const final
void interrupt()
Interrupts event dispatching.
void unregisterSocketNotifier(QSocketNotifier *notifier)
Unregisters notifier from the event dispatcher.
void registerSocketNotifier(QSocketNotifier *notifier)
Registers notifier with the event loop.
QCocoaEventDispatcher(QAbstractEventDispatcherPrivate &priv, QObject *parent=nullptr)
bool unregisterTimers(QObject *object) final
Unregisters all the timers associated with the given object.
void registerTimer(Qt::TimerId timerId, Duration interval, Qt::TimerType timerType, QObject *object) final
Duration remainingTime(Qt::TimerId timerId) const final
Returns the remaining time of the timer with the given timerId.
bool unregisterTimer(Qt::TimerId timerId) final
friend void qt_mac_maybeCancelWaitForMoreEventsForwarder(QAbstractEventDispatcher *eventDispatcher)
static void clearCurrentThreadCocoaEventDispatcherInterruptFlag()
bool processEvents(QEventLoop::ProcessEventsFlags flags)
Processes pending events that match flags until there are no more events to process.
QRect geometry() const override
Returns the current geometry of a window.
NSWindow * nativeWindow() const
void setGeometry(const QRect &rect) override
This function is called by Qt whenever a window is moved or resized using the QWindow API.
static void sendPostedEvents(QObject *receiver=nullptr, int event_type=0)
Immediately dispatches all events which have been previously queued with QCoreApplication::postEvent(...
bool isEmpty() const noexcept
static QObjectPrivate * get(QObject *o)
QAtomicPointer< QThreadData > threadData
QThread * thread() const
Returns the thread in which the object lives.
void deleteLater()
\threadsafe
\inmodule QtCore\reentrant
static QThread * currentThread()
std::optional< Duration > timerWait()
static bool sendWindowSystemEvents(QEventLoop::ProcessEventsFlags flags)
static void cancelInterruptLater()
static void interruptLater()
Combined button and popup list for selecting options.
struct _NSModalSession * NSModalSession
static CFRunLoopRef mainRunLoop()
static void qt_mac_waitForMoreEvents(NSString *runLoopMode=NSDefaultRunLoopMode)
static Boolean runLoopSourceEqualCallback(const void *info1, const void *info2)
void qt_mac_maybeCancelWaitForMoreEventsForwarder(QAbstractEventDispatcher *eventDispatcher)
static bool isUserInputEvent(NSEvent *event)
#define Q_LOGGING_CATEGORY(name,...)
#define qCWarning(category,...)
#define qCDebug(category,...)
constexpr const T & qMax(const T &a, const T &b)
GLdouble GLdouble GLdouble GLdouble q
QScopeGuard< typename std::decay< F >::type > qScopeGuard(F &&f)
[qScopeGuard]
QT_BEGIN_NAMESPACE constexpr std::underlying_type_t< Enum > qToUnderlying(Enum e) noexcept