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/. */
9 #include "nsServiceManagerUtils.h"
11 #include "WindowsUIUtils.h"
13 #include "nsIObserverService.h"
14 #include "nsIAppShellService.h"
15 #include "nsAppShellCID.h"
16 #include "mozilla/ClearOnShutdown.h"
17 #include "mozilla/ResultVariant.h"
18 #include "mozilla/Services.h"
19 #include "mozilla/StaticPrefs_widget.h"
20 #include "mozilla/WidgetUtils.h"
21 #include "mozilla/WindowsVersion.h"
22 #include "mozilla/LookAndFeel.h"
23 #include "mozilla/ScopeExit.h"
24 #include "mozilla/media/MediaUtils.h"
26 #include "nsGlobalWindowOuter.h"
27 #include "nsIWidget.h"
28 #include "nsIWindowMediator.h"
29 #include "nsPIDOMWindow.h"
30 #include "nsWindowGfx.h"
33 /* mingw currently doesn't support windows.ui.viewmanagement.h, so we disable it
34 * until it's fixed. */
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.
41 # include <inspectable.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 # ifndef RuntimeClass_Windows_UI_ViewManagement_UIViewSettings
55 # define RuntimeClass_Windows_UI_ViewManagement_UIViewSettings \
56 L"Windows.UI.ViewManagement.UIViewSettings"
59 # ifndef IUIViewSettingsInterop
61 using IUIViewSettingsInterop
= interface IUIViewSettingsInterop
;
63 MIDL_INTERFACE("3694dbf9-8f68-44be-8ff5-195c98ede8a6")
64 IUIViewSettingsInterop
: public IInspectable
{
66 virtual HRESULT STDMETHODCALLTYPE
GetForWindow(HWND hwnd
, REFIID riid
,
71 # ifndef __IDataTransferManagerInterop_INTERFACE_DEFINED__
72 # define __IDataTransferManagerInterop_INTERFACE_DEFINED__
74 using IDataTransferManagerInterop
= interface IDataTransferManagerInterop
;
76 MIDL_INTERFACE("3A3DCD6C-3EAB-43DC-BCDE-45671CE800C8")
77 IDataTransferManagerInterop
: public IUnknown
{
79 virtual HRESULT STDMETHODCALLTYPE
GetForWindow(
80 HWND appWindow
, REFIID riid
, void** dataTransferManager
) = 0;
81 virtual HRESULT STDMETHODCALLTYPE
ShowShareUIForWindow(HWND appWindow
) = 0;
87 ____x_ABI_CWindows_CApplicationModel_CDataTransfer_CIDataPackage4_INTERFACE_DEFINED__)
88 # define ____x_ABI_CWindows_CApplicationModel_CDataTransfer_CIDataPackage4_INTERFACE_DEFINED__
90 MIDL_INTERFACE("13a24ec8-9382-536f-852a-3045e1b29a3b")
91 IDataPackage4
: public IInspectable
{
93 virtual HRESULT STDMETHODCALLTYPE
add_ShareCanceled(
94 __FITypedEventHandler_2_Windows__CApplicationModel__CDataTransfer__CDataPackage_IInspectable
*
96 EventRegistrationToken
* token
) = 0;
97 virtual HRESULT STDMETHODCALLTYPE
remove_ShareCanceled(
98 EventRegistrationToken token
) = 0;
103 # ifndef RuntimeClass_Windows_UI_ViewManagement_UISettings
104 # define RuntimeClass_Windows_UI_ViewManagement_UISettings \
105 L"Windows.UI.ViewManagement.UISettings"
107 # if WINDOWS_FOUNDATION_UNIVERSALAPICONTRACT_VERSION < 0x80000
111 namespace ViewManagement
{
114 class UISettingsAutoHideScrollBarsChangedEventArgs
;
115 interface IUISettingsAutoHideScrollBarsChangedEventArgs
;
116 MIDL_INTERFACE("87afd4b2-9146-5f02-8f6b-06d454174c0f")
117 IUISettingsAutoHideScrollBarsChangedEventArgs
: public IInspectable
{};
119 } // namespace ViewManagement
121 } // namespace Windows
126 namespace Foundation
{
129 struct __declspec(uuid("808aef30-2660-51b0-9c11-f75dd42006b4"))
130 ITypedEventHandler
<ABI::Windows::UI::ViewManagement::UISettings
*,
131 ABI::Windows::UI::ViewManagement::
132 UISettingsAutoHideScrollBarsChangedEventArgs
*>
133 : ITypedEventHandler_impl
<
134 ABI::Windows::Foundation::Internal::AggregateType
<
135 ABI::Windows::UI::ViewManagement::UISettings
*,
136 ABI::Windows::UI::ViewManagement::IUISettings
*>,
137 ABI::Windows::Foundation::Internal::AggregateType
<
138 ABI::Windows::UI::ViewManagement::
139 UISettingsAutoHideScrollBarsChangedEventArgs
*,
140 ABI::Windows::UI::ViewManagement::
141 IUISettingsAutoHideScrollBarsChangedEventArgs
*>> {
142 static const wchar_t* z_get_rc_name_impl() {
143 return L
"Windows.Foundation.TypedEventHandler`2<Windows.UI.ViewManagement."
145 L
"Windows.UI.ViewManagement."
146 L
"UISettingsAutoHideScrollBarsChangedEventArgs>";
149 // Define a typedef for the parameterized interface specialization's mangled
150 // name. This allows code which uses the mangled name for the parameterized
151 // interface to access the correct parameterized interface specialization.
152 typedef ITypedEventHandler
<ABI::Windows::UI::ViewManagement::UISettings
*,
153 ABI::Windows::UI::ViewManagement::
154 UISettingsAutoHideScrollBarsChangedEventArgs
*>
155 __FITypedEventHandler_2_Windows__CUI__CViewManagement__CUISettings_Windows__CUI__CViewManagement__CUISettingsAutoHideScrollBarsChangedEventArgs_t
;
156 # define __FITypedEventHandler_2_Windows__CUI__CViewManagement__CUISettings_Windows__CUI__CViewManagement__CUISettingsAutoHideScrollBarsChangedEventArgs \
157 ABI::Windows::Foundation:: \
158 __FITypedEventHandler_2_Windows__CUI__CViewManagement__CUISettings_Windows__CUI__CViewManagement__CUISettingsAutoHideScrollBarsChangedEventArgs_t
160 } // namespace Foundation
161 } // namespace Windows
167 namespace ViewManagement
{
169 class UISettingsAutoHideScrollBarsChangedEventArgs
;
170 interface IUISettings5
;
171 MIDL_INTERFACE("5349d588-0cb5-5f05-bd34-706b3231f0bd")
172 IUISettings5
: public IInspectable
{
174 virtual HRESULT STDMETHODCALLTYPE
get_AutoHideScrollBars(boolean
* value
) = 0;
175 virtual HRESULT STDMETHODCALLTYPE
add_AutoHideScrollBarsChanged(
176 __FITypedEventHandler_2_Windows__CUI__CViewManagement__CUISettings_Windows__CUI__CViewManagement__CUISettingsAutoHideScrollBarsChangedEventArgs
*
178 EventRegistrationToken
* token
) = 0;
179 virtual HRESULT STDMETHODCALLTYPE
remove_AutoHideScrollBarsChanged(
180 EventRegistrationToken token
) = 0;
182 } // namespace ViewManagement
184 } // namespace Windows
189 using namespace mozilla
;
191 enum class TabletModeState
: uint8_t { Unknown
, Off
, On
};
192 static TabletModeState sInTabletModeState
;
194 WindowsUIUtils::WindowsUIUtils() = default;
195 WindowsUIUtils::~WindowsUIUtils() = default;
197 NS_IMPL_ISUPPORTS(WindowsUIUtils
, nsIWindowsUIUtils
)
200 WindowsUIUtils::GetSystemSmallIconSize(int32_t* aSize
) {
201 NS_ENSURE_ARG(aSize
);
203 mozilla::LayoutDeviceIntSize size
=
204 nsWindowGfx::GetIconMetrics(nsWindowGfx::kSmallIcon
);
205 *aSize
= std::max(size
.width
, size
.height
);
210 WindowsUIUtils::GetSystemLargeIconSize(int32_t* aSize
) {
211 NS_ENSURE_ARG(aSize
);
213 mozilla::LayoutDeviceIntSize size
=
214 nsWindowGfx::GetIconMetrics(nsWindowGfx::kRegularIcon
);
215 *aSize
= std::max(size
.width
, size
.height
);
220 WindowsUIUtils::SetWindowIcon(mozIDOMWindowProxy
* aWindow
,
221 imgIContainer
* aSmallIcon
,
222 imgIContainer
* aBigIcon
) {
223 NS_ENSURE_ARG(aWindow
);
225 nsCOMPtr
<nsIWidget
> widget
=
226 nsGlobalWindowOuter::Cast(aWindow
)->GetMainWidget();
227 nsWindow
* window
= static_cast<nsWindow
*>(widget
.get());
232 HICON hIcon
= nullptr;
233 rv
= nsWindowGfx::CreateIcon(
234 aSmallIcon
, false, mozilla::LayoutDeviceIntPoint(),
235 nsWindowGfx::GetIconMetrics(nsWindowGfx::kSmallIcon
), &hIcon
);
236 NS_ENSURE_SUCCESS(rv
, rv
);
238 window
->SetSmallIcon(hIcon
);
242 HICON hIcon
= nullptr;
243 rv
= nsWindowGfx::CreateIcon(
244 aBigIcon
, false, mozilla::LayoutDeviceIntPoint(),
245 nsWindowGfx::GetIconMetrics(nsWindowGfx::kRegularIcon
), &hIcon
);
246 NS_ENSURE_SUCCESS(rv
, rv
);
248 window
->SetBigIcon(hIcon
);
255 WindowsUIUtils::SetWindowIconFromExe(mozIDOMWindowProxy
* aWindow
,
256 const nsAString
& aExe
, uint16_t aIndex
) {
257 NS_ENSURE_ARG(aWindow
);
259 nsCOMPtr
<nsIWidget
> widget
=
260 nsGlobalWindowOuter::Cast(aWindow
)->GetMainWidget();
261 nsWindow
* window
= static_cast<nsWindow
*>(widget
.get());
263 HICON icon
= ::LoadIconW(::GetModuleHandleW(PromiseFlatString(aExe
).get()),
264 MAKEINTRESOURCEW(aIndex
));
265 window
->SetBigIcon(icon
);
266 window
->SetSmallIcon(icon
);
272 WindowsUIUtils::SetWindowIconNoData(mozIDOMWindowProxy
* aWindow
) {
273 NS_ENSURE_ARG(aWindow
);
275 nsCOMPtr
<nsIWidget
> widget
=
276 nsGlobalWindowOuter::Cast(aWindow
)->GetMainWidget();
277 nsWindow
* window
= static_cast<nsWindow
*>(widget
.get());
279 window
->SetSmallIconNoData();
280 window
->SetBigIconNoData();
285 bool WindowsUIUtils::GetInTabletMode() {
286 MOZ_DIAGNOSTIC_ASSERT(NS_IsMainThread());
287 if (sInTabletModeState
== TabletModeState::Unknown
) {
288 UpdateInTabletMode();
290 return sInTabletModeState
== TabletModeState::On
;
294 WindowsUIUtils::GetInTabletMode(bool* aResult
) {
295 *aResult
= GetInTabletMode();
299 static IInspectable
* GetUISettings() {
300 MOZ_DIAGNOSTIC_ASSERT(NS_IsMainThread());
302 // We need to keep this alive for ~ever so that change callbacks work as
304 static StaticRefPtr
<IInspectable
> sUiSettingsAsInspectable
;
306 if (!sUiSettingsAsInspectable
) {
307 ComPtr
<IInspectable
> uiSettingsAsInspectable
;
308 ::RoActivateInstance(
309 HStringReference(RuntimeClass_Windows_UI_ViewManagement_UISettings
)
311 &uiSettingsAsInspectable
);
312 if (NS_WARN_IF(!uiSettingsAsInspectable
)) {
316 ComPtr
<IUISettings5
> uiSettings5
;
317 if (SUCCEEDED(uiSettingsAsInspectable
.As(&uiSettings5
))) {
318 EventRegistrationToken unusedToken
;
319 auto callback
= Callback
<ITypedEventHandler
<
320 UISettings
*, UISettingsAutoHideScrollBarsChangedEventArgs
*>>(
322 // Scrollbar sizes change layout.
323 LookAndFeel::NotifyChangedAllWindows(
324 widget::ThemeChangeKind::StyleAndLayout
);
327 (void)NS_WARN_IF(FAILED(uiSettings5
->add_AutoHideScrollBarsChanged(
328 callback
.Get(), &unusedToken
)));
331 ComPtr
<IUISettings2
> uiSettings2
;
332 if (SUCCEEDED(uiSettingsAsInspectable
.As(&uiSettings2
))) {
333 EventRegistrationToken unusedToken
;
335 Callback
<ITypedEventHandler
<UISettings
*, IInspectable
*>>([](auto...) {
336 // Text scale factor changes style and layout.
337 LookAndFeel::NotifyChangedAllWindows(
338 widget::ThemeChangeKind::StyleAndLayout
);
341 (void)NS_WARN_IF(FAILED(uiSettings2
->add_TextScaleFactorChanged(
342 callback
.Get(), &unusedToken
)));
345 ComPtr
<IUISettings3
> uiSettings3
;
346 if (SUCCEEDED(uiSettingsAsInspectable
.As(&uiSettings3
))) {
347 EventRegistrationToken unusedToken
;
349 Callback
<ITypedEventHandler
<UISettings
*, IInspectable
*>>([](auto...) {
350 // System color changes change style only.
351 LookAndFeel::NotifyChangedAllWindows(
352 widget::ThemeChangeKind::Style
);
355 (void)NS_WARN_IF(FAILED(
356 uiSettings3
->add_ColorValuesChanged(callback
.Get(), &unusedToken
)));
359 ComPtr
<IUISettings4
> uiSettings4
;
360 if (SUCCEEDED(uiSettingsAsInspectable
.As(&uiSettings4
))) {
361 EventRegistrationToken unusedToken
;
363 Callback
<ITypedEventHandler
<UISettings
*, IInspectable
*>>([](auto...) {
364 // Transparent effects changes change media queries only.
365 LookAndFeel::NotifyChangedAllWindows(
366 widget::ThemeChangeKind::MediaQueriesOnly
);
369 (void)NS_WARN_IF(FAILED(uiSettings4
->add_AdvancedEffectsEnabledChanged(
370 callback
.Get(), &unusedToken
)));
373 sUiSettingsAsInspectable
= dont_AddRef(uiSettingsAsInspectable
.Detach());
374 ClearOnShutdown(&sUiSettingsAsInspectable
);
377 return sUiSettingsAsInspectable
.get();
383 Maybe
<nscolor
> WindowsUIUtils::GetAccentColor(int aTone
) {
384 MOZ_ASSERT(aTone
>= -3);
385 MOZ_ASSERT(aTone
<= 3);
387 ComPtr
<IInspectable
> settings
= GetUISettings();
388 if (NS_WARN_IF(!settings
)) {
391 ComPtr
<IUISettings3
> uiSettings3
;
392 if (NS_WARN_IF(FAILED(settings
.As(&uiSettings3
)))) {
396 auto colorType
= UIColorType(int(UIColorType_Accent
) + aTone
);
397 if (NS_WARN_IF(FAILED(uiSettings3
->GetColorValue(colorType
, &color
)))) {
400 return Some(NS_RGBA(color
.R
, color
.G
, color
.B
, color
.A
));
406 Maybe
<nscolor
> WindowsUIUtils::GetSystemColor(ColorScheme aScheme
,
409 if (!StaticPrefs::widget_windows_uwp_system_colors_enabled()) {
413 // https://docs.microsoft.com/en-us/windows/apps/design/style/color
414 // Is a useful resource to see which values have decent contrast.
415 if (StaticPrefs::widget_windows_uwp_system_colors_highlight_accent()) {
416 if (aSysColor
== COLOR_HIGHLIGHT
) {
417 int tone
= aScheme
== ColorScheme::Light
? 0 : -1;
418 if (auto c
= GetAccentColor(tone
)) {
422 if (aSysColor
== COLOR_HIGHLIGHTTEXT
&& GetAccentColor()) {
423 return Some(NS_RGBA(255, 255, 255, 255));
427 if (aScheme
== ColorScheme::Dark
) {
428 // There are no explicitly dark colors in UWP, other than the highlight
433 auto knownType
= [&]() -> Maybe
<UIElementType
> {
434 # define MAP(_win32, _uwp) \
435 case COLOR_##_win32: \
436 return Some(UIElementType_##_uwp)
438 MAP(HIGHLIGHT
, Highlight
);
439 MAP(HIGHLIGHTTEXT
, HighlightText
);
440 MAP(ACTIVECAPTION
, ActiveCaption
);
441 MAP(BTNFACE
, ButtonFace
);
442 MAP(BTNTEXT
, ButtonText
);
443 MAP(CAPTIONTEXT
, CaptionText
);
444 MAP(GRAYTEXT
, GrayText
);
445 MAP(HOTLIGHT
, Hotlight
);
446 MAP(INACTIVECAPTION
, InactiveCaption
);
447 MAP(INACTIVECAPTIONTEXT
, InactiveCaptionText
);
449 MAP(WINDOWTEXT
, WindowText
);
458 ComPtr
<IInspectable
> settings
= GetUISettings();
459 if (NS_WARN_IF(!settings
)) {
462 ComPtr
<IUISettings
> uiSettings
;
463 if (NS_WARN_IF(FAILED(settings
.As(&uiSettings
)))) {
467 if (NS_WARN_IF(FAILED(uiSettings
->UIElementColor(*knownType
, &color
)))) {
470 return Some(NS_RGBA(color
.R
, color
.G
, color
.B
, color
.A
));
475 bool WindowsUIUtils::ComputeOverlayScrollbars() {
477 if (!IsWin11OrLater()) {
478 // While in theory Windows 10 supports overlay scrollbar settings, it's off
479 // by default and it's untested whether our Win10 scrollbar drawing code
480 // deals with it properly.
483 if (!StaticPrefs::widget_windows_overlay_scrollbars_enabled()) {
486 ComPtr
<IInspectable
> settings
= GetUISettings();
487 if (NS_WARN_IF(!settings
)) {
490 ComPtr
<IUISettings5
> uiSettings5
;
491 if (NS_WARN_IF(FAILED(settings
.As(&uiSettings5
)))) {
494 boolean autoHide
= false;
495 if (NS_WARN_IF(FAILED(uiSettings5
->get_AutoHideScrollBars(&autoHide
)))) {
504 double WindowsUIUtils::ComputeTextScaleFactor() {
506 ComPtr
<IInspectable
> settings
= GetUISettings();
507 if (NS_WARN_IF(!settings
)) {
510 ComPtr
<IUISettings2
> uiSettings2
;
511 if (NS_WARN_IF(FAILED(settings
.As(&uiSettings2
)))) {
514 double scaleFactor
= 1.0;
515 if (NS_WARN_IF(FAILED(uiSettings2
->get_TextScaleFactor(&scaleFactor
)))) {
524 bool WindowsUIUtils::ComputeTransparencyEffects() {
525 constexpr bool kDefault
= true;
527 ComPtr
<IInspectable
> settings
= GetUISettings();
528 if (NS_WARN_IF(!settings
)) {
531 ComPtr
<IUISettings4
> uiSettings4
;
532 if (NS_WARN_IF(FAILED(settings
.As(&uiSettings4
)))) {
535 boolean transparencyEffects
= kDefault
;
536 if (NS_WARN_IF(FAILED(
537 uiSettings4
->get_AdvancedEffectsEnabled(&transparencyEffects
)))) {
540 return transparencyEffects
;
546 void WindowsUIUtils::UpdateInTabletMode() {
549 nsCOMPtr
<nsIWindowMediator
> winMediator(
550 do_GetService(NS_WINDOWMEDIATOR_CONTRACTID
, &rv
));
555 nsCOMPtr
<nsIWidget
> widget
;
556 nsCOMPtr
<mozIDOMWindowProxy
> navWin
;
558 rv
= winMediator
->GetMostRecentWindow(u
"navigator:browser",
559 getter_AddRefs(navWin
));
560 if (NS_FAILED(rv
) || !navWin
) {
561 // Fall back to the hidden window
562 nsCOMPtr
<nsIAppShellService
> appShell(
563 do_GetService(NS_APPSHELLSERVICE_CONTRACTID
));
565 rv
= appShell
->GetHiddenDOMWindow(getter_AddRefs(navWin
));
566 if (NS_FAILED(rv
) || !navWin
) {
571 nsPIDOMWindowOuter
* win
= nsPIDOMWindowOuter::From(navWin
);
572 widget
= widget::WidgetUtils::DOMWindowToWidget(win
);
578 HWND winPtr
= (HWND
)widget
->GetNativeData(NS_NATIVE_WINDOW
);
579 ComPtr
<IUIViewSettingsInterop
> uiViewSettingsInterop
;
581 HRESULT hr
= GetActivationFactory(
582 HStringReference(RuntimeClass_Windows_UI_ViewManagement_UIViewSettings
)
584 &uiViewSettingsInterop
);
588 ComPtr
<IUIViewSettings
> uiViewSettings
;
589 hr
= uiViewSettingsInterop
->GetForWindow(winPtr
,
590 IID_PPV_ARGS(&uiViewSettings
));
594 UserInteractionMode mode
;
595 hr
= uiViewSettings
->get_UserInteractionMode(&mode
);
600 TabletModeState oldTabletModeState
= sInTabletModeState
;
601 sInTabletModeState
= mode
== UserInteractionMode_Touch
? TabletModeState::On
602 : TabletModeState::Off
;
603 if (sInTabletModeState
!= oldTabletModeState
) {
604 nsCOMPtr
<nsIObserverService
> observerService
=
605 mozilla::services::GetObserverService();
606 observerService
->NotifyObservers(nullptr, "tablet-mode-change",
607 sInTabletModeState
== TabletModeState::On
615 struct HStringDeleter
{
616 using pointer
= HSTRING
;
617 void operator()(pointer aString
) { WindowsDeleteString(aString
); }
620 using HStringUniquePtr
= UniquePtr
<HSTRING
, HStringDeleter
>;
622 Result
<HStringUniquePtr
, HRESULT
> ConvertToWindowsString(
623 const nsAString
& aStr
) {
625 HRESULT hr
= WindowsCreateString(PromiseFlatString(aStr
).get(), aStr
.Length(),
630 return HStringUniquePtr(rawStr
);
633 static Result
<Ok
, nsresult
> RequestShare(
634 const std::function
<HRESULT(IDataRequestedEventArgs
* pArgs
)>& aCallback
) {
635 HWND hwnd
= GetForegroundWindow();
637 return Err(NS_ERROR_FAILURE
);
640 ComPtr
<IDataTransferManagerInterop
> dtmInterop
;
641 ComPtr
<IDataTransferManager
> dtm
;
643 HRESULT hr
= RoGetActivationFactory(
645 RuntimeClass_Windows_ApplicationModel_DataTransfer_DataTransferManager
)
647 IID_PPV_ARGS(&dtmInterop
));
649 FAILED(dtmInterop
->GetForWindow(hwnd
, IID_PPV_ARGS(&dtm
)))) {
650 return Err(NS_ERROR_FAILURE
);
653 auto callback
= Callback
<
654 ITypedEventHandler
<DataTransferManager
*, DataRequestedEventArgs
*>>(
655 [aCallback
](IDataTransferManager
*,
656 IDataRequestedEventArgs
* pArgs
) -> HRESULT
{
657 return aCallback(pArgs
);
660 EventRegistrationToken dataRequestedToken
;
661 if (FAILED(dtm
->add_DataRequested(callback
.Get(), &dataRequestedToken
)) ||
662 FAILED(dtmInterop
->ShowShareUIForWindow(hwnd
))) {
663 return Err(NS_ERROR_FAILURE
);
669 static Result
<Ok
, nsresult
> AddShareEventListeners(
670 const RefPtr
<mozilla::media::Refcountable
<MozPromiseHolder
<SharePromise
>>>&
672 const ComPtr
<IDataPackage
>& aDataPackage
) {
673 ComPtr
<IDataPackage3
> spDataPackage3
;
675 if (FAILED(aDataPackage
.As(&spDataPackage3
))) {
676 return Err(NS_ERROR_FAILURE
);
679 auto completedCallback
=
680 Callback
<ITypedEventHandler
<DataPackage
*, ShareCompletedEventArgs
*>>(
681 [aPromiseHolder
](IDataPackage
*,
682 IShareCompletedEventArgs
*) -> HRESULT
{
683 aPromiseHolder
->Resolve(true, __func__
);
687 EventRegistrationToken dataRequestedToken
;
688 if (FAILED(spDataPackage3
->add_ShareCompleted(completedCallback
.Get(),
689 &dataRequestedToken
))) {
690 return Err(NS_ERROR_FAILURE
);
693 ComPtr
<IDataPackage4
> spDataPackage4
;
694 if (SUCCEEDED(aDataPackage
.As(&spDataPackage4
))) {
695 // Use SharedCanceled API only on supported versions of Windows
696 // So that the older ones can still use ShareUrl()
698 auto canceledCallback
=
699 Callback
<ITypedEventHandler
<DataPackage
*, IInspectable
*>>(
700 [aPromiseHolder
](IDataPackage
*, IInspectable
*) -> HRESULT
{
701 aPromiseHolder
->Reject(NS_ERROR_FAILURE
, __func__
);
705 if (FAILED(spDataPackage4
->add_ShareCanceled(canceledCallback
.Get(),
706 &dataRequestedToken
))) {
707 return Err(NS_ERROR_FAILURE
);
715 RefPtr
<SharePromise
> WindowsUIUtils::Share(nsAutoString aTitle
,
718 auto promiseHolder
= MakeRefPtr
<
719 mozilla::media::Refcountable
<MozPromiseHolder
<SharePromise
>>>();
720 RefPtr
<SharePromise
> promise
= promiseHolder
->Ensure(__func__
);
723 auto result
= RequestShare([promiseHolder
, title
= std::move(aTitle
),
724 text
= std::move(aText
), url
= std::move(aUrl
)](
725 IDataRequestedEventArgs
* pArgs
) {
726 ComPtr
<IDataRequest
> spDataRequest
;
727 ComPtr
<IDataPackage
> spDataPackage
;
728 ComPtr
<IDataPackage2
> spDataPackage2
;
729 ComPtr
<IDataPackagePropertySet
> spDataPackageProperties
;
731 if (FAILED(pArgs
->get_Request(&spDataRequest
)) ||
732 FAILED(spDataRequest
->get_Data(&spDataPackage
)) ||
733 FAILED(spDataPackage
.As(&spDataPackage2
)) ||
734 FAILED(spDataPackage
->get_Properties(&spDataPackageProperties
))) {
735 promiseHolder
->Reject(NS_ERROR_FAILURE
, __func__
);
740 * Windows always requires a title, and an empty string does not work.
741 * Thus we trick the API by passing a whitespace when we have no title.
742 * https://docs.microsoft.com/en-us/windows/uwp/app-to-app/share-data
744 auto wTitle
= ConvertToWindowsString((title
.IsVoid() || title
.Length() == 0)
745 ? nsAutoString(u
" "_ns
)
747 if (wTitle
.isErr() ||
748 FAILED(spDataPackageProperties
->put_Title(wTitle
.unwrap().get()))) {
749 promiseHolder
->Reject(NS_ERROR_FAILURE
, __func__
);
753 // Assign even if empty, as Windows requires some data to share
754 auto wText
= ConvertToWindowsString(text
);
755 if (wText
.isErr() || FAILED(spDataPackage
->SetText(wText
.unwrap().get()))) {
756 promiseHolder
->Reject(NS_ERROR_FAILURE
, __func__
);
761 auto wUrl
= ConvertToWindowsString(url
);
763 promiseHolder
->Reject(NS_ERROR_FAILURE
, __func__
);
764 return wUrl
.unwrapErr();
767 ComPtr
<IUriRuntimeClassFactory
> uriFactory
;
768 ComPtr
<IUriRuntimeClass
> uri
;
770 auto hr
= GetActivationFactory(
771 HStringReference(RuntimeClass_Windows_Foundation_Uri
).Get(),
775 FAILED(uriFactory
->CreateUri(wUrl
.unwrap().get(), &uri
)) ||
776 FAILED(spDataPackage2
->SetWebLink(uri
.Get()))) {
777 promiseHolder
->Reject(NS_ERROR_FAILURE
, __func__
);
782 if (!StaticPrefs::widget_windows_share_wait_action_enabled()) {
783 promiseHolder
->Resolve(true, __func__
);
784 } else if (AddShareEventListeners(promiseHolder
, spDataPackage
).isErr()) {
785 promiseHolder
->Reject(NS_ERROR_FAILURE
, __func__
);
791 if (result
.isErr()) {
792 promiseHolder
->Reject(result
.unwrapErr(), __func__
);
795 promiseHolder
->Reject(NS_ERROR_FAILURE
, __func__
);
802 WindowsUIUtils::ShareUrl(const nsAString
& aUrlToShare
,
803 const nsAString
& aShareTitle
) {
805 text
.SetIsVoid(true);
806 WindowsUIUtils::Share(nsAutoString(aShareTitle
), text
,
807 nsAutoString(aUrlToShare
));