void nsBaseAppShell::NativeEventCallback() { PRInt32 hasPending = PR_AtomicSet(&mNativeEventPending, 0); if (hasPending == 0) return; // If DoProcessNextNativeEvent is on the stack, then we assume that we can // just unwind and let nsThread::ProcessNextEvent process the next event. // However, if we are called from a nested native event loop (maybe via some // plug-in or library function), then go ahead and process Gecko events now. if (mEventloopNestingState == eEventloopXPCOM) { mEventloopNestingState = eEventloopOther; // XXX there is a tiny risk we will never get a new NativeEventCallback, // XXX see discussion in bug 389931. return; } // nsBaseAppShell::Run is not being used to pump events, so this may be // our only opportunity to process pending gecko events. nsIThread *thread = NS_GetCurrentThread(); PRBool prevBlockNativeEvent = mBlockNativeEvent; if (mEventloopNestingState == eEventloopOther) { if (!NS_HasPendingEvents(thread)) return; // We're in a nested native event loop and have some gecko events to // process. While doing that we block processing native events from the // appshell - instead, we want to get back to the nested native event // loop ASAP (bug 420148). mBlockNativeEvent = PR_TRUE; } ++mEventloopNestingLevel; EventloopNestingState prevVal = mEventloopNestingState; NS_ProcessPendingEvents(thread, THREAD_EVENT_STARVATION_LIMIT); mEventloopNestingState = prevVal; mBlockNativeEvent = prevBlockNativeEvent; // Continue processing pending events later (we don't want to starve the // embedders event loop). if (NS_HasPendingEvents(thread)) OnDispatchedEvent(nsnull); --mEventloopNestingLevel; }
// Called from the main thread NS_IMETHODIMP nsBaseAppShell::OnProcessNextEvent(nsIThreadInternal *thr, bool mayWait, uint32_t recursionDepth) { if (mBlockNativeEvent) { if (!mayWait) return NS_OK; // Hmm, we're in a nested native event loop and would like to get // back to it ASAP, but it seems a gecko event has caused us to // spin up a nested XPCOM event loop (eg. modal window), so we // really must start processing native events here again. mBlockNativeEvent = false; if (NS_HasPendingEvents(thr)) OnDispatchedEvent(thr); // in case we blocked it earlier } PRIntervalTime start = PR_IntervalNow(); PRIntervalTime limit = THREAD_EVENT_STARVATION_LIMIT; // Unblock outer nested wait loop (below). if (mBlockedWait) *mBlockedWait = false; bool *oldBlockedWait = mBlockedWait; mBlockedWait = &mayWait; // When mayWait is true, we need to make sure that there is an event in the // thread's event queue before we return. Otherwise, the thread will block // on its event queue waiting for an event. bool needEvent = mayWait; // Reset prior to invoking DoProcessNextNativeEvent which might cause // NativeEventCallback to process gecko events. mProcessedGeckoEvents = false; if (mFavorPerf <= 0 && start > mSwitchTime + mStarvationDelay) { // Favor pending native events PRIntervalTime now = start; bool keepGoing; do { mLastNativeEventTime = now; keepGoing = DoProcessNextNativeEvent(false, recursionDepth); } while (keepGoing && ((now = PR_IntervalNow()) - start) < limit); } else { // Avoid starving native events completely when in performance mode if (start - mLastNativeEventTime > limit) { mLastNativeEventTime = start; DoProcessNextNativeEvent(false, recursionDepth); } } while (!NS_HasPendingEvents(thr) && !mProcessedGeckoEvents) { // If we have been asked to exit from Run, then we should not wait for // events to process. Note that an inner nested event loop causes // 'mayWait' to become false too, through 'mBlockedWait'. if (mExiting) mayWait = false; mLastNativeEventTime = PR_IntervalNow(); if (!DoProcessNextNativeEvent(mayWait, recursionDepth) || !mayWait) break; } mBlockedWait = oldBlockedWait; // Make sure that the thread event queue does not block on its monitor, as // it normally would do if it did not have any pending events. To avoid // that, we simply insert a dummy event into its queue during shutdown. if (needEvent && !mExiting && !NS_HasPendingEvents(thr)) { DispatchDummyEvent(thr); } // We're about to run an event, so we're in a stable state. RunSyncSections(true, recursionDepth); return NS_OK; }
// Note, this is currently overidden on windows, see comments in nsAppShell for // details. void nsBaseAppShell::DoProcessMoreGeckoEvents() { OnDispatchedEvent(nullptr); }