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:
daxpedda
2024-08-05 20:51:38 +02:00
committed by Kirill Chibisov
parent f3d1f922f9
commit fa3ec006e2
12 changed files with 83 additions and 21 deletions

View File

@@ -16,7 +16,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};
@@ -33,7 +33,7 @@ use crate::event_loop::{
use crate::platform::macos::ActivationPolicy;
use crate::platform::pump_events::PumpStatus;
use crate::platform_impl::platform::cursor::CustomCursor;
use crate::window::{CustomCursor as RootCustomCursor, CustomCursorSource};
use crate::window::{CustomCursor as RootCustomCursor, CustomCursorSource, Theme};
#[derive(Default)]
pub struct PanicInfo {
@@ -106,6 +106,17 @@ impl ActiveEventLoop {
rwh_05::RawDisplayHandle::AppKit(rwh_05::AppKitDisplayHandle::empty())
}
#[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(

View File

@@ -1645,14 +1645,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>) {
@@ -1835,7 +1839,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(),