/* -*- Mode: c++; tab-width: 40; indent-tabs-mode: nil; c-basic-offset: 4; -*- */ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #ifndef nsAppShell_h__ #define nsAppShell_h__ #include "mozilla/HangMonitor.h" #include "mozilla/LinkedList.h" #include "mozilla/Monitor.h" #include "mozilla/Move.h" #include "mozilla/UniquePtr.h" #include "mozilla/unused.h" #include "mozilla/jni/Natives.h" #include "nsBaseAppShell.h" #include "nsCOMPtr.h" #include "nsTArray.h" #include "nsInterfaceHashtable.h" #include "nsIAndroidBridge.h" namespace mozilla { class AndroidGeckoEvent; bool ProcessNextEvent(); void NotifyEvent(); } class nsWindow; class nsAppShell : public nsBaseAppShell { public: struct Event : mozilla::LinkedListElement { bool HasSameTypeAs(const Event* other) const { // Compare vtable addresses to determine same type. return *reinterpret_cast(this) == *reinterpret_cast(other); } virtual ~Event() {} virtual void Run() = 0; virtual void PostTo(mozilla::LinkedList& queue) { queue.insertBack(this); } virtual mozilla::HangMonitor::ActivityType ActivityType() const { return mozilla::HangMonitor::kGeneralActivity; } }; class LegacyGeckoEvent; template class LambdaEvent : public Event { protected: T lambda; public: LambdaEvent(T&& l) : lambda(mozilla::Move(l)) {} void Run() override { return lambda(); } }; static nsAppShell *gAppShell; nsAppShell(); NS_DECL_ISUPPORTS_INHERITED NS_DECL_NSIOBSERVER nsresult Init(); void NotifyNativeEvent(); bool ProcessNextNativeEvent(bool mayWait) override; // Post a subclass of Event. // e.g. PostEvent(mozilla::MakeUnique()); template void PostEvent(mozilla::UniquePtr&& event) { mEventQueue.Post(mozilla::Move(event)); } // Post a event that will call a lambda // e.g. PostEvent([=] { /* do something */ }); template void PostEvent(T&& lambda) { mEventQueue.Post(mozilla::MakeUnique>( mozilla::Move(lambda))); } void PostEvent(mozilla::AndroidGeckoEvent* event); void ResendLastResizeEvent(nsWindow* aDest); void OnResume() {} void SetBrowserApp(nsIAndroidBrowserApp* aBrowserApp) { mBrowserApp = aBrowserApp; } void GetBrowserApp(nsIAndroidBrowserApp* *aBrowserApp) { *aBrowserApp = mBrowserApp; } protected: virtual ~nsAppShell(); nsresult AddObserver(const nsAString &aObserverKey, nsIObserver *aObserver); class NativeCallbackEvent : public Event { // Capturing the nsAppShell instance is safe because if the app // shell is detroyed, this lambda will not be called either. nsAppShell* const appShell; public: NativeCallbackEvent(nsAppShell* as) : appShell(as) {} void Run() override { appShell->NativeEventCallback(); } }; void ScheduleNativeEventCallback() override { mEventQueue.Post(mozilla::MakeUnique(this)); } class Queue { private: mozilla::Monitor mMonitor; mozilla::LinkedList mQueue; public: Queue() : mMonitor("nsAppShell.Queue") {} void Signal() { mozilla::MonitorAutoLock lock(mMonitor); lock.NotifyAll(); } void Post(mozilla::UniquePtr&& event) { MOZ_ASSERT(event && !event->isInList()); mozilla::MonitorAutoLock lock(mMonitor); event->PostTo(mQueue); if (event->isInList()) { // Ownership of event object transfers to the queue. mozilla::unused << event.release(); } lock.NotifyAll(); } mozilla::UniquePtr Pop(bool mayWait) { mozilla::MonitorAutoLock lock(mMonitor); if (mayWait && mQueue.isEmpty()) { lock.Wait(); } // Ownership of event object transfers to the return value. return mozilla::UniquePtr(mQueue.popFirst()); } } mEventQueue; bool mAllowCoalescingTouches; nsCOMPtr mBrowserApp; nsInterfaceHashtable mObserversHash; }; // Class that implement native JNI methods can inherit from // UsesGeckoThreadProxy to have the native call forwarded // automatically to the Gecko thread. class UsesGeckoThreadProxy : public mozilla::jni::UsesNativeCallProxy { public: template static void OnNativeCall(Functor&& call) { nsAppShell::gAppShell->PostEvent(mozilla::Move(call)); } }; #endif // nsAppShell_h__