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