/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
# ifndef RuntimeClass_Windows_UI_ViewManagement_UISettings # define RuntimeClass_Windows_UI_ViewManagement_UISettings \
L"Windows.UI.ViewManagement.UISettings" # endif # if WINDOWS_FOUNDATION_UNIVERSALAPICONTRACT_VERSION < 0x80000 namespace ABI { namespace Windows { namespace UI { namespace ViewManagement {
class UISettings; class UISettingsAutoHideScrollBarsChangedEventArgs;
interface IUISettingsAutoHideScrollBarsChangedEventArgs;
MIDL_INTERFACE("87afd4b2-9146-5f02-8f6b-06d454174c0f")
IUISettingsAutoHideScrollBarsChangedEventArgs : public IInspectable{};
} // namespace ViewManagement
} // namespace UI
} // namespace Windows
} // namespace ABI
namespace ABI { namespace Windows { namespace Foundation {
template <> struct __declspec(uuid("808aef30-2660-51b0-9c11-f75dd42006b4"))
ITypedEventHandler<ABI::Windows::UI::ViewManagement::UISettings*,
ABI::Windows::UI::ViewManagement::
UISettingsAutoHideScrollBarsChangedEventArgs*>
: ITypedEventHandler_impl<
ABI::Windows::Foundation::Internal::AggregateType<
ABI::Windows::UI::ViewManagement::UISettings*,
ABI::Windows::UI::ViewManagement::IUISettings*>,
ABI::Windows::Foundation::Internal::AggregateType<
ABI::Windows::UI::ViewManagement::
UISettingsAutoHideScrollBarsChangedEventArgs*,
ABI::Windows::UI::ViewManagement::
IUISettingsAutoHideScrollBarsChangedEventArgs*>> { staticconstwchar_t* z_get_rc_name_impl() { return L"Windows.Foundation.TypedEventHandler`2
L"UISettings, "
L"Windows.UI.ViewManagement."
L"UISettingsAutoHideScrollBarsChangedEventArgs>";
}
}; // Define a typedef for the parameterized interface specialization's mangled // name. This allows code which uses the mangled name for the parameterized // interface to access the correct parameterized interface specialization. typedef ITypedEventHandler<ABI::Windows::UI::ViewManagement::UISettings*,
ABI::Windows::UI::ViewManagement::
UISettingsAutoHideScrollBarsChangedEventArgs*>
__FITypedEventHandler_2_Windows__CUI__CViewManagement__CUISettings_Windows__CUI__CViewManagement__CUISettingsAutoHideScrollBarsChangedEventArgs_t; # define __FITypedEventHandler_2_Windows__CUI__CViewManagement__CUISettings_Windows__CUI__CViewManagement__CUISettingsAutoHideScrollBarsChangedEventArgs \
ABI::Windows::Foundation:: \
__FITypedEventHandler_2_Windows__CUI__CViewManagement__CUISettings_Windows__CUI__CViewManagement__CUISettingsAutoHideScrollBarsChangedEventArgs_t
} // namespace Foundation
} // namespace Windows
} // namespace ABI
// Since Win10 and Win11 tablet modes can't both be simultaneously active, we // only need one backing variable for the both of them. enumclass TabletModeState : uint8_t { Unknown, Off, On }; static TabletModeState sInTabletModeState = TabletModeState::Unknown;
static IInspectable* GetUISettings() {
MOZ_DIAGNOSTIC_ASSERT(NS_IsMainThread()); #ifndef __MINGW32__ // We need to keep this alive for ~ever so that change callbacks work as // expected, sigh. static StaticRefPtr<IInspectable> sUiSettingsAsInspectable;
if (!sUiSettingsAsInspectable) {
ComPtr<IInspectable> uiSettingsAsInspectable;
::RoActivateInstance(
HStringReference(RuntimeClass_Windows_UI_ViewManagement_UISettings)
.Get(),
&uiSettingsAsInspectable); if (NS_WARN_IF(!uiSettingsAsInspectable)) { return nullptr;
}
Maybe<nscolor> WindowsUIUtils::GetSystemColor(ColorScheme aScheme, int aSysColor) { #ifndef __MINGW32__ if (!StaticPrefs::widget_windows_uwp_system_colors_enabled()) { return Nothing();
}
// https://docs.microsoft.com/en-us/windows/apps/design/style/color // Is a useful resource to see which values have decent contrast. if (StaticPrefs::widget_windows_uwp_system_colors_highlight_accent()) { if (aSysColor == COLOR_HIGHLIGHT) { int tone = aScheme == ColorScheme::Light ? 0 : -1; if (auto c = GetAccentColor(tone)) { return c;
}
} if (aSysColor == COLOR_HIGHLIGHTTEXT && GetAccentColor()) { return Some(NS_RGBA(255, 255, 255, 255));
}
}
if (aScheme == ColorScheme::Dark) { // There are no explicitly dark colors in UWP, other than the highlight // colors above. return Nothing();
}
auto knownType = [&]() -> Maybe<UIElementType> { # define MAP(_win32, _uwp) \ case COLOR_##_win32: \ return Some(UIElementType_##_uwp) switch (aSysColor) {
MAP(HIGHLIGHT, Highlight);
MAP(HIGHLIGHTTEXT, HighlightText);
MAP(ACTIVECAPTION, ActiveCaption);
MAP(BTNFACE, ButtonFace);
MAP(BTNTEXT, ButtonText);
MAP(CAPTIONTEXT, CaptionText);
MAP(GRAYTEXT, GrayText);
MAP(HOTLIGHT, Hotlight);
MAP(INACTIVECAPTION, InactiveCaption);
MAP(INACTIVECAPTIONTEXT, InactiveCaptionText);
MAP(WINDOW, Window);
MAP(WINDOWTEXT, WindowText); default: return Nothing();
} # undef MAP
}(); if (!knownType) { return Nothing();
}
ComPtr<IInspectable> settings = GetUISettings(); if (NS_WARN_IF(!settings)) { return Nothing();
}
ComPtr<IUISettings> uiSettings; if (NS_WARN_IF(FAILED(settings.As(&uiSettings)))) { return Nothing();
}
Color color; if (NS_WARN_IF(FAILED(uiSettings->UIElementColor(*knownType, &color)))) { return Nothing();
} return Some(NS_RGBA(color.R, color.G, color.B, color.A)); #else return Nothing(); #endif
} bool WindowsUIUtils::ComputeOverlayScrollbars() { #ifndef __MINGW32__ if (!IsWin11OrLater()) { // While in theory Windows 10 supports overlay scrollbar settings, it's off // by default and it's untested whether our Win10 scrollbar drawing code // deals with it properly. returnfalse;
} if (!StaticPrefs::widget_windows_overlay_scrollbars_enabled()) { returnfalse;
}
ComPtr<IInspectable> settings = GetUISettings(); if (NS_WARN_IF(!settings)) { returnfalse;
}
ComPtr<IUISettings5> uiSettings5; if (NS_WARN_IF(FAILED(settings.As(&uiSettings5)))) { returnfalse;
}
boolean autoHide = false; if (NS_WARN_IF(FAILED(uiSettings5->get_AutoHideScrollBars(&autoHide)))) { returnfalse;
} return autoHide; #else returnfalse; #endif
}
void WindowsUIUtils::UpdateInWin10TabletMode() { if (IsWin11OrLater()) { // (In theory we should never get here under Win11; but it's conceivable // that there are third-party applications that try to "assist" legacy Win10 // apps by synthesizing Win10-style tablet-mode notifications.) return;
}
// The getter below relies on querying a HWND which is affine to the main // thread; its operation is not known to be thread-safe, let alone lock-free.
MOZ_DIAGNOSTIC_ASSERT(NS_IsMainThread());
// Cache: whether this device is believed to be capable of entering tablet mode. // // Meaningful only if `IsWin11OrLater()`. static Maybe<bool> sIsTabletCapable = Nothing();
// The UUID of a GPIO pin which indicates whether or not a convertible device is // currently in tablet mode. (We copy `DEFINE_GUID`'s implementation here since // we can't control `INITGUID`, which the canonical one is conditional on.) // // https://learn.microsoft.com/en-us/windows-hardware/drivers/gpiobtn/laptop-slate-mode-toggling-between-states #define MOZ_DEFINE_GUID(name, l, w1, w2, b1, b2, b3, b4, b5, b6, b7, b8) \
EXTERN_C const GUID DECLSPEC_SELECTANY name = { \
l, w1, w2, {b1, b2, b3, b4, b5, b6, b7, b8}} /* 317fc439-3f77-41c8-b09e-08ad63272aa3 */ MOZ_DEFINE_GUID(
MOZ_GUID_GPIOBUTTONS_LAPTOPSLATE_INTERFACE, 0x317fc439, 0x3f77, 0x41c8,
0xb0, 0x9e, 0x08, 0xad, 0x63, 0x27, 0x2a, 0xa3);
void WindowsUIUtils::UpdateInWin11TabletMode() { // The OS-level getter itself is threadsafe, but we retain the main-thread // restriction to parallel the Win10 getter's (presumed) restriction.
MOZ_DIAGNOSTIC_ASSERT(NS_IsMainThread());
if (!IsWin11OrLater()) { // We should ordinarily never reach this point in Win10 -- but there may // well be some third-party application out there that synthesizes Win11- // style tablet-mode notifications. return;
}
// *** *** *** WARNING: RELIANCE ON UNDOCUMENTED BEHAVIOR *** *** *** // // Windows 10's `UserInteractionMode` API is no longer useful under Windows // 11: it always returns `UserInteractionMode_Mouse`. // // The documented API to query whether we're in tablet mode (alt.: "slate // mode") under Windows 11 is `::GetSystemMetrics(SM_CONVERTIBLESLATEMODE)`. // This returns 0 if we are in slate mode and 1 otherwise... except on devices // where tablet mode is unavailable (such as desktops), in which case it // returns 0 unconditionally. // // Unfortunately, there is no documented API to determine whether // `SM_CONVERTIBLESLATEMODE` is `0` because the device is currently in slate // mode or because the device can never be in slate mode. // // As such, we follow Chromium's lead here, and attempt to determine // heuristically whether that API is going to return anything sensible. // (Indeed, the heuristic below is in large part taken from Chromium.)
if (sIsTabletCapable.isNothing()) { boolconst heuristic = ([]() -> bool { // If the user has set the relevant pref to override our tablet-detection // heuristics, go with that. switch (StaticPrefs::widget_windows_tablet_detection_override()) { case -1:
MOZ_LOG(gTabletModeLog, LogLevel::Info,
("TCH: override detected (-1)")); returnfalse; case 1:
MOZ_LOG(gTabletModeLog, LogLevel::Info,
("TCH: override detected (+1)")); returntrue; default: break;
}
// If ::GSM(SM_CONVERTIBLESLATEMODE) is _currently_ nonzero, we must be on // a system that does somnething with SM_CONVERTIBLESLATEMODE, so we can // trust it. if (::GetSystemMetrics(SM_CONVERTIBLESLATEMODE) != 0) {
MOZ_LOG(gTabletModeLog, LogLevel::Info,
("TCH: SM_CONVERTIBLESLATEMODE != 0")); returntrue;
}
// If the device does not support touch it can't possibly be a tablet. if (GetSystemMetrics(SM_MAXIMUMTOUCHES) == 0) {
MOZ_LOG(gTabletModeLog, LogLevel::Info,
("TCH: SM_MAXIMUMTOUCHES != 0")); returnfalse;
}
if (MOZ_LOG_TEST(gTabletModeLog, LogLevel::Info)) {
[&]() -> void { // Check to see if a particular registry key [1] exists, and what its // value is. // // This is not presently considered reliable, as some // non-tablet-capable devices have this registry key present, but not // set to 1 -- see bug 1932775, as well as comments in Chromium [2]. // // This is probably strictly redundant with the CONVERTIBLESLATEMODE // check above, so we only even look at it if we're logging. // // [1] https://learn.microsoft.com/en-us/windows-hardware/customize/desktop/unattend/microsoft-windows-gpiobuttons-convertibleslatemode // [2] https://source.chromium.org/chromium/chromium/src/+/main:base/win/win_util.cc;l=240;drc=5a02fc6cdee77d0a39e9c43a4c2a29bbccc88852 namespace Reg = mozilla::widget::WinRegistry;
Reg::Key key(
HKEY_LOCAL_MACHINE,
uR"(System\CurrentControlSet\Control\PriorityControl)"_ns,
Reg::KeyMode::QueryValue); if (!key) {
MOZ_LOG(gTabletModeLog, LogLevel::Info,
("TCH: \"PriorityControl\" registry path not found"));
}
autoconst valueType = key.GetValueType(u"ConvertibleSlateMode"_ns); if (valueType == Reg::ValueType::None) {
MOZ_LOG(gTabletModeLog, LogLevel::Info,
("TCH: 'ConvertibleSlateMode' not found")); return;
}
if (autoconst val =
key.GetValueAsDword(u"ConvertibleSlateMode"_ns)) {
MOZ_LOG(gTabletModeLog, LogLevel::Info,
("TCH: 'ConvertibleSlateMode' found; value is 0x%08" PRIX32,
*val));
} else {
MOZ_LOG(gTabletModeLog, LogLevel::Info,
("TCH: 'ConvertibleSlateMode' found, but not a DWORD " "(type=0x%08" PRIX32 ")",
uint32_t(valueType)));
}
}();
}
// (The next step at this point would usually be to call the function // "::CM_Get_Device_Interface_ListW()" -- but we don't care where the // associated device interface is actually mapped to; we only care // whether it's mapped at all. // // For our purposes, a zero-length null-terminated string doesn't count // as "present".) return err == CR_SUCCESS && size > 1;
}(); if (hasTabletGpioPin) {
MOZ_LOG(gTabletModeLog, LogLevel::Info,
("TCH: relevant GPIO interface found")); returntrue;
}
// If the device has no rotation sensor, it's _probably_ not a convertible // device. (There are exceptions! See bug 1918292.)
AR_STATE rotation_state; if (HRESULT hr = ::GetAutoRotationState(&rotation_state); !FAILED(hr)) { if ((rotation_state & (AR_NOT_SUPPORTED | AR_LAPTOP | AR_NOSENSOR)) !=
0) {
MOZ_LOG(gTabletModeLog, LogLevel::Info, ("TCH: no rotation sensor")); returnfalse;
}
}
// If the device returns `PlatformRoleSlate` for its POWER_PLATFORM_ROLE, // it's probably tablet-capable. // // The converse is known to be false; the tablet-capable Dell Inspiron 14 // 7445 2-in-1 returns `PlatformRoleMobile`. // // (Chromium checks for PlatformRoleMobile as well, but (e.g.) a Dell XPS // 15 9500 also returns `PlatformRoleMobile` despite *not* being tablet- // capable.)
POWER_PLATFORM_ROLE const role =
mozilla::widget::WinUtils::GetPowerPlatformRole(); if (role == PlatformRoleSlate) {
MOZ_LOG(gTabletModeLog, LogLevel::Info,
("TCH: role == PlatformRoleSlate")); returntrue;
}
// Without some specific indicator of tablet-capability, assume that we're // tablet-incapable.
MOZ_LOG(gTabletModeLog, LogLevel::Info,
("TCH: no indication; falling through")); returnfalse;
})();
sIsTabletCapable = Some(heuristic); // If we appear not to be tablet-capable, don't bother doing the check. // (We also don't need to send a signal.) if (!heuristic) {
sInTabletModeState = TabletModeState::Off; return;
}
} elseif (sIsTabletCapable == Some(false)) { // We've been in here before, and the heuristic came back false... but // somehow, we've just gotten an update for the convertible-slate-mode // state. // // Clearly the heuristic was wrong! // // TODO(rkraesig): should we add telemetry to see how often this gets hit?
MOZ_LOG(gTabletModeLog, LogLevel::Warning,
("recv'd update signal after false heuristic run; reversing"));
sIsTabletCapable = Some(true);
}
// at this point, we must be tablet-capable
MOZ_ASSERT(sIsTabletCapable == Some(true));
EventRegistrationToken dataRequestedToken; if (FAILED(spDataPackage3->add_ShareCompleted(completedCallback.Get(),
&dataRequestedToken))) { return Err(NS_ERROR_FAILURE);
}
ComPtr<IDataPackage4> spDataPackage4; if (SUCCEEDED(aDataPackage.As(&spDataPackage4))) { // Use SharedCanceled API only on supported versions of Windows // So that the older ones can still use ShareUrl()
/* * Windows always requires a title, and an empty string does not work. * Thus we trick the API by passing a whitespace when we have no title. * https://docs.microsoft.com/en-us/windows/uwp/app-to-app/share-data
*/ auto wTitle = ConvertToWindowsString((title.IsVoid() || title.Length() == 0)
? nsAutoString(u" "_ns)
: title); if (wTitle.isErr() ||
FAILED(spDataPackageProperties->put_Title(wTitle.unwrap().get()))) {
promiseHolder->Reject(NS_ERROR_FAILURE, __func__); return E_FAIL;
}
// Assign even if empty, as Windows requires some data to share auto wText = ConvertToWindowsString(text); if (wText.isErr() || FAILED(spDataPackage->SetText(wText.unwrap().get()))) {
promiseHolder->Reject(NS_ERROR_FAILURE, __func__); return E_FAIL;
}
if (!url.IsVoid()) { auto wUrl = ConvertToWindowsString(url); if (wUrl.isErr()) {
promiseHolder->Reject(NS_ERROR_FAILURE, __func__); return wUrl.unwrapErr();
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung ist noch experimentell.