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