widget/windows/winrt/nsWinMetroUtils.cpp

changeset 0
6474c204b198
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/widget/windows/winrt/nsWinMetroUtils.cpp	Wed Dec 31 06:09:35 2014 +0100
     1.3 @@ -0,0 +1,402 @@
     1.4 +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
     1.5 +/* This Source Code Form is subject to the terms of the Mozilla Public
     1.6 + * License, v. 2.0. If a copy of the MPL was not distributed with this
     1.7 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     1.8 +
     1.9 +#include "nsWinMetroUtils.h"
    1.10 +#include "MetroUtils.h"
    1.11 +#include "nsXULAppAPI.h"
    1.12 +#include "FrameworkView.h"
    1.13 +#include "MetroApp.h"
    1.14 +#include "ToastNotificationHandler.h"
    1.15 +#include "mozilla/Preferences.h"
    1.16 +#include "mozilla/WindowsVersion.h"
    1.17 +#include "nsIWindowsRegKey.h"
    1.18 +#include "mozilla/widget/MetroD3DCheckHelper.h"
    1.19 +
    1.20 +#include <shldisp.h>
    1.21 +#include <shellapi.h>
    1.22 +#include <windows.ui.viewmanagement.h>
    1.23 +#include <windows.ui.startscreen.h>
    1.24 +
    1.25 +using namespace ABI::Windows::Foundation;
    1.26 +using namespace ABI::Windows::UI::StartScreen;
    1.27 +using namespace ABI::Windows::UI::ViewManagement;
    1.28 +using namespace Microsoft::WRL;
    1.29 +using namespace Microsoft::WRL::Wrappers;
    1.30 +using namespace mozilla::widget::winrt;
    1.31 +
    1.32 +namespace mozilla {
    1.33 +namespace widget {
    1.34 +namespace winrt {
    1.35 +extern ComPtr<MetroApp> sMetroApp;
    1.36 +extern nsTArray<nsString>* sSettingsArray;
    1.37 +} } }
    1.38 +
    1.39 +namespace mozilla {
    1.40 +namespace widget {
    1.41 +
    1.42 +bool nsWinMetroUtils::sUpdatePending = false;
    1.43 +
    1.44 +NS_IMPL_ISUPPORTS(nsWinMetroUtils, nsIWinMetroUtils)
    1.45 +
    1.46 +nsWinMetroUtils::nsWinMetroUtils()
    1.47 +{
    1.48 +}
    1.49 +
    1.50 +nsWinMetroUtils::~nsWinMetroUtils()
    1.51 +{
    1.52 +}
    1.53 +
    1.54 +/**
    1.55 + * Pins a new tile to the Windows 8 start screen.
    1.56 + *
    1.57 + * @param aTileID         An ID which can later be used to remove the tile
    1.58 + * @param aShortName      A short name for the tile
    1.59 + * @param aDiplayName     The name that will be displayed on the tile
    1.60 + * @param aActivationArgs The arguments to pass to the browser upon
    1.61 + *                        activation of the tile
    1.62 + * @param aTileImage An image for the normal tile view
    1.63 + * @param aSmallTileImage An image for the small tile view
    1.64 + */
    1.65 +NS_IMETHODIMP
    1.66 +nsWinMetroUtils::PinTileAsync(const nsAString &aTileID,
    1.67 +                              const nsAString &aShortName,
    1.68 +                              const nsAString &aDisplayName,
    1.69 +                              const nsAString &aActivationArgs,
    1.70 +                              const nsAString &aTileImage,
    1.71 +                              const nsAString &aSmallTileImage)
    1.72 +{
    1.73 +  if (XRE_GetWindowsEnvironment() != WindowsEnvironmentType_Metro) {
    1.74 +    NS_WARNING("PinTileAsync can't be called on the desktop.");
    1.75 +    return NS_ERROR_FAILURE;
    1.76 +  }
    1.77 +  HRESULT hr;
    1.78 +
    1.79 +  HString logoStr, smallLogoStr, displayName, shortName;
    1.80 +
    1.81 +  logoStr.Set(aTileImage.BeginReading());
    1.82 +  smallLogoStr.Set(aSmallTileImage.BeginReading());
    1.83 +  displayName.Set(aDisplayName.BeginReading());
    1.84 +  shortName.Set(aShortName.BeginReading());
    1.85 +
    1.86 +  ComPtr<IUriRuntimeClass> logo, smallLogo;
    1.87 +  AssertRetHRESULT(MetroUtils::CreateUri(logoStr, logo), NS_ERROR_FAILURE);
    1.88 +  AssertRetHRESULT(MetroUtils::CreateUri(smallLogoStr, smallLogo), NS_ERROR_FAILURE);
    1.89 +
    1.90 +  HString tileActivationArgumentsStr, tileIdStr;
    1.91 +  tileActivationArgumentsStr.Set(aActivationArgs.BeginReading());
    1.92 +  tileIdStr.Set(aTileID.BeginReading());
    1.93 +
    1.94 +  ComPtr<ISecondaryTileFactory> tileFactory;
    1.95 +  ComPtr<ISecondaryTile> secondaryTile;
    1.96 +  hr = GetActivationFactory(HStringReference(RuntimeClass_Windows_UI_StartScreen_SecondaryTile).Get(),
    1.97 +                            tileFactory.GetAddressOf());
    1.98 +  AssertRetHRESULT(hr, NS_ERROR_FAILURE);
    1.99 +  hr = tileFactory->CreateWithId(tileIdStr.Get(), secondaryTile.GetAddressOf());
   1.100 +  AssertRetHRESULT(hr, NS_ERROR_FAILURE);
   1.101 +
   1.102 +  secondaryTile->put_Logo(logo.Get());
   1.103 +  secondaryTile->put_SmallLogo(smallLogo.Get());
   1.104 +  secondaryTile->put_DisplayName(displayName.Get());
   1.105 +  secondaryTile->put_ShortName(shortName.Get());
   1.106 +  secondaryTile->put_Arguments(tileActivationArgumentsStr.Get());
   1.107 +  secondaryTile->put_TileOptions(TileOptions::TileOptions_ShowNameOnLogo);
   1.108 +
   1.109 +  // The tile is created and we can now attempt to pin the tile.
   1.110 +  ComPtr<IAsyncOperationCompletedHandler<bool>> callback(Callback<IAsyncOperationCompletedHandler<bool>>(
   1.111 +    sMetroApp.Get(), &MetroApp::OnAsyncTileCreated));
   1.112 +  ComPtr<IAsyncOperation<bool>> operation;
   1.113 +  AssertRetHRESULT(secondaryTile->RequestCreateAsync(operation.GetAddressOf()), NS_ERROR_FAILURE);
   1.114 +  operation->put_Completed(callback.Get());
   1.115 +  return NS_OK;
   1.116 +}
   1.117 +
   1.118 +/**
   1.119 + * Unpins a tile from the Windows 8 start screen.
   1.120 + *
   1.121 + * @param aTileID An existing ID which was previously pinned
   1.122 + */
   1.123 +NS_IMETHODIMP
   1.124 +nsWinMetroUtils::UnpinTileAsync(const nsAString &aTileID)
   1.125 +{
   1.126 +  if (XRE_GetWindowsEnvironment() != WindowsEnvironmentType_Metro) {
   1.127 +    NS_WARNING("UnpinTileAsync can't be called on the desktop.");
   1.128 +    return NS_ERROR_FAILURE;
   1.129 +  }
   1.130 +  HRESULT hr;
   1.131 +  HString tileIdStr;
   1.132 +  tileIdStr.Set(aTileID.BeginReading());
   1.133 +
   1.134 +  ComPtr<ISecondaryTileFactory> tileFactory;
   1.135 +  ComPtr<ISecondaryTile> secondaryTile;
   1.136 +  hr = GetActivationFactory(HStringReference(RuntimeClass_Windows_UI_StartScreen_SecondaryTile).Get(),
   1.137 +                            tileFactory.GetAddressOf());
   1.138 +  AssertRetHRESULT(hr, NS_ERROR_FAILURE);
   1.139 +  hr = tileFactory->CreateWithId(tileIdStr.Get(), secondaryTile.GetAddressOf());
   1.140 +  AssertRetHRESULT(hr, NS_ERROR_FAILURE);
   1.141 +
   1.142 +  // Attempt to unpin the tile
   1.143 +  ComPtr<IAsyncOperationCompletedHandler<bool>> callback(Callback<IAsyncOperationCompletedHandler<bool>>(
   1.144 +    sMetroApp.Get(), &MetroApp::OnAsyncTileCreated));
   1.145 +  ComPtr<IAsyncOperation<bool>> operation;
   1.146 +  AssertRetHRESULT(secondaryTile->RequestDeleteAsync(operation.GetAddressOf()), NS_ERROR_FAILURE);
   1.147 +  operation->put_Completed(callback.Get());
   1.148 +  return NS_OK;
   1.149 +}
   1.150 +
   1.151 +/**
   1.152 + * Determines if a tile is pinned to the Windows 8 start screen.
   1.153 + *
   1.154 + * @param aTileID   An ID which may have been pinned with pinTileAsync
   1.155 + * @param aIsPinned Out parameter for determining if the tile is pinned or not
   1.156 + */
   1.157 +NS_IMETHODIMP
   1.158 +nsWinMetroUtils::IsTilePinned(const nsAString &aTileID, bool *aIsPinned)
   1.159 +{
   1.160 +  if (XRE_GetWindowsEnvironment() != WindowsEnvironmentType_Metro) {
   1.161 +    NS_WARNING("IsTilePinned can't be called on the desktop.");
   1.162 +    return NS_ERROR_FAILURE;
   1.163 +  }
   1.164 +  NS_ENSURE_ARG_POINTER(aIsPinned);
   1.165 +
   1.166 +  HRESULT hr;
   1.167 +  HString tileIdStr;
   1.168 +  tileIdStr.Set(aTileID.BeginReading());
   1.169 +
   1.170 +  ComPtr<ISecondaryTileStatics> tileStatics;
   1.171 +  hr = GetActivationFactory(HStringReference(RuntimeClass_Windows_UI_StartScreen_SecondaryTile).Get(),
   1.172 +                            tileStatics.GetAddressOf());
   1.173 +  AssertRetHRESULT(hr, NS_ERROR_FAILURE);
   1.174 +  boolean result = false;
   1.175 +  tileStatics->Exists(tileIdStr.Get(), &result);
   1.176 +  *aIsPinned = result;
   1.177 +  return NS_OK;
   1.178 +}
   1.179 +
   1.180 +/**
   1.181 + * Launches the specified application with the specified arguments and
   1.182 + * switches to Desktop mode if in metro mode.
   1.183 +*/
   1.184 +NS_IMETHODIMP
   1.185 +nsWinMetroUtils::LaunchInDesktop(const nsAString &aPath, const nsAString &aArguments)
   1.186 +{
   1.187 +  SHELLEXECUTEINFOW sinfo;
   1.188 +  memset(&sinfo, 0, sizeof(SHELLEXECUTEINFOW));
   1.189 +  sinfo.cbSize       = sizeof(SHELLEXECUTEINFOW);
   1.190 +  // Per the Metro style enabled desktop browser, for some reason,
   1.191 +  // SEE_MASK_FLAG_LOG_USAGE is needed to change from immersive mode
   1.192 +  // to desktop.
   1.193 +  sinfo.fMask        = SEE_MASK_FLAG_LOG_USAGE;
   1.194 +  sinfo.hwnd         = nullptr;
   1.195 +  sinfo.lpFile       = aPath.BeginReading();
   1.196 +  sinfo.lpParameters = aArguments.BeginReading();
   1.197 +  sinfo.lpVerb       = L"open";
   1.198 +  sinfo.nShow        = SW_SHOWNORMAL;
   1.199 +
   1.200 +  if (!ShellExecuteEx(&sinfo)) {
   1.201 +    return NS_ERROR_FAILURE;
   1.202 +  }
   1.203 +  return NS_OK;
   1.204 +}
   1.205 +
   1.206 +NS_IMETHODIMP
   1.207 +nsWinMetroUtils::ShowNativeToast(const nsAString &aTitle,
   1.208 +  const nsAString &aMessage, const nsAString &anImage,
   1.209 +  const nsAString &aCookie, const nsAString& aAppId)
   1.210 +{
   1.211 +  ToastNotificationHandler* notification_handler =
   1.212 +      new ToastNotificationHandler;
   1.213 +
   1.214 +  HSTRING title = HStringReference(aTitle.BeginReading()).Get();
   1.215 +  HSTRING msg = HStringReference(aMessage.BeginReading()).Get();
   1.216 +
   1.217 +  bool ret;
   1.218 +  if (anImage.Length() > 0) {
   1.219 +    HSTRING imagePath = HStringReference(anImage.BeginReading()).Get();
   1.220 +    ret = notification_handler->DisplayNotification(title, msg, imagePath,
   1.221 +                                                    aCookie,
   1.222 +                                                    aAppId);
   1.223 +  } else {
   1.224 +    ret = notification_handler->DisplayTextNotification(title, msg, aCookie,
   1.225 +                                                        aAppId);
   1.226 +  }
   1.227 +
   1.228 +  if (!ret) {
   1.229 +    delete notification_handler;
   1.230 +    return NS_ERROR_FAILURE;
   1.231 +  }
   1.232 +
   1.233 +  return NS_OK;
   1.234 +}
   1.235 +
   1.236 +NS_IMETHODIMP
   1.237 +nsWinMetroUtils::ShowSettingsFlyout()
   1.238 +{
   1.239 +  if (XRE_GetWindowsEnvironment() != WindowsEnvironmentType_Metro) {
   1.240 +    NS_WARNING("Settings flyout can't be shown on the desktop.");
   1.241 +    return NS_ERROR_FAILURE;
   1.242 +  }
   1.243 +
   1.244 +  HRESULT hr = MetroUtils::ShowSettingsFlyout();
   1.245 +  return SUCCEEDED(hr) ? NS_OK : NS_ERROR_FAILURE;
   1.246 +}
   1.247 +
   1.248 +NS_IMETHODIMP
   1.249 +nsWinMetroUtils::GetImmersive(bool *aImersive)
   1.250 +{
   1.251 +  *aImersive =
   1.252 +    XRE_GetWindowsEnvironment() == WindowsEnvironmentType_Metro;
   1.253 +  return NS_OK;
   1.254 +}
   1.255 +
   1.256 +NS_IMETHODIMP
   1.257 +nsWinMetroUtils::GetActivationURI(nsAString &aActivationURI)
   1.258 +{
   1.259 +  if (XRE_GetWindowsEnvironment() != WindowsEnvironmentType_Metro) {
   1.260 +    return NS_ERROR_FAILURE;
   1.261 +  }
   1.262 +  FrameworkView::GetActivationURI(aActivationURI);
   1.263 +  return NS_OK;
   1.264 +}
   1.265 +
   1.266 +NS_IMETHODIMP
   1.267 +nsWinMetroUtils::GetPreviousExecutionState(int32_t *out)
   1.268 +{
   1.269 +  if (XRE_GetWindowsEnvironment() != WindowsEnvironmentType_Metro) {
   1.270 +    return NS_ERROR_FAILURE;
   1.271 +  }
   1.272 +  *out = FrameworkView::GetPreviousExecutionState();
   1.273 +  return NS_OK;
   1.274 +}
   1.275 +
   1.276 +NS_IMETHODIMP
   1.277 +nsWinMetroUtils::GetKeyboardVisible(bool *aImersive)
   1.278 +{
   1.279 +  *aImersive = FrameworkView::IsKeyboardVisible();
   1.280 +  return NS_OK;
   1.281 +}
   1.282 +
   1.283 +NS_IMETHODIMP
   1.284 +nsWinMetroUtils::GetKeyboardX(uint32_t *aX)
   1.285 +{
   1.286 +  *aX = static_cast<uint32_t>(floor(FrameworkView::KeyboardVisibleRect().X));
   1.287 +  return NS_OK;
   1.288 +}
   1.289 +
   1.290 +NS_IMETHODIMP
   1.291 +nsWinMetroUtils::GetKeyboardY(uint32_t *aY)
   1.292 +{
   1.293 +  *aY = static_cast<uint32_t>(floor(FrameworkView::KeyboardVisibleRect().Y));
   1.294 +  return NS_OK;
   1.295 +}
   1.296 +
   1.297 +NS_IMETHODIMP
   1.298 +nsWinMetroUtils::GetKeyboardWidth(uint32_t *aWidth)
   1.299 +{
   1.300 +  *aWidth = static_cast<uint32_t>(ceil(FrameworkView::KeyboardVisibleRect().Width));
   1.301 +  return NS_OK;
   1.302 +}
   1.303 +
   1.304 +NS_IMETHODIMP
   1.305 +nsWinMetroUtils::GetKeyboardHeight(uint32_t *aHeight)
   1.306 +{
   1.307 +  *aHeight = static_cast<uint32_t>(ceil(FrameworkView::KeyboardVisibleRect().Height));
   1.308 +  return NS_OK;
   1.309 +}
   1.310 +
   1.311 +NS_IMETHODIMP
   1.312 +nsWinMetroUtils::AddSettingsPanelEntry(const nsAString &aLabel, uint32_t *aId)
   1.313 +{
   1.314 +  NS_ENSURE_ARG_POINTER(aId);
   1.315 +  if (!sSettingsArray)
   1.316 +    return NS_ERROR_UNEXPECTED;
   1.317 +
   1.318 +  *aId = sSettingsArray->Length();
   1.319 +  sSettingsArray->AppendElement(nsString(aLabel));
   1.320 +  return NS_OK;
   1.321 +}
   1.322 +
   1.323 +NS_IMETHODIMP
   1.324 +nsWinMetroUtils::SwapMouseButton(bool aValue, bool *aOriginalValue)
   1.325 +{
   1.326 +  *aOriginalValue = ::SwapMouseButton(aValue);
   1.327 +  return NS_OK;
   1.328 +}
   1.329 +
   1.330 +NS_IMETHODIMP
   1.331 +nsWinMetroUtils::GetUpdatePending(bool *aUpdatePending)
   1.332 +{
   1.333 +  *aUpdatePending = sUpdatePending;
   1.334 +  return NS_OK;
   1.335 +}
   1.336 +
   1.337 +NS_IMETHODIMP
   1.338 +nsWinMetroUtils::SetUpdatePending(bool aUpdatePending)
   1.339 +{
   1.340 +  sUpdatePending = aUpdatePending;
   1.341 +  return NS_OK;
   1.342 +}
   1.343 +
   1.344 +NS_IMETHODIMP
   1.345 +nsWinMetroUtils::GetForeground(bool* aForeground)
   1.346 +{
   1.347 +  *aForeground = (::GetActiveWindow() == ::GetForegroundWindow());
   1.348 +  return NS_OK;
   1.349 +}
   1.350 +
   1.351 +NS_IMETHODIMP
   1.352 +nsWinMetroUtils::GetSupported(bool *aSupported)
   1.353 +{
   1.354 +  *aSupported = false;
   1.355 +  if (!IsWin8OrLater()) {
   1.356 +    return NS_OK;
   1.357 +  }
   1.358 +
   1.359 +  // if last_used_feature_level_idx is set, we've previously created a
   1.360 +  // d3d device that's compatible. See gfxEindowsPlatform for details.
   1.361 +  if (Preferences::GetInt("gfx.direct3d.last_used_feature_level_idx", -1) != -1) {
   1.362 +    *aSupported = true;
   1.363 +    return NS_OK;
   1.364 +  }
   1.365 +
   1.366 +  // if last_used_feature_level_idx isn't set, gfx hasn't attempted to create
   1.367 +  // a device yet. This could be a case where d2d is pref'd off or blacklisted
   1.368 +  // on desktop, or we tried to create a device and failed. This could also be
   1.369 +  // a first run case where we haven't created an accelerated top level window
   1.370 +  // yet.
   1.371 +
   1.372 +  NS_NAMED_LITERAL_STRING(metroRegValueName, "MetroD3DAvailable");
   1.373 +  NS_NAMED_LITERAL_STRING(metroRegValuePath, "Software\\Mozilla\\Firefox");
   1.374 +
   1.375 +  // Check to see if the ceh launched us, it also does this check and caches
   1.376 +  // a flag in the registry.
   1.377 +  nsresult rv;
   1.378 +  uint32_t value = 0;
   1.379 +  nsCOMPtr<nsIWindowsRegKey> regKey =
   1.380 +    do_CreateInstance("@mozilla.org/windows-registry-key;1", &rv);
   1.381 +  if (NS_SUCCEEDED(rv)) {
   1.382 +    rv = regKey->Open(nsIWindowsRegKey::ROOT_KEY_CURRENT_USER,
   1.383 +                      metroRegValuePath,
   1.384 +                      nsIWindowsRegKey::ACCESS_ALL);
   1.385 +    if (NS_SUCCEEDED(rv)) {
   1.386 +      rv = regKey->ReadIntValue(metroRegValueName, &value);
   1.387 +      if (NS_SUCCEEDED(rv)) {
   1.388 +        *aSupported = (bool)value;
   1.389 +        return NS_OK;
   1.390 +      }
   1.391 +
   1.392 +      // If all else fails, do the check here. This call is costly but
   1.393 +      // we shouldn't hit this except in rare situations where the
   1.394 +      // ceh never launched the browser that's running. 
   1.395 +      value = D3DFeatureLevelCheck();
   1.396 +      regKey->WriteIntValue(metroRegValueName, value);
   1.397 +      *aSupported = (bool)value;
   1.398 +      return NS_OK;
   1.399 +    }
   1.400 +  }
   1.401 +  return NS_OK;
   1.402 +}
   1.403 +
   1.404 +} // widget
   1.405 +} // mozilla

mercurial