runmat_plot/gui/
native_window.rs1use crate::plots::Figure;
8use std::sync::{Arc, Mutex, OnceLock};
9
10#[derive(Debug, Clone)]
12pub enum NativeWindowResult {
13 Success(String),
14 Error(String),
15 WindowClosed,
16}
17
18impl std::fmt::Display for NativeWindowResult {
19 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
20 match self {
21 NativeWindowResult::Success(msg) => write!(f, "Success: {msg}"),
22 NativeWindowResult::Error(msg) => write!(f, "Error: {msg}"),
23 NativeWindowResult::WindowClosed => write!(f, "Window closed by user"),
24 }
25 }
26}
27
28pub struct NativeWindowManager {
30 is_initialized: bool,
31}
32
33impl Default for NativeWindowManager {
34 fn default() -> Self {
35 Self::new()
36 }
37}
38
39impl NativeWindowManager {
40 pub fn new() -> Self {
42 Self {
43 is_initialized: false,
44 }
45 }
46
47 pub fn initialize(&mut self) -> Result<(), String> {
49 if self.is_initialized {
50 return Ok(());
51 }
52
53 #[cfg(target_os = "macos")]
55 {
56 if !crate::gui::thread_manager::is_main_thread() {
57 return Err(
58 "Native window manager must be initialized on the main thread on macOS"
59 .to_string(),
60 );
61 }
62 }
63
64 self.is_initialized = true;
65 Ok(())
66 }
67
68 pub fn show_plot_native(&self, figure: Figure) -> Result<NativeWindowResult, String> {
70 if !self.is_initialized {
71 return Err("Native window manager not initialized".to_string());
72 }
73
74 #[cfg(target_os = "macos")]
76 {
77 self.show_plot_main_thread(figure)
78 }
79
80 #[cfg(not(target_os = "macos"))]
82 {
83 self.show_plot_threaded(figure)
84 }
85 }
86
87 #[cfg(target_os = "macos")]
89 fn show_plot_main_thread(&self, figure: Figure) -> Result<NativeWindowResult, String> {
90 use pollster;
91
92 let config = crate::gui::window::WindowConfig::default();
94 match pollster::block_on(crate::gui::PlotWindow::new(config)) {
99 Ok(mut window) => {
100 window.set_figure(figure);
102
103 match pollster::block_on(window.run()) {
105 Ok(_) => Ok(NativeWindowResult::Success(
106 "Plot window closed successfully".to_string(),
107 )),
108 Err(e) => Err(format!("Window runtime error: {e}")),
109 }
110 }
111 Err(e) => Err(format!("Failed to create plot window: {e}")),
112 }
113 }
114
115 #[cfg(not(target_os = "macos"))]
117 fn show_plot_threaded(&self, figure: Figure) -> Result<NativeWindowResult, String> {
118 match crate::gui::show_plot_global(figure) {
121 Ok(result) => match result {
122 crate::gui::GuiOperationResult::Success(msg) => {
123 Ok(NativeWindowResult::Success(msg))
124 }
125 crate::gui::GuiOperationResult::Cancelled(_msg) => {
126 Ok(NativeWindowResult::WindowClosed)
127 }
128 crate::gui::GuiOperationResult::Error { message, .. } => {
129 Ok(NativeWindowResult::Error(message))
130 }
131 },
132 Err(result) => match result {
133 crate::gui::GuiOperationResult::Success(msg) => {
134 Ok(NativeWindowResult::Success(msg))
135 }
136 crate::gui::GuiOperationResult::Cancelled(_msg) => {
137 Ok(NativeWindowResult::WindowClosed)
138 }
139 crate::gui::GuiOperationResult::Error { message, .. } => Err(message),
140 },
141 }
142 }
143}
144
145static NATIVE_WINDOW_MANAGER: OnceLock<Arc<Mutex<NativeWindowManager>>> = OnceLock::new();
147
148pub fn initialize_native_window() -> Result<(), String> {
150 let manager_mutex =
151 NATIVE_WINDOW_MANAGER.get_or_init(|| Arc::new(Mutex::new(NativeWindowManager::new())));
152
153 let mut manager = manager_mutex
154 .lock()
155 .map_err(|_| "Failed to acquire manager lock".to_string())?;
156
157 manager.initialize()
158}
159
160pub fn show_plot_native_window(figure: Figure) -> Result<String, String> {
162 let manager_mutex = NATIVE_WINDOW_MANAGER
163 .get()
164 .ok_or_else(|| "Native window system not initialized".to_string())?;
165
166 let manager = manager_mutex
167 .lock()
168 .map_err(|_| "Failed to acquire manager lock".to_string())?;
169
170 match manager.show_plot_native(figure) {
171 Ok(NativeWindowResult::Success(msg)) => Ok(msg),
172 Ok(NativeWindowResult::WindowClosed) => Ok("Plot window closed by user".to_string()),
173 Ok(NativeWindowResult::Error(msg)) => Err(msg),
174 Err(msg) => Err(msg),
175 }
176}
177
178pub fn is_native_window_available() -> bool {
180 NATIVE_WINDOW_MANAGER.get().is_some()
181}