diff options
Diffstat (limited to 'src/plugins/platforms/cocoa/qcocoaeventdispatcher.mm')
-rw-r--r-- | src/plugins/platforms/cocoa/qcocoaeventdispatcher.mm | 132 |
1 files changed, 74 insertions, 58 deletions
diff --git a/src/plugins/platforms/cocoa/qcocoaeventdispatcher.mm b/src/plugins/platforms/cocoa/qcocoaeventdispatcher.mm index bf9ba4eccf..b0f2b6d940 100644 --- a/src/plugins/platforms/cocoa/qcocoaeventdispatcher.mm +++ b/src/plugins/platforms/cocoa/qcocoaeventdispatcher.mm @@ -120,20 +120,26 @@ void QCocoaEventDispatcherPrivate::runLoopTimerCallback(CFRunLoopTimerRef, void void QCocoaEventDispatcherPrivate::activateTimersSourceCallback(void *info) { QCocoaEventDispatcherPrivate *d = static_cast<QCocoaEventDispatcherPrivate *>(info); - (void) d->timerInfoList.activateTimers(); - d->maybeStartCFRunLoopTimer(); + d->processTimers(); d->maybeCancelWaitForMoreEvents(); } +bool QCocoaEventDispatcherPrivate::processTimers() +{ + int activated = timerInfoList.activateTimers(); + maybeStartCFRunLoopTimer(); + return activated > 0; +} + void QCocoaEventDispatcherPrivate::maybeStartCFRunLoopTimer() { if (timerInfoList.isEmpty()) { // no active timers, so the CFRunLoopTimerRef should not be active either - Q_ASSERT(runLoopTimerRef == 0); + Q_ASSERT(!runLoopTimerRef); return; } - if (runLoopTimerRef == 0) { + if (!runLoopTimerRef) { // start the CFRunLoopTimer CFAbsoluteTime ttf = CFAbsoluteTimeGetCurrent(); CFTimeInterval interval; @@ -150,11 +156,11 @@ void QCocoaEventDispatcherPrivate::maybeStartCFRunLoopTimer() } ttf += interval; - CFRunLoopTimerContext info = { 0, this, 0, 0, 0 }; + CFRunLoopTimerContext info = { 0, this, nullptr, nullptr, nullptr }; // create the timer with a large interval, as recommended by the CFRunLoopTimerSetNextFireDate() // documentation, since we will adjust the timer's time-to-fire as needed to keep Qt timers working - runLoopTimerRef = CFRunLoopTimerCreate(0, ttf, oneyear, 0, 0, QCocoaEventDispatcherPrivate::runLoopTimerCallback, &info); - Q_ASSERT(runLoopTimerRef != 0); + runLoopTimerRef = CFRunLoopTimerCreate(nullptr, ttf, oneyear, 0, 0, QCocoaEventDispatcherPrivate::runLoopTimerCallback, &info); + Q_ASSERT(runLoopTimerRef); CFRunLoopAddTimer(mainRunLoop(), runLoopTimerRef, kCFRunLoopCommonModes); } else { @@ -180,12 +186,12 @@ void QCocoaEventDispatcherPrivate::maybeStartCFRunLoopTimer() void QCocoaEventDispatcherPrivate::maybeStopCFRunLoopTimer() { - if (runLoopTimerRef == 0) + if (!runLoopTimerRef) return; CFRunLoopTimerInvalidate(runLoopTimerRef); CFRelease(runLoopTimerRef); - runLoopTimerRef = 0; + runLoopTimerRef = nullptr; } void QCocoaEventDispatcher::registerTimer(int timerId, int interval, Qt::TimerType timerType, QObject *obj) @@ -293,25 +299,25 @@ static bool IsMouseOrKeyEvent( NSEvent* event ) switch( [event type] ) { - case NSLeftMouseDown: - case NSLeftMouseUp: - case NSRightMouseDown: - case NSRightMouseUp: - case NSMouseMoved: // ?? - case NSLeftMouseDragged: - case NSRightMouseDragged: - case NSMouseEntered: - case NSMouseExited: - case NSKeyDown: - case NSKeyUp: - case NSFlagsChanged: // key modifiers changed? - case NSCursorUpdate: // ?? - case NSScrollWheel: - case NSTabletPoint: - case NSTabletProximity: - case NSOtherMouseDown: - case NSOtherMouseUp: - case NSOtherMouseDragged: + case NSEventTypeLeftMouseDown: + case NSEventTypeLeftMouseUp: + case NSEventTypeRightMouseDown: + case NSEventTypeRightMouseUp: + case NSEventTypeMouseMoved: // ?? + case NSEventTypeLeftMouseDragged: + case NSEventTypeRightMouseDragged: + case NSEventTypeMouseEntered: + case NSEventTypeMouseExited: + case NSEventTypeKeyDown: + case NSEventTypeKeyUp: + case NSEventTypeFlagsChanged: // key modifiers changed? + case NSEventTypeCursorUpdate: // ?? + case NSEventTypeScrollWheel: + case NSEventTypeTabletPoint: + case NSEventTypeTabletProximity: + case NSEventTypeOtherMouseDown: + case NSEventTypeOtherMouseUp: + case NSEventTypeOtherMouseDragged: #ifndef QT_NO_GESTURES case NSEventTypeGesture: // touch events case NSEventTypeMagnify: @@ -335,7 +341,7 @@ static inline void qt_mac_waitForMoreEvents(NSString *runLoopMode = NSDefaultRun // at least one event occur. Setting 'dequeuing' to 'no' in the following call // causes it to hang under certain circumstances (QTBUG-28283), so we tell it // to dequeue instead, just to repost the event again: - NSEvent* event = [NSApp nextEventMatchingMask:NSAnyEventMask + NSEvent* event = [NSApp nextEventMatchingMask:NSEventMaskAny untilDate:[NSDate distantFuture] inMode:runLoopMode dequeue:YES]; @@ -368,13 +374,13 @@ bool QCocoaEventDispatcher::processEvents(QEventLoop::ProcessEventsFlags flags) break; QMacAutoReleasePool pool; - NSEvent* event = 0; + NSEvent* event = nil; // First, send all previously excluded input events, if any: if (!excludeUserEvents) { while (!d->queuedUserInputEvents.isEmpty()) { event = static_cast<NSEvent *>(d->queuedUserInputEvents.takeFirst()); - if (!filterNativeEvent("NSEvent", event, 0)) { + if (!filterNativeEvent("NSEvent", event, nullptr)) { [NSApp sendEvent:event]; retVal = true; } @@ -432,7 +438,7 @@ bool QCocoaEventDispatcher::processEvents(QEventLoop::ProcessEventsFlags flags) retVal = true; } else { int lastSerialCopy = d->lastSerial; - bool hadModalSession = d->currentModalSessionCached != 0; + const bool hadModalSession = d->currentModalSessionCached; // We cannot block the thread (and run in a tight loop). // Instead we will process all current pending events and return. d->ensureNSAppInitialized(); @@ -460,7 +466,7 @@ bool QCocoaEventDispatcher::processEvents(QEventLoop::ProcessEventsFlags flags) // Dispatch all non-user events (but que non-user events up for later). In // this case, we need more control over which events gets dispatched, and // cannot use [NSApp runModalSession:session]: - event = [NSApp nextEventMatchingMask:NSAnyEventMask + event = [NSApp nextEventMatchingMask:NSEventMaskAny untilDate:nil inMode:NSModalPanelRunLoopMode dequeue: YES]; @@ -471,15 +477,15 @@ bool QCocoaEventDispatcher::processEvents(QEventLoop::ProcessEventsFlags flags) d->queuedUserInputEvents.append(event); continue; } - if (!filterNativeEvent("NSEvent", event, 0)) { + if (!filterNativeEvent("NSEvent", event, nullptr)) { [NSApp sendEvent:event]; retVal = true; } } - } while (!d->interrupt && event != nil); + } while (!d->interrupt && event); } else do { // INVARIANT: No modal window is executing. - event = [NSApp nextEventMatchingMask:NSAnyEventMask + event = [NSApp nextEventMatchingMask:NSEventMaskAny untilDate:nil inMode:NSDefaultRunLoopMode dequeue: YES]; @@ -492,18 +498,17 @@ bool QCocoaEventDispatcher::processEvents(QEventLoop::ProcessEventsFlags flags) continue; } } - if (!filterNativeEvent("NSEvent", event, 0)) { + if (!filterNativeEvent("NSEvent", event, nullptr)) { [NSApp sendEvent:event]; retVal = true; } } - } while (!d->interrupt && event != nil); + } while (!d->interrupt && event); if ((d->processEventsFlags & QEventLoop::EventLoopExec) == 0) { - // when called "manually", always send posted events and timers + // When called "manually", always process posted events and timers d->processPostedEvents(); - retVal = d->timerInfoList.activateTimers() > 0 || retVal; - d->maybeStartCFRunLoopTimer(); + retVal = d->processTimers() || retVal; } // be sure to return true if the posted event source fired @@ -514,7 +519,7 @@ bool QCocoaEventDispatcher::processEvents(QEventLoop::ProcessEventsFlags flags) // event recursion to ensure that we spin the correct modal session. // We do the interruptLater at the end of the function to ensure that we don't // disturb the 'wait for more events' below (as deleteLater will post an event): - if (hadModalSession && d->currentModalSessionCached == 0) + if (hadModalSession && !d->currentModalSessionCached) interruptLater = true; } bool canWait = (d->threadData->canWait @@ -611,11 +616,11 @@ void QCocoaEventDispatcherPrivate::temporarilyStopAllModalSessions() QCocoaModalSessionInfo &info = cocoaModalSessionStack[i]; if (info.session) { [NSApp endModalSession:info.session]; - info.session = 0; + info.session = nullptr; [(NSWindow*) info.nswindow release]; } } - currentModalSessionCached = 0; + currentModalSessionCached = nullptr; } NSModalSession QCocoaEventDispatcherPrivate::currentModalSession() @@ -626,7 +631,7 @@ NSModalSession QCocoaEventDispatcherPrivate::currentModalSession() return currentModalSessionCached; if (cocoaModalSessionStack.isEmpty()) - return 0; + return nullptr; int sessionCount = cocoaModalSessionStack.size(); for (int i=0; i<sessionCount; ++i) { @@ -637,6 +642,8 @@ NSModalSession QCocoaEventDispatcherPrivate::currentModalSession() if (!info.session) { QMacAutoReleasePool pool; QCocoaWindow *cocoaWindow = static_cast<QCocoaWindow *>(info.window->handle()); + if (!cocoaWindow) + continue; NSWindow *nswindow = cocoaWindow->nativeWindow(); if (!nswindow) continue; @@ -647,6 +654,15 @@ NSModalSession QCocoaEventDispatcherPrivate::currentModalSession() [(NSWindow*) info.nswindow retain]; QRect rect = cocoaWindow->geometry(); info.session = [NSApp beginModalSessionForWindow:nswindow]; + + // The call to beginModalSessionForWindow above processes events and may + // have deleted or destroyed the window. Check if it's still valid. + if (!info.window) + continue; + cocoaWindow = static_cast<QCocoaWindow *>(info.window->handle()); + if (!cocoaWindow) + continue; + if (rect != cocoaWindow->geometry()) cocoaWindow->setGeometry(rect); } @@ -717,9 +733,9 @@ void QCocoaEventDispatcherPrivate::cleanupModalSessions() currentModalSessionCached = info.session; break; } - currentModalSessionCached = 0; + currentModalSessionCached = nullptr; if (info.session) { - Q_ASSERT(info.nswindow != 0); + Q_ASSERT(info.nswindow); [NSApp endModalSession:info.session]; [(NSWindow *)info.nswindow release]; } @@ -746,10 +762,10 @@ void QCocoaEventDispatcherPrivate::beginModalSession(QWindow *window) // currentModalSession). A QCocoaModalSessionInfo is considered pending to be stopped if // the window pointer is zero, and the session pointer is non-zero (it will be fully // stopped in cleanupModalSessions()). - QCocoaModalSessionInfo info = {window, 0, 0}; + QCocoaModalSessionInfo info = {window, nullptr, nullptr}; cocoaModalSessionStack.push(info); updateChildrenWorksWhenModal(); - currentModalSessionCached = 0; + currentModalSessionCached = nullptr; } void QCocoaEventDispatcherPrivate::endModalSession(QWindow *window) @@ -768,12 +784,12 @@ void QCocoaEventDispatcherPrivate::endModalSession(QWindow *window) if (!info.window) endedSessions++; if (info.window == window) { - info.window = 0; + info.window = nullptr; if (i + endedSessions == stackSize-1) { // The top sessions ended. Interrupt the event dispatcher to // start spinning the correct session immediately. q->interrupt(); - currentModalSessionCached = 0; + currentModalSessionCached = nullptr; cleanupModalSessionsNeeded = true; } } @@ -782,13 +798,13 @@ void QCocoaEventDispatcherPrivate::endModalSession(QWindow *window) QCocoaEventDispatcherPrivate::QCocoaEventDispatcherPrivate() : processEventsFlags(0), - runLoopTimerRef(0), + runLoopTimerRef(nullptr), blockSendPostedEvents(false), currentExecIsNSAppRun(false), nsAppRunCalledByQt(false), cleanupModalSessionsNeeded(false), processEventsCalled(0), - currentModalSessionCached(0), + currentModalSessionCached(nullptr), lastSerial(-1), interrupt(false) { @@ -925,8 +941,8 @@ void QCocoaEventDispatcherPrivate::cancelWaitForMoreEvents() // In case the event dispatcher is waiting for more // events somewhere, we post a dummy event to wake it up: QMacAutoReleasePool pool; - [NSApp postEvent:[NSEvent otherEventWithType:NSApplicationDefined location:NSZeroPoint - modifierFlags:0 timestamp:0. windowNumber:0 context:0 + [NSApp postEvent:[NSEvent otherEventWithType:NSEventTypeApplicationDefined location:NSZeroPoint + modifierFlags:0 timestamp:0. windowNumber:0 context:nil subtype:QtCocoaEventSubTypeWakeup data1:0 data2:0] atStart:NO]; } @@ -1008,7 +1024,7 @@ QCocoaEventDispatcher::~QCocoaEventDispatcher() CFRelease(d->firstTimeObserver); } -QtCocoaInterruptDispatcher* QtCocoaInterruptDispatcher::instance = 0; +QtCocoaInterruptDispatcher* QtCocoaInterruptDispatcher::instance = nullptr; QtCocoaInterruptDispatcher::QtCocoaInterruptDispatcher() : cancelled(false) { @@ -1025,7 +1041,7 @@ QtCocoaInterruptDispatcher::~QtCocoaInterruptDispatcher() { if (cancelled) return; - instance = 0; + instance = nullptr; QCocoaEventDispatcher::instance()->interrupt(); } @@ -1035,7 +1051,7 @@ void QtCocoaInterruptDispatcher::cancelInterruptLater() return; instance->cancelled = true; delete instance; - instance = 0; + instance = nullptr; } void QtCocoaInterruptDispatcher::interruptLater() |