Thu, 15 Jan 2015 15:59:08 +0100
Implement a real Private Browsing Mode condition by changing the API/ABI;
This solves Tor bug #9701, complying with disk avoidance documented in
https://www.torproject.org/projects/torbrowser/design/#disk-avoidance.
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/. */
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"
17 #include <shldisp.h>
18 #include <shellapi.h>
19 #include <windows.ui.viewmanagement.h>
20 #include <windows.ui.startscreen.h>
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;
29 namespace mozilla {
30 namespace widget {
31 namespace winrt {
32 extern ComPtr<MetroApp> sMetroApp;
33 extern nsTArray<nsString>* sSettingsArray;
34 } } }
36 namespace mozilla {
37 namespace widget {
39 bool nsWinMetroUtils::sUpdatePending = false;
41 NS_IMPL_ISUPPORTS(nsWinMetroUtils, nsIWinMetroUtils)
43 nsWinMetroUtils::nsWinMetroUtils()
44 {
45 }
47 nsWinMetroUtils::~nsWinMetroUtils()
48 {
49 }
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;
76 HString logoStr, smallLogoStr, displayName, shortName;
78 logoStr.Set(aTileImage.BeginReading());
79 smallLogoStr.Set(aSmallTileImage.BeginReading());
80 displayName.Set(aDisplayName.BeginReading());
81 shortName.Set(aShortName.BeginReading());
83 ComPtr<IUriRuntimeClass> logo, smallLogo;
84 AssertRetHRESULT(MetroUtils::CreateUri(logoStr, logo), NS_ERROR_FAILURE);
85 AssertRetHRESULT(MetroUtils::CreateUri(smallLogoStr, smallLogo), NS_ERROR_FAILURE);
87 HString tileActivationArgumentsStr, tileIdStr;
88 tileActivationArgumentsStr.Set(aActivationArgs.BeginReading());
89 tileIdStr.Set(aTileID.BeginReading());
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);
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);
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 }
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());
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);
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 }
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);
163 HRESULT hr;
164 HString tileIdStr;
165 tileIdStr.Set(aTileID.BeginReading());
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 }
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;
197 if (!ShellExecuteEx(&sinfo)) {
198 return NS_ERROR_FAILURE;
199 }
200 return NS_OK;
201 }
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;
211 HSTRING title = HStringReference(aTitle.BeginReading()).Get();
212 HSTRING msg = HStringReference(aMessage.BeginReading()).Get();
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 }
225 if (!ret) {
226 delete notification_handler;
227 return NS_ERROR_FAILURE;
228 }
230 return NS_OK;
231 }
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 }
241 HRESULT hr = MetroUtils::ShowSettingsFlyout();
242 return SUCCEEDED(hr) ? NS_OK : NS_ERROR_FAILURE;
243 }
245 NS_IMETHODIMP
246 nsWinMetroUtils::GetImmersive(bool *aImersive)
247 {
248 *aImersive =
249 XRE_GetWindowsEnvironment() == WindowsEnvironmentType_Metro;
250 return NS_OK;
251 }
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 }
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 }
273 NS_IMETHODIMP
274 nsWinMetroUtils::GetKeyboardVisible(bool *aImersive)
275 {
276 *aImersive = FrameworkView::IsKeyboardVisible();
277 return NS_OK;
278 }
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 }
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 }
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 }
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 }
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;
315 *aId = sSettingsArray->Length();
316 sSettingsArray->AppendElement(nsString(aLabel));
317 return NS_OK;
318 }
320 NS_IMETHODIMP
321 nsWinMetroUtils::SwapMouseButton(bool aValue, bool *aOriginalValue)
322 {
323 *aOriginalValue = ::SwapMouseButton(aValue);
324 return NS_OK;
325 }
327 NS_IMETHODIMP
328 nsWinMetroUtils::GetUpdatePending(bool *aUpdatePending)
329 {
330 *aUpdatePending = sUpdatePending;
331 return NS_OK;
332 }
334 NS_IMETHODIMP
335 nsWinMetroUtils::SetUpdatePending(bool aUpdatePending)
336 {
337 sUpdatePending = aUpdatePending;
338 return NS_OK;
339 }
341 NS_IMETHODIMP
342 nsWinMetroUtils::GetForeground(bool* aForeground)
343 {
344 *aForeground = (::GetActiveWindow() == ::GetForegroundWindow());
345 return NS_OK;
346 }
348 NS_IMETHODIMP
349 nsWinMetroUtils::GetSupported(bool *aSupported)
350 {
351 *aSupported = false;
352 if (!IsWin8OrLater()) {
353 return NS_OK;
354 }
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 }
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.
369 NS_NAMED_LITERAL_STRING(metroRegValueName, "MetroD3DAvailable");
370 NS_NAMED_LITERAL_STRING(metroRegValuePath, "Software\\Mozilla\\Firefox");
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 }
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 }
401 } // widget
402 } // mozilla