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 ComPtr
<IUISettings4
> uiSettings4
;
404 if (SUCCEEDED(uiSettingsAsInspectable
.As(&uiSettings4
))) {
405 EventRegistrationToken unusedToken
;
407 Callback
<ITypedEventHandler
<UISettings
*, IInspectable
*>>([](auto...) {
408 // Transparent effects changes change media queries only.
409 LookAndFeel::NotifyChangedAllWindows(
410 widget::ThemeChangeKind::MediaQueriesOnly
);
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();
427 Maybe
<nscolor
> WindowsUIUtils::GetAccentColor(int aTone
) {
428 MOZ_ASSERT(aTone
>= -3);
429 MOZ_ASSERT(aTone
<= 3);
431 ComPtr
<IInspectable
> settings
= GetUISettings();
432 if (NS_WARN_IF(!settings
)) {
435 ComPtr
<IUISettings3
> uiSettings3
;
436 if (NS_WARN_IF(FAILED(settings
.As(&uiSettings3
)))) {
440 auto colorType
= UIColorType(int(UIColorType_Accent
) + aTone
);
441 if (NS_WARN_IF(FAILED(uiSettings3
->GetColorValue(colorType
, &color
)))) {
444 return Some(NS_RGBA(color
.R
, color
.G
, color
.B
, color
.A
));
450 Maybe
<nscolor
> WindowsUIUtils::GetSystemColor(ColorScheme aScheme
,
453 if (!StaticPrefs::widget_windows_uwp_system_colors_enabled()) {
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
)) {
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
477 auto knownType
= [&]() -> Maybe
<UIElementType
> {
478 # define MAP(_win32, _uwp) \
479 case COLOR_##_win32: \
480 return Some(UIElementType_##_uwp)
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
);
493 MAP(WINDOWTEXT
, WindowText
);
502 ComPtr
<IInspectable
> settings
= GetUISettings();
503 if (NS_WARN_IF(!settings
)) {
506 ComPtr
<IUISettings
> uiSettings
;
507 if (NS_WARN_IF(FAILED(settings
.As(&uiSettings
)))) {
511 if (NS_WARN_IF(FAILED(uiSettings
->UIElementColor(*knownType
, &color
)))) {
514 return Some(NS_RGBA(color
.R
, color
.G
, color
.B
, color
.A
));
519 bool WindowsUIUtils::ComputeOverlayScrollbars() {
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.
527 if (!StaticPrefs::widget_windows_overlay_scrollbars_enabled()) {
530 ComPtr
<IInspectable
> settings
= GetUISettings();
531 if (NS_WARN_IF(!settings
)) {
534 ComPtr
<IUISettings5
> uiSettings5
;
535 if (NS_WARN_IF(FAILED(settings
.As(&uiSettings5
)))) {
538 boolean autoHide
= false;
539 if (NS_WARN_IF(FAILED(uiSettings5
->get_AutoHideScrollBars(&autoHide
)))) {
548 double WindowsUIUtils::ComputeTextScaleFactor() {
550 ComPtr
<IInspectable
> settings
= GetUISettings();
551 if (NS_WARN_IF(!settings
)) {
554 ComPtr
<IUISettings2
> uiSettings2
;
555 if (NS_WARN_IF(FAILED(settings
.As(&uiSettings2
)))) {
558 double scaleFactor
= 1.0;
559 if (NS_WARN_IF(FAILED(uiSettings2
->get_TextScaleFactor(&scaleFactor
)))) {
568 bool WindowsUIUtils::ComputeTransparencyEffects() {
569 constexpr bool kDefault
= true;
571 ComPtr
<IInspectable
> settings
= GetUISettings();
572 if (NS_WARN_IF(!settings
)) {
575 ComPtr
<IUISettings4
> uiSettings4
;
576 if (NS_WARN_IF(FAILED(settings
.As(&uiSettings4
)))) {
579 boolean transparencyEffects
= kDefault
;
580 if (NS_WARN_IF(FAILED(
581 uiSettings4
->get_AdvancedEffectsEnabled(&transparencyEffects
)))) {
584 return transparencyEffects
;
590 void WindowsUIUtils::UpdateInTabletMode() {
592 if (!IsWin10OrLater()) {
597 nsCOMPtr
<nsIWindowMediator
> winMediator(
598 do_GetService(NS_WINDOWMEDIATOR_CONTRACTID
, &rv
));
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
) {
619 nsPIDOMWindowOuter
* win
= nsPIDOMWindowOuter::From(navWin
);
620 widget
= widget::WidgetUtils::DOMWindowToWidget(win
);
626 HWND winPtr
= (HWND
)widget
->GetNativeData(NS_NATIVE_WINDOW
);
627 ComPtr
<IUIViewSettingsInterop
> uiViewSettingsInterop
;
629 HRESULT hr
= GetActivationFactory(
630 HStringReference(RuntimeClass_Windows_UI_ViewManagement_UIViewSettings
)
632 &uiViewSettingsInterop
);
636 ComPtr
<IUIViewSettings
> uiViewSettings
;
637 hr
= uiViewSettingsInterop
->GetForWindow(winPtr
,
638 IID_PPV_ARGS(&uiViewSettings
));
642 UserInteractionMode mode
;
643 hr
= uiViewSettings
->get_UserInteractionMode(&mode
);
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
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
) {
673 HRESULT hr
= WindowsCreateString(PromiseFlatString(aStr
).get(), aStr
.Length(),
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();
689 return Err(NS_ERROR_FAILURE
);
692 ComPtr
<IDataTransferManagerInterop
> dtmInterop
;
693 ComPtr
<IDataTransferManager
> dtm
;
695 HRESULT hr
= RoGetActivationFactory(
697 RuntimeClass_Windows_ApplicationModel_DataTransfer_DataTransferManager
)
699 IID_PPV_ARGS(&dtmInterop
));
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
);
721 static Result
<Ok
, nsresult
> AddShareEventListeners(
722 const RefPtr
<mozilla::media::Refcountable
<MozPromiseHolder
<SharePromise
>>>&
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__
);
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__
);
757 if (FAILED(spDataPackage4
->add_ShareCanceled(canceledCallback
.Get(),
758 &dataRequestedToken
))) {
759 return Err(NS_ERROR_FAILURE
);
767 RefPtr
<SharePromise
> WindowsUIUtils::Share(nsAutoString aTitle
,
770 auto promiseHolder
= MakeRefPtr
<
771 mozilla::media::Refcountable
<MozPromiseHolder
<SharePromise
>>>();
772 RefPtr
<SharePromise
> promise
= promiseHolder
->Ensure(__func__
);
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__
);
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
)
799 if (wTitle
.isErr() ||
800 FAILED(spDataPackageProperties
->put_Title(wTitle
.unwrap().get()))) {
801 promiseHolder
->Reject(NS_ERROR_FAILURE
, __func__
);
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__
);
813 auto wUrl
= ConvertToWindowsString(url
);
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(),
827 FAILED(uriFactory
->CreateUri(wUrl
.unwrap().get(), &uri
)) ||
828 FAILED(spDataPackage2
->SetWebLink(uri
.Get()))) {
829 promiseHolder
->Reject(NS_ERROR_FAILURE
, __func__
);
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__
);
843 if (result
.isErr()) {
844 promiseHolder
->Reject(result
.unwrapErr(), __func__
);
847 promiseHolder
->Reject(NS_ERROR_FAILURE
, __func__
);
854 WindowsUIUtils::ShareUrl(const nsAString
& aUrlToShare
,
855 const nsAString
& aShareTitle
) {
857 text
.SetIsVoid(true);
858 WindowsUIUtils::Share(nsAutoString(aShareTitle
), text
,
859 nsAutoString(aUrlToShare
));