diff -r 000000000000 -r 6474c204b198 widget/windows/winrt/MetroApp.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/widget/windows/winrt/MetroApp.cpp Wed Dec 31 06:09:35 2014 +0100 @@ -0,0 +1,282 @@ +/* -*- 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; +} +