1 /* -*- Mode: c++; tab-width: 2; indent-tabs-mode: nil; -*- */ 2 /* This Source Code Form is subject to the terms of the Mozilla Public 3 * License, v. 2.0. If a copy of the MPL was not distributed with this 4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 5 6 #ifndef nsBaseAppShell_h__ 7 #define nsBaseAppShell_h__ 8 9 #include "mozilla/Atomics.h" 10 #include "nsIAppShell.h" 11 #include "nsIThreadInternal.h" 12 #include "nsIObserver.h" 13 #include "nsIRunnable.h" 14 #include "nsCOMPtr.h" 15 #include "nsTArray.h" 16 #include "prinrval.h" 17 18 /** 19 * A singleton that manages the UI thread's event queue. Subclass this class 20 * to enable platform-specific event queue support. 21 */ 22 class nsBaseAppShell : public nsIAppShell, 23 public nsIThreadObserver, 24 public nsIObserver { 25 public: 26 NS_DECL_THREADSAFE_ISUPPORTS 27 NS_DECL_NSIAPPSHELL 28 29 NS_DECL_NSITHREADOBSERVER 30 NS_DECL_NSIOBSERVER 31 32 nsBaseAppShell(); 33 34 protected: 35 virtual ~nsBaseAppShell(); 36 37 /** 38 * This method is called by subclasses when the app shell singleton is 39 * instantiated. 40 */ 41 nsresult Init(); 42 43 /** 44 * Called by subclasses from a native event. See ScheduleNativeEventCallback. 45 */ 46 void NativeEventCallback(); 47 48 /** 49 * Make a decision as to whether or not NativeEventCallback will 50 * trigger gecko event processing when there are pending gecko 51 * events. 52 */ 53 virtual void DoProcessMoreGeckoEvents(); 54 55 /** 56 * Implemented by subclasses. Invoke NativeEventCallback from a native 57 * event. This method may be called on any thread. 58 */ 59 virtual void ScheduleNativeEventCallback() = 0; 60 61 /** 62 * Implemented by subclasses. Process the next native event. Only wait for 63 * the next native event if mayWait is true. This method is only called on 64 * the main application thread. 65 * 66 * @param mayWait 67 * If "true", then this method may wait if necessary for the next available 68 * native event. DispatchNativeEvent may be called to unblock a call to 69 * ProcessNextNativeEvent that is waiting. 70 * @return 71 * This method returns "true" if a native event was processed. 72 */ 73 virtual bool ProcessNextNativeEvent(bool mayWait) = 0; 74 75 int32_t mSuspendNativeCount; 76 uint32_t mEventloopNestingLevel; 77 78 private: 79 bool DoProcessNextNativeEvent(bool mayWait); 80 81 bool DispatchDummyEvent(nsIThread* target); 82 83 void IncrementEventloopNestingLevel(); 84 void DecrementEventloopNestingLevel(); 85 86 nsCOMPtr<nsIRunnable> mDummyEvent; 87 /** 88 * mBlockedWait points back to a slot that controls the wait loop in 89 * an outer OnProcessNextEvent invocation. Nested calls always set 90 * it to false to unblock an outer loop, since all events may 91 * have been consumed by the inner event loop(s). 92 */ 93 bool* mBlockedWait; 94 int32_t mFavorPerf; 95 mozilla::Atomic<bool> mNativeEventPending; 96 PRIntervalTime mStarvationDelay; 97 PRIntervalTime mSwitchTime; 98 PRIntervalTime mLastNativeEventTime; 99 enum EventloopNestingState { 100 eEventloopNone, // top level thread execution 101 eEventloopXPCOM, // innermost native event loop is ProcessNextNativeEvent 102 eEventloopOther // innermost native event loop is a native library/plugin 103 // etc 104 }; 105 EventloopNestingState mEventloopNestingState; 106 bool mRunning; 107 bool mExiting; 108 /** 109 * mBlockNativeEvent blocks the appshell from processing native events. 110 * It is set to true while a nested native event loop (eEventloopOther) 111 * is processing gecko events in NativeEventCallback(), thus queuing up 112 * native events until we return to that loop (bug 420148). 113 * We force mBlockNativeEvent to false in case handling one of the gecko 114 * events spins up a nested XPCOM event loop (eg. modal window) which would 115 * otherwise lead to a "deadlock" where native events aren't processed at all. 116 */ 117 bool mBlockNativeEvent; 118 /** 119 * Tracks whether we have processed any gecko events in NativeEventCallback so 120 * that we can avoid erroneously entering a blocking loop waiting for gecko 121 * events to show up during OnProcessNextEvent. This is required because on 122 * OS X ProcessGeckoEvents may be invoked inside the context of 123 * ProcessNextNativeEvent and may result in NativeEventCallback being invoked 124 * and in turn invoking NS_ProcessPendingEvents. Because 125 * ProcessNextNativeEvent may be invoked prior to the NS_HasPendingEvents 126 * waiting loop, this is the only way to make the loop aware that events may 127 * have been processed. 128 * 129 * This variable is set to false in OnProcessNextEvent prior to the first 130 * call to DoProcessNextNativeEvent. It is set to true by 131 * NativeEventCallback after calling NS_ProcessPendingEvents. 132 */ 133 bool mProcessedGeckoEvents; 134 }; 135 136 #endif // nsBaseAppShell_h__ 137