michael@0: /* -*- Mode: c++; tab-width: 2; indent-tabs-mode: nil; -*- */ michael@0: /* This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this michael@0: * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: michael@0: #ifndef nsBaseAppShell_h__ michael@0: #define nsBaseAppShell_h__ michael@0: michael@0: #include "mozilla/Atomics.h" michael@0: #include "nsIAppShell.h" michael@0: #include "nsIThreadInternal.h" michael@0: #include "nsIObserver.h" michael@0: #include "nsIRunnable.h" michael@0: #include "nsCOMPtr.h" michael@0: #include "nsTArray.h" michael@0: #include "prinrval.h" michael@0: michael@0: /** michael@0: * A singleton that manages the UI thread's event queue. Subclass this class michael@0: * to enable platform-specific event queue support. michael@0: */ michael@0: class nsBaseAppShell : public nsIAppShell, public nsIThreadObserver, michael@0: public nsIObserver michael@0: { michael@0: public: michael@0: NS_DECL_THREADSAFE_ISUPPORTS michael@0: NS_DECL_NSIAPPSHELL michael@0: NS_DECL_NSITHREADOBSERVER michael@0: NS_DECL_NSIOBSERVER michael@0: michael@0: nsBaseAppShell(); michael@0: michael@0: protected: michael@0: virtual ~nsBaseAppShell(); michael@0: michael@0: /** michael@0: * This method is called by subclasses when the app shell singleton is michael@0: * instantiated. michael@0: */ michael@0: nsresult Init(); michael@0: michael@0: /** michael@0: * Called by subclasses from a native event. See ScheduleNativeEventCallback. michael@0: */ michael@0: void NativeEventCallback(); michael@0: michael@0: /** michael@0: * Make a decision as to whether or not NativeEventCallback will michael@0: * trigger gecko event processing when there are pending gecko michael@0: * events. michael@0: */ michael@0: virtual void DoProcessMoreGeckoEvents(); michael@0: michael@0: /** michael@0: * Implemented by subclasses. Invoke NativeEventCallback from a native michael@0: * event. This method may be called on any thread. michael@0: */ michael@0: virtual void ScheduleNativeEventCallback() = 0; michael@0: michael@0: /** michael@0: * Implemented by subclasses. Process the next native event. Only wait for michael@0: * the next native event if mayWait is true. This method is only called on michael@0: * the main application thread. michael@0: * michael@0: * @param mayWait michael@0: * If "true", then this method may wait if necessary for the next available michael@0: * native event. DispatchNativeEvent may be called to unblock a call to michael@0: * ProcessNextNativeEvent that is waiting. michael@0: * @return michael@0: * This method returns "true" if a native event was processed. michael@0: */ michael@0: virtual bool ProcessNextNativeEvent(bool mayWait) = 0; michael@0: michael@0: int32_t mSuspendNativeCount; michael@0: uint32_t mEventloopNestingLevel; michael@0: michael@0: private: michael@0: bool DoProcessNextNativeEvent(bool mayWait, uint32_t recursionDepth); michael@0: michael@0: bool DispatchDummyEvent(nsIThread* target); michael@0: michael@0: void IncrementEventloopNestingLevel(); michael@0: void DecrementEventloopNestingLevel(); michael@0: michael@0: /** michael@0: * Runs all synchronous sections which are queued up in mSyncSections. michael@0: */ michael@0: void RunSyncSectionsInternal(bool stable, uint32_t threadRecursionLevel); michael@0: michael@0: void RunSyncSections(bool stable, uint32_t threadRecursionLevel) michael@0: { michael@0: if (!mSyncSections.IsEmpty()) { michael@0: RunSyncSectionsInternal(stable, threadRecursionLevel); michael@0: } michael@0: } michael@0: michael@0: void ScheduleSyncSection(nsIRunnable* runnable, bool stable); michael@0: michael@0: struct SyncSection { michael@0: SyncSection() michael@0: : mStable(false), mEventloopNestingLevel(0), mThreadRecursionLevel(0) michael@0: { } michael@0: michael@0: void Forget(SyncSection* other) { michael@0: other->mStable = mStable; michael@0: other->mEventloopNestingLevel = mEventloopNestingLevel; michael@0: other->mThreadRecursionLevel = mThreadRecursionLevel; michael@0: other->mRunnable = mRunnable.forget(); michael@0: } michael@0: michael@0: bool mStable; michael@0: uint32_t mEventloopNestingLevel; michael@0: uint32_t mThreadRecursionLevel; michael@0: nsCOMPtr mRunnable; michael@0: }; michael@0: michael@0: nsCOMPtr mDummyEvent; michael@0: /** michael@0: * mBlockedWait points back to a slot that controls the wait loop in michael@0: * an outer OnProcessNextEvent invocation. Nested calls always set michael@0: * it to false to unblock an outer loop, since all events may michael@0: * have been consumed by the inner event loop(s). michael@0: */ michael@0: bool *mBlockedWait; michael@0: int32_t mFavorPerf; michael@0: mozilla::Atomic mNativeEventPending; michael@0: PRIntervalTime mStarvationDelay; michael@0: PRIntervalTime mSwitchTime; michael@0: PRIntervalTime mLastNativeEventTime; michael@0: enum EventloopNestingState { michael@0: eEventloopNone, // top level thread execution michael@0: eEventloopXPCOM, // innermost native event loop is ProcessNextNativeEvent michael@0: eEventloopOther // innermost native event loop is a native library/plugin etc michael@0: }; michael@0: EventloopNestingState mEventloopNestingState; michael@0: nsTArray mSyncSections; michael@0: bool mRunning; michael@0: bool mExiting; michael@0: /** michael@0: * mBlockNativeEvent blocks the appshell from processing native events. michael@0: * It is set to true while a nested native event loop (eEventloopOther) michael@0: * is processing gecko events in NativeEventCallback(), thus queuing up michael@0: * native events until we return to that loop (bug 420148). michael@0: * We force mBlockNativeEvent to false in case handling one of the gecko michael@0: * events spins up a nested XPCOM event loop (eg. modal window) which would michael@0: * otherwise lead to a "deadlock" where native events aren't processed at all. michael@0: */ michael@0: bool mBlockNativeEvent; michael@0: /** michael@0: * Tracks whether we have processed any gecko events in NativeEventCallback so michael@0: * that we can avoid erroneously entering a blocking loop waiting for gecko michael@0: * events to show up during OnProcessNextEvent. This is required because on michael@0: * OS X ProcessGeckoEvents may be invoked inside the context of michael@0: * ProcessNextNativeEvent and may result in NativeEventCallback being invoked michael@0: * and in turn invoking NS_ProcessPendingEvents. Because michael@0: * ProcessNextNativeEvent may be invoked prior to the NS_HasPendingEvents michael@0: * waiting loop, this is the only way to make the loop aware that events may michael@0: * have been processed. michael@0: * michael@0: * This variable is set to false in OnProcessNextEvent prior to the first michael@0: * call to DoProcessNextNativeEvent. It is set to true by michael@0: * NativeEventCallback after calling NS_ProcessPendingEvents. michael@0: */ michael@0: bool mProcessedGeckoEvents; michael@0: }; michael@0: michael@0: #endif // nsBaseAppShell_h__