Bug 1826326 [wpt PR 39360] - Get rid of ResourceWarnings produced by the tests, a...
[gecko.git] / widget / windows / WindowsUIUtils.cpp
blobb6db95055512c7f22a5e0812f97c1a91bc273e7b
1 /* -*- Mode: C++; tab-width: 2; 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 <windows.h>
7 #include <winsdkver.h>
8 #include <wrl.h>
10 #include "nsServiceManagerUtils.h"
12 #include "WindowsUIUtils.h"
14 #include "nsIObserverService.h"
15 #include "nsIAppShellService.h"
16 #include "nsAppShellCID.h"
17 #include "mozilla/ClearOnShutdown.h"
18 #include "mozilla/ResultVariant.h"
19 #include "mozilla/Services.h"
20 #include "mozilla/StaticPrefs_widget.h"
21 #include "mozilla/WidgetUtils.h"
22 #include "mozilla/WindowsVersion.h"
23 #include "mozilla/LookAndFeel.h"
24 #include "mozilla/ScopeExit.h"
25 #include "mozilla/media/MediaUtils.h"
26 #include "nsString.h"
27 #include "nsIWidget.h"
28 #include "nsIWindowMediator.h"
29 #include "nsPIDOMWindow.h"
30 #include "nsWindowGfx.h"
31 #include "Units.h"
33 /* mingw currently doesn't support windows.ui.viewmanagement.h, so we disable it
34 * until it's fixed. */
36 // See
37 // https://github.com/tpn/winsdk-10/blob/master/Include/10.0.14393.0/winrt/windows.ui.viewmanagement.h
38 // for the source of some of these definitions for older SDKs.
39 #ifndef __MINGW32__
41 # include <inspectable.h>
42 # include <roapi.h>
43 # include <windows.ui.viewmanagement.h>
45 # pragma comment(lib, "runtimeobject.lib")
47 using namespace ABI::Windows::UI;
48 using namespace ABI::Windows::UI::ViewManagement;
49 using namespace Microsoft::WRL;
50 using namespace Microsoft::WRL::Wrappers;
51 using namespace ABI::Windows::Foundation;
52 using namespace ABI::Windows::ApplicationModel::DataTransfer;
54 /* All of this is win10 stuff and we're compiling against win81 headers
55 * for now, so we may need to do some legwork: */
56 # if WINVER_MAXVER < 0x0A00
57 namespace ABI {
58 namespace Windows {
59 namespace UI {
60 namespace ViewManagement {
61 enum UserInteractionMode {
62 UserInteractionMode_Mouse = 0,
63 UserInteractionMode_Touch = 1
66 } // namespace UI
67 } // namespace Windows
68 } // namespace ABI
70 # endif
72 # ifndef RuntimeClass_Windows_UI_ViewManagement_UIViewSettings
73 # define RuntimeClass_Windows_UI_ViewManagement_UIViewSettings \
74 L"Windows.UI.ViewManagement.UIViewSettings"
75 # endif
77 # if WINVER_MAXVER < 0x0A00
78 namespace ABI {
79 namespace Windows {
80 namespace UI {
81 namespace ViewManagement {
82 interface IUIViewSettings;
83 MIDL_INTERFACE("C63657F6-8850-470D-88F8-455E16EA2C26")
84 IUIViewSettings : public IInspectable {
85 public:
86 virtual HRESULT STDMETHODCALLTYPE get_UserInteractionMode(
87 UserInteractionMode * value) = 0;
90 extern const __declspec(selectany) IID& IID_IUIViewSettings =
91 __uuidof(IUIViewSettings);
92 } // namespace ViewManagement
93 } // namespace UI
94 } // namespace Windows
95 } // namespace ABI
96 # endif
98 # ifndef IUIViewSettingsInterop
100 using IUIViewSettingsInterop = interface IUIViewSettingsInterop;
102 MIDL_INTERFACE("3694dbf9-8f68-44be-8ff5-195c98ede8a6")
103 IUIViewSettingsInterop : public IInspectable {
104 public:
105 virtual HRESULT STDMETHODCALLTYPE GetForWindow(HWND hwnd, REFIID riid,
106 void** ppv) = 0;
108 # endif
110 # ifndef __IDataTransferManagerInterop_INTERFACE_DEFINED__
111 # define __IDataTransferManagerInterop_INTERFACE_DEFINED__
113 using IDataTransferManagerInterop = interface IDataTransferManagerInterop;
115 MIDL_INTERFACE("3A3DCD6C-3EAB-43DC-BCDE-45671CE800C8")
116 IDataTransferManagerInterop : public IUnknown {
117 public:
118 virtual HRESULT STDMETHODCALLTYPE GetForWindow(
119 HWND appWindow, REFIID riid, void** dataTransferManager) = 0;
120 virtual HRESULT STDMETHODCALLTYPE ShowShareUIForWindow(HWND appWindow) = 0;
123 # endif
125 # if !defined( \
126 ____x_ABI_CWindows_CApplicationModel_CDataTransfer_CIDataPackage4_INTERFACE_DEFINED__)
127 # define ____x_ABI_CWindows_CApplicationModel_CDataTransfer_CIDataPackage4_INTERFACE_DEFINED__
129 MIDL_INTERFACE("13a24ec8-9382-536f-852a-3045e1b29a3b")
130 IDataPackage4 : public IInspectable {
131 public:
132 virtual HRESULT STDMETHODCALLTYPE add_ShareCanceled(
133 __FITypedEventHandler_2_Windows__CApplicationModel__CDataTransfer__CDataPackage_IInspectable *
134 handler,
135 EventRegistrationToken * token) = 0;
136 virtual HRESULT STDMETHODCALLTYPE remove_ShareCanceled(
137 EventRegistrationToken token) = 0;
140 # endif
142 # ifndef RuntimeClass_Windows_UI_ViewManagement_UISettings
143 # define RuntimeClass_Windows_UI_ViewManagement_UISettings \
144 L"Windows.UI.ViewManagement.UISettings"
145 # endif
146 # if WINDOWS_FOUNDATION_UNIVERSALAPICONTRACT_VERSION < 0x80000
147 namespace ABI {
148 namespace Windows {
149 namespace UI {
150 namespace ViewManagement {
152 class UISettings;
153 class UISettingsAutoHideScrollBarsChangedEventArgs;
154 interface IUISettingsAutoHideScrollBarsChangedEventArgs;
155 MIDL_INTERFACE("87afd4b2-9146-5f02-8f6b-06d454174c0f")
156 IUISettingsAutoHideScrollBarsChangedEventArgs : public IInspectable{};
158 } // namespace ViewManagement
159 } // namespace UI
160 } // namespace Windows
161 } // namespace ABI
163 namespace ABI {
164 namespace Windows {
165 namespace Foundation {
167 template <>
168 struct __declspec(uuid("808aef30-2660-51b0-9c11-f75dd42006b4"))
169 ITypedEventHandler<ABI::Windows::UI::ViewManagement::UISettings*,
170 ABI::Windows::UI::ViewManagement::
171 UISettingsAutoHideScrollBarsChangedEventArgs*>
172 : ITypedEventHandler_impl<
173 ABI::Windows::Foundation::Internal::AggregateType<
174 ABI::Windows::UI::ViewManagement::UISettings*,
175 ABI::Windows::UI::ViewManagement::IUISettings*>,
176 ABI::Windows::Foundation::Internal::AggregateType<
177 ABI::Windows::UI::ViewManagement::
178 UISettingsAutoHideScrollBarsChangedEventArgs*,
179 ABI::Windows::UI::ViewManagement::
180 IUISettingsAutoHideScrollBarsChangedEventArgs*>> {
181 static const wchar_t* z_get_rc_name_impl() {
182 return L"Windows.Foundation.TypedEventHandler`2<Windows.UI.ViewManagement."
183 L"UISettings, "
184 L"Windows.UI.ViewManagement."
185 L"UISettingsAutoHideScrollBarsChangedEventArgs>";
188 // Define a typedef for the parameterized interface specialization's mangled
189 // name. This allows code which uses the mangled name for the parameterized
190 // interface to access the correct parameterized interface specialization.
191 typedef ITypedEventHandler<ABI::Windows::UI::ViewManagement::UISettings*,
192 ABI::Windows::UI::ViewManagement::
193 UISettingsAutoHideScrollBarsChangedEventArgs*>
194 __FITypedEventHandler_2_Windows__CUI__CViewManagement__CUISettings_Windows__CUI__CViewManagement__CUISettingsAutoHideScrollBarsChangedEventArgs_t;
195 # define __FITypedEventHandler_2_Windows__CUI__CViewManagement__CUISettings_Windows__CUI__CViewManagement__CUISettingsAutoHideScrollBarsChangedEventArgs \
196 ABI::Windows::Foundation:: \
197 __FITypedEventHandler_2_Windows__CUI__CViewManagement__CUISettings_Windows__CUI__CViewManagement__CUISettingsAutoHideScrollBarsChangedEventArgs_t
199 } // namespace Foundation
200 } // namespace Windows
201 } // namespace ABI
203 namespace ABI {
204 namespace Windows {
205 namespace UI {
206 namespace ViewManagement {
207 class UISettings;
208 class UISettingsAutoHideScrollBarsChangedEventArgs;
209 interface IUISettings5;
210 MIDL_INTERFACE("5349d588-0cb5-5f05-bd34-706b3231f0bd")
211 IUISettings5 : public IInspectable {
212 public:
213 virtual HRESULT STDMETHODCALLTYPE get_AutoHideScrollBars(boolean * value) = 0;
214 virtual HRESULT STDMETHODCALLTYPE add_AutoHideScrollBarsChanged(
215 __FITypedEventHandler_2_Windows__CUI__CViewManagement__CUISettings_Windows__CUI__CViewManagement__CUISettingsAutoHideScrollBarsChangedEventArgs *
216 handler,
217 EventRegistrationToken * token) = 0;
218 virtual HRESULT STDMETHODCALLTYPE remove_AutoHideScrollBarsChanged(
219 EventRegistrationToken token) = 0;
221 } // namespace ViewManagement
222 } // namespace UI
223 } // namespace Windows
224 } // namespace ABI
225 # endif
226 #endif
228 using namespace mozilla;
230 enum class TabletModeState : uint8_t { Unknown, Off, On };
231 static TabletModeState sInTabletModeState;
233 WindowsUIUtils::WindowsUIUtils() = default;
234 WindowsUIUtils::~WindowsUIUtils() = default;
236 NS_IMPL_ISUPPORTS(WindowsUIUtils, nsIWindowsUIUtils)
238 NS_IMETHODIMP
239 WindowsUIUtils::GetSystemSmallIconSize(int32_t* aSize) {
240 NS_ENSURE_ARG(aSize);
242 mozilla::LayoutDeviceIntSize size =
243 nsWindowGfx::GetIconMetrics(nsWindowGfx::kSmallIcon);
244 *aSize = std::max(size.width, size.height);
245 return NS_OK;
248 NS_IMETHODIMP
249 WindowsUIUtils::GetSystemLargeIconSize(int32_t* aSize) {
250 NS_ENSURE_ARG(aSize);
252 mozilla::LayoutDeviceIntSize size =
253 nsWindowGfx::GetIconMetrics(nsWindowGfx::kRegularIcon);
254 *aSize = std::max(size.width, size.height);
255 return NS_OK;
258 NS_IMETHODIMP
259 WindowsUIUtils::SetWindowIcon(mozIDOMWindowProxy* aWindow,
260 imgIContainer* aSmallIcon,
261 imgIContainer* aBigIcon) {
262 NS_ENSURE_ARG(aWindow);
264 nsCOMPtr<nsIWidget> widget =
265 nsGlobalWindowOuter::Cast(aWindow)->GetMainWidget();
266 nsWindow* window = static_cast<nsWindow*>(widget.get());
268 nsresult rv;
270 if (aSmallIcon) {
271 HICON hIcon = nullptr;
272 rv = nsWindowGfx::CreateIcon(
273 aSmallIcon, false, mozilla::LayoutDeviceIntPoint(),
274 nsWindowGfx::GetIconMetrics(nsWindowGfx::kSmallIcon), &hIcon);
275 NS_ENSURE_SUCCESS(rv, rv);
277 window->SetSmallIcon(hIcon);
280 if (aBigIcon) {
281 HICON hIcon = nullptr;
282 rv = nsWindowGfx::CreateIcon(
283 aBigIcon, false, mozilla::LayoutDeviceIntPoint(),
284 nsWindowGfx::GetIconMetrics(nsWindowGfx::kRegularIcon), &hIcon);
285 NS_ENSURE_SUCCESS(rv, rv);
287 window->SetBigIcon(hIcon);
290 return NS_OK;
293 NS_IMETHODIMP
294 WindowsUIUtils::SetWindowIconFromExe(mozIDOMWindowProxy* aWindow,
295 const nsAString& aExe, uint16_t aIndex) {
296 NS_ENSURE_ARG(aWindow);
298 nsCOMPtr<nsIWidget> widget =
299 nsGlobalWindowOuter::Cast(aWindow)->GetMainWidget();
300 nsWindow* window = static_cast<nsWindow*>(widget.get());
302 HICON icon = ::LoadIconW(::GetModuleHandleW(PromiseFlatString(aExe).get()),
303 MAKEINTRESOURCEW(aIndex));
304 window->SetBigIcon(icon);
305 window->SetSmallIcon(icon);
307 return NS_OK;
310 NS_IMETHODIMP
311 WindowsUIUtils::SetWindowIconNoData(mozIDOMWindowProxy* aWindow) {
312 NS_ENSURE_ARG(aWindow);
314 nsCOMPtr<nsIWidget> widget =
315 nsGlobalWindowOuter::Cast(aWindow)->GetMainWidget();
316 nsWindow* window = static_cast<nsWindow*>(widget.get());
318 window->SetSmallIconNoData();
319 window->SetBigIconNoData();
321 return NS_OK;
324 bool WindowsUIUtils::GetInTabletMode() {
325 MOZ_DIAGNOSTIC_ASSERT(NS_IsMainThread());
326 if (sInTabletModeState == TabletModeState::Unknown) {
327 UpdateInTabletMode();
329 return sInTabletModeState == TabletModeState::On;
332 NS_IMETHODIMP
333 WindowsUIUtils::GetInTabletMode(bool* aResult) {
334 *aResult = GetInTabletMode();
335 return NS_OK;
338 static IInspectable* GetUISettings() {
339 MOZ_DIAGNOSTIC_ASSERT(NS_IsMainThread());
340 #ifndef __MINGW32__
341 // We need to keep this alive for ~ever so that change callbacks work as
342 // expected, sigh.
343 static StaticRefPtr<IInspectable> sUiSettingsAsInspectable;
345 if (!IsWin10OrLater()) {
346 // Windows.UI.ViewManagement.UISettings is Win10+ only.
347 return nullptr;
350 if (!sUiSettingsAsInspectable) {
351 ComPtr<IInspectable> uiSettingsAsInspectable;
352 ::RoActivateInstance(
353 HStringReference(RuntimeClass_Windows_UI_ViewManagement_UISettings)
354 .Get(),
355 &uiSettingsAsInspectable);
356 if (NS_WARN_IF(!uiSettingsAsInspectable)) {
357 return nullptr;
360 ComPtr<IUISettings5> uiSettings5;
361 if (SUCCEEDED(uiSettingsAsInspectable.As(&uiSettings5))) {
362 EventRegistrationToken unusedToken;
363 auto callback = Callback<ITypedEventHandler<
364 UISettings*, UISettingsAutoHideScrollBarsChangedEventArgs*>>(
365 [](auto...) {
366 // Scrollbar sizes change layout.
367 LookAndFeel::NotifyChangedAllWindows(
368 widget::ThemeChangeKind::StyleAndLayout);
369 return S_OK;
371 (void)NS_WARN_IF(FAILED(uiSettings5->add_AutoHideScrollBarsChanged(
372 callback.Get(), &unusedToken)));
375 ComPtr<IUISettings2> uiSettings2;
376 if (SUCCEEDED(uiSettingsAsInspectable.As(&uiSettings2))) {
377 EventRegistrationToken unusedToken;
378 auto callback =
379 Callback<ITypedEventHandler<UISettings*, IInspectable*>>([](auto...) {
380 // Text scale factor changes style and layout.
381 LookAndFeel::NotifyChangedAllWindows(
382 widget::ThemeChangeKind::StyleAndLayout);
383 return S_OK;
385 (void)NS_WARN_IF(FAILED(uiSettings2->add_TextScaleFactorChanged(
386 callback.Get(), &unusedToken)));
389 ComPtr<IUISettings3> uiSettings3;
390 if (SUCCEEDED(uiSettingsAsInspectable.As(&uiSettings3))) {
391 EventRegistrationToken unusedToken;
392 auto callback =
393 Callback<ITypedEventHandler<UISettings*, IInspectable*>>([](auto...) {
394 // System color changes change style only.
395 LookAndFeel::NotifyChangedAllWindows(
396 widget::ThemeChangeKind::Style);
397 return S_OK;
399 (void)NS_WARN_IF(FAILED(
400 uiSettings3->add_ColorValuesChanged(callback.Get(), &unusedToken)));
403 ComPtr<IUISettings4> uiSettings4;
404 if (SUCCEEDED(uiSettingsAsInspectable.As(&uiSettings4))) {
405 EventRegistrationToken unusedToken;
406 auto callback =
407 Callback<ITypedEventHandler<UISettings*, IInspectable*>>([](auto...) {
408 // Transparent effects changes change media queries only.
409 LookAndFeel::NotifyChangedAllWindows(
410 widget::ThemeChangeKind::MediaQueriesOnly);
411 return S_OK;
413 (void)NS_WARN_IF(FAILED(uiSettings4->add_AdvancedEffectsEnabledChanged(
414 callback.Get(), &unusedToken)));
417 sUiSettingsAsInspectable = dont_AddRef(uiSettingsAsInspectable.Detach());
418 ClearOnShutdown(&sUiSettingsAsInspectable);
421 return sUiSettingsAsInspectable.get();
422 #else
423 return nullptr;
424 #endif
427 Maybe<nscolor> WindowsUIUtils::GetAccentColor(int aTone) {
428 MOZ_ASSERT(aTone >= -3);
429 MOZ_ASSERT(aTone <= 3);
430 #ifndef __MINGW32__
431 ComPtr<IInspectable> settings = GetUISettings();
432 if (NS_WARN_IF(!settings)) {
433 return Nothing();
435 ComPtr<IUISettings3> uiSettings3;
436 if (NS_WARN_IF(FAILED(settings.As(&uiSettings3)))) {
437 return Nothing();
439 Color color;
440 auto colorType = UIColorType(int(UIColorType_Accent) + aTone);
441 if (NS_WARN_IF(FAILED(uiSettings3->GetColorValue(colorType, &color)))) {
442 return Nothing();
444 return Some(NS_RGBA(color.R, color.G, color.B, color.A));
445 #else
446 return Nothing();
447 #endif
450 Maybe<nscolor> WindowsUIUtils::GetSystemColor(ColorScheme aScheme,
451 int aSysColor) {
452 #ifndef __MINGW32__
453 if (!StaticPrefs::widget_windows_uwp_system_colors_enabled()) {
454 return Nothing();
457 // https://docs.microsoft.com/en-us/windows/apps/design/style/color
458 // Is a useful resource to see which values have decent contrast.
459 if (StaticPrefs::widget_windows_uwp_system_colors_highlight_accent()) {
460 if (aSysColor == COLOR_HIGHLIGHT) {
461 int tone = aScheme == ColorScheme::Light ? 0 : -1;
462 if (auto c = GetAccentColor(tone)) {
463 return c;
466 if (aSysColor == COLOR_HIGHLIGHTTEXT && GetAccentColor()) {
467 return Some(NS_RGBA(255, 255, 255, 255));
471 if (aScheme == ColorScheme::Dark) {
472 // There are no explicitly dark colors in UWP, other than the highlight
473 // colors above.
474 return Nothing();
477 auto knownType = [&]() -> Maybe<UIElementType> {
478 # define MAP(_win32, _uwp) \
479 case COLOR_##_win32: \
480 return Some(UIElementType_##_uwp)
481 switch (aSysColor) {
482 MAP(HIGHLIGHT, Highlight);
483 MAP(HIGHLIGHTTEXT, HighlightText);
484 MAP(ACTIVECAPTION, ActiveCaption);
485 MAP(BTNFACE, ButtonFace);
486 MAP(BTNTEXT, ButtonText);
487 MAP(CAPTIONTEXT, CaptionText);
488 MAP(GRAYTEXT, GrayText);
489 MAP(HOTLIGHT, Hotlight);
490 MAP(INACTIVECAPTION, InactiveCaption);
491 MAP(INACTIVECAPTIONTEXT, InactiveCaptionText);
492 MAP(WINDOW, Window);
493 MAP(WINDOWTEXT, WindowText);
494 default:
495 return Nothing();
497 # undef MAP
498 }();
499 if (!knownType) {
500 return Nothing();
502 ComPtr<IInspectable> settings = GetUISettings();
503 if (NS_WARN_IF(!settings)) {
504 return Nothing();
506 ComPtr<IUISettings> uiSettings;
507 if (NS_WARN_IF(FAILED(settings.As(&uiSettings)))) {
508 return Nothing();
510 Color color;
511 if (NS_WARN_IF(FAILED(uiSettings->UIElementColor(*knownType, &color)))) {
512 return Nothing();
514 return Some(NS_RGBA(color.R, color.G, color.B, color.A));
515 #else
516 return Nothing();
517 #endif
519 bool WindowsUIUtils::ComputeOverlayScrollbars() {
520 #ifndef __MINGW32__
521 if (!IsWin11OrLater()) {
522 // While in theory Windows 10 supports overlay scrollbar settings, it's off
523 // by default and it's untested whether our Win10 scrollbar drawing code
524 // deals with it properly.
525 return false;
527 if (!StaticPrefs::widget_windows_overlay_scrollbars_enabled()) {
528 return false;
530 ComPtr<IInspectable> settings = GetUISettings();
531 if (NS_WARN_IF(!settings)) {
532 return false;
534 ComPtr<IUISettings5> uiSettings5;
535 if (NS_WARN_IF(FAILED(settings.As(&uiSettings5)))) {
536 return false;
538 boolean autoHide = false;
539 if (NS_WARN_IF(FAILED(uiSettings5->get_AutoHideScrollBars(&autoHide)))) {
540 return false;
542 return autoHide;
543 #else
544 return false;
545 #endif
548 double WindowsUIUtils::ComputeTextScaleFactor() {
549 #ifndef __MINGW32__
550 ComPtr<IInspectable> settings = GetUISettings();
551 if (NS_WARN_IF(!settings)) {
552 return 1.0;
554 ComPtr<IUISettings2> uiSettings2;
555 if (NS_WARN_IF(FAILED(settings.As(&uiSettings2)))) {
556 return false;
558 double scaleFactor = 1.0;
559 if (NS_WARN_IF(FAILED(uiSettings2->get_TextScaleFactor(&scaleFactor)))) {
560 return 1.0;
562 return scaleFactor;
563 #else
564 return 1.0;
565 #endif
568 bool WindowsUIUtils::ComputeTransparencyEffects() {
569 constexpr bool kDefault = true;
570 #ifndef __MINGW32__
571 ComPtr<IInspectable> settings = GetUISettings();
572 if (NS_WARN_IF(!settings)) {
573 return kDefault;
575 ComPtr<IUISettings4> uiSettings4;
576 if (NS_WARN_IF(FAILED(settings.As(&uiSettings4)))) {
577 return kDefault;
579 boolean transparencyEffects = kDefault;
580 if (NS_WARN_IF(FAILED(
581 uiSettings4->get_AdvancedEffectsEnabled(&transparencyEffects)))) {
582 return kDefault;
584 return transparencyEffects;
585 #else
586 return kDefault;
587 #endif
590 void WindowsUIUtils::UpdateInTabletMode() {
591 #ifndef __MINGW32__
592 if (!IsWin10OrLater()) {
593 return;
596 nsresult rv;
597 nsCOMPtr<nsIWindowMediator> winMediator(
598 do_GetService(NS_WINDOWMEDIATOR_CONTRACTID, &rv));
599 if (NS_FAILED(rv)) {
600 return;
603 nsCOMPtr<nsIWidget> widget;
604 nsCOMPtr<mozIDOMWindowProxy> navWin;
606 rv = winMediator->GetMostRecentWindow(u"navigator:browser",
607 getter_AddRefs(navWin));
608 if (NS_FAILED(rv) || !navWin) {
609 // Fall back to the hidden window
610 nsCOMPtr<nsIAppShellService> appShell(
611 do_GetService(NS_APPSHELLSERVICE_CONTRACTID));
613 rv = appShell->GetHiddenDOMWindow(getter_AddRefs(navWin));
614 if (NS_FAILED(rv) || !navWin) {
615 return;
619 nsPIDOMWindowOuter* win = nsPIDOMWindowOuter::From(navWin);
620 widget = widget::WidgetUtils::DOMWindowToWidget(win);
622 if (!widget) {
623 return;
626 HWND winPtr = (HWND)widget->GetNativeData(NS_NATIVE_WINDOW);
627 ComPtr<IUIViewSettingsInterop> uiViewSettingsInterop;
629 HRESULT hr = GetActivationFactory(
630 HStringReference(RuntimeClass_Windows_UI_ViewManagement_UIViewSettings)
631 .Get(),
632 &uiViewSettingsInterop);
633 if (FAILED(hr)) {
634 return;
636 ComPtr<IUIViewSettings> uiViewSettings;
637 hr = uiViewSettingsInterop->GetForWindow(winPtr,
638 IID_PPV_ARGS(&uiViewSettings));
639 if (FAILED(hr)) {
640 return;
642 UserInteractionMode mode;
643 hr = uiViewSettings->get_UserInteractionMode(&mode);
644 if (FAILED(hr)) {
645 return;
648 TabletModeState oldTabletModeState = sInTabletModeState;
649 sInTabletModeState = mode == UserInteractionMode_Touch ? TabletModeState::On
650 : TabletModeState::Off;
651 if (sInTabletModeState != oldTabletModeState) {
652 nsCOMPtr<nsIObserverService> observerService =
653 mozilla::services::GetObserverService();
654 observerService->NotifyObservers(nullptr, "tablet-mode-change",
655 sInTabletModeState == TabletModeState::On
656 ? u"tablet-mode"
657 : u"normal-mode");
659 #endif
662 #ifndef __MINGW32__
663 struct HStringDeleter {
664 using pointer = HSTRING;
665 void operator()(pointer aString) { WindowsDeleteString(aString); }
668 using HStringUniquePtr = UniquePtr<HSTRING, HStringDeleter>;
670 Result<HStringUniquePtr, HRESULT> ConvertToWindowsString(
671 const nsAString& aStr) {
672 HSTRING rawStr;
673 HRESULT hr = WindowsCreateString(PromiseFlatString(aStr).get(), aStr.Length(),
674 &rawStr);
675 if (FAILED(hr)) {
676 return Err(hr);
678 return HStringUniquePtr(rawStr);
681 static Result<Ok, nsresult> RequestShare(
682 const std::function<HRESULT(IDataRequestedEventArgs* pArgs)>& aCallback) {
683 if (!IsWin10OrLater()) {
684 return Err(NS_ERROR_FAILURE);
687 HWND hwnd = GetForegroundWindow();
688 if (!hwnd) {
689 return Err(NS_ERROR_FAILURE);
692 ComPtr<IDataTransferManagerInterop> dtmInterop;
693 ComPtr<IDataTransferManager> dtm;
695 HRESULT hr = RoGetActivationFactory(
696 HStringReference(
697 RuntimeClass_Windows_ApplicationModel_DataTransfer_DataTransferManager)
698 .Get(),
699 IID_PPV_ARGS(&dtmInterop));
700 if (FAILED(hr) ||
701 FAILED(dtmInterop->GetForWindow(hwnd, IID_PPV_ARGS(&dtm)))) {
702 return Err(NS_ERROR_FAILURE);
705 auto callback = Callback<
706 ITypedEventHandler<DataTransferManager*, DataRequestedEventArgs*>>(
707 [aCallback](IDataTransferManager*,
708 IDataRequestedEventArgs* pArgs) -> HRESULT {
709 return aCallback(pArgs);
712 EventRegistrationToken dataRequestedToken;
713 if (FAILED(dtm->add_DataRequested(callback.Get(), &dataRequestedToken)) ||
714 FAILED(dtmInterop->ShowShareUIForWindow(hwnd))) {
715 return Err(NS_ERROR_FAILURE);
718 return Ok();
721 static Result<Ok, nsresult> AddShareEventListeners(
722 const RefPtr<mozilla::media::Refcountable<MozPromiseHolder<SharePromise>>>&
723 aPromiseHolder,
724 const ComPtr<IDataPackage>& aDataPackage) {
725 ComPtr<IDataPackage3> spDataPackage3;
727 if (FAILED(aDataPackage.As(&spDataPackage3))) {
728 return Err(NS_ERROR_FAILURE);
731 auto completedCallback =
732 Callback<ITypedEventHandler<DataPackage*, ShareCompletedEventArgs*>>(
733 [aPromiseHolder](IDataPackage*,
734 IShareCompletedEventArgs*) -> HRESULT {
735 aPromiseHolder->Resolve(true, __func__);
736 return S_OK;
739 EventRegistrationToken dataRequestedToken;
740 if (FAILED(spDataPackage3->add_ShareCompleted(completedCallback.Get(),
741 &dataRequestedToken))) {
742 return Err(NS_ERROR_FAILURE);
745 ComPtr<IDataPackage4> spDataPackage4;
746 if (SUCCEEDED(aDataPackage.As(&spDataPackage4))) {
747 // Use SharedCanceled API only on supported versions of Windows
748 // So that the older ones can still use ShareUrl()
750 auto canceledCallback =
751 Callback<ITypedEventHandler<DataPackage*, IInspectable*>>(
752 [aPromiseHolder](IDataPackage*, IInspectable*) -> HRESULT {
753 aPromiseHolder->Reject(NS_ERROR_FAILURE, __func__);
754 return S_OK;
757 if (FAILED(spDataPackage4->add_ShareCanceled(canceledCallback.Get(),
758 &dataRequestedToken))) {
759 return Err(NS_ERROR_FAILURE);
763 return Ok();
765 #endif
767 RefPtr<SharePromise> WindowsUIUtils::Share(nsAutoString aTitle,
768 nsAutoString aText,
769 nsAutoString aUrl) {
770 auto promiseHolder = MakeRefPtr<
771 mozilla::media::Refcountable<MozPromiseHolder<SharePromise>>>();
772 RefPtr<SharePromise> promise = promiseHolder->Ensure(__func__);
774 #ifndef __MINGW32__
775 auto result = RequestShare([promiseHolder, title = std::move(aTitle),
776 text = std::move(aText), url = std::move(aUrl)](
777 IDataRequestedEventArgs* pArgs) {
778 ComPtr<IDataRequest> spDataRequest;
779 ComPtr<IDataPackage> spDataPackage;
780 ComPtr<IDataPackage2> spDataPackage2;
781 ComPtr<IDataPackagePropertySet> spDataPackageProperties;
783 if (FAILED(pArgs->get_Request(&spDataRequest)) ||
784 FAILED(spDataRequest->get_Data(&spDataPackage)) ||
785 FAILED(spDataPackage.As(&spDataPackage2)) ||
786 FAILED(spDataPackage->get_Properties(&spDataPackageProperties))) {
787 promiseHolder->Reject(NS_ERROR_FAILURE, __func__);
788 return E_FAIL;
792 * Windows always requires a title, and an empty string does not work.
793 * Thus we trick the API by passing a whitespace when we have no title.
794 * https://docs.microsoft.com/en-us/windows/uwp/app-to-app/share-data
796 auto wTitle = ConvertToWindowsString((title.IsVoid() || title.Length() == 0)
797 ? nsAutoString(u" "_ns)
798 : title);
799 if (wTitle.isErr() ||
800 FAILED(spDataPackageProperties->put_Title(wTitle.unwrap().get()))) {
801 promiseHolder->Reject(NS_ERROR_FAILURE, __func__);
802 return E_FAIL;
805 // Assign even if empty, as Windows requires some data to share
806 auto wText = ConvertToWindowsString(text);
807 if (wText.isErr() || FAILED(spDataPackage->SetText(wText.unwrap().get()))) {
808 promiseHolder->Reject(NS_ERROR_FAILURE, __func__);
809 return E_FAIL;
812 if (!url.IsVoid()) {
813 auto wUrl = ConvertToWindowsString(url);
814 if (wUrl.isErr()) {
815 promiseHolder->Reject(NS_ERROR_FAILURE, __func__);
816 return wUrl.unwrapErr();
819 ComPtr<IUriRuntimeClassFactory> uriFactory;
820 ComPtr<IUriRuntimeClass> uri;
822 auto hr = GetActivationFactory(
823 HStringReference(RuntimeClass_Windows_Foundation_Uri).Get(),
824 &uriFactory);
826 if (FAILED(hr) ||
827 FAILED(uriFactory->CreateUri(wUrl.unwrap().get(), &uri)) ||
828 FAILED(spDataPackage2->SetWebLink(uri.Get()))) {
829 promiseHolder->Reject(NS_ERROR_FAILURE, __func__);
830 return E_FAIL;
834 if (!StaticPrefs::widget_windows_share_wait_action_enabled()) {
835 promiseHolder->Resolve(true, __func__);
836 } else if (AddShareEventListeners(promiseHolder, spDataPackage).isErr()) {
837 promiseHolder->Reject(NS_ERROR_FAILURE, __func__);
838 return E_FAIL;
841 return S_OK;
843 if (result.isErr()) {
844 promiseHolder->Reject(result.unwrapErr(), __func__);
846 #else
847 promiseHolder->Reject(NS_ERROR_FAILURE, __func__);
848 #endif
850 return promise;
853 NS_IMETHODIMP
854 WindowsUIUtils::ShareUrl(const nsAString& aUrlToShare,
855 const nsAString& aShareTitle) {
856 nsAutoString text;
857 text.SetIsVoid(true);
858 WindowsUIUtils::Share(nsAutoString(aShareTitle), text,
859 nsAutoString(aUrlToShare));
860 return NS_OK;