1 /* -*- Mode: c++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2; -*- */
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/. */
11 #include <type_traits>
14 #include "mozilla/BackgroundHangMonitor.h"
15 #include "mozilla/LinkedList.h"
16 #include "mozilla/Monitor.h"
17 #include "mozilla/StaticPtr.h"
18 #include "mozilla/TimeStamp.h" // for mozilla::TimeDuration
19 #include "mozilla/UniquePtr.h"
20 #include "mozilla/Unused.h"
21 #include "mozilla/jni/Natives.h"
22 #include "nsBaseAppShell.h"
24 #include "nsIAndroidBridge.h"
25 #include "nsInterfaceHashtable.h"
29 bool ProcessNextEvent();
31 } // namespace mozilla
35 class nsAppShell
: public nsBaseAppShell
{
37 struct Event
: mozilla::LinkedListElement
<Event
> {
38 static uint64_t GetTime() {
40 if (clock_gettime(CLOCK_MONOTONIC
, &time
)) {
43 return uint64_t(time
.tv_sec
) * 1000000000ull + time
.tv_nsec
;
46 uint64_t mPostTime
{0};
48 bool HasSameTypeAs(const Event
* other
) const {
49 // Compare vtable addresses to determine same type.
50 return *reinterpret_cast<const uintptr_t*>(this) ==
51 *reinterpret_cast<const uintptr_t*>(other
);
55 virtual void Run() = 0;
57 virtual void PostTo(mozilla::LinkedList
<Event
>& queue
) {
58 queue
.insertBack(this);
61 virtual bool IsUIEvent() const { return false; }
65 class LambdaEvent
: public Event
{
70 explicit LambdaEvent(T
&& l
) : lambda(std::move(l
)) {}
71 void Run() override
{ lambda(); }
74 class ProxyEvent
: public Event
{
76 mozilla::UniquePtr
<Event
> baseEvent
;
79 explicit ProxyEvent(mozilla::UniquePtr
<Event
>&& event
)
80 : baseEvent(std::move(event
)) {}
82 void PostTo(mozilla::LinkedList
<Event
>& queue
) override
{
83 baseEvent
->PostTo(queue
);
86 void Run() override
{ baseEvent
->Run(); }
89 static nsAppShell
* Get() {
90 MOZ_ASSERT(NS_IsMainThread());
96 NS_DECL_ISUPPORTS_INHERITED
101 void NotifyNativeEvent();
102 bool ProcessNextNativeEvent(bool mayWait
) override
;
104 // Post a subclass of Event.
105 // e.g. PostEvent(mozilla::MakeUnique<MyEvent>());
106 template <typename T
, typename D
>
107 static void PostEvent(mozilla::UniquePtr
<T
, D
>&& event
) {
108 mozilla::MutexAutoLock
lock(*sAppShellLock
);
112 sAppShell
->mEventQueue
.Post(std::move(event
));
115 // Post a event that will call a lambda
116 // e.g. PostEvent([=] { /* do something */ });
117 template <typename T
>
118 static void PostEvent(T
&& lambda
) {
119 mozilla::MutexAutoLock
lock(*sAppShellLock
);
123 sAppShell
->mEventQueue
.Post(
124 mozilla::MakeUnique
<LambdaEvent
<T
>>(std::move(lambda
)));
127 // Post a event and wait for it to finish running on the Gecko thread.
128 static bool SyncRunEvent(
130 mozilla::UniquePtr
<Event
> (*eventFactory
)(mozilla::UniquePtr
<Event
>&&) =
132 const mozilla::TimeDuration timeout
= mozilla::TimeDuration::Forever());
134 template <typename T
>
135 static std::enable_if_t
<!std::is_base_of
<Event
, T
>::value
, void> SyncRunEvent(
137 SyncRunEvent(LambdaEvent
<T
>(std::forward
<T
>(lambda
)));
140 static already_AddRefed
<nsIURI
> ResolveURI(const nsCString
& aUriStr
);
143 static nsAppShell
* sAppShell
;
144 static mozilla::StaticAutoPtr
<mozilla::Mutex
> sAppShellLock
;
146 virtual ~nsAppShell();
148 NS_IMETHOD
Exit() override
;
149 nsresult
AddObserver(const nsAString
& aObserverKey
, nsIObserver
* aObserver
);
151 class NativeCallbackEvent
: public Event
{
152 // Capturing the nsAppShell instance is safe because if the app
153 // shell is destroyed, this lambda will not be called either.
154 nsAppShell
* const appShell
;
157 explicit NativeCallbackEvent(nsAppShell
* as
) : appShell(as
) {}
158 void Run() override
{ appShell
->NativeEventCallback(); }
161 void ScheduleNativeEventCallback() override
{
162 mEventQueue
.Post(mozilla::MakeUnique
<NativeCallbackEvent
>(this));
167 mozilla::Monitor mMonitor
;
168 mozilla::LinkedList
<Event
> mQueue
;
171 enum { LATENCY_UI
, LATENCY_OTHER
, LATENCY_COUNT
};
172 Queue() : mMonitor("nsAppShell.Queue") {}
175 mozilla::MonitorAutoLock
lock(mMonitor
);
179 void Post(mozilla::UniquePtr
<Event
>&& event
) {
180 MOZ_ASSERT(event
&& !event
->isInList());
182 mozilla::MonitorAutoLock
lock(mMonitor
);
183 event
->PostTo(mQueue
);
184 if (event
->isInList()) {
185 event
->mPostTime
= Event::GetTime();
186 // Ownership of event object transfers to the queue.
187 mozilla::Unused
<< event
.release();
192 mozilla::UniquePtr
<Event
> Pop(bool mayWait
) {
193 mozilla::MonitorAutoLock
lock(mMonitor
);
195 if (mayWait
&& mQueue
.isEmpty()) {
199 // Ownership of event object transfers to the return value.
200 mozilla::UniquePtr
<Event
> event(mQueue
.popFirst());
201 if (!event
|| !event
->mPostTime
) {
211 mozilla::CondVar mSyncRunFinished
;
214 nsInterfaceHashtable
<nsStringHashKey
, nsIObserver
> mObserversHash
;
217 #endif // nsAppShell_h__