widget/windows/winrt/MetroApp.cpp

Thu, 22 Jan 2015 13:21:57 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Thu, 22 Jan 2015 13:21:57 +0100
branch
TOR_BUG_9701
changeset 15
b8a032363ba2
permissions
-rw-r--r--

Incorporate requested changes from Mozilla in review:
https://bugzilla.mozilla.org/show_bug.cgi?id=1123480#c6

michael@0 1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
michael@0 2 /* This Source Code Form is subject to the terms of the Mozilla Public
michael@0 3 * License, v. 2.0. If a copy of the MPL was not distributed with this
michael@0 4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
michael@0 5
michael@0 6 #include "MetroApp.h"
michael@0 7 #include "MetroWidget.h"
michael@0 8 #include "mozilla/IOInterposer.h"
michael@0 9 #include "mozilla/widget/AudioSession.h"
michael@0 10 #include "nsIRunnable.h"
michael@0 11 #include "MetroUtils.h"
michael@0 12 #include "MetroAppShell.h"
michael@0 13 #include "nsICommandLineRunner.h"
michael@0 14 #include "FrameworkView.h"
michael@0 15 #include "nsAppDirectoryServiceDefs.h"
michael@0 16 #include "GeckoProfiler.h"
michael@0 17 #include <shellapi.h>
michael@0 18
michael@0 19 using namespace ABI::Windows::ApplicationModel;
michael@0 20 using namespace ABI::Windows::ApplicationModel::Core;
michael@0 21 using namespace ABI::Windows::UI::Core;
michael@0 22 using namespace ABI::Windows::System;
michael@0 23 using namespace ABI::Windows::Foundation;
michael@0 24 using namespace Microsoft::WRL;
michael@0 25 using namespace Microsoft::WRL::Wrappers;
michael@0 26 using namespace mozilla::widget;
michael@0 27
michael@0 28 // Metro specific XRE methods we call from here on an
michael@0 29 // appropriate thread.
michael@0 30 extern nsresult XRE_metroStartup(bool runXREMain);
michael@0 31 extern void XRE_metroShutdown();
michael@0 32
michael@0 33 static const char* gGeckoThreadName = "GeckoMain";
michael@0 34
michael@0 35 #ifdef PR_LOGGING
michael@0 36 extern PRLogModuleInfo* gWindowsLog;
michael@0 37 #endif
michael@0 38
michael@0 39 namespace mozilla {
michael@0 40 namespace widget {
michael@0 41 namespace winrt {
michael@0 42
michael@0 43 ComPtr<FrameworkView> sFrameworkView;
michael@0 44 ComPtr<MetroApp> sMetroApp;
michael@0 45 ComPtr<ICoreApplication> sCoreApp;
michael@0 46 bool MetroApp::sGeckoShuttingDown = false;
michael@0 47
michael@0 48 ////////////////////////////////////////////////////
michael@0 49 // IFrameworkViewSource impl.
michael@0 50
michael@0 51 // Called after CoreApplication::Run(app)
michael@0 52 HRESULT
michael@0 53 MetroApp::CreateView(ABI::Windows::ApplicationModel::Core::IFrameworkView **aViewProvider)
michael@0 54 {
michael@0 55 // This entry point is called on the metro main thread, but the thread won't
michael@0 56 // be recognized as such until after Run() is called below. XPCOM has not
michael@0 57 // gone through startup at this point.
michael@0 58
michael@0 59 // Note that we create the view which creates our native window for us. The
michael@0 60 // gecko widget gets created by gecko, and the two get hooked up later in
michael@0 61 // MetroWidget::Create().
michael@0 62
michael@0 63 LogFunction();
michael@0 64
michael@0 65 sFrameworkView = Make<FrameworkView>(this);
michael@0 66 sFrameworkView.Get()->AddRef();
michael@0 67 *aViewProvider = sFrameworkView.Get();
michael@0 68 return !sFrameworkView ? E_FAIL : S_OK;
michael@0 69 }
michael@0 70
michael@0 71 ////////////////////////////////////////////////////
michael@0 72 // MetroApp impl.
michael@0 73
michael@0 74 void
michael@0 75 MetroApp::Run()
michael@0 76 {
michael@0 77 LogThread();
michael@0 78
michael@0 79 // Name this thread for debugging and register it with the profiler
michael@0 80 // and IOInterposer as the main gecko thread.
michael@0 81 char aLocal;
michael@0 82 PR_SetCurrentThreadName(gGeckoThreadName);
michael@0 83 profiler_register_thread(gGeckoThreadName, &aLocal);
michael@0 84 IOInterposer::RegisterCurrentThread(true);
michael@0 85
michael@0 86 HRESULT hr;
michael@0 87 hr = sCoreApp->add_Suspending(Callback<__FIEventHandler_1_Windows__CApplicationModel__CSuspendingEventArgs_t>(
michael@0 88 this, &MetroApp::OnSuspending).Get(), &mSuspendEvent);
michael@0 89 AssertHRESULT(hr);
michael@0 90
michael@0 91 hr = sCoreApp->add_Resuming(Callback<__FIEventHandler_1_IInspectable_t>(
michael@0 92 this, &MetroApp::OnResuming).Get(), &mResumeEvent);
michael@0 93 AssertHRESULT(hr);
michael@0 94
michael@0 95 WinUtils::Log("Calling XRE_metroStartup.");
michael@0 96 nsresult rv = XRE_metroStartup(true);
michael@0 97 WinUtils::Log("Exiting XRE_metroStartup.");
michael@0 98 if (NS_FAILED(rv)) {
michael@0 99 WinUtils::Log("XPCOM startup initialization failed, bailing. rv=%X", rv);
michael@0 100 CoreExit();
michael@0 101 }
michael@0 102 }
michael@0 103
michael@0 104 // Free all xpcom related resources before calling the xre shutdown call.
michael@0 105 // Must be called on the metro main thread. Currently called from appshell.
michael@0 106 void
michael@0 107 MetroApp::Shutdown()
michael@0 108 {
michael@0 109 LogThread();
michael@0 110
michael@0 111 if (sCoreApp) {
michael@0 112 sCoreApp->remove_Suspending(mSuspendEvent);
michael@0 113 sCoreApp->remove_Resuming(mResumeEvent);
michael@0 114 }
michael@0 115
michael@0 116 if (sFrameworkView) {
michael@0 117 sFrameworkView->Shutdown();
michael@0 118 }
michael@0 119
michael@0 120 MetroApp::sGeckoShuttingDown = true;
michael@0 121
michael@0 122 // Shut down xpcom
michael@0 123 XRE_metroShutdown();
michael@0 124
michael@0 125 // Unhook this thread from the profiler
michael@0 126 profiler_unregister_thread();
michael@0 127 }
michael@0 128
michael@0 129 // Request a shutdown of the application
michael@0 130 void
michael@0 131 MetroApp::CoreExit()
michael@0 132 {
michael@0 133 LogFunction();
michael@0 134 HRESULT hr;
michael@0 135 ComPtr<ICoreApplicationExit> coreExit;
michael@0 136 HStringReference className(RuntimeClass_Windows_ApplicationModel_Core_CoreApplication);
michael@0 137 hr = GetActivationFactory(className.Get(), coreExit.GetAddressOf());
michael@0 138 NS_ASSERTION(SUCCEEDED(hr), "Activation of ICoreApplicationExit");
michael@0 139 if (SUCCEEDED(hr)) {
michael@0 140 coreExit->Exit();
michael@0 141 }
michael@0 142 }
michael@0 143
michael@0 144 void
michael@0 145 MetroApp::ActivateBaseView()
michael@0 146 {
michael@0 147 if (sFrameworkView) {
michael@0 148 sFrameworkView->ActivateView();
michael@0 149 }
michael@0 150 }
michael@0 151
michael@0 152 /*
michael@0 153 * TBD: when we support multiple widgets, we'll need a way to sync up the view
michael@0 154 * created in CreateView with the widget gecko creates. Currently we only have
michael@0 155 * one view (sFrameworkView) and one main widget.
michael@0 156 */
michael@0 157 void
michael@0 158 MetroApp::SetWidget(MetroWidget* aPtr)
michael@0 159 {
michael@0 160 LogThread();
michael@0 161
michael@0 162 NS_ASSERTION(aPtr, "setting null base widget?");
michael@0 163
michael@0 164 // Both of these calls AddRef the ptr we pass in
michael@0 165 aPtr->SetView(sFrameworkView.Get());
michael@0 166 sFrameworkView->SetWidget(aPtr);
michael@0 167 }
michael@0 168
michael@0 169 ////////////////////////////////////////////////////
michael@0 170 // MetroApp events
michael@0 171
michael@0 172 HRESULT
michael@0 173 MetroApp::OnSuspending(IInspectable* aSender, ISuspendingEventArgs* aArgs)
michael@0 174 {
michael@0 175 LogThread();
michael@0 176 PostSuspendResumeProcessNotification(true);
michael@0 177 return S_OK;
michael@0 178 }
michael@0 179
michael@0 180 HRESULT
michael@0 181 MetroApp::OnResuming(IInspectable* aSender, IInspectable* aArgs)
michael@0 182 {
michael@0 183 LogThread();
michael@0 184 PostSuspendResumeProcessNotification(false);
michael@0 185 return S_OK;
michael@0 186 }
michael@0 187
michael@0 188 HRESULT
michael@0 189 MetroApp::OnAsyncTileCreated(ABI::Windows::Foundation::IAsyncOperation<bool>* aOperation,
michael@0 190 AsyncStatus aStatus)
michael@0 191 {
michael@0 192 WinUtils::Log("Async operation status: %d", aStatus);
michael@0 193 MetroUtils::FireObserver("metro_on_async_tile_created");
michael@0 194 return S_OK;
michael@0 195 }
michael@0 196
michael@0 197 // static
michael@0 198 void
michael@0 199 MetroApp::PostSuspendResumeProcessNotification(const bool aIsSuspend)
michael@0 200 {
michael@0 201 static bool isSuspend = false;
michael@0 202 if (isSuspend == aIsSuspend) {
michael@0 203 return;
michael@0 204 }
michael@0 205 isSuspend = aIsSuspend;
michael@0 206 MetroUtils::FireObserver(aIsSuspend ? "suspend_process_notification" :
michael@0 207 "resume_process_notification");
michael@0 208 }
michael@0 209
michael@0 210 // static
michael@0 211 void
michael@0 212 MetroApp::PostSleepWakeNotification(const bool aIsSleep)
michael@0 213 {
michael@0 214 static bool isSleep = false;
michael@0 215 if (isSleep == aIsSleep) {
michael@0 216 return;
michael@0 217 }
michael@0 218 isSleep = aIsSleep;
michael@0 219 MetroUtils::FireObserver(aIsSleep ? "sleep_notification" :
michael@0 220 "wake_notification");
michael@0 221 }
michael@0 222
michael@0 223 } } }
michael@0 224
michael@0 225
michael@0 226 static bool
michael@0 227 IsBackgroundSessionClosedStartup()
michael@0 228 {
michael@0 229 int argc;
michael@0 230 LPWSTR *argv = CommandLineToArgvW(GetCommandLineW(), &argc);
michael@0 231 bool backgroundSessionClosed = argc > 1 && !wcsicmp(argv[1], L"-BackgroundSessionClosed");
michael@0 232 LocalFree(argv);
michael@0 233 return backgroundSessionClosed;
michael@0 234 }
michael@0 235
michael@0 236 bool
michael@0 237 XRE_MetroCoreApplicationRun()
michael@0 238 {
michael@0 239 HRESULT hr;
michael@0 240 LogThread();
michael@0 241
michael@0 242 using namespace mozilla::widget::winrt;
michael@0 243
michael@0 244 sMetroApp = Make<MetroApp>();
michael@0 245
michael@0 246 HStringReference className(RuntimeClass_Windows_ApplicationModel_Core_CoreApplication);
michael@0 247 hr = GetActivationFactory(className.Get(), sCoreApp.GetAddressOf());
michael@0 248 if (FAILED(hr)) {
michael@0 249 LogHRESULT(hr);
michael@0 250 return false;
michael@0 251 }
michael@0 252
michael@0 253 // Perform any cleanup for unclean shutdowns here, such as when the background session
michael@0 254 // is closed via the appbar on the left when outside of Metro. Windows restarts the
michael@0 255 // process solely for cleanup reasons.
michael@0 256 if (IsBackgroundSessionClosedStartup() && SUCCEEDED(XRE_metroStartup(false))) {
michael@0 257
michael@0 258 // Whether or not to use sessionstore depends on if the bak exists. Since host process
michael@0 259 // shutdown isn't a crash we shouldn't restore sessionstore.
michael@0 260 nsCOMPtr<nsIFile> sessionBAK;
michael@0 261 if (NS_FAILED(NS_GetSpecialDirectory("ProfDS", getter_AddRefs(sessionBAK)))) {
michael@0 262 return false;
michael@0 263 }
michael@0 264
michael@0 265 sessionBAK->AppendNative(nsDependentCString("sessionstore.bak"));
michael@0 266 bool exists;
michael@0 267 if (NS_SUCCEEDED(sessionBAK->Exists(&exists)) && exists) {
michael@0 268 sessionBAK->Remove(false);
michael@0 269 }
michael@0 270 return false;
michael@0 271 }
michael@0 272
michael@0 273 hr = sCoreApp->Run(sMetroApp.Get());
michael@0 274
michael@0 275 WinUtils::Log("Exiting CoreApplication::Run");
michael@0 276
michael@0 277 sCoreApp = nullptr;
michael@0 278 sMetroApp = nullptr;
michael@0 279
michael@0 280 return true;
michael@0 281 }
michael@0 282

mercurial