Add ActiveEventLoop::system_theme()
This also fixes macOS returning `None` in `Window::theme()` if no theme override is set, instead it now returns the system theme. MacOS and Wayland were the only ones working correctly according to the documentation, which was an oversight. The documentation was "fixed" now. Fixes #3837.
This commit is contained in:
parent
54ff9c3bb5
commit
15b79b18e1
12 changed files with 82 additions and 20 deletions
|
|
@ -55,6 +55,7 @@ changelog entry.
|
|||
information is available. This "detailed monitors" can be used in `Window::set_fullscreen()` as
|
||||
well.
|
||||
- On Android, add `{Active,}EventLoopExtAndroid::android_app()` to access the app used to create the loop.
|
||||
- Add `ActiveEventLoop::system_theme()`, returning the current system theme.
|
||||
|
||||
### Changed
|
||||
|
||||
|
|
@ -111,3 +112,4 @@ changelog entry.
|
|||
|
||||
- On Web, pen events are now routed through to `WindowEvent::Cursor*`.
|
||||
- On macOS, fix panic when releasing not available monitor.
|
||||
- On MacOS, return the system theme in `Window::theme()` if no theme override is set.
|
||||
|
|
|
|||
|
|
@ -23,7 +23,7 @@ use crate::application::ApplicationHandler;
|
|||
use crate::error::{EventLoopError, OsError};
|
||||
use crate::monitor::MonitorHandle;
|
||||
use crate::platform_impl;
|
||||
use crate::window::{CustomCursor, CustomCursorSource, Window, WindowAttributes};
|
||||
use crate::window::{CustomCursor, CustomCursorSource, Theme, Window, WindowAttributes};
|
||||
|
||||
/// Provides a way to retrieve events from the system and from the windows that were registered to
|
||||
/// the events loop.
|
||||
|
|
@ -403,6 +403,17 @@ impl ActiveEventLoop {
|
|||
self.p.listen_device_events(allowed);
|
||||
}
|
||||
|
||||
/// Returns the current system theme.
|
||||
///
|
||||
/// Returns `None` if it cannot be determined on the current platform.
|
||||
///
|
||||
/// ## Platform-specific
|
||||
///
|
||||
/// - **iOS / Android / Wayland / x11 / Orbital:** Unsupported.
|
||||
pub fn system_theme(&self) -> Option<Theme> {
|
||||
self.p.system_theme()
|
||||
}
|
||||
|
||||
/// Sets the [`ControlFlow`].
|
||||
pub fn set_control_flow(&self, control_flow: ControlFlow) {
|
||||
self.p.set_control_flow(control_flow)
|
||||
|
|
|
|||
|
|
@ -605,6 +605,11 @@ impl ActiveEventLoop {
|
|||
#[inline]
|
||||
pub fn listen_device_events(&self, _allowed: DeviceEvents) {}
|
||||
|
||||
#[inline]
|
||||
pub fn system_theme(&self) -> Option<Theme> {
|
||||
None
|
||||
}
|
||||
|
||||
#[cfg(feature = "rwh_06")]
|
||||
#[inline]
|
||||
pub fn raw_display_handle_rwh_06(
|
||||
|
|
|
|||
|
|
@ -17,7 +17,7 @@ use core_foundation::runloop::{
|
|||
};
|
||||
use objc2::rc::{autoreleasepool, Retained};
|
||||
use objc2::runtime::ProtocolObject;
|
||||
use objc2::{msg_send_id, ClassType};
|
||||
use objc2::{msg_send_id, sel, ClassType};
|
||||
use objc2_app_kit::{NSApplication, NSApplicationActivationPolicy, NSWindow};
|
||||
use objc2_foundation::{MainThreadMarker, NSObjectProtocol};
|
||||
|
||||
|
|
@ -32,7 +32,7 @@ use crate::error::EventLoopError;
|
|||
use crate::event_loop::{ActiveEventLoop as RootWindowTarget, ControlFlow, DeviceEvents};
|
||||
use crate::platform::macos::ActivationPolicy;
|
||||
use crate::platform::pump_events::PumpStatus;
|
||||
use crate::window::{CustomCursor as RootCustomCursor, CustomCursorSource};
|
||||
use crate::window::{CustomCursor as RootCustomCursor, CustomCursorSource, Theme};
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct PanicInfo {
|
||||
|
|
@ -103,6 +103,17 @@ impl ActiveEventLoop {
|
|||
#[inline]
|
||||
pub fn listen_device_events(&self, _allowed: DeviceEvents) {}
|
||||
|
||||
#[inline]
|
||||
pub fn system_theme(&self) -> Option<Theme> {
|
||||
let app = NSApplication::sharedApplication(self.mtm);
|
||||
|
||||
if app.respondsToSelector(sel!(effectiveAppearance)) {
|
||||
Some(super::window_delegate::appearance_to_theme(&app.effectiveAppearance()))
|
||||
} else {
|
||||
Some(Theme::Light)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "rwh_06")]
|
||||
#[inline]
|
||||
pub fn raw_display_handle_rwh_06(
|
||||
|
|
|
|||
|
|
@ -1623,14 +1623,18 @@ impl WindowDelegate {
|
|||
}
|
||||
|
||||
pub fn theme(&self) -> Option<Theme> {
|
||||
// Note: We could choose between returning the value of `effectiveAppearance` or
|
||||
// `appearance`, depending on what the user is asking about:
|
||||
// - "how should I render on this particular frame".
|
||||
// - "what is the configuration for this window".
|
||||
//
|
||||
// We choose the latter for consistency with the `set_theme` call, though it might also be
|
||||
// useful to expose the former.
|
||||
Some(appearance_to_theme(unsafe { &*self.window().appearance()? }))
|
||||
unsafe { self.window().appearance() }
|
||||
.map(|appearance| appearance_to_theme(&appearance))
|
||||
.or_else(|| {
|
||||
let mtm = MainThreadMarker::from(self);
|
||||
let app = NSApplication::sharedApplication(mtm);
|
||||
|
||||
if app.respondsToSelector(sel!(effectiveAppearance)) {
|
||||
Some(super::window_delegate::appearance_to_theme(&app.effectiveAppearance()))
|
||||
} else {
|
||||
Some(Theme::Light)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
pub fn set_theme(&self, theme: Option<Theme>) {
|
||||
|
|
@ -1813,7 +1817,7 @@ fn dark_appearance_name() -> &'static NSString {
|
|||
ns_string!("NSAppearanceNameDarkAqua")
|
||||
}
|
||||
|
||||
fn appearance_to_theme(appearance: &NSAppearance) -> Theme {
|
||||
pub fn appearance_to_theme(appearance: &NSAppearance) -> Theme {
|
||||
let best_match = appearance.bestMatchFromAppearancesWithNames(&NSArray::from_id_slice(&[
|
||||
unsafe { NSAppearanceNameAqua.copy() },
|
||||
dark_appearance_name().copy(),
|
||||
|
|
|
|||
|
|
@ -24,7 +24,7 @@ use crate::application::ApplicationHandler;
|
|||
use crate::error::EventLoopError;
|
||||
use crate::event::Event;
|
||||
use crate::event_loop::{ActiveEventLoop as RootActiveEventLoop, ControlFlow, DeviceEvents};
|
||||
use crate::window::{CustomCursor, CustomCursorSource};
|
||||
use crate::window::{CustomCursor, CustomCursorSource, Theme};
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct ActiveEventLoop {
|
||||
|
|
@ -53,6 +53,11 @@ impl ActiveEventLoop {
|
|||
#[inline]
|
||||
pub fn listen_device_events(&self, _allowed: DeviceEvents) {}
|
||||
|
||||
#[inline]
|
||||
pub fn system_theme(&self) -> Option<Theme> {
|
||||
None
|
||||
}
|
||||
|
||||
#[cfg(feature = "rwh_06")]
|
||||
#[inline]
|
||||
pub fn raw_display_handle_rwh_06(
|
||||
|
|
|
|||
|
|
@ -864,6 +864,11 @@ impl ActiveEventLoop {
|
|||
x11_or_wayland!(match self; Self(evlp) => evlp.listen_device_events(allowed))
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn system_theme(&self) -> Option<Theme> {
|
||||
None
|
||||
}
|
||||
|
||||
#[cfg(feature = "rwh_06")]
|
||||
#[inline]
|
||||
pub fn raw_display_handle_rwh_06(
|
||||
|
|
|
|||
|
|
@ -25,7 +25,7 @@ use crate::keyboard::{
|
|||
PhysicalKey,
|
||||
};
|
||||
use crate::window::{
|
||||
CustomCursor as RootCustomCursor, CustomCursorSource, WindowId as RootWindowId,
|
||||
CustomCursor as RootCustomCursor, CustomCursorSource, Theme, WindowId as RootWindowId,
|
||||
};
|
||||
|
||||
fn convert_scancode(scancode: u8) -> (PhysicalKey, Option<NamedKey>) {
|
||||
|
|
@ -747,6 +747,11 @@ impl ActiveEventLoop {
|
|||
#[inline]
|
||||
pub fn listen_device_events(&self, _allowed: DeviceEvents) {}
|
||||
|
||||
#[inline]
|
||||
pub fn system_theme(&self) -> Option<Theme> {
|
||||
None
|
||||
}
|
||||
|
||||
#[cfg(feature = "rwh_06")]
|
||||
#[inline]
|
||||
pub fn raw_display_handle_rwh_06(
|
||||
|
|
|
|||
|
|
@ -611,6 +611,16 @@ impl ActiveEventLoop {
|
|||
self.runner.listen_device_events(allowed)
|
||||
}
|
||||
|
||||
pub fn system_theme(&self) -> Option<Theme> {
|
||||
backend::is_dark_mode(self.runner.window()).map(|is_dark_mode| {
|
||||
if is_dark_mode {
|
||||
Theme::Dark
|
||||
} else {
|
||||
Theme::Light
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
pub(crate) fn set_control_flow(&self, control_flow: ControlFlow) {
|
||||
self.runner.set_control_flow(control_flow)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -122,7 +122,7 @@ fn set_dark_mode_for_window(hwnd: HWND, is_dark_mode: bool) -> bool {
|
|||
}
|
||||
}
|
||||
|
||||
fn should_use_dark_mode() -> bool {
|
||||
pub fn should_use_dark_mode() -> bool {
|
||||
should_apps_use_dark_mode() && !is_high_contrast()
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -82,7 +82,7 @@ use crate::platform_impl::platform::{
|
|||
};
|
||||
use crate::utils::Lazy;
|
||||
use crate::window::{
|
||||
CustomCursor as RootCustomCursor, CustomCursorSource, WindowId as RootWindowId,
|
||||
CustomCursor as RootCustomCursor, CustomCursorSource, Theme, WindowId as RootWindowId,
|
||||
};
|
||||
|
||||
pub(crate) struct WindowData {
|
||||
|
|
@ -516,6 +516,10 @@ impl ActiveEventLoop {
|
|||
raw_input::register_all_mice_and_keyboards_for_raw_input(self.thread_msg_target, allowed);
|
||||
}
|
||||
|
||||
pub fn system_theme(&self) -> Option<Theme> {
|
||||
Some(if super::dark_mode::should_use_dark_mode() { Theme::Dark } else { Theme::Light })
|
||||
}
|
||||
|
||||
pub(crate) fn set_control_flow(&self, control_flow: ControlFlow) {
|
||||
self.runner_shared.set_control_flow(control_flow)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1367,14 +1367,14 @@ impl Window {
|
|||
self.window.maybe_queue_on_main(move |w| w.set_theme(theme))
|
||||
}
|
||||
|
||||
/// Returns the current window theme override.
|
||||
/// Returns the current window theme.
|
||||
///
|
||||
/// Returns `None` if the current theme is set as the system default, or if it cannot be
|
||||
/// determined on the current platform.
|
||||
/// Returns `None` if it cannot be determined on the current platform.
|
||||
///
|
||||
/// ## Platform-specific
|
||||
///
|
||||
/// - **iOS / Android / Wayland / x11 / Orbital:** Unsupported, returns `None`.
|
||||
/// - **iOS / Android / x11 / Orbital:** Unsupported.
|
||||
/// - **Wayland:** Only returns theme overrides.
|
||||
#[inline]
|
||||
pub fn theme(&self) -> Option<Theme> {
|
||||
let _span = tracing::debug_span!("winit::Window::theme",).entered();
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue