#[cfg(not(alloc_frugal))]
use crate::compat::OnceLock;
#[cfg(not(alloc_frugal))]
use crate::core::MutexExt as _;
#[cfg(all(target_os = "android", not(alloc_frugal), not(embedded_surface)))]
use crate::platform::android::AndroidPlatform;
#[cfg(all(
any(target_env = "ohos", feature = "harmony"),
not(target_os = "android"),
not(alloc_frugal),
not(embedded_surface)
))]
use crate::platform::harmony::HarmonyPlatform;
#[cfg(all(not(alloc_frugal), target_os = "ios", not(embedded_surface)))]
use crate::platform::ios::IosMobilePlatform;
#[cfg(all(
target_os = "linux",
not(target_env = "ohos"),
not(alloc_frugal),
not(embedded_surface),
not(feature = "harmony")
))]
use crate::platform::linux::LinuxPlatform;
#[cfg(all(
not(alloc_frugal),
target_os = "macos",
not(embedded_surface),
any(feature = "macos", feature = "cocoa-legacy"),
// Must mirror the `create_native_platform` gate below exactly: this import has
// no other user, so if the two ever diverge the build warns about an unused
// import (or fails outright).
not(feature = "harmony")
))]
use crate::platform::macos::macos_bridge::SelectedMacOSPlatform;
#[cfg(all(not(embedded_surface), feature = "mobile-api"))]
use crate::platform::mobile;
#[cfg(not(alloc_frugal))]
pub use crate::platform::types::*;
#[cfg(all(
target_os = "linux",
not(target_env = "ohos"),
not(embedded_surface),
feature = "wayland-native",
not(feature = "harmony")
))]
use crate::platform::wayland::WaylandPlatform;
#[cfg(all(
not(alloc_frugal),
target_os = "windows",
not(embedded_surface),
// Must mirror its only user, `create_native_platform`, exactly.
not(feature = "harmony")
))]
use crate::platform::windows::WindowsPlatform;
#[cfg(not(alloc_frugal))]
use crate::platform::Platform;
#[cfg(all(
target_os = "linux",
not(target_env = "ohos"),
not(embedded_surface),
feature = "wayland-native",
not(feature = "harmony")
))]
fn is_wayland_session() -> bool {
std::env::var("WAYLAND_DISPLAY").is_ok()
|| std::env::var("XDG_SESSION_TYPE")
.map(|t| t.eq_ignore_ascii_case("wayland"))
.unwrap_or(false)
}
#[cfg(all(not(alloc_frugal), embedded_surface))]
fn create_native_platform() -> Box<dyn Platform> {
Box::new(crate::platform::stub::StubPlatform::new(
"embedded-runtime-stub",
crate::core::PlatformFamily::Embedded,
))
}
#[cfg(all(
not(alloc_frugal),
target_os = "windows",
not(embedded_surface),
// Mirrors the macOS/Linux/iOS arms: the `harmony` preview backend must win on
// any host, otherwise `--features full` defines this function twice.
not(feature = "harmony")
))]
fn create_native_platform() -> Box<dyn Platform> {
Box::new(WindowsPlatform::new())
}
#[cfg(all(
not(alloc_frugal),
target_os = "macos",
not(embedded_surface),
any(feature = "macos", feature = "cocoa-legacy"),
not(feature = "harmony")
))]
fn create_native_platform() -> Box<dyn Platform> {
Box::new(SelectedMacOSPlatform::new())
}
#[cfg(all(
not(alloc_frugal),
target_os = "macos",
not(embedded_surface),
not(any(feature = "macos", feature = "cocoa-legacy")),
not(feature = "harmony")
))]
fn create_native_platform() -> Box<dyn Platform> {
Box::new(crate::platform::stub::StubPlatform::new(
"macos-fallback-stub",
crate::core::PlatformFamily::Desktop,
))
}
#[cfg(all(
not(alloc_frugal),
target_os = "linux",
not(target_env = "ohos"),
not(embedded_surface),
feature = "wayland-native",
not(feature = "harmony")
))]
fn create_native_platform() -> Box<dyn Platform> {
if is_wayland_session() {
Box::new(WaylandPlatform::new())
} else {
Box::new(LinuxPlatform::new())
}
}
#[cfg(all(
not(alloc_frugal),
target_os = "linux",
not(target_env = "ohos"),
not(embedded_surface),
not(feature = "wayland-native"),
not(feature = "harmony")
))]
fn create_native_platform() -> Box<dyn Platform> {
Box::new(LinuxPlatform::new())
}
#[cfg(all(
not(alloc_frugal),
target_os = "android",
not(embedded_surface),
// Mirrors the HarmonyOS arm's own `not(target_os = "android")` exclusion, and
// keeps the two mutually exclusive when the feature is set on an Android host.
not(feature = "harmony")
))]
fn create_native_platform() -> Box<dyn Platform> {
Box::new(AndroidPlatform::new())
}
#[cfg(all(
any(target_env = "ohos", feature = "harmony"),
not(target_os = "android"),
not(alloc_frugal),
not(embedded_surface)
))]
fn create_native_platform() -> Box<dyn Platform> {
Box::new(HarmonyPlatform::new())
}
#[cfg(all(not(alloc_frugal), target_os = "ios", not(embedded_surface), not(feature = "harmony")))]
fn create_native_platform() -> Box<dyn Platform> {
Box::new(IosMobilePlatform::new())
}
#[cfg(all(not(alloc_frugal), not(embedded_surface), feature = "wasm", target_arch = "wasm32"))]
fn create_native_platform() -> Box<dyn Platform> {
Box::new(crate::platform::wasm::WasmPlatform::default())
}
#[cfg(all(
not(alloc_frugal),
not(embedded_surface),
not(all(feature = "wasm", target_arch = "wasm32")),
not(target_os = "android"),
not(any(target_env = "ohos", feature = "harmony")),
not(any(target_os = "windows", target_os = "macos", target_os = "linux", target_os = "ios"))
))]
fn create_native_platform() -> Box<dyn Platform> {
Box::new(crate::platform::stub::StubPlatform::new(
"unknown-runtime-stub",
crate::core::PlatformFamily::Desktop,
))
}
#[cfg(not(alloc_frugal))]
static PLATFORM: OnceLock<Box<dyn Platform>> = OnceLock::new();
#[cfg(not(alloc_frugal))]
pub fn get_platform() -> &'static dyn Platform {
if let Some(overridden) = PLATFORM_OVERRIDE.try_with(|slot| *slot.borrow()).ok().flatten() {
return overridden;
}
PLATFORM.get_or_init(create_native_platform).as_ref()
}
#[cfg(not(alloc_frugal))]
pub struct RecordingInvalidations {
calls:
crate::compat::Mutex<alloc::vec::Vec<(crate::core::ObjectId, Option<crate::core::Rect>)>>,
narrows: core::sync::atomic::AtomicBool,
}
#[cfg(not(alloc_frugal))]
impl RecordingInvalidations {
pub fn new() -> Self {
Self {
calls: crate::compat::Mutex::new(alloc::vec::Vec::new()),
narrows: core::sync::atomic::AtomicBool::new(true),
}
}
pub fn refusing_narrowing() -> Self {
Self {
calls: crate::compat::Mutex::new(alloc::vec::Vec::new()),
narrows: core::sync::atomic::AtomicBool::new(false),
}
}
pub fn calls(&self) -> alloc::vec::Vec<(crate::core::ObjectId, Option<crate::core::Rect>)> {
self.calls.lock_guard().clone()
}
pub fn clear(&self) {
self.calls.lock_guard().clear();
}
}
#[cfg(not(alloc_frugal))]
impl Default for RecordingInvalidations {
fn default() -> Self {
Self::new()
}
}
#[cfg(not(alloc_frugal))]
impl Platform for RecordingInvalidations {
fn backend_name(&self) -> &'static str {
"recording-test-backend"
}
fn family(&self) -> crate::core::PlatformFamily {
crate::core::PlatformFamily::Desktop
}
fn init(&self) {}
fn run(&self) {}
fn quit(&self) {}
fn create_window(
&self,
_title: &str,
_x: i32,
_y: i32,
_width: u32,
_height: u32,
) -> crate::core::ObjectId {
0
}
fn invalidate_surface(&self, id: crate::core::ObjectId) -> bool {
self.calls.lock_guard().push((id, None));
true
}
fn invalidate_surface_rect(&self, id: crate::core::ObjectId, rect: crate::core::Rect) -> bool {
if !self.narrows.load(core::sync::atomic::Ordering::SeqCst) {
return false;
}
self.calls.lock_guard().push((id, Some(rect)));
true
}
}
#[cfg(not(alloc_frugal))]
thread_local! {
#[allow(clippy::missing_const_for_thread_local)]
static PLATFORM_OVERRIDE: core::cell::RefCell<Option<&'static dyn Platform>> =
core::cell::RefCell::new(None);
}
#[cfg(not(alloc_frugal))]
pub fn with_recorded_invalidations<R>(
recorder: &'static RecordingInvalidations,
f: impl FnOnce() -> R,
) -> R {
struct Restore(Option<&'static dyn Platform>);
impl Drop for Restore {
fn drop(&mut self) {
let previous = self.0;
let _ = PLATFORM_OVERRIDE.try_with(|slot| *slot.borrow_mut() = previous);
}
}
let previous = PLATFORM_OVERRIDE
.try_with(|slot| {
let previous = *slot.borrow();
*slot.borrow_mut() = Some(recorder);
previous
})
.unwrap_or(None);
let _restore = Restore(previous);
f()
}
#[cfg(not(alloc_frugal))]
pub fn init() {
get_platform().init();
}
#[cfg(not(alloc_frugal))]
pub fn run() {
get_platform().run();
}
#[cfg(not(alloc_frugal))]
pub fn quit() {
get_platform().quit();
}
#[cfg(not(alloc_frugal))]
pub fn capabilities() -> PlatformCapabilities {
get_platform().capabilities()
}
#[cfg(not(alloc_frugal))]
pub fn backend_name() -> &'static str {
get_platform().backend_name()
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum RuntimeGuiMode {
NativeInteractive,
PreviewOrStub,
}
#[cfg(not(alloc_frugal))]
pub fn runtime_gui_mode_for(platform: &dyn Platform) -> RuntimeGuiMode {
match platform.backend_name() {
"cocoa" | "WindowsPlatform" => RuntimeGuiMode::NativeInteractive,
"wayland" => {
#[cfg(all(target_os = "linux", feature = "wayland-native"))]
{
RuntimeGuiMode::NativeInteractive
}
#[cfg(not(all(target_os = "linux", feature = "wayland-native")))]
{
RuntimeGuiMode::PreviewOrStub
}
}
"gtk" => {
#[cfg(all(target_os = "linux", feature = "gtk-native"))]
{
RuntimeGuiMode::NativeInteractive
}
#[cfg(not(all(target_os = "linux", feature = "gtk-native")))]
{
RuntimeGuiMode::PreviewOrStub
}
}
"harmony-desktop"
| "harmony-state-backend"
| "macos-objc2-preview"
| "macos-fallback-stub"
| "android-state-backend"
| "ios-mobile-stub" => RuntimeGuiMode::PreviewOrStub,
_ => RuntimeGuiMode::PreviewOrStub,
}
}
#[cfg(not(alloc_frugal))]
pub fn runtime_gui_mode() -> RuntimeGuiMode {
runtime_gui_mode_for(get_platform())
}
#[cfg(not(alloc_frugal))]
pub fn dpi_scale_factor() -> f32 {
get_platform().dpi_scale_factor()
}
#[cfg(feature = "mobile-api")]
pub fn mobile_backend_name() -> &'static str {
#[cfg(not(embedded_surface))]
{
if let Some(ext) = get_platform().mobile_extension() {
return match ext.mobile_backend() {
crate::platform::types::MobileBackend::Android => "android-mobile",
crate::platform::types::MobileBackend::Ios => "ios-mobile",
crate::platform::types::MobileBackend::HarmonyMobile => "harmony-mobile",
};
}
mobile::get_mobile_platform().backend_name()
}
#[cfg(embedded_surface)]
{
"embedded"
}
}
#[cfg(feature = "mobile-api")]
pub fn mobile_attach_to_native_view(native_handle: usize) -> bool {
#[cfg(not(embedded_surface))]
{
if let Some(ext) = get_platform().mobile_extension() {
return ext.attach_to_native_view(native_handle);
}
mobile::get_mobile_platform().attach_to_native_view(native_handle)
}
#[cfg(embedded_surface)]
{
let _ = native_handle;
false
}
}