|
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 "nsWinMetroUtils.h" |
|
7 #include "MetroUtils.h" |
|
8 #include "nsXULAppAPI.h" |
|
9 #include "FrameworkView.h" |
|
10 #include "MetroApp.h" |
|
11 #include "ToastNotificationHandler.h" |
|
12 #include "mozilla/Preferences.h" |
|
13 #include "mozilla/WindowsVersion.h" |
|
14 #include "nsIWindowsRegKey.h" |
|
15 #include "mozilla/widget/MetroD3DCheckHelper.h" |
|
16 |
|
17 #include <shldisp.h> |
|
18 #include <shellapi.h> |
|
19 #include <windows.ui.viewmanagement.h> |
|
20 #include <windows.ui.startscreen.h> |
|
21 |
|
22 using namespace ABI::Windows::Foundation; |
|
23 using namespace ABI::Windows::UI::StartScreen; |
|
24 using namespace ABI::Windows::UI::ViewManagement; |
|
25 using namespace Microsoft::WRL; |
|
26 using namespace Microsoft::WRL::Wrappers; |
|
27 using namespace mozilla::widget::winrt; |
|
28 |
|
29 namespace mozilla { |
|
30 namespace widget { |
|
31 namespace winrt { |
|
32 extern ComPtr<MetroApp> sMetroApp; |
|
33 extern nsTArray<nsString>* sSettingsArray; |
|
34 } } } |
|
35 |
|
36 namespace mozilla { |
|
37 namespace widget { |
|
38 |
|
39 bool nsWinMetroUtils::sUpdatePending = false; |
|
40 |
|
41 NS_IMPL_ISUPPORTS(nsWinMetroUtils, nsIWinMetroUtils) |
|
42 |
|
43 nsWinMetroUtils::nsWinMetroUtils() |
|
44 { |
|
45 } |
|
46 |
|
47 nsWinMetroUtils::~nsWinMetroUtils() |
|
48 { |
|
49 } |
|
50 |
|
51 /** |
|
52 * Pins a new tile to the Windows 8 start screen. |
|
53 * |
|
54 * @param aTileID An ID which can later be used to remove the tile |
|
55 * @param aShortName A short name for the tile |
|
56 * @param aDiplayName The name that will be displayed on the tile |
|
57 * @param aActivationArgs The arguments to pass to the browser upon |
|
58 * activation of the tile |
|
59 * @param aTileImage An image for the normal tile view |
|
60 * @param aSmallTileImage An image for the small tile view |
|
61 */ |
|
62 NS_IMETHODIMP |
|
63 nsWinMetroUtils::PinTileAsync(const nsAString &aTileID, |
|
64 const nsAString &aShortName, |
|
65 const nsAString &aDisplayName, |
|
66 const nsAString &aActivationArgs, |
|
67 const nsAString &aTileImage, |
|
68 const nsAString &aSmallTileImage) |
|
69 { |
|
70 if (XRE_GetWindowsEnvironment() != WindowsEnvironmentType_Metro) { |
|
71 NS_WARNING("PinTileAsync can't be called on the desktop."); |
|
72 return NS_ERROR_FAILURE; |
|
73 } |
|
74 HRESULT hr; |
|
75 |
|
76 HString logoStr, smallLogoStr, displayName, shortName; |
|
77 |
|
78 logoStr.Set(aTileImage.BeginReading()); |
|
79 smallLogoStr.Set(aSmallTileImage.BeginReading()); |
|
80 displayName.Set(aDisplayName.BeginReading()); |
|
81 shortName.Set(aShortName.BeginReading()); |
|
82 |
|
83 ComPtr<IUriRuntimeClass> logo, smallLogo; |
|
84 AssertRetHRESULT(MetroUtils::CreateUri(logoStr, logo), NS_ERROR_FAILURE); |
|
85 AssertRetHRESULT(MetroUtils::CreateUri(smallLogoStr, smallLogo), NS_ERROR_FAILURE); |
|
86 |
|
87 HString tileActivationArgumentsStr, tileIdStr; |
|
88 tileActivationArgumentsStr.Set(aActivationArgs.BeginReading()); |
|
89 tileIdStr.Set(aTileID.BeginReading()); |
|
90 |
|
91 ComPtr<ISecondaryTileFactory> tileFactory; |
|
92 ComPtr<ISecondaryTile> secondaryTile; |
|
93 hr = GetActivationFactory(HStringReference(RuntimeClass_Windows_UI_StartScreen_SecondaryTile).Get(), |
|
94 tileFactory.GetAddressOf()); |
|
95 AssertRetHRESULT(hr, NS_ERROR_FAILURE); |
|
96 hr = tileFactory->CreateWithId(tileIdStr.Get(), secondaryTile.GetAddressOf()); |
|
97 AssertRetHRESULT(hr, NS_ERROR_FAILURE); |
|
98 |
|
99 secondaryTile->put_Logo(logo.Get()); |
|
100 secondaryTile->put_SmallLogo(smallLogo.Get()); |
|
101 secondaryTile->put_DisplayName(displayName.Get()); |
|
102 secondaryTile->put_ShortName(shortName.Get()); |
|
103 secondaryTile->put_Arguments(tileActivationArgumentsStr.Get()); |
|
104 secondaryTile->put_TileOptions(TileOptions::TileOptions_ShowNameOnLogo); |
|
105 |
|
106 // The tile is created and we can now attempt to pin the tile. |
|
107 ComPtr<IAsyncOperationCompletedHandler<bool>> callback(Callback<IAsyncOperationCompletedHandler<bool>>( |
|
108 sMetroApp.Get(), &MetroApp::OnAsyncTileCreated)); |
|
109 ComPtr<IAsyncOperation<bool>> operation; |
|
110 AssertRetHRESULT(secondaryTile->RequestCreateAsync(operation.GetAddressOf()), NS_ERROR_FAILURE); |
|
111 operation->put_Completed(callback.Get()); |
|
112 return NS_OK; |
|
113 } |
|
114 |
|
115 /** |
|
116 * Unpins a tile from the Windows 8 start screen. |
|
117 * |
|
118 * @param aTileID An existing ID which was previously pinned |
|
119 */ |
|
120 NS_IMETHODIMP |
|
121 nsWinMetroUtils::UnpinTileAsync(const nsAString &aTileID) |
|
122 { |
|
123 if (XRE_GetWindowsEnvironment() != WindowsEnvironmentType_Metro) { |
|
124 NS_WARNING("UnpinTileAsync can't be called on the desktop."); |
|
125 return NS_ERROR_FAILURE; |
|
126 } |
|
127 HRESULT hr; |
|
128 HString tileIdStr; |
|
129 tileIdStr.Set(aTileID.BeginReading()); |
|
130 |
|
131 ComPtr<ISecondaryTileFactory> tileFactory; |
|
132 ComPtr<ISecondaryTile> secondaryTile; |
|
133 hr = GetActivationFactory(HStringReference(RuntimeClass_Windows_UI_StartScreen_SecondaryTile).Get(), |
|
134 tileFactory.GetAddressOf()); |
|
135 AssertRetHRESULT(hr, NS_ERROR_FAILURE); |
|
136 hr = tileFactory->CreateWithId(tileIdStr.Get(), secondaryTile.GetAddressOf()); |
|
137 AssertRetHRESULT(hr, NS_ERROR_FAILURE); |
|
138 |
|
139 // Attempt to unpin the tile |
|
140 ComPtr<IAsyncOperationCompletedHandler<bool>> callback(Callback<IAsyncOperationCompletedHandler<bool>>( |
|
141 sMetroApp.Get(), &MetroApp::OnAsyncTileCreated)); |
|
142 ComPtr<IAsyncOperation<bool>> operation; |
|
143 AssertRetHRESULT(secondaryTile->RequestDeleteAsync(operation.GetAddressOf()), NS_ERROR_FAILURE); |
|
144 operation->put_Completed(callback.Get()); |
|
145 return NS_OK; |
|
146 } |
|
147 |
|
148 /** |
|
149 * Determines if a tile is pinned to the Windows 8 start screen. |
|
150 * |
|
151 * @param aTileID An ID which may have been pinned with pinTileAsync |
|
152 * @param aIsPinned Out parameter for determining if the tile is pinned or not |
|
153 */ |
|
154 NS_IMETHODIMP |
|
155 nsWinMetroUtils::IsTilePinned(const nsAString &aTileID, bool *aIsPinned) |
|
156 { |
|
157 if (XRE_GetWindowsEnvironment() != WindowsEnvironmentType_Metro) { |
|
158 NS_WARNING("IsTilePinned can't be called on the desktop."); |
|
159 return NS_ERROR_FAILURE; |
|
160 } |
|
161 NS_ENSURE_ARG_POINTER(aIsPinned); |
|
162 |
|
163 HRESULT hr; |
|
164 HString tileIdStr; |
|
165 tileIdStr.Set(aTileID.BeginReading()); |
|
166 |
|
167 ComPtr<ISecondaryTileStatics> tileStatics; |
|
168 hr = GetActivationFactory(HStringReference(RuntimeClass_Windows_UI_StartScreen_SecondaryTile).Get(), |
|
169 tileStatics.GetAddressOf()); |
|
170 AssertRetHRESULT(hr, NS_ERROR_FAILURE); |
|
171 boolean result = false; |
|
172 tileStatics->Exists(tileIdStr.Get(), &result); |
|
173 *aIsPinned = result; |
|
174 return NS_OK; |
|
175 } |
|
176 |
|
177 /** |
|
178 * Launches the specified application with the specified arguments and |
|
179 * switches to Desktop mode if in metro mode. |
|
180 */ |
|
181 NS_IMETHODIMP |
|
182 nsWinMetroUtils::LaunchInDesktop(const nsAString &aPath, const nsAString &aArguments) |
|
183 { |
|
184 SHELLEXECUTEINFOW sinfo; |
|
185 memset(&sinfo, 0, sizeof(SHELLEXECUTEINFOW)); |
|
186 sinfo.cbSize = sizeof(SHELLEXECUTEINFOW); |
|
187 // Per the Metro style enabled desktop browser, for some reason, |
|
188 // SEE_MASK_FLAG_LOG_USAGE is needed to change from immersive mode |
|
189 // to desktop. |
|
190 sinfo.fMask = SEE_MASK_FLAG_LOG_USAGE; |
|
191 sinfo.hwnd = nullptr; |
|
192 sinfo.lpFile = aPath.BeginReading(); |
|
193 sinfo.lpParameters = aArguments.BeginReading(); |
|
194 sinfo.lpVerb = L"open"; |
|
195 sinfo.nShow = SW_SHOWNORMAL; |
|
196 |
|
197 if (!ShellExecuteEx(&sinfo)) { |
|
198 return NS_ERROR_FAILURE; |
|
199 } |
|
200 return NS_OK; |
|
201 } |
|
202 |
|
203 NS_IMETHODIMP |
|
204 nsWinMetroUtils::ShowNativeToast(const nsAString &aTitle, |
|
205 const nsAString &aMessage, const nsAString &anImage, |
|
206 const nsAString &aCookie, const nsAString& aAppId) |
|
207 { |
|
208 ToastNotificationHandler* notification_handler = |
|
209 new ToastNotificationHandler; |
|
210 |
|
211 HSTRING title = HStringReference(aTitle.BeginReading()).Get(); |
|
212 HSTRING msg = HStringReference(aMessage.BeginReading()).Get(); |
|
213 |
|
214 bool ret; |
|
215 if (anImage.Length() > 0) { |
|
216 HSTRING imagePath = HStringReference(anImage.BeginReading()).Get(); |
|
217 ret = notification_handler->DisplayNotification(title, msg, imagePath, |
|
218 aCookie, |
|
219 aAppId); |
|
220 } else { |
|
221 ret = notification_handler->DisplayTextNotification(title, msg, aCookie, |
|
222 aAppId); |
|
223 } |
|
224 |
|
225 if (!ret) { |
|
226 delete notification_handler; |
|
227 return NS_ERROR_FAILURE; |
|
228 } |
|
229 |
|
230 return NS_OK; |
|
231 } |
|
232 |
|
233 NS_IMETHODIMP |
|
234 nsWinMetroUtils::ShowSettingsFlyout() |
|
235 { |
|
236 if (XRE_GetWindowsEnvironment() != WindowsEnvironmentType_Metro) { |
|
237 NS_WARNING("Settings flyout can't be shown on the desktop."); |
|
238 return NS_ERROR_FAILURE; |
|
239 } |
|
240 |
|
241 HRESULT hr = MetroUtils::ShowSettingsFlyout(); |
|
242 return SUCCEEDED(hr) ? NS_OK : NS_ERROR_FAILURE; |
|
243 } |
|
244 |
|
245 NS_IMETHODIMP |
|
246 nsWinMetroUtils::GetImmersive(bool *aImersive) |
|
247 { |
|
248 *aImersive = |
|
249 XRE_GetWindowsEnvironment() == WindowsEnvironmentType_Metro; |
|
250 return NS_OK; |
|
251 } |
|
252 |
|
253 NS_IMETHODIMP |
|
254 nsWinMetroUtils::GetActivationURI(nsAString &aActivationURI) |
|
255 { |
|
256 if (XRE_GetWindowsEnvironment() != WindowsEnvironmentType_Metro) { |
|
257 return NS_ERROR_FAILURE; |
|
258 } |
|
259 FrameworkView::GetActivationURI(aActivationURI); |
|
260 return NS_OK; |
|
261 } |
|
262 |
|
263 NS_IMETHODIMP |
|
264 nsWinMetroUtils::GetPreviousExecutionState(int32_t *out) |
|
265 { |
|
266 if (XRE_GetWindowsEnvironment() != WindowsEnvironmentType_Metro) { |
|
267 return NS_ERROR_FAILURE; |
|
268 } |
|
269 *out = FrameworkView::GetPreviousExecutionState(); |
|
270 return NS_OK; |
|
271 } |
|
272 |
|
273 NS_IMETHODIMP |
|
274 nsWinMetroUtils::GetKeyboardVisible(bool *aImersive) |
|
275 { |
|
276 *aImersive = FrameworkView::IsKeyboardVisible(); |
|
277 return NS_OK; |
|
278 } |
|
279 |
|
280 NS_IMETHODIMP |
|
281 nsWinMetroUtils::GetKeyboardX(uint32_t *aX) |
|
282 { |
|
283 *aX = static_cast<uint32_t>(floor(FrameworkView::KeyboardVisibleRect().X)); |
|
284 return NS_OK; |
|
285 } |
|
286 |
|
287 NS_IMETHODIMP |
|
288 nsWinMetroUtils::GetKeyboardY(uint32_t *aY) |
|
289 { |
|
290 *aY = static_cast<uint32_t>(floor(FrameworkView::KeyboardVisibleRect().Y)); |
|
291 return NS_OK; |
|
292 } |
|
293 |
|
294 NS_IMETHODIMP |
|
295 nsWinMetroUtils::GetKeyboardWidth(uint32_t *aWidth) |
|
296 { |
|
297 *aWidth = static_cast<uint32_t>(ceil(FrameworkView::KeyboardVisibleRect().Width)); |
|
298 return NS_OK; |
|
299 } |
|
300 |
|
301 NS_IMETHODIMP |
|
302 nsWinMetroUtils::GetKeyboardHeight(uint32_t *aHeight) |
|
303 { |
|
304 *aHeight = static_cast<uint32_t>(ceil(FrameworkView::KeyboardVisibleRect().Height)); |
|
305 return NS_OK; |
|
306 } |
|
307 |
|
308 NS_IMETHODIMP |
|
309 nsWinMetroUtils::AddSettingsPanelEntry(const nsAString &aLabel, uint32_t *aId) |
|
310 { |
|
311 NS_ENSURE_ARG_POINTER(aId); |
|
312 if (!sSettingsArray) |
|
313 return NS_ERROR_UNEXPECTED; |
|
314 |
|
315 *aId = sSettingsArray->Length(); |
|
316 sSettingsArray->AppendElement(nsString(aLabel)); |
|
317 return NS_OK; |
|
318 } |
|
319 |
|
320 NS_IMETHODIMP |
|
321 nsWinMetroUtils::SwapMouseButton(bool aValue, bool *aOriginalValue) |
|
322 { |
|
323 *aOriginalValue = ::SwapMouseButton(aValue); |
|
324 return NS_OK; |
|
325 } |
|
326 |
|
327 NS_IMETHODIMP |
|
328 nsWinMetroUtils::GetUpdatePending(bool *aUpdatePending) |
|
329 { |
|
330 *aUpdatePending = sUpdatePending; |
|
331 return NS_OK; |
|
332 } |
|
333 |
|
334 NS_IMETHODIMP |
|
335 nsWinMetroUtils::SetUpdatePending(bool aUpdatePending) |
|
336 { |
|
337 sUpdatePending = aUpdatePending; |
|
338 return NS_OK; |
|
339 } |
|
340 |
|
341 NS_IMETHODIMP |
|
342 nsWinMetroUtils::GetForeground(bool* aForeground) |
|
343 { |
|
344 *aForeground = (::GetActiveWindow() == ::GetForegroundWindow()); |
|
345 return NS_OK; |
|
346 } |
|
347 |
|
348 NS_IMETHODIMP |
|
349 nsWinMetroUtils::GetSupported(bool *aSupported) |
|
350 { |
|
351 *aSupported = false; |
|
352 if (!IsWin8OrLater()) { |
|
353 return NS_OK; |
|
354 } |
|
355 |
|
356 // if last_used_feature_level_idx is set, we've previously created a |
|
357 // d3d device that's compatible. See gfxEindowsPlatform for details. |
|
358 if (Preferences::GetInt("gfx.direct3d.last_used_feature_level_idx", -1) != -1) { |
|
359 *aSupported = true; |
|
360 return NS_OK; |
|
361 } |
|
362 |
|
363 // if last_used_feature_level_idx isn't set, gfx hasn't attempted to create |
|
364 // a device yet. This could be a case where d2d is pref'd off or blacklisted |
|
365 // on desktop, or we tried to create a device and failed. This could also be |
|
366 // a first run case where we haven't created an accelerated top level window |
|
367 // yet. |
|
368 |
|
369 NS_NAMED_LITERAL_STRING(metroRegValueName, "MetroD3DAvailable"); |
|
370 NS_NAMED_LITERAL_STRING(metroRegValuePath, "Software\\Mozilla\\Firefox"); |
|
371 |
|
372 // Check to see if the ceh launched us, it also does this check and caches |
|
373 // a flag in the registry. |
|
374 nsresult rv; |
|
375 uint32_t value = 0; |
|
376 nsCOMPtr<nsIWindowsRegKey> regKey = |
|
377 do_CreateInstance("@mozilla.org/windows-registry-key;1", &rv); |
|
378 if (NS_SUCCEEDED(rv)) { |
|
379 rv = regKey->Open(nsIWindowsRegKey::ROOT_KEY_CURRENT_USER, |
|
380 metroRegValuePath, |
|
381 nsIWindowsRegKey::ACCESS_ALL); |
|
382 if (NS_SUCCEEDED(rv)) { |
|
383 rv = regKey->ReadIntValue(metroRegValueName, &value); |
|
384 if (NS_SUCCEEDED(rv)) { |
|
385 *aSupported = (bool)value; |
|
386 return NS_OK; |
|
387 } |
|
388 |
|
389 // If all else fails, do the check here. This call is costly but |
|
390 // we shouldn't hit this except in rare situations where the |
|
391 // ceh never launched the browser that's running. |
|
392 value = D3DFeatureLevelCheck(); |
|
393 regKey->WriteIntValue(metroRegValueName, value); |
|
394 *aSupported = (bool)value; |
|
395 return NS_OK; |
|
396 } |
|
397 } |
|
398 return NS_OK; |
|
399 } |
|
400 |
|
401 } // widget |
|
402 } // mozilla |