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.

     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

mercurial