blob: 3f737b20fac6039c2423d36a61737fdd915dad87 [file] [log] [blame]
// Copyright 2025 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef UI_NATIVE_THEME_OS_SETTINGS_PROVIDER_H_
#define UI_NATIVE_THEME_OS_SETTINGS_PROVIDER_H_
#include <optional>
#include "base/callback_list.h"
#include "base/component_export.h"
#include "base/functional/callback.h"
#include "base/time/time.h"
#include "build/build_config.h"
#include "third_party/skia/include/core/SkColor.h"
#include "ui/color/color_provider_key.h"
#include "ui/native_theme/native_theme.h"
namespace ui {
#if BUILDFLAG(IS_ANDROID)
class OsSettingsProviderAndroid;
using OsSettingsProviderImpl = OsSettingsProviderAndroid;
#elif BUILDFLAG(IS_CHROMEOS)
class OsSettingsProviderAsh;
using OsSettingsProviderImpl = OsSettingsProviderAsh;
#elif BUILDFLAG(IS_MAC)
class OsSettingsProviderMac;
using OsSettingsProviderImpl = OsSettingsProviderMac;
#elif BUILDFLAG(IS_WIN)
class OsSettingsProviderWin;
using OsSettingsProviderImpl = OsSettingsProviderWin;
#else
class OsSettingsProvider;
using OsSettingsProviderImpl = OsSettingsProvider;
#endif
// A singleton used to query the operating system for theme-related settings.
// Callers should use `Get()` to obtain the current instance.
class COMPONENT_EXPORT(NATIVE_THEME) OsSettingsProvider {
public:
using SettingsChangedCallbackT = void(bool force_notify);
// Higher-numbered (i.e. higher-priority) providers override lower-priority
// ones. Within a priority class, the most-recently-created provider wins.
enum class PriorityLevel { kProduction = 0, kTesting, kLast = kTesting };
enum class ColorId {
kButtonFace,
kButtonHighlight,
kScrollbar,
kWindow,
kWindowText,
};
// The caret blink interval reported when the OS provides no value.
static constexpr auto kDefaultCaretBlinkInterval = base::Milliseconds(500);
// Creating a provider sets it as the object to be returned by `Get()`.
//
// NOTE: If you want to control behavior in tests, you probably want to use
// `MockOsSettingsProvider` instead of instantiating this or some other
// subclass.
explicit OsSettingsProvider(
PriorityLevel priority_level = PriorityLevel::kProduction);
OsSettingsProvider(const OsSettingsProvider&) = delete;
OsSettingsProvider& operator=(const OsSettingsProvider&) = delete;
// Unhooks this provider from the list of providers checked by `Get()`.
// Typically, this provider was the currently-active one, which means the
// previous provider will become active.
virtual ~OsSettingsProvider();
// Returns the most recently-constructed `OsSettingsProvider` that has not
// been destroyed. If there is no such provider, first creates an instance of
// `OsSettingsProviderImpl`.
//
// CAUTION: On Windows, this will not create an `OsSettingsProviderWin`
// outside the browser process, since it won't work elsewhere (due to sandbox)
// and shouldn't be needed anyway. It will still return a non-null pointer,
// but the default instance will be the base `OsSettingsProvider`, not the
// platform-specific one.
static OsSettingsProvider& Get();
// Registers a callback to be invoked when the OS settings change. The
// `force_notify` argument will be true if settings may have changed in a way
// that does not affect the return values of the functions below, but
// nevertheless should trigger theme updates. For example, a change that does
// not affect the default `ColorProviderKey`, but affects the values of colors
// inside that key's provider, would set this to `true`.
static base::CallbackListSubscription RegisterOsSettingsChangedCallback(
base::RepeatingCallback<SettingsChangedCallbackT> cb);
// Returns whether the dark color scheme is available at an OS level.
// NOTE: Even if this is false, it may be reasonable for Chrome to use a dark
// theme; see comments on `PreferredColorScheme()` below.
virtual bool DarkColorSchemeAvailable() const;
// Returns preferred color scheme based on OS-level factors, or
// `kNoPreference` if not set/applicable. This is not affected by e.g.
// `switches::kForceDarkMode`; that should be handled at the `NativeTheme`
// (i.e. caller) level.
// NOTE: It's possible for this to be `kDark` even if
// `DarkColorSchemeAvailable()` returns false, e.g. when the OS has no notion
// of a native "dark scheme" but is using colors that correspond to Chrome
// using a dark theme. A historical example would have been the "high contrast
// black" theme in old versions of Windows.
virtual NativeTheme::PreferredColorScheme PreferredColorScheme() const;
// Returns the appropriate material color palette source for this OS.
virtual ColorProviderKey::UserColorSource PreferredColorSource() const;
// Returns OS-level preferred contrast, or `kNoPreference` if not
// set/applicable. This is not affected by e.g.
// `switches::kForceHighContrast`; that should be handled at the `NativeTheme`
// (i.e. caller) level.
virtual NativeTheme::PreferredContrast PreferredContrast() const;
// Returns whether the OS prefers reduced transparency.
virtual bool PrefersReducedTransparency() const;
// Returns whether the OS prefers inverted colors.
virtual bool PrefersInvertedColors() const;
// Returns whether forced colors are active at the OS level. This implies that
// various methods above should check `Color()` to decide how to behave. (They
// do not do so by default because when forced colors are not active, system
// colors may give an incomplete or incorrect picture of desired behavior.)
// This is not affected by e.g. "page colors"; that should be handled at the
// `NativeTheme` (i.e. caller) level.
virtual bool ForcedColorsActive() const;
// Returns OS-level accent color, if any.
virtual std::optional<SkColor> AccentColor() const;
// Returns OS-level colors, if available.
virtual std::optional<SkColor> Color(ColorId color_id) const;
// Returns OS' current scheme variant, if any.
virtual std::optional<ColorProviderKey::SchemeVariant> SchemeVariant() const;
// Returns the interval between caret blinks. If this is zero, the caret will
// not blink.
virtual base::TimeDelta CaretBlinkInterval() const;
protected:
// Invokes all registered callbacks.
void NotifyOnSettingsChanged(bool force_notify = false);
private:
PriorityLevel priority_level_;
};
} // namespace ui
#endif // UI_NATIVE_THEME_OS_SETTINGS_PROVIDER_H_