michael@0: /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 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: #include "MetroApp.h" michael@0: #include "MetroWidget.h" michael@0: #include "mozilla/IOInterposer.h" michael@0: #include "mozilla/widget/AudioSession.h" michael@0: #include "nsIRunnable.h" michael@0: #include "MetroUtils.h" michael@0: #include "MetroAppShell.h" michael@0: #include "nsICommandLineRunner.h" michael@0: #include "FrameworkView.h" michael@0: #include "nsAppDirectoryServiceDefs.h" michael@0: #include "GeckoProfiler.h" michael@0: #include michael@0: michael@0: using namespace ABI::Windows::ApplicationModel; michael@0: using namespace ABI::Windows::ApplicationModel::Core; michael@0: using namespace ABI::Windows::UI::Core; michael@0: using namespace ABI::Windows::System; michael@0: using namespace ABI::Windows::Foundation; michael@0: using namespace Microsoft::WRL; michael@0: using namespace Microsoft::WRL::Wrappers; michael@0: using namespace mozilla::widget; michael@0: michael@0: // Metro specific XRE methods we call from here on an michael@0: // appropriate thread. michael@0: extern nsresult XRE_metroStartup(bool runXREMain); michael@0: extern void XRE_metroShutdown(); michael@0: michael@0: static const char* gGeckoThreadName = "GeckoMain"; michael@0: michael@0: #ifdef PR_LOGGING michael@0: extern PRLogModuleInfo* gWindowsLog; michael@0: #endif michael@0: michael@0: namespace mozilla { michael@0: namespace widget { michael@0: namespace winrt { michael@0: michael@0: ComPtr sFrameworkView; michael@0: ComPtr sMetroApp; michael@0: ComPtr sCoreApp; michael@0: bool MetroApp::sGeckoShuttingDown = false; michael@0: michael@0: //////////////////////////////////////////////////// michael@0: // IFrameworkViewSource impl. michael@0: michael@0: // Called after CoreApplication::Run(app) michael@0: HRESULT michael@0: MetroApp::CreateView(ABI::Windows::ApplicationModel::Core::IFrameworkView **aViewProvider) michael@0: { michael@0: // This entry point is called on the metro main thread, but the thread won't michael@0: // be recognized as such until after Run() is called below. XPCOM has not michael@0: // gone through startup at this point. michael@0: michael@0: // Note that we create the view which creates our native window for us. The michael@0: // gecko widget gets created by gecko, and the two get hooked up later in michael@0: // MetroWidget::Create(). michael@0: michael@0: LogFunction(); michael@0: michael@0: sFrameworkView = Make(this); michael@0: sFrameworkView.Get()->AddRef(); michael@0: *aViewProvider = sFrameworkView.Get(); michael@0: return !sFrameworkView ? E_FAIL : S_OK; michael@0: } michael@0: michael@0: //////////////////////////////////////////////////// michael@0: // MetroApp impl. michael@0: michael@0: void michael@0: MetroApp::Run() michael@0: { michael@0: LogThread(); michael@0: michael@0: // Name this thread for debugging and register it with the profiler michael@0: // and IOInterposer as the main gecko thread. michael@0: char aLocal; michael@0: PR_SetCurrentThreadName(gGeckoThreadName); michael@0: profiler_register_thread(gGeckoThreadName, &aLocal); michael@0: IOInterposer::RegisterCurrentThread(true); michael@0: michael@0: HRESULT hr; michael@0: hr = sCoreApp->add_Suspending(Callback<__FIEventHandler_1_Windows__CApplicationModel__CSuspendingEventArgs_t>( michael@0: this, &MetroApp::OnSuspending).Get(), &mSuspendEvent); michael@0: AssertHRESULT(hr); michael@0: michael@0: hr = sCoreApp->add_Resuming(Callback<__FIEventHandler_1_IInspectable_t>( michael@0: this, &MetroApp::OnResuming).Get(), &mResumeEvent); michael@0: AssertHRESULT(hr); michael@0: michael@0: WinUtils::Log("Calling XRE_metroStartup."); michael@0: nsresult rv = XRE_metroStartup(true); michael@0: WinUtils::Log("Exiting XRE_metroStartup."); michael@0: if (NS_FAILED(rv)) { michael@0: WinUtils::Log("XPCOM startup initialization failed, bailing. rv=%X", rv); michael@0: CoreExit(); michael@0: } michael@0: } michael@0: michael@0: // Free all xpcom related resources before calling the xre shutdown call. michael@0: // Must be called on the metro main thread. Currently called from appshell. michael@0: void michael@0: MetroApp::Shutdown() michael@0: { michael@0: LogThread(); michael@0: michael@0: if (sCoreApp) { michael@0: sCoreApp->remove_Suspending(mSuspendEvent); michael@0: sCoreApp->remove_Resuming(mResumeEvent); michael@0: } michael@0: michael@0: if (sFrameworkView) { michael@0: sFrameworkView->Shutdown(); michael@0: } michael@0: michael@0: MetroApp::sGeckoShuttingDown = true; michael@0: michael@0: // Shut down xpcom michael@0: XRE_metroShutdown(); michael@0: michael@0: // Unhook this thread from the profiler michael@0: profiler_unregister_thread(); michael@0: } michael@0: michael@0: // Request a shutdown of the application michael@0: void michael@0: MetroApp::CoreExit() michael@0: { michael@0: LogFunction(); michael@0: HRESULT hr; michael@0: ComPtr coreExit; michael@0: HStringReference className(RuntimeClass_Windows_ApplicationModel_Core_CoreApplication); michael@0: hr = GetActivationFactory(className.Get(), coreExit.GetAddressOf()); michael@0: NS_ASSERTION(SUCCEEDED(hr), "Activation of ICoreApplicationExit"); michael@0: if (SUCCEEDED(hr)) { michael@0: coreExit->Exit(); michael@0: } michael@0: } michael@0: michael@0: void michael@0: MetroApp::ActivateBaseView() michael@0: { michael@0: if (sFrameworkView) { michael@0: sFrameworkView->ActivateView(); michael@0: } michael@0: } michael@0: michael@0: /* michael@0: * TBD: when we support multiple widgets, we'll need a way to sync up the view michael@0: * created in CreateView with the widget gecko creates. Currently we only have michael@0: * one view (sFrameworkView) and one main widget. michael@0: */ michael@0: void michael@0: MetroApp::SetWidget(MetroWidget* aPtr) michael@0: { michael@0: LogThread(); michael@0: michael@0: NS_ASSERTION(aPtr, "setting null base widget?"); michael@0: michael@0: // Both of these calls AddRef the ptr we pass in michael@0: aPtr->SetView(sFrameworkView.Get()); michael@0: sFrameworkView->SetWidget(aPtr); michael@0: } michael@0: michael@0: //////////////////////////////////////////////////// michael@0: // MetroApp events michael@0: michael@0: HRESULT michael@0: MetroApp::OnSuspending(IInspectable* aSender, ISuspendingEventArgs* aArgs) michael@0: { michael@0: LogThread(); michael@0: PostSuspendResumeProcessNotification(true); michael@0: return S_OK; michael@0: } michael@0: michael@0: HRESULT michael@0: MetroApp::OnResuming(IInspectable* aSender, IInspectable* aArgs) michael@0: { michael@0: LogThread(); michael@0: PostSuspendResumeProcessNotification(false); michael@0: return S_OK; michael@0: } michael@0: michael@0: HRESULT michael@0: MetroApp::OnAsyncTileCreated(ABI::Windows::Foundation::IAsyncOperation* aOperation, michael@0: AsyncStatus aStatus) michael@0: { michael@0: WinUtils::Log("Async operation status: %d", aStatus); michael@0: MetroUtils::FireObserver("metro_on_async_tile_created"); michael@0: return S_OK; michael@0: } michael@0: michael@0: // static michael@0: void michael@0: MetroApp::PostSuspendResumeProcessNotification(const bool aIsSuspend) michael@0: { michael@0: static bool isSuspend = false; michael@0: if (isSuspend == aIsSuspend) { michael@0: return; michael@0: } michael@0: isSuspend = aIsSuspend; michael@0: MetroUtils::FireObserver(aIsSuspend ? "suspend_process_notification" : michael@0: "resume_process_notification"); michael@0: } michael@0: michael@0: // static michael@0: void michael@0: MetroApp::PostSleepWakeNotification(const bool aIsSleep) michael@0: { michael@0: static bool isSleep = false; michael@0: if (isSleep == aIsSleep) { michael@0: return; michael@0: } michael@0: isSleep = aIsSleep; michael@0: MetroUtils::FireObserver(aIsSleep ? "sleep_notification" : michael@0: "wake_notification"); michael@0: } michael@0: michael@0: } } } michael@0: michael@0: michael@0: static bool michael@0: IsBackgroundSessionClosedStartup() michael@0: { michael@0: int argc; michael@0: LPWSTR *argv = CommandLineToArgvW(GetCommandLineW(), &argc); michael@0: bool backgroundSessionClosed = argc > 1 && !wcsicmp(argv[1], L"-BackgroundSessionClosed"); michael@0: LocalFree(argv); michael@0: return backgroundSessionClosed; michael@0: } michael@0: michael@0: bool michael@0: XRE_MetroCoreApplicationRun() michael@0: { michael@0: HRESULT hr; michael@0: LogThread(); michael@0: michael@0: using namespace mozilla::widget::winrt; michael@0: michael@0: sMetroApp = Make(); michael@0: michael@0: HStringReference className(RuntimeClass_Windows_ApplicationModel_Core_CoreApplication); michael@0: hr = GetActivationFactory(className.Get(), sCoreApp.GetAddressOf()); michael@0: if (FAILED(hr)) { michael@0: LogHRESULT(hr); michael@0: return false; michael@0: } michael@0: michael@0: // Perform any cleanup for unclean shutdowns here, such as when the background session michael@0: // is closed via the appbar on the left when outside of Metro. Windows restarts the michael@0: // process solely for cleanup reasons. michael@0: if (IsBackgroundSessionClosedStartup() && SUCCEEDED(XRE_metroStartup(false))) { michael@0: michael@0: // Whether or not to use sessionstore depends on if the bak exists. Since host process michael@0: // shutdown isn't a crash we shouldn't restore sessionstore. michael@0: nsCOMPtr sessionBAK; michael@0: if (NS_FAILED(NS_GetSpecialDirectory("ProfDS", getter_AddRefs(sessionBAK)))) { michael@0: return false; michael@0: } michael@0: michael@0: sessionBAK->AppendNative(nsDependentCString("sessionstore.bak")); michael@0: bool exists; michael@0: if (NS_SUCCEEDED(sessionBAK->Exists(&exists)) && exists) { michael@0: sessionBAK->Remove(false); michael@0: } michael@0: return false; michael@0: } michael@0: michael@0: hr = sCoreApp->Run(sMetroApp.Get()); michael@0: michael@0: WinUtils::Log("Exiting CoreApplication::Run"); michael@0: michael@0: sCoreApp = nullptr; michael@0: sMetroApp = nullptr; michael@0: michael@0: return true; michael@0: } michael@0: