ventana_backend_auto/
lib.rs1pub mod backend;
2
3use {
4 backend::{
5 appkit::AppKit,
6 linux::Linux,
7 win32::Win32,
8 },
9 hal::{
10 backend::Backend as HalBackend,
11 error::RequestError,
12 monitor::BackendMonitor,
13 settings::WindowSettings,
14 window::BackendWindow,
15 },
16 std::{
17 collections::VecDeque,
18 fmt::Debug,
19 sync::{
20 Arc,
21 LazyLock,
22 Mutex,
23 },
24 },
25};
26
27#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
28pub enum Backend {
29 #[default]
30 Win32 = 0,
31 AppKit = 1,
32 X11 = 2,
33 Wayland = 3,
34 Web = 4,
35 Android = 5,
36 UIKit = 6,
37}
38
39impl Backend {
40 pub fn backend(self) -> Option<&'static dyn HalBackend> {
41 match self {
42 Backend::Win32 => Win32::backend(),
43 Backend::AppKit => AppKit::backend(),
44 Backend::X11 => Linux::x11(),
45 Backend::Wayland => Linux::wayland(),
46 Backend::Web => unimplemented!(),
47 Backend::Android => unimplemented!(),
48 Backend::UIKit => unimplemented!(),
49 }
50 }
51
52 pub fn is_available(&self) -> bool {
53 match self {
54 Backend::Win32 => Win32::is_available(),
55 Backend::AppKit => AppKit::is_available(),
56 Backend::X11 => Linux::is_x11_available(),
57 Backend::Wayland => Linux::is_wayland_available(),
58 Backend::Web => false,
59 Backend::Android => false,
60 Backend::UIKit => false,
61 }
62 }
63}
64
65static PREFERENCES: LazyLock<Mutex<&'static [Backend]>> = LazyLock::new(|| {
66 Mutex::new(&[
67 Backend::Win32,
68 Backend::AppKit,
69 Backend::X11,
70 Backend::Wayland,
71 Backend::Web,
72 Backend::Android,
73 Backend::UIKit,
74 ])
75});
76
77#[derive(Clone)]
78pub struct AutoBackend(&'static dyn HalBackend);
79
80impl Debug for AutoBackend {
81 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
82 write!(f, "{}", self.name())
83 }
84}
85
86impl HalBackend for AutoBackend {
87 fn instance() -> Option<&'static Self>
88 where
89 Self: Sized,
90 {
91 static INSTANCE: LazyLock<Option<AutoBackend>> =
92 LazyLock::new(|| AutoBackend::auto().ok().map(AutoBackend));
93 INSTANCE.as_ref()
94 }
95
96 fn is_available() -> bool
97 where
98 Self: Sized,
99 {
100 Win32::is_available() || Linux::is_available() || AppKit::is_available()
101 }
102
103 fn name(&self) -> &'static str {
104 self.0.name()
105 }
106
107 fn create_window(&self, settings: WindowSettings) -> Result<Arc<dyn BackendWindow>, RequestError> {
108 self.0.create_window(settings)
109 }
110
111 fn list_available_monitors(&self) -> Result<VecDeque<Arc<dyn BackendMonitor>>, RequestError> {
112 self.0.list_available_monitors()
113 }
114
115 fn primary_monitor(&self) -> Result<Arc<dyn BackendMonitor>, RequestError> {
116 self.0.primary_monitor()
117 }
118}
119
120impl AutoBackend {
121 fn auto() -> Result<&'static dyn HalBackend, RequestError> {
123 let Some(backend) = PREFERENCES.lock().unwrap().iter().find(|b| b.is_available()) else {
124 return Err(RequestError::not_supported("no supported backend available to auto-select from"));
125 };
126 backend.backend().ok_or(RequestError::not_supported("failed to initialize backend"))
127 }
128
129 pub fn set_preferences(preferences: &'static [Backend]) {
133 *PREFERENCES.lock().unwrap() = preferences;
134 }
135}