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