Beispiel #1
0
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);
}