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/. */
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"
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 /* 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
60 namespace ViewManagement
{
61 enum UserInteractionMode
{
62 UserInteractionMode_Mouse
= 0,
63 UserInteractionMode_Touch
= 1
67 } // namespace Windows
72 # ifndef RuntimeClass_Windows_UI_ViewManagement_UIViewSettings
73 # define RuntimeClass_Windows_UI_ViewManagement_UIViewSettings \
74 L"Windows.UI.ViewManagement.UIViewSettings"
77 # if WINVER_MAXVER < 0x0A00
81 namespace ViewManagement
{
82 interface IUIViewSettings
;
83 MIDL_INTERFACE("C63657F6-8850-470D-88F8-455E16EA2C26")
84 IUIViewSettings
: public IInspectable
{
86 virtual HRESULT STDMETHODCALLTYPE
get_UserInteractionMode(
87 UserInteractionMode
* value
) = 0;
90 extern const __declspec(selectany
) IID
& IID_IUIViewSettings
=
91 __uuidof(IUIViewSettings
);
92 } // namespace ViewManagement
94 } // namespace Windows
98 # ifndef IUIViewSettingsInterop
100 using IUIViewSettingsInterop
= interface IUIViewSettingsInterop
;
102 MIDL_INTERFACE("3694dbf9-8f68-44be-8ff5-195c98ede8a6")
103 IUIViewSettingsInterop
: public IInspectable
{
105 virtual HRESULT STDMETHODCALLTYPE
GetForWindow(HWND hwnd
, REFIID riid
,
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
{
118 virtual HRESULT STDMETHODCALLTYPE
GetForWindow(
119 HWND appWindow
, REFIID riid
, void** dataTransferManager
) = 0;
120 virtual HRESULT STDMETHODCALLTYPE
ShowShareUIForWindow(HWND appWindow
) = 0;
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
{
132 virtual HRESULT STDMETHODCALLTYPE
add_ShareCanceled(
133 __FITypedEventHandler_2_Windows__CApplicationModel__CDataTransfer__CDataPackage_IInspectable
*
135 EventRegistrationToken
* token
) = 0;
136 virtual HRESULT STDMETHODCALLTYPE
remove_ShareCanceled(
137 EventRegistrationToken token
) = 0;
142 # ifndef RuntimeClass_Windows_UI_ViewManagement_UISettings
143 # define RuntimeClass_Windows_UI_ViewManagement_UISettings \
144 L"Windows.UI.ViewManagement.UISettings"
146 # if WINDOWS_FOUNDATION_UNIVERSALAPICONTRACT_VERSION < 0x80000
150 namespace ViewManagement
{
153 class UISettingsAutoHideScrollBarsChangedEventArgs
;
154 interface IUISettingsAutoHideScrollBarsChangedEventArgs
;
155 MIDL_INTERFACE("87afd4b2-9146-5f02-8f6b-06d454174c0f")
156 IUISettingsAutoHideScrollBarsChangedEventArgs
: public IInspectable
{};
158 } // namespace ViewManagement
160 } // namespace Windows
165 namespace Foundation
{
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."
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
206 namespace ViewManagement
{
208 class UISettingsAutoHideScrollBarsChangedEventArgs
;
209 interface IUISettings5
;
210 MIDL_INTERFACE("5349d588-0cb5-5f05-bd34-706b3231f0bd")
211 IUISettings5
: public IInspectable
{
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
*
217 EventRegistrationToken
* token
) = 0;
218 virtual HRESULT STDMETHODCALLTYPE
remove_AutoHideScrollBarsChanged(
219 EventRegistrationToken token
) = 0;
221 } // namespace ViewManagement
223 } // namespace Windows
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
)
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
);
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
);
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());
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
);
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
);
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
);
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();
324 bool WindowsUIUtils::GetInTabletMode() {
325 MOZ_DIAGNOSTIC_ASSERT(NS_IsMainThread());
326 if (sInTabletModeState
== TabletModeState::Unknown
) {
327 UpdateInTabletMode();
329 return sInTabletModeState
== TabletModeState::On
;
333 WindowsUIUtils::GetInTabletMode(bool* aResult
) {
334 *aResult
= GetInTabletMode();
338 static IInspectable
* GetUISettings() {
339 MOZ_DIAGNOSTIC_ASSERT(NS_IsMainThread());
341 // We need to keep this alive for ~ever so that change callbacks work as
343 static StaticRefPtr
<IInspectable
> sUiSettingsAsInspectable
;
345 if (!IsWin10OrLater()) {
346 // Windows.UI.ViewManagement.UISettings is Win10+ only.
350 if (!sUiSettingsAsInspectable
) {
351 ComPtr
<IInspectable
> uiSettingsAsInspectable
;
352 ::RoActivateInstance(
353 HStringReference(RuntimeClass_Windows_UI_ViewManagement_UISettings
)
355 &uiSettingsAsInspectable
);
356 if (NS_WARN_IF(!uiSettingsAsInspectable
)) {
360 ComPtr
<IUISettings5
> uiSettings5
;
361 if (SUCCEEDED(uiSettingsAsInspectable
.As(&uiSettings5
))) {
362 EventRegistrationToken unusedToken
;
363 auto callback
= Callback
<ITypedEventHandler
<
364 UISettings
*, UISettingsAutoHideScrollBarsChangedEventArgs
*>>(
366 // Scrollbar sizes change layout.
367 LookAndFeel::NotifyChangedAllWindows(
368 widget::ThemeChangeKind::StyleAndLayout
);
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
;
379 Callback
<ITypedEventHandler
<UISettings
*, IInspectable
*>>([](auto...) {
380 // Text scale factor changes style and layout.
381 LookAndFeel::NotifyChangedAllWindows(
382 widget::ThemeChangeKind::StyleAndLayout
);
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
;
393 Callback
<ITypedEventHandler
<UISettings
*, IInspectable
*>>([](auto...) {
394 // System color changes change style only.
395 LookAndFeel::NotifyChangedAllWindows(
396 widget::ThemeChangeKind::Style
);
399 (void)NS_WARN_IF(FAILED(
400 uiSettings3
->add_ColorValuesChanged(callback
.Get(), &unusedToken
)));
403 sUiSettingsAsInspectable
= dont_AddRef(uiSettingsAsInspectable
.Detach());
404 ClearOnShutdown(&sUiSettingsAsInspectable
);
407 return sUiSettingsAsInspectable
.get();
413 Maybe
<nscolor
> WindowsUIUtils::GetAccentColor(int aTone
) {
414 MOZ_ASSERT(aTone
>= -3);
415 MOZ_ASSERT(aTone
<= 3);
417 ComPtr
<IInspectable
> settings
= GetUISettings();
418 if (NS_WARN_IF(!settings
)) {
421 ComPtr
<IUISettings3
> uiSettings3
;
422 if (NS_WARN_IF(FAILED(settings
.As(&uiSettings3
)))) {
426 auto colorType
= UIColorType(int(UIColorType_Accent
) + aTone
);
427 if (NS_WARN_IF(FAILED(uiSettings3
->GetColorValue(colorType
, &color
)))) {
430 return Some(NS_RGBA(color
.R
, color
.G
, color
.B
, color
.A
));
436 Maybe
<nscolor
> WindowsUIUtils::GetSystemColor(ColorScheme aScheme
,
439 if (!StaticPrefs::widget_windows_uwp_system_colors_enabled()) {
443 // https://docs.microsoft.com/en-us/windows/apps/design/style/color
444 // Is a useful resource to see which values have decent contrast.
445 if (StaticPrefs::widget_windows_uwp_system_colors_highlight_accent()) {
446 if (aSysColor
== COLOR_HIGHLIGHT
) {
447 int tone
= aScheme
== ColorScheme::Light
? 0 : -1;
448 if (auto c
= GetAccentColor(tone
)) {
452 if (aSysColor
== COLOR_HIGHLIGHTTEXT
&& GetAccentColor()) {
453 return Some(NS_RGBA(255, 255, 255, 255));
457 if (aScheme
== ColorScheme::Dark
) {
458 // There are no explicitly dark colors in UWP, other than the highlight
463 auto knownType
= [&]() -> Maybe
<UIElementType
> {
464 # define MAP(_win32, _uwp) \
465 case COLOR_##_win32: \
466 return Some(UIElementType_##_uwp)
468 MAP(HIGHLIGHT
, Highlight
);
469 MAP(HIGHLIGHTTEXT
, HighlightText
);
470 MAP(ACTIVECAPTION
, ActiveCaption
);
471 MAP(BTNFACE
, ButtonFace
);
472 MAP(BTNTEXT
, ButtonText
);
473 MAP(CAPTIONTEXT
, CaptionText
);
474 MAP(GRAYTEXT
, GrayText
);
475 MAP(HOTLIGHT
, Hotlight
);
476 MAP(INACTIVECAPTION
, InactiveCaption
);
477 MAP(INACTIVECAPTIONTEXT
, InactiveCaptionText
);
479 MAP(WINDOWTEXT
, WindowText
);
488 ComPtr
<IInspectable
> settings
= GetUISettings();
489 if (NS_WARN_IF(!settings
)) {
492 ComPtr
<IUISettings
> uiSettings
;
493 if (NS_WARN_IF(FAILED(settings
.As(&uiSettings
)))) {
497 if (NS_WARN_IF(FAILED(uiSettings
->UIElementColor(*knownType
, &color
)))) {
500 return Some(NS_RGBA(color
.R
, color
.G
, color
.B
, color
.A
));
505 bool WindowsUIUtils::ComputeOverlayScrollbars() {
507 if (!IsWin11OrLater()) {
508 // While in theory Windows 10 supports overlay scrollbar settings, it's off
509 // by default and it's untested whether our Win10 scrollbar drawing code
510 // deals with it properly.
513 if (!StaticPrefs::widget_windows_overlay_scrollbars_enabled()) {
516 ComPtr
<IInspectable
> settings
= GetUISettings();
517 if (NS_WARN_IF(!settings
)) {
520 ComPtr
<IUISettings5
> uiSettings5
;
521 if (NS_WARN_IF(FAILED(settings
.As(&uiSettings5
)))) {
524 boolean autoHide
= false;
525 if (NS_WARN_IF(FAILED(uiSettings5
->get_AutoHideScrollBars(&autoHide
)))) {
534 double WindowsUIUtils::ComputeTextScaleFactor() {
536 ComPtr
<IInspectable
> settings
= GetUISettings();
537 if (NS_WARN_IF(!settings
)) {
540 ComPtr
<IUISettings2
> uiSettings2
;
541 if (NS_WARN_IF(FAILED(settings
.As(&uiSettings2
)))) {
544 double scaleFactor
= 1.0;
545 if (NS_WARN_IF(FAILED(uiSettings2
->get_TextScaleFactor(&scaleFactor
)))) {
554 void WindowsUIUtils::UpdateInTabletMode() {
556 if (!IsWin10OrLater()) {
561 nsCOMPtr
<nsIWindowMediator
> winMediator(
562 do_GetService(NS_WINDOWMEDIATOR_CONTRACTID
, &rv
));
567 nsCOMPtr
<nsIWidget
> widget
;
568 nsCOMPtr
<mozIDOMWindowProxy
> navWin
;
570 rv
= winMediator
->GetMostRecentWindow(u
"navigator:browser",
571 getter_AddRefs(navWin
));
572 if (NS_FAILED(rv
) || !navWin
) {
573 // Fall back to the hidden window
574 nsCOMPtr
<nsIAppShellService
> appShell(
575 do_GetService(NS_APPSHELLSERVICE_CONTRACTID
));
577 rv
= appShell
->GetHiddenDOMWindow(getter_AddRefs(navWin
));
578 if (NS_FAILED(rv
) || !navWin
) {
583 nsPIDOMWindowOuter
* win
= nsPIDOMWindowOuter::From(navWin
);
584 widget
= widget::WidgetUtils::DOMWindowToWidget(win
);
590 HWND winPtr
= (HWND
)widget
->GetNativeData(NS_NATIVE_WINDOW
);
591 ComPtr
<IUIViewSettingsInterop
> uiViewSettingsInterop
;
593 HRESULT hr
= GetActivationFactory(
594 HStringReference(RuntimeClass_Windows_UI_ViewManagement_UIViewSettings
)
596 &uiViewSettingsInterop
);
600 ComPtr
<IUIViewSettings
> uiViewSettings
;
601 hr
= uiViewSettingsInterop
->GetForWindow(winPtr
,
602 IID_PPV_ARGS(&uiViewSettings
));
606 UserInteractionMode mode
;
607 hr
= uiViewSettings
->get_UserInteractionMode(&mode
);
612 TabletModeState oldTabletModeState
= sInTabletModeState
;
613 sInTabletModeState
= mode
== UserInteractionMode_Touch
? TabletModeState::On
614 : TabletModeState::Off
;
615 if (sInTabletModeState
!= oldTabletModeState
) {
616 nsCOMPtr
<nsIObserverService
> observerService
=
617 mozilla::services::GetObserverService();
618 observerService
->NotifyObservers(nullptr, "tablet-mode-change",
619 sInTabletModeState
== TabletModeState::On
627 struct HStringDeleter
{
628 using pointer
= HSTRING
;
629 void operator()(pointer aString
) { WindowsDeleteString(aString
); }
632 using HStringUniquePtr
= UniquePtr
<HSTRING
, HStringDeleter
>;
634 Result
<HStringUniquePtr
, HRESULT
> ConvertToWindowsString(
635 const nsAString
& aStr
) {
637 HRESULT hr
= WindowsCreateString(PromiseFlatString(aStr
).get(), aStr
.Length(),
642 return HStringUniquePtr(rawStr
);
645 static Result
<Ok
, nsresult
> RequestShare(
646 const std::function
<HRESULT(IDataRequestedEventArgs
* pArgs
)>& aCallback
) {
647 if (!IsWin10OrLater()) {
648 return Err(NS_ERROR_FAILURE
);
651 HWND hwnd
= GetForegroundWindow();
653 return Err(NS_ERROR_FAILURE
);
656 ComPtr
<IDataTransferManagerInterop
> dtmInterop
;
657 ComPtr
<IDataTransferManager
> dtm
;
659 HRESULT hr
= RoGetActivationFactory(
661 RuntimeClass_Windows_ApplicationModel_DataTransfer_DataTransferManager
)
663 IID_PPV_ARGS(&dtmInterop
));
665 FAILED(dtmInterop
->GetForWindow(hwnd
, IID_PPV_ARGS(&dtm
)))) {
666 return Err(NS_ERROR_FAILURE
);
669 auto callback
= Callback
<
670 ITypedEventHandler
<DataTransferManager
*, DataRequestedEventArgs
*>>(
671 [aCallback
](IDataTransferManager
*,
672 IDataRequestedEventArgs
* pArgs
) -> HRESULT
{
673 return aCallback(pArgs
);
676 EventRegistrationToken dataRequestedToken
;
677 if (FAILED(dtm
->add_DataRequested(callback
.Get(), &dataRequestedToken
)) ||
678 FAILED(dtmInterop
->ShowShareUIForWindow(hwnd
))) {
679 return Err(NS_ERROR_FAILURE
);
685 static Result
<Ok
, nsresult
> AddShareEventListeners(
686 const RefPtr
<mozilla::media::Refcountable
<MozPromiseHolder
<SharePromise
>>>&
688 const ComPtr
<IDataPackage
>& aDataPackage
) {
689 ComPtr
<IDataPackage3
> spDataPackage3
;
691 if (FAILED(aDataPackage
.As(&spDataPackage3
))) {
692 return Err(NS_ERROR_FAILURE
);
695 auto completedCallback
=
696 Callback
<ITypedEventHandler
<DataPackage
*, ShareCompletedEventArgs
*>>(
697 [aPromiseHolder
](IDataPackage
*,
698 IShareCompletedEventArgs
*) -> HRESULT
{
699 aPromiseHolder
->Resolve(true, __func__
);
703 EventRegistrationToken dataRequestedToken
;
704 if (FAILED(spDataPackage3
->add_ShareCompleted(completedCallback
.Get(),
705 &dataRequestedToken
))) {
706 return Err(NS_ERROR_FAILURE
);
709 ComPtr
<IDataPackage4
> spDataPackage4
;
710 if (SUCCEEDED(aDataPackage
.As(&spDataPackage4
))) {
711 // Use SharedCanceled API only on supported versions of Windows
712 // So that the older ones can still use ShareUrl()
714 auto canceledCallback
=
715 Callback
<ITypedEventHandler
<DataPackage
*, IInspectable
*>>(
716 [aPromiseHolder
](IDataPackage
*, IInspectable
*) -> HRESULT
{
717 aPromiseHolder
->Reject(NS_ERROR_FAILURE
, __func__
);
721 if (FAILED(spDataPackage4
->add_ShareCanceled(canceledCallback
.Get(),
722 &dataRequestedToken
))) {
723 return Err(NS_ERROR_FAILURE
);
731 RefPtr
<SharePromise
> WindowsUIUtils::Share(nsAutoString aTitle
,
734 auto promiseHolder
= MakeRefPtr
<
735 mozilla::media::Refcountable
<MozPromiseHolder
<SharePromise
>>>();
736 RefPtr
<SharePromise
> promise
= promiseHolder
->Ensure(__func__
);
739 auto result
= RequestShare([promiseHolder
, title
= std::move(aTitle
),
740 text
= std::move(aText
), url
= std::move(aUrl
)](
741 IDataRequestedEventArgs
* pArgs
) {
742 ComPtr
<IDataRequest
> spDataRequest
;
743 ComPtr
<IDataPackage
> spDataPackage
;
744 ComPtr
<IDataPackage2
> spDataPackage2
;
745 ComPtr
<IDataPackagePropertySet
> spDataPackageProperties
;
747 if (FAILED(pArgs
->get_Request(&spDataRequest
)) ||
748 FAILED(spDataRequest
->get_Data(&spDataPackage
)) ||
749 FAILED(spDataPackage
.As(&spDataPackage2
)) ||
750 FAILED(spDataPackage
->get_Properties(&spDataPackageProperties
))) {
751 promiseHolder
->Reject(NS_ERROR_FAILURE
, __func__
);
756 * Windows always requires a title, and an empty string does not work.
757 * Thus we trick the API by passing a whitespace when we have no title.
758 * https://docs.microsoft.com/en-us/windows/uwp/app-to-app/share-data
760 auto wTitle
= ConvertToWindowsString((title
.IsVoid() || title
.Length() == 0)
761 ? nsAutoString(u
" "_ns
)
763 if (wTitle
.isErr() ||
764 FAILED(spDataPackageProperties
->put_Title(wTitle
.unwrap().get()))) {
765 promiseHolder
->Reject(NS_ERROR_FAILURE
, __func__
);
769 // Assign even if empty, as Windows requires some data to share
770 auto wText
= ConvertToWindowsString(text
);
771 if (wText
.isErr() || FAILED(spDataPackage
->SetText(wText
.unwrap().get()))) {
772 promiseHolder
->Reject(NS_ERROR_FAILURE
, __func__
);
777 auto wUrl
= ConvertToWindowsString(url
);
779 promiseHolder
->Reject(NS_ERROR_FAILURE
, __func__
);
780 return wUrl
.unwrapErr();
783 ComPtr
<IUriRuntimeClassFactory
> uriFactory
;
784 ComPtr
<IUriRuntimeClass
> uri
;
786 auto hr
= GetActivationFactory(
787 HStringReference(RuntimeClass_Windows_Foundation_Uri
).Get(),
791 FAILED(uriFactory
->CreateUri(wUrl
.unwrap().get(), &uri
)) ||
792 FAILED(spDataPackage2
->SetWebLink(uri
.Get()))) {
793 promiseHolder
->Reject(NS_ERROR_FAILURE
, __func__
);
798 if (!StaticPrefs::widget_windows_share_wait_action_enabled()) {
799 promiseHolder
->Resolve(true, __func__
);
800 } else if (AddShareEventListeners(promiseHolder
, spDataPackage
).isErr()) {
801 promiseHolder
->Reject(NS_ERROR_FAILURE
, __func__
);
807 if (result
.isErr()) {
808 promiseHolder
->Reject(result
.unwrapErr(), __func__
);
811 promiseHolder
->Reject(NS_ERROR_FAILURE
, __func__
);
818 WindowsUIUtils::ShareUrl(const nsAString
& aUrlToShare
,
819 const nsAString
& aShareTitle
) {
821 text
.SetIsVoid(true);
822 WindowsUIUtils::Share(nsAutoString(aShareTitle
), text
,
823 nsAutoString(aUrlToShare
));