widget/windows/winrt/nsWinMetroUtils.cpp

Thu, 15 Jan 2015 15:59:08 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Thu, 15 Jan 2015 15:59:08 +0100
branch
TOR_BUG_9701
changeset 10
ac0c01689b40
permissions
-rw-r--r--

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.

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

mercurial